Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #import <OpenGLES/ES2/glext.h>
- //we can't muck around with the pvrt code without going into objective-c++ mode, thus the .mm extension on Model.
- #import "PVRTModelPOD.h"
- #import "PVRTResourceFile.h" //for CPVRTResourceFile::SetReadPath and model loading
- #import "PVRTTextureAPI.h" //for PVRTTextureLoadFromPVR
- #include "PVRShell.h" //For debugging
- #import "Model.h"
- #import "GLProgram.h"
- // vertex attributes
- enum EVertexAttrib {
- VERTEX_ARRAY,
- NORMAL_ARRAY,
- TEXCOORD_ARRAY,
- TANGENT_ARRAY,
- BINORMAL_ARRAY,
- BONEWEIGHT_ARRAY,
- BONEINDEX_ARRAY,
- eNumAttribs
- };
- // shader uniforms
- enum ESkinnnedUniform {
- eViewProj,
- eLightPos,
- eBoneCount,
- eBoneMatrices,
- eBoneMatricesIT,
- ebUseDot3,
- eNumSkinnedUniforms
- };
- // Default
- // vertex attributes
- enum EDefaultVertexAttrib {
- DEFAULT_VERTEX_ARRAY,
- DEFAULT_TEXCOORD_ARRAY,
- eNumDefaultAttribs
- };
- // shader uniforms
- enum EDefaultUniform {
- eDefaultMVPMatrix,
- eDefaultUOffset,
- eNumDefaultUniforms
- };
- // Camera constants. Used for making the projection matrix
- const float g_fCameraNear = 4.0f;
- const float g_fCameraFar = 5000.0f;
- const float g_fDemoFrameRate = 1.0f / 30.0f;
- // The camera to use from the pod file
- const int g_ui32Camera = 0;
- /*
- // Group shader programs and their uniform locations together
- struct m_SkinnedShaderProgram
- {
- GLuint uiId;
- GLuint auiLoc[eNumSkinnedUniforms];
- };
- struct m_DefaultShaderProgram
- {
- GLuint uiId;
- GLuint auiLoc[eNumDefaultUniforms];
- };
- */
- // Variables to handle the animation in a time-based manner
- unsigned long m_iTimePrev;
- float m_fFrame;
- @implementation Model
- @synthesize defaultProgram;
- @synthesize skinnedVertexProgram;
- @synthesize textureProgram;
- @synthesize lightProgram;
- #pragma mark -
- #pragma mark Helper Methods
- -(void)setupShaders
- {
- //Setup shaders
- self.defaultProgram = [[GLProgram alloc]initWithVertexShaderFilename:@"VertShader" fragmentShaderFilename:@"FragShader"];
- [self.defaultProgram addAttribute:@"inVertex"];
- [self.defaultProgram addAttribute:@"inNormal"];
- [self.defaultProgram addAttribute:@"inTexCoord"];
- [self.defaultProgram link];
- /*
- self.defaultProgram = [[GLProgram alloc]initWithVertexShaderFilename:@"DefaultVertShader" fragmentShaderFilename:@"DefaultFragShader"];
- [self.defaultProgram addAttribute:@"inVertex"];
- [self.defaultProgram addAttribute:@"inTexCoord"];
- [self.defaultProgram link];
- self.skinnedVertexProgram = [[GLProgram alloc]initWithVertexShaderFilename:@"SkinnedVertShader" fragmentShaderFilename:@"SkinnedFragShader"];
- [self.skinnedVertexProgram addAttribute:@"inVertex"];
- [self.skinnedVertexProgram addAttribute:@"inNormal"];
- [self.skinnedVertexProgram addAttribute:@"inTangent"];
- [self.skinnedVertexProgram addAttribute:@"inBiNormal"];
- [self.skinnedVertexProgram addAttribute:@"inTexCoord"];
- [self.skinnedVertexProgram addAttribute:@"inBoneIndex"];
- [self.skinnedVertexProgram addAttribute:@"inBoneWeights"];
- [self.skinnedVertexProgram link];
- self.textureProgram = [[GLProgram alloc]initWithVertexShaderFilename:@"Print3DVertShader" fragmentShaderFilename:@"Print3DFragShader"];
- [self.textureProgram addAttribute:@"myVertex"];
- [self.textureProgram addAttribute:@"myUV"];
- [self.textureProgram addAttribute:@"myColour"];
- [self.textureProgram link];
- self.lightProgram = [[GLProgram alloc]initWithVertexShaderFilename:@"LightShader3D" fragmentShaderFilename:@"LightShader3D"];
- [self.lightProgram addAttribute:@"myVertex"];
- [self.lightProgram addAttribute:@"myNormal"];
- [self.lightProgram link];
- */
- }
- #pragma mark Mesh Setup
- -(void)loadVbosInScene:(CPVRTModelPOD*)scene
- {
- if (!vbo)
- vbo = new GLuint[scene->nNumMesh];
- if (!indexvbo)
- indexvbo = new GLuint[scene->nNumMesh];
- /*
- Load vertex data of all meshes in the scene into VBOs
- The meshes have been exported with the "Interleave Vectors" option,
- so all data is interleaved in the buffer at pMesh->pInterleaved.
- Interleaving data improves the memory access pattern and cache efficiency,
- thus it can be read faster by the hardware.
- */
- glGenBuffers(scene->nNumMesh, vbo);
- for(unsigned int i=0; i < scene->nNumMesh;i++)
- {
- SPODMesh& mesh = scene->pMesh[i];
- unsigned int size = mesh.nNumVertex * mesh.sVertex.nStride;
- assert(mesh.pInterleaved);
- assert(mesh.sFaces.pData);
- NSLog(@"size %d, interleaved 0x%x", size, mesh.pInterleaved);
- //shove vertex data into a vertex buffer object
- glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);
- glBufferData(GL_ARRAY_BUFFER, size, mesh.pInterleaved, GL_STATIC_DRAW);
- //shove index data into a vertex buffer object
- indexvbo[i] = 0;
- if(mesh.sFaces.pData)
- {
- glGenBuffers(1, &indexvbo[i]);
- size = PVRTModelPODCountIndices(mesh) * sizeof(GLshort);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbo[i]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, mesh.sFaces.pData, GL_STATIC_DRAW);
- }
- }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
- -(void)setupTexturesInScene:(CPVRTModelPOD*)scene withErrorString:(CPVRTString*)error
- {
- //load any textures for the scene's materials.
- //Initializes an array to lookup the textures
- //for each material in the scene.
- texture = new GLuint[scene->nNumMaterial];
- for(unsigned int i=0;i<scene->nNumMaterial;i++)
- {
- texture[i] = 0;
- SPODMaterial* mat = &scene->pMaterial[i];
- if(mat->nIdxTexDiffuse != -1)
- {
- //load the texture file.
- CPVRTString filenamePVR = scene->pTexture[mat->nIdxTexDiffuse].pszName;
- //todo: global buffer of textures Bad access error at this point.
- printf("%s", filenamePVR.c_str());
- if(PVRTTextureLoadFromPVR(filenamePVR.c_str(), &texture[i], NULL, true, 0) != PVR_SUCCESS)
- {
- //NSLog(@"texture load failed for file %s", filenamePVR.c_str());
- //More detailed error handling
- *error = "ERROR: Failed to load " + filenamePVR + ".";
- // Check to see if we're trying to load .pvr or not
- CPVRTString sFileExtension = PVRTStringGetFileExtension(filenamePVR);
- if(sFileExtension.toLower() != "pvr")
- *error += "Note: IntroducingPOD can only load pvr files.";
- }
- }
- }
- }
- #pragma mark -
- #pragma mark Setup and Initialization Methods
- - (void) load:(NSString*)filename
- {
- const char* cpath = [[NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] resourcePath]] cStringUsingEncoding: NSASCIIStringEncoding];
- printf("cpath %s\n", cpath);
- model = CPVRTModelPOD(); //todo: dealloc, also check if already alloc'd
- //CPVRTModelPOD* scene = (CPVRTModelPOD*)model;
- CPVRTResourceFile::SetReadPath(cpath);
- if(model.ReadFromFile([filename cStringUsingEncoding:NSASCIIStringEncoding]) != PVR_SUCCESS)
- {
- NSLog(@"ERROR: Couldn't load %@.", filename);
- delete &model;
- //model = NULL;
- return;
- }
- else
- {
- NSLog(@"Loading %@...", filename);
- CPVRTString errorStr;
- [self loadVbosInScene:&model];
- [self setupTexturesInScene:&model withErrorString:&errorStr];
- }
- }
- + (Model*) modelFromFile:(NSString*) filename
- {
- //Allocate memory for model
- Model* retval = [[Model alloc] init];
- //Load file for model
- [retval load:filename];
- [retval setupShaders];
- //Return a model after all that setup...finally!
- return [retval autorelease];
- }
- #pragma mark -
- #pragma mark Graphics Methods
- -(void)drawMeshWithNodeIndex:(int)i32NodeIndex withModelView:(PVRTMat4)view
- {
- int i32MeshIndex = model.pNode[i32NodeIndex].nIdx;
- SPODMesh* pMesh = &model.pMesh[i32MeshIndex];
- // bind the VBO for the mesh
- glBindBuffer(GL_ARRAY_BUFFER, vbo[i32MeshIndex]);
- // bind the index buffer, won't hurt if the handle is 0
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexvbo[i32MeshIndex]);
- // Enable the vertex attribute arrays
- glEnableVertexAttribArray(VERTEX_ARRAY);
- glEnableVertexAttribArray(NORMAL_ARRAY);
- glEnableVertexAttribArray(TEXCOORD_ARRAY);
- // Set the vertex attribute offsets
- glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
- glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
- glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
- /*
- The geometry can be exported in 4 ways:
- - Indexed Triangle list
- - Non-Indexed Triangle list
- - Indexed Triangle strips
- - Non-Indexed Triangle strips
- */
- if(pMesh->nNumStrips == 0)
- {
- if(indexvbo[i32MeshIndex])
- {
- // Indexed Triangle list
- glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
- }
- else
- {
- // Non-Indexed Triangle list
- glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
- }
- }
- else
- {
- int offset = 0;
- for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
- {
- if(indexvbo[i32MeshIndex])
- {
- // Indexed Triangle strips
- glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
- }
- else
- {
- // Non-Indexed Triangle strips
- glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
- }
- offset += pMesh->pnStripLength[i]+2;
- }
- }
- // Safely disable the vertex attribute arrays
- glDisableVertexAttribArray(VERTEX_ARRAY);
- glDisableVertexAttribArray(NORMAL_ARRAY);
- glDisableVertexAttribArray(TEXCOORD_ARRAY);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
- -(void)draw
- {
- //CPVRTModelPOD *scene = (CPVRTModelPOD*)model;
- // Clear the color and depth buffer
- //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // Use shader program
- [defaultProgram use];
- /*
- //Calculates the frame number to animate in a time-based manner.
- //Uses the shell function PVRShellGetTime() to get the time in milliseconds.
- int iTime = PVRShell::PVRShellGetTime();
- int iDeltaTime = iTime - m_iTimePrev;
- m_iTimePrev = iTime;
- m_fFrame += (float)iDeltaTime * g_fDemoFrameRate;
- if (m_fFrame > scene->nNumFrame - 1)
- m_fFrame = 0;
- */
- /*
- //Modifying the above code to use an NSTimer instead.
- int iTime = PVRShell::PVRShellGetTime();
- int iDeltaTime = iTime - m_iTimePrev;
- m_iTimePrev = iTime;
- m_fFrame += (float)iDeltaTime * g_fDemoFrameRate;
- if (m_fFrame > scene->nNumFrame - 1)
- m_fFrame = 0;
- // Sets the scene animation to this frame
- scene->SetFrame(m_fFrame);
- */
- //Get the direction of the first light from the scene.
- PVRTVec4 vLightDirection;
- vLightDirection = model.GetLightDirection(0);
- // For direction vectors, w should be 0
- vLightDirection.w = 0.0f;
- //Set up the view and projection matrices from the camera
- PVRTMat4 mView, mProjection;
- PVRTVec3 vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f);
- float fFOV;
- // Setup the camera, this code may be unnecessary
- // Camera nodes are after the mesh and light nodes in the array
- int i32CamID = model.pNode[model.nNumMeshNode + model.nNumLight + g_ui32Camera].nIdx;
- printf("132CamID: %d", i32CamID);
- //printf("Camera Index Target: %d", (int)indexTarget);
- // Get the camera position, target and field of view (fov)
- if(model.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target?
- fFOV = model.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node
- else
- fFOV = model.GetCamera( vFrom, vTo, vUp, g_ui32Camera); // vTo is calculated from the rotation
- // We can build the model view matrix from the camera position, target and an up vector.
- // For this we usePVRTMat4LookAtRH()
- mView = mView.LookAtRH(vFrom, vTo, vUp);
- // Calculate the projection matrix
- //bool bRotate = PVRShell::PVRShellGet(prefIsRotated) && PVRShell::PVRShellGet(prefFullScreen);
- float aspectRatio = [UIScreen mainScreen].bounds.size.width/[UIScreen mainScreen].bounds.size.height;
- mProjection = mProjection.PerspectiveFovRH(fFOV, aspectRatio, g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, false);
- /*
- A scene is composed of nodes. There are 3 types of nodes:
- - MeshNodes :
- references a mesh in the pMesh[].
- These nodes are at the beginning of the pNode[] array.
- And there are nNumMeshNode number of them.
- This way the .pod format can instantiate several times the same mesh
- with different attributes.
- - lights
- - cameras
- To draw a scene, you must go through all the MeshNodes and draw the referenced meshes.
- */
- for (unsigned int i = 0; i < model.nNumMeshNode; ++i)
- {
- SPODNode& Node = model.pNode[i];
- // Get the node model matrix
- PVRTMat4 mWorld;
- mWorld = model.GetWorldMatrix(Node);
- // Pass the model-view-projection matrix (MVP) to the shader to transform the vertices
- PVRTMat4 mModelView, mMVP;
- mModelView = mView * mWorld;
- mMVP = mProjection * mModelView;
- glUniformMatrix4fv([defaultProgram uniformIndex:@"MVPMatrix"], 1, GL_FALSE, mMVP.f);
- // Pass the light direction in model space to the shader
- PVRTVec4 vLightDir;
- vLightDir = mWorld.inverse() * vLightDirection;
- PVRTVec3 vLightDirModel = *(PVRTVec3*)&vLightDir;
- vLightDirModel.normalize();
- glUniform3fv([defaultProgram uniformIndex:@"LightDirection"], 1, &vLightDirModel.x);
- // Load the correct texture using our texture lookup table
- GLuint uiTex = 0;
- if(Node.nIdxMaterial != -1)
- uiTex = texture[Node.nIdxMaterial];
- glBindTexture(GL_TEXTURE_2D, uiTex);
- // Now that the model-view matrix is set and the materials ready,
- //call another function to actually draw the mesh.
- [self drawMeshWithNodeIndex:1 withModelView:mModelView];
- }
- }
- #pragma mark Animation Methods
- - (void) setFrame:(float) frame
- {
- model.SetFrame(frame);
- }
- - (int) numFrames
- {
- return model.nNumFrame;
- }
- #pragma mark Skeleton Methods
- -(PVRTMat4)boneWorldMatrixForNode:(SPODNode)nodeMesh withBone:(SPODNode)nodeBone
- {
- return model.GetBoneWorldMatrix(nodeMesh, nodeBone);
- }
- -(void)boneWorldMatrixWithOutput:(PVRTMATRIX)output ForNode:(SPODNode)nodeMesh withBone:(SPODNode)nodeBone
- {
- model.GetBoneWorldMatrix(output, nodeMesh, nodeBone);
- }
- #pragma mark -
- #pragma mark Memory Managements
- - (void) dealloc
- {
- //CPVRTModelPOD* scene = (CPVRTModelPOD*)model;
- //todo: global buffer of textures
- glDeleteTextures(model.nNumMaterial, texture);
- glDeleteBuffers(model.nNumMesh, vbo);
- glDeleteBuffers(model.nNumMesh, indexvbo); //note that not all the indexvbos will be non-zero, but glDeleteBuffers silently ignores those, per http://www.opengl.org/sdk/docs/man/xhtml/glDeleteBuffers.xml
- delete vbo;
- delete indexvbo;
- delete texture;
- model.Destroy();
- [defaultProgram release];
- [skinnedVertexProgram release];
- [lightProgram release];
- [textureProgram release];
- [super dealloc];
- }
- @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement