| /****************************************************************************** | |
| @File OGLES2DisplacementMap.cpp | |
| @Title Displacement Map | |
| @Version | |
| @Copyright Copyright (c) Imagination Technologies Limited. | |
| @Platform Independent | |
| @Description Shows how to displace geometry in the vertex shader using a | |
| texture. | |
| ******************************************************************************/ | |
| #include <string.h> | |
| #include "PVRShell.h" | |
| #include "OGLES2Tools.h" | |
| /****************************************************************************** | |
| Defines | |
| ******************************************************************************/ | |
| // Index to bind the attributes to vertex shaders | |
| #define VERTEX_ARRAY 0 | |
| #define NORMAL_ARRAY 1 | |
| #define TEXCOORD_ARRAY 2 | |
| /****************************************************************************** | |
| Consts | |
| ******************************************************************************/ | |
| // Camera constants. Used for making the projection matrix | |
| const float g_fCameraNear = 4.0f; | |
| const float g_fCameraFar = 2000.0f; | |
| const float g_fDemoFrameRate = 1.0f / 90.0f; | |
| // The camera to use from the pod file | |
| const int g_ui32Camera = 0; | |
| /****************************************************************************** | |
| Content file names | |
| ******************************************************************************/ | |
| // Source and binary shaders | |
| const char c_szFragShaderSrcFile[] = "FragShader.fsh"; | |
| const char c_szFragShaderBinFile[] = "FragShader.fsc"; | |
| const char c_szVertShaderSrcFile[] = "VertShader.vsh"; | |
| const char c_szVertShaderBinFile[] = "VertShader.vsc"; | |
| // POD scene files | |
| const char c_szSceneFile[] = "DisMapScene.pod"; | |
| const char c_szDisMapFile[] = "DisMap.pvr"; | |
| /*!**************************************************************************** | |
| Class implementing the PVRShell functions. | |
| ******************************************************************************/ | |
| class OGLES2DisplacementMap : public PVRShell | |
| { | |
| // Print3D class used to display text | |
| CPVRTPrint3D m_Print3D; | |
| // 3D Model | |
| CPVRTModelPOD m_Scene; | |
| // OpenGL handles for shaders, textures and VBOs | |
| GLuint m_uiVertShader; | |
| GLuint m_uiFragShader; | |
| GLuint* m_puiVbo; | |
| GLuint* m_puiIndexVbo; | |
| GLuint* m_puiTextureIDs; | |
| GLuint m_uiDisMapID; | |
| // Group shader programs and their uniform locations together | |
| struct | |
| { | |
| GLuint uiId; | |
| GLuint uiMVPMatrixLoc; | |
| GLuint uiLightDirLoc; | |
| GLuint uiTexture; | |
| GLuint uiDisMap; | |
| GLuint uiDisplacementFactor; | |
| } | |
| m_ShaderProgram; | |
| // Variables to handle the animation in a time-based manner | |
| unsigned long m_ulTimePrev; | |
| // App variables | |
| PVRTVec4 m_LightDir; | |
| PVRTMat4 m_View, m_Projection; | |
| float m_DisplacementFactor; | |
| bool m_bGrow; | |
| public: | |
| virtual bool InitApplication(); | |
| virtual bool InitView(); | |
| virtual bool ReleaseView(); | |
| virtual bool QuitApplication(); | |
| virtual bool RenderScene(); | |
| OGLES2DisplacementMap(); | |
| bool LoadTextures(CPVRTString* pErrorStr); | |
| bool LoadShaders(CPVRTString* pErrorStr); | |
| bool LoadVbos(CPVRTString* pErrorStr); | |
| void DrawMesh(int i32NodeIndex); | |
| }; | |
| /*!**************************************************************************** | |
| @Function OGLES2DisplacementMap | |
| @Description Constructor | |
| ******************************************************************************/ | |
| OGLES2DisplacementMap::OGLES2DisplacementMap() : m_puiVbo(0), | |
| m_puiIndexVbo(0), | |
| m_puiTextureIDs(0), | |
| m_ulTimePrev(0), | |
| m_DisplacementFactor(0), | |
| m_bGrow(false) | |
| { | |
| } | |
| /*!**************************************************************************** | |
| @Function LoadTextures | |
| @Return bool true if no error occurred | |
| @Description Loads the textures required for this training course | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::LoadTextures(CPVRTString* pErrorStr) | |
| { | |
| /* | |
| Load the textures. | |
| For a more detailed explanation, see Texturing and IntroducingPVRTools | |
| */ | |
| /* | |
| Initialises an array to lookup the textures | |
| for each material in the scene. | |
| */ | |
| m_puiTextureIDs = new GLuint[m_Scene.nNumMaterial]; | |
| if(!m_puiTextureIDs) | |
| { | |
| *pErrorStr = "ERROR: Insufficient memory."; | |
| return false; | |
| } | |
| for(int i = 0; i < (int) m_Scene.nNumMaterial; ++i) | |
| { | |
| m_puiTextureIDs[i] = 0; | |
| SPODMaterial* pMaterial = &m_Scene.pMaterial[i]; | |
| if(pMaterial->nIdxTexDiffuse != -1) | |
| { | |
| /* | |
| Using the tools function PVRTTextureLoadFromPVR load the textures required by the pod file. | |
| Note: This function only loads .pvr files. You can set the textures in 3D Studio Max to .pvr | |
| files using the PVRTexTool plug-in for max. Alternatively, the pod material properties can be | |
| modified in PVRShaman. | |
| */ | |
| CPVRTString sTextureName = m_Scene.pTexture[pMaterial->nIdxTexDiffuse].pszName; | |
| if(PVRTTextureLoadFromPVR(sTextureName.c_str(), &m_puiTextureIDs[i]) != PVR_SUCCESS) | |
| { | |
| *pErrorStr = "ERROR: Failed to load " + sTextureName + "."; | |
| // Check to see if we're trying to load .pvr or not | |
| CPVRTString sFileExtension = PVRTStringGetFileExtension(sTextureName); | |
| if(sFileExtension.toLower() == "pvr") | |
| *pErrorStr += "Note: Can only load pvr files."; | |
| return false; | |
| } | |
| } | |
| } | |
| // Load the texture used for the displacement map | |
| if(PVRTTextureLoadFromPVR(c_szDisMapFile, &m_uiDisMapID) != PVR_SUCCESS) | |
| { | |
| *pErrorStr = "ERROR: Failed to load " + CPVRTString(c_szDisMapFile) + "."; | |
| return false; | |
| } | |
| // Define the wrapping to use for the displacement map | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function LoadShaders | |
| @Output pErrorStr A string describing the error on failure | |
| @Return bool true if no error occurred | |
| @Description Loads and compiles the shaders and links the shader programs | |
| required for this training course | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::LoadShaders(CPVRTString* pErrorStr) | |
| { | |
| /* | |
| Load and compile the shaders from files. | |
| Binary shaders are tried first, source shaders | |
| are used as fallback. | |
| */ | |
| if(PVRTShaderLoadFromFile( | |
| c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS) | |
| { | |
| return false; | |
| } | |
| if (PVRTShaderLoadFromFile( | |
| c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS) | |
| { | |
| return false; | |
| } | |
| /* | |
| Set up and link the shader program | |
| */ | |
| const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" }; | |
| if(PVRTCreateProgram( | |
| &m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS) | |
| { | |
| PVRShellSet(prefExitMessage, pErrorStr->c_str()); | |
| return false; | |
| } | |
| // Store the location of uniforms for later use | |
| m_ShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix"); | |
| m_ShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection"); | |
| m_ShaderProgram.uiDisplacementFactor = glGetUniformLocation(m_ShaderProgram.uiId, "DisplacementFactor"); | |
| m_ShaderProgram.uiTexture = glGetUniformLocation(m_ShaderProgram.uiId, "sTexture"); | |
| m_ShaderProgram.uiDisMap = glGetUniformLocation(m_ShaderProgram.uiId, "sDisMap"); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function LoadVbos | |
| @Description Loads the mesh data required for this training course into | |
| vertex buffer objects | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::LoadVbos(CPVRTString* pErrorStr) | |
| { | |
| if(!m_Scene.pMesh[0].pInterleaved) | |
| { | |
| *pErrorStr = "ERROR: IntroducingPOD requires the pod data to be interleaved. Please re-export with the interleaved option enabled."; | |
| return false; | |
| } | |
| if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh]; | |
| if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_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(m_Scene.nNumMesh, m_puiVbo); | |
| for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i) | |
| { | |
| // Load vertex data into buffer object | |
| SPODMesh& Mesh = m_Scene.pMesh[i]; | |
| unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride; | |
| glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]); | |
| glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW); | |
| // Load index data into buffer object if available | |
| m_puiIndexVbo[i] = 0; | |
| if (Mesh.sFaces.pData) | |
| { | |
| glGenBuffers(1, &m_puiIndexVbo[i]); | |
| uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]); | |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW); | |
| } | |
| } | |
| glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function InitApplication | |
| @Return bool true if no error occurred | |
| @Description Code in InitApplication() will be called by PVRShell once per | |
| run, before the rendering context is created. | |
| Used to initialize variables that are not dependent on it | |
| (e.g. external modules, loading meshes, etc.) | |
| If the rendering context is lost, InitApplication() will | |
| not be called again. | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::InitApplication() | |
| { | |
| // Get and set the read path for content files | |
| CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath)); | |
| // Get and set the load/release functions for loading external files. | |
| // In the majority of cases the PVRShell will return NULL function pointers implying that | |
| // nothing special is required to load external files. | |
| CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc)); | |
| // Load the scene | |
| if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS) | |
| { | |
| PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n"); | |
| return false; | |
| } | |
| // The cameras are stored in the file. We check it contains at least one. | |
| if(m_Scene.nNumCamera == 0) | |
| { | |
| PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera. Please add one and re-export.\n"); | |
| return false; | |
| } | |
| // We also check that the scene contains at least one light | |
| if(m_Scene.nNumLight == 0) | |
| { | |
| PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light. Please add one and re-export.\n"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function QuitApplication | |
| @Return bool true if no error occurred | |
| @Description Code in QuitApplication() will be called by PVRShell once per | |
| run, just before exiting the program. | |
| If the rendering context is lost, QuitApplication() will | |
| not be called. | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::QuitApplication() | |
| { | |
| // Free the memory allocated for the scene | |
| m_Scene.Destroy(); | |
| delete[] m_puiVbo; | |
| delete[] m_puiIndexVbo; | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function InitView | |
| @Return bool true if no error occurred | |
| @Description Code in InitView() will be called by PVRShell upon | |
| initialization or after a change in the rendering context. | |
| Used to initialize variables that are dependent on the rendering | |
| context (e.g. textures, vertex buffers, etc.) | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::InitView() | |
| { | |
| CPVRTString ErrorStr; | |
| /* | |
| Initialize VBO data | |
| */ | |
| if(!LoadVbos(&ErrorStr)) | |
| { | |
| PVRShellSet(prefExitMessage, ErrorStr.c_str()); | |
| return false; | |
| } | |
| /* | |
| Load textures | |
| */ | |
| if(!LoadTextures(&ErrorStr)) | |
| { | |
| PVRShellSet(prefExitMessage, ErrorStr.c_str()); | |
| return false; | |
| } | |
| /* | |
| Load and compile the shaders & link programs | |
| */ | |
| if(!LoadShaders(&ErrorStr)) | |
| { | |
| PVRShellSet(prefExitMessage, ErrorStr.c_str()); | |
| return false; | |
| } | |
| /* | |
| Initialize Print3D | |
| */ | |
| bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); | |
| if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS) | |
| { | |
| PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n"); | |
| return false; | |
| } | |
| /* | |
| Set OpenGL ES render states needed for this training course | |
| */ | |
| // Enable backface culling and depth test | |
| glCullFace(GL_BACK); | |
| glEnable(GL_CULL_FACE); | |
| glEnable(GL_DEPTH_TEST); | |
| // Use a nice bright blue as clear colour | |
| glClearColor(0.6f, 0.8f, 1.0f, 1.0f); | |
| //Get the direction of the first light from the scene. | |
| m_LightDir = m_Scene.GetLightDirection(0); | |
| // For direction vectors, w should be 0 | |
| m_LightDir.w = 0.0f; | |
| // Set up the view and projection matrices from the camera | |
| PVRTVec3 vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f); | |
| float fFOV; | |
| // Setup the camera | |
| // Camera nodes are after the mesh and light nodes in the array | |
| int i32CamID = m_Scene.pNode[m_Scene.nNumMeshNode + m_Scene.nNumLight + g_ui32Camera].nIdx; | |
| // Get the camera position, target and field of view (fov) | |
| if(m_Scene.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target? | |
| fFOV = m_Scene.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node | |
| else | |
| fFOV = m_Scene.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() | |
| m_View = PVRTMat4::LookAtRH(vFrom, vTo, vUp); | |
| // Calculate the projection matrix | |
| m_Projection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate); | |
| // Initialize variables used for the animation | |
| m_ulTimePrev = PVRShellGetTime(); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function ReleaseView | |
| @Return bool true if no error occurred | |
| @Description Code in ReleaseView() will be called by PVRShell when the | |
| application quits or before a change in the rendering context. | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::ReleaseView() | |
| { | |
| // Deletes the textures | |
| glDeleteTextures(m_Scene.nNumMaterial, &m_puiTextureIDs[0]); | |
| glDeleteTextures(1, &m_uiDisMapID); | |
| // Frees the texture lookup array | |
| delete[] m_puiTextureIDs; | |
| m_puiTextureIDs = 0; | |
| // Delete program and shader objects | |
| glDeleteProgram(m_ShaderProgram.uiId); | |
| glDeleteShader(m_uiVertShader); | |
| glDeleteShader(m_uiFragShader); | |
| // Delete buffer objects | |
| glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo); | |
| glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo); | |
| // Release Print3D Textures | |
| m_Print3D.ReleaseTextures(); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function RenderScene | |
| @Return bool true if no error occurred | |
| @Description Main rendering loop function of the program. The shell will | |
| call this function every frame. | |
| eglSwapBuffers() will be performed by PVRShell automatically. | |
| PVRShell will also manage important OS events. | |
| Will also manage relevant OS events. The user has access to | |
| these events through an abstraction layer provided by PVRShell. | |
| ******************************************************************************/ | |
| bool OGLES2DisplacementMap::RenderScene() | |
| { | |
| // Clear the color and depth buffer | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| // Calculates the the time since the last frame | |
| unsigned long ulTime = PVRShellGetTime(); | |
| unsigned long ulDeltaTime = ulTime - m_ulTimePrev; | |
| m_ulTimePrev = ulTime; | |
| // Use shader program | |
| glUseProgram(m_ShaderProgram.uiId); | |
| // Enable 2D texturing for the first texture. | |
| glActiveTexture(GL_TEXTURE0); | |
| // Set the sampler2D variable to the first texture unit | |
| glUniform1i(m_ShaderProgram.uiTexture, 0); | |
| // Enable 2D texturing for the second texture. | |
| glActiveTexture(GL_TEXTURE1); | |
| // Set the displacement map variable to the second texture unit | |
| glUniform1i(m_ShaderProgram.uiDisMap, 1); | |
| // Calculate and set the displacement factor | |
| if(m_bGrow) | |
| { | |
| m_DisplacementFactor += (float)ulDeltaTime * g_fDemoFrameRate; | |
| if(m_DisplacementFactor > 25.0f) | |
| { | |
| m_bGrow = false; | |
| m_DisplacementFactor = 25.0f; | |
| } | |
| } | |
| else | |
| { | |
| m_DisplacementFactor -= (float)ulDeltaTime * g_fDemoFrameRate; | |
| if(m_DisplacementFactor < 0.0f) | |
| { | |
| m_bGrow = true; | |
| m_DisplacementFactor = 0.0f; | |
| } | |
| } | |
| glUniform1f(m_ShaderProgram.uiDisplacementFactor, m_DisplacementFactor); | |
| // Bind the displacement map texture | |
| glBindTexture(GL_TEXTURE_2D, m_uiDisMapID); | |
| // Now the displacement map texture is bound set the active texture to texture 0 | |
| glActiveTexture(GL_TEXTURE0); | |
| // Draw the scene | |
| // Enable the vertex attribute arrays | |
| glEnableVertexAttribArray(VERTEX_ARRAY); | |
| glEnableVertexAttribArray(NORMAL_ARRAY); | |
| glEnableVertexAttribArray(TEXCOORD_ARRAY); | |
| for(unsigned int i = 0; i < m_Scene.nNumMeshNode; ++i) | |
| { | |
| SPODNode& Node = m_Scene.pNode[i]; | |
| // Get the node model matrix | |
| PVRTMat4 mWorld; | |
| mWorld = m_Scene.GetWorldMatrix(Node); | |
| // Pass the model-view-projection matrix (MVP) to the shader to transform the vertices | |
| PVRTMat4 mModelView, mMVP; | |
| mModelView = m_View * mWorld; | |
| mMVP = m_Projection * mModelView; | |
| glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.f); | |
| // Pass the light direction in model space to the shader | |
| PVRTVec4 vLightDir; | |
| vLightDir = mWorld.inverse() * m_LightDir; | |
| PVRTVec3 vLightDirModel = *(PVRTVec3*) vLightDir.ptr(); | |
| vLightDirModel.normalize(); | |
| glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x); | |
| // Load the correct texture for the mesh using our texture lookup table | |
| GLuint uiTex = 0; | |
| if(Node.nIdxMaterial != -1) | |
| uiTex = m_puiTextureIDs[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. | |
| */ | |
| DrawMesh(i); | |
| } | |
| // 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); | |
| // Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools | |
| m_Print3D.DisplayDefaultTitle("DisplacementMapping", "", ePVRTPrint3DSDKLogo); | |
| m_Print3D.Flush(); | |
| return true; | |
| } | |
| /*!**************************************************************************** | |
| @Function DrawMesh | |
| @Input i32NodeIndex Node index of the mesh to draw | |
| @Description Draws a SPODMesh after the model view matrix has been set and | |
| the material prepared. | |
| ******************************************************************************/ | |
| void OGLES2DisplacementMap::DrawMesh(int i32NodeIndex) | |
| { | |
| int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx; | |
| SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex]; | |
| // bind the VBO for the mesh | |
| glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]); | |
| // bind the index buffer, won't hurt if the handle is 0 | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]); | |
| // 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(m_puiIndexVbo[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(m_puiIndexVbo[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; | |
| } | |
| } | |
| } | |
| /*!**************************************************************************** | |
| @Function NewDemo | |
| @Return PVRShell* The demo supplied by the user | |
| @Description This function must be implemented by the user of the shell. | |
| The user should return its PVRShell object defining the | |
| behaviour of the application. | |
| ******************************************************************************/ | |
| PVRShell* NewDemo() | |
| { | |
| return new OGLES2DisplacementMap(); | |
| } | |
| /****************************************************************************** | |
| End of file (OGLES2DisplacementMap.cpp) | |
| ******************************************************************************/ | |