1 /****************************************************************************** 2 3 @File OGLES2DisplacementMap.cpp 4 5 @Title Displacement Map 6 7 @Version 8 9 @Copyright Copyright (c) Imagination Technologies Limited. 10 11 @Platform Independent 12 13 @Description Shows how to displace geometry in the vertex shader using a 14 texture. 15 16 ******************************************************************************/ 17 #include <string.h> 18 19 #include "PVRShell.h" 20 #include "OGLES2Tools.h" 21 22 /****************************************************************************** 23 Defines 24 ******************************************************************************/ 25 // Index to bind the attributes to vertex shaders 26 #define VERTEX_ARRAY 0 27 #define NORMAL_ARRAY 1 28 #define TEXCOORD_ARRAY 2 29 30 /****************************************************************************** 31 Consts 32 ******************************************************************************/ 33 // Camera constants. Used for making the projection matrix 34 const float g_fCameraNear = 4.0f; 35 const float g_fCameraFar = 2000.0f; 36 37 const float g_fDemoFrameRate = 1.0f / 90.0f; 38 39 // The camera to use from the pod file 40 const int g_ui32Camera = 0; 41 42 /****************************************************************************** 43 Content file names 44 ******************************************************************************/ 45 46 // Source and binary shaders 47 const char c_szFragShaderSrcFile[] = "FragShader.fsh"; 48 const char c_szFragShaderBinFile[] = "FragShader.fsc"; 49 const char c_szVertShaderSrcFile[] = "VertShader.vsh"; 50 const char c_szVertShaderBinFile[] = "VertShader.vsc"; 51 52 // POD scene files 53 const char c_szSceneFile[] = "DisMapScene.pod"; 54 const char c_szDisMapFile[] = "DisMap.pvr"; 55 56 /*!**************************************************************************** 57 Class implementing the PVRShell functions. 58 ******************************************************************************/ 59 class OGLES2DisplacementMap : public PVRShell 60 { 61 // Print3D class used to display text 62 CPVRTPrint3D m_Print3D; 63 64 // 3D Model 65 CPVRTModelPOD m_Scene; 66 67 // OpenGL handles for shaders, textures and VBOs 68 GLuint m_uiVertShader; 69 GLuint m_uiFragShader; 70 GLuint* m_puiVbo; 71 GLuint* m_puiIndexVbo; 72 GLuint* m_puiTextureIDs; 73 GLuint m_uiDisMapID; 74 75 // Group shader programs and their uniform locations together 76 struct 77 { 78 GLuint uiId; 79 GLuint uiMVPMatrixLoc; 80 GLuint uiLightDirLoc; 81 GLuint uiTexture; 82 GLuint uiDisMap; 83 GLuint uiDisplacementFactor; 84 } 85 m_ShaderProgram; 86 87 // Variables to handle the animation in a time-based manner 88 unsigned long m_ulTimePrev; 89 90 // App variables 91 PVRTVec4 m_LightDir; 92 PVRTMat4 m_View, m_Projection; 93 float m_DisplacementFactor; 94 bool m_bGrow; 95 96 public: 97 virtual bool InitApplication(); 98 virtual bool InitView(); 99 virtual bool ReleaseView(); 100 virtual bool QuitApplication(); 101 virtual bool RenderScene(); 102 103 OGLES2DisplacementMap(); 104 bool LoadTextures(CPVRTString* pErrorStr); 105 bool LoadShaders(CPVRTString* pErrorStr); 106 bool LoadVbos(CPVRTString* pErrorStr); 107 108 void DrawMesh(int i32NodeIndex); 109 }; 110 111 /*!**************************************************************************** 112 @Function OGLES2DisplacementMap 113 @Description Constructor 114 ******************************************************************************/ 115 OGLES2DisplacementMap::OGLES2DisplacementMap() : m_puiVbo(0), 116 m_puiIndexVbo(0), 117 m_puiTextureIDs(0), 118 m_ulTimePrev(0), 119 m_DisplacementFactor(0), 120 m_bGrow(false) 121 { 122 } 123 124 /*!**************************************************************************** 125 @Function LoadTextures 126 @Return bool true if no error occurred 127 @Description Loads the textures required for this training course 128 ******************************************************************************/ 129 bool OGLES2DisplacementMap::LoadTextures(CPVRTString* pErrorStr) 130 { 131 /* 132 Load the textures. 133 For a more detailed explanation, see Texturing and IntroducingPVRTools 134 */ 135 136 /* 137 Initialises an array to lookup the textures 138 for each material in the scene. 139 */ 140 m_puiTextureIDs = new GLuint[m_Scene.nNumMaterial]; 141 142 if(!m_puiTextureIDs) 143 { 144 *pErrorStr = "ERROR: Insufficient memory."; 145 return false; 146 } 147 148 for(int i = 0; i < (int) m_Scene.nNumMaterial; ++i) 149 { 150 m_puiTextureIDs[i] = 0; 151 SPODMaterial* pMaterial = &m_Scene.pMaterial[i]; 152 153 if(pMaterial->nIdxTexDiffuse != -1) 154 { 155 /* 156 Using the tools function PVRTTextureLoadFromPVR load the textures required by the pod file. 157 158 Note: This function only loads .pvr files. You can set the textures in 3D Studio Max to .pvr 159 files using the PVRTexTool plug-in for max. Alternatively, the pod material properties can be 160 modified in PVRShaman. 161 */ 162 163 CPVRTString sTextureName = m_Scene.pTexture[pMaterial->nIdxTexDiffuse].pszName; 164 165 if(PVRTTextureLoadFromPVR(sTextureName.c_str(), &m_puiTextureIDs[i]) != PVR_SUCCESS) 166 { 167 *pErrorStr = "ERROR: Failed to load " + sTextureName + "."; 168 169 // Check to see if we're trying to load .pvr or not 170 CPVRTString sFileExtension = PVRTStringGetFileExtension(sTextureName); 171 172 if(sFileExtension.toLower() == "pvr") 173 *pErrorStr += "Note: Can only load pvr files."; 174 175 return false; 176 } 177 } 178 } 179 180 // Load the texture used for the displacement map 181 if(PVRTTextureLoadFromPVR(c_szDisMapFile, &m_uiDisMapID) != PVR_SUCCESS) 182 { 183 *pErrorStr = "ERROR: Failed to load " + CPVRTString(c_szDisMapFile) + "."; 184 return false; 185 } 186 187 // Define the wrapping to use for the displacement map 188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 190 191 return true; 192 } 193 194 /*!**************************************************************************** 195 @Function LoadShaders 196 @Output pErrorStr A string describing the error on failure 197 @Return bool true if no error occurred 198 @Description Loads and compiles the shaders and links the shader programs 199 required for this training course 200 ******************************************************************************/ 201 bool OGLES2DisplacementMap::LoadShaders(CPVRTString* pErrorStr) 202 { 203 /* 204 Load and compile the shaders from files. 205 Binary shaders are tried first, source shaders 206 are used as fallback. 207 */ 208 if(PVRTShaderLoadFromFile( 209 c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS) 210 { 211 return false; 212 } 213 214 if (PVRTShaderLoadFromFile( 215 c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS) 216 { 217 return false; 218 } 219 220 /* 221 Set up and link the shader program 222 */ 223 const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" }; 224 225 if(PVRTCreateProgram( 226 &m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS) 227 { 228 PVRShellSet(prefExitMessage, pErrorStr->c_str()); 229 return false; 230 } 231 232 // Store the location of uniforms for later use 233 m_ShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix"); 234 m_ShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection"); 235 m_ShaderProgram.uiDisplacementFactor = glGetUniformLocation(m_ShaderProgram.uiId, "DisplacementFactor"); 236 237 m_ShaderProgram.uiTexture = glGetUniformLocation(m_ShaderProgram.uiId, "sTexture"); 238 m_ShaderProgram.uiDisMap = glGetUniformLocation(m_ShaderProgram.uiId, "sDisMap"); 239 240 return true; 241 } 242 243 /*!**************************************************************************** 244 @Function LoadVbos 245 @Description Loads the mesh data required for this training course into 246 vertex buffer objects 247 ******************************************************************************/ 248 bool OGLES2DisplacementMap::LoadVbos(CPVRTString* pErrorStr) 249 { 250 if(!m_Scene.pMesh[0].pInterleaved) 251 { 252 *pErrorStr = "ERROR: IntroducingPOD requires the pod data to be interleaved. Please re-export with the interleaved option enabled."; 253 return false; 254 } 255 256 if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh]; 257 if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh]; 258 259 /* 260 Load vertex data of all meshes in the scene into VBOs 261 262 The meshes have been exported with the "Interleave Vectors" option, 263 so all data is interleaved in the buffer at pMesh->pInterleaved. 264 Interleaving data improves the memory access pattern and cache efficiency, 265 thus it can be read faster by the hardware. 266 */ 267 glGenBuffers(m_Scene.nNumMesh, m_puiVbo); 268 for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i) 269 { 270 // Load vertex data into buffer object 271 SPODMesh& Mesh = m_Scene.pMesh[i]; 272 unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride; 273 glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]); 274 glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW); 275 276 // Load index data into buffer object if available 277 m_puiIndexVbo[i] = 0; 278 if (Mesh.sFaces.pData) 279 { 280 glGenBuffers(1, &m_puiIndexVbo[i]); 281 uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort); 282 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]); 283 glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW); 284 } 285 } 286 glBindBuffer(GL_ARRAY_BUFFER, 0); 287 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 288 289 return true; 290 } 291 292 /*!**************************************************************************** 293 @Function InitApplication 294 @Return bool true if no error occurred 295 @Description Code in InitApplication() will be called by PVRShell once per 296 run, before the rendering context is created. 297 Used to initialize variables that are not dependent on it 298 (e.g. external modules, loading meshes, etc.) 299 If the rendering context is lost, InitApplication() will 300 not be called again. 301 ******************************************************************************/ 302 bool OGLES2DisplacementMap::InitApplication() 303 { 304 // Get and set the read path for content files 305 CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath)); 306 307 // Get and set the load/release functions for loading external files. 308 // In the majority of cases the PVRShell will return NULL function pointers implying that 309 // nothing special is required to load external files. 310 CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc)); 311 312 // Load the scene 313 if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS) 314 { 315 PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n"); 316 return false; 317 } 318 319 // The cameras are stored in the file. We check it contains at least one. 320 if(m_Scene.nNumCamera == 0) 321 { 322 PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera. Please add one and re-export.\n"); 323 return false; 324 } 325 326 // We also check that the scene contains at least one light 327 if(m_Scene.nNumLight == 0) 328 { 329 PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light. Please add one and re-export.\n"); 330 return false; 331 } 332 333 return true; 334 } 335 336 /*!**************************************************************************** 337 @Function QuitApplication 338 @Return bool true if no error occurred 339 @Description Code in QuitApplication() will be called by PVRShell once per 340 run, just before exiting the program. 341 If the rendering context is lost, QuitApplication() will 342 not be called. 343 ******************************************************************************/ 344 bool OGLES2DisplacementMap::QuitApplication() 345 { 346 // Free the memory allocated for the scene 347 m_Scene.Destroy(); 348 349 delete[] m_puiVbo; 350 delete[] m_puiIndexVbo; 351 352 return true; 353 } 354 355 /*!**************************************************************************** 356 @Function InitView 357 @Return bool true if no error occurred 358 @Description Code in InitView() will be called by PVRShell upon 359 initialization or after a change in the rendering context. 360 Used to initialize variables that are dependent on the rendering 361 context (e.g. textures, vertex buffers, etc.) 362 ******************************************************************************/ 363 bool OGLES2DisplacementMap::InitView() 364 { 365 CPVRTString ErrorStr; 366 367 /* 368 Initialize VBO data 369 */ 370 if(!LoadVbos(&ErrorStr)) 371 { 372 PVRShellSet(prefExitMessage, ErrorStr.c_str()); 373 return false; 374 } 375 376 /* 377 Load textures 378 */ 379 if(!LoadTextures(&ErrorStr)) 380 { 381 PVRShellSet(prefExitMessage, ErrorStr.c_str()); 382 return false; 383 } 384 385 /* 386 Load and compile the shaders & link programs 387 */ 388 if(!LoadShaders(&ErrorStr)) 389 { 390 PVRShellSet(prefExitMessage, ErrorStr.c_str()); 391 return false; 392 } 393 394 /* 395 Initialize Print3D 396 */ 397 bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen); 398 399 if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS) 400 { 401 PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n"); 402 return false; 403 } 404 405 /* 406 Set OpenGL ES render states needed for this training course 407 */ 408 // Enable backface culling and depth test 409 glCullFace(GL_BACK); 410 glEnable(GL_CULL_FACE); 411 412 glEnable(GL_DEPTH_TEST); 413 414 // Use a nice bright blue as clear colour 415 glClearColor(0.6f, 0.8f, 1.0f, 1.0f); 416 417 //Get the direction of the first light from the scene. 418 m_LightDir = m_Scene.GetLightDirection(0); 419 420 // For direction vectors, w should be 0 421 m_LightDir.w = 0.0f; 422 423 424 // Set up the view and projection matrices from the camera 425 PVRTVec3 vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f); 426 float fFOV; 427 428 // Setup the camera 429 430 // Camera nodes are after the mesh and light nodes in the array 431 int i32CamID = m_Scene.pNode[m_Scene.nNumMeshNode + m_Scene.nNumLight + g_ui32Camera].nIdx; 432 433 // Get the camera position, target and field of view (fov) 434 if(m_Scene.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target? 435 fFOV = m_Scene.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node 436 else 437 fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, g_ui32Camera); // vTo is calculated from the rotation 438 439 // We can build the model view matrix from the camera position, target and an up vector. 440 // For this we usePVRTMat4LookAtRH() 441 m_View = PVRTMat4::LookAtRH(vFrom, vTo, vUp); 442 443 // Calculate the projection matrix 444 m_Projection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate); 445 446 // Initialize variables used for the animation 447 m_ulTimePrev = PVRShellGetTime(); 448 449 return true; 450 } 451 452 /*!**************************************************************************** 453 @Function ReleaseView 454 @Return bool true if no error occurred 455 @Description Code in ReleaseView() will be called by PVRShell when the 456 application quits or before a change in the rendering context. 457 ******************************************************************************/ 458 bool OGLES2DisplacementMap::ReleaseView() 459 { 460 // Deletes the textures 461 glDeleteTextures(m_Scene.nNumMaterial, &m_puiTextureIDs[0]); 462 glDeleteTextures(1, &m_uiDisMapID); 463 464 // Frees the texture lookup array 465 delete[] m_puiTextureIDs; 466 m_puiTextureIDs = 0; 467 468 // Delete program and shader objects 469 glDeleteProgram(m_ShaderProgram.uiId); 470 471 glDeleteShader(m_uiVertShader); 472 glDeleteShader(m_uiFragShader); 473 474 // Delete buffer objects 475 glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo); 476 glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo); 477 478 // Release Print3D Textures 479 m_Print3D.ReleaseTextures(); 480 481 return true; 482 } 483 484 /*!**************************************************************************** 485 @Function RenderScene 486 @Return bool true if no error occurred 487 @Description Main rendering loop function of the program. The shell will 488 call this function every frame. 489 eglSwapBuffers() will be performed by PVRShell automatically. 490 PVRShell will also manage important OS events. 491 Will also manage relevant OS events. The user has access to 492 these events through an abstraction layer provided by PVRShell. 493 ******************************************************************************/ 494 bool OGLES2DisplacementMap::RenderScene() 495 { 496 // Clear the color and depth buffer 497 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 498 499 500 // Calculates the the time since the last frame 501 unsigned long ulTime = PVRShellGetTime(); 502 unsigned long ulDeltaTime = ulTime - m_ulTimePrev; 503 m_ulTimePrev = ulTime; 504 505 // Use shader program 506 glUseProgram(m_ShaderProgram.uiId); 507 508 // Enable 2D texturing for the first texture. 509 glActiveTexture(GL_TEXTURE0); 510 511 // Set the sampler2D variable to the first texture unit 512 glUniform1i(m_ShaderProgram.uiTexture, 0); 513 514 // Enable 2D texturing for the second texture. 515 glActiveTexture(GL_TEXTURE1); 516 517 // Set the displacement map variable to the second texture unit 518 glUniform1i(m_ShaderProgram.uiDisMap, 1); 519 520 // Calculate and set the displacement factor 521 if(m_bGrow) 522 { 523 m_DisplacementFactor += (float)ulDeltaTime * g_fDemoFrameRate; 524 525 if(m_DisplacementFactor > 25.0f) 526 { 527 m_bGrow = false; 528 m_DisplacementFactor = 25.0f; 529 } 530 } 531 else 532 { 533 m_DisplacementFactor -= (float)ulDeltaTime * g_fDemoFrameRate; 534 535 if(m_DisplacementFactor < 0.0f) 536 { 537 m_bGrow = true; 538 m_DisplacementFactor = 0.0f; 539 } 540 } 541 542 glUniform1f(m_ShaderProgram.uiDisplacementFactor, m_DisplacementFactor); 543 544 // Bind the displacement map texture 545 glBindTexture(GL_TEXTURE_2D, m_uiDisMapID); 546 547 // Now the displacement map texture is bound set the active texture to texture 0 548 glActiveTexture(GL_TEXTURE0); 549 550 // Draw the scene 551 552 // Enable the vertex attribute arrays 553 glEnableVertexAttribArray(VERTEX_ARRAY); 554 glEnableVertexAttribArray(NORMAL_ARRAY); 555 glEnableVertexAttribArray(TEXCOORD_ARRAY); 556 557 for(unsigned int i = 0; i < m_Scene.nNumMeshNode; ++i) 558 { 559 SPODNode& Node = m_Scene.pNode[i]; 560 561 // Get the node model matrix 562 PVRTMat4 mWorld; 563 mWorld = m_Scene.GetWorldMatrix(Node); 564 565 // Pass the model-view-projection matrix (MVP) to the shader to transform the vertices 566 PVRTMat4 mModelView, mMVP; 567 mModelView = m_View * mWorld; 568 mMVP = m_Projection * mModelView; 569 glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.f); 570 571 // Pass the light direction in model space to the shader 572 PVRTVec4 vLightDir; 573 vLightDir = mWorld.inverse() * m_LightDir; 574 575 PVRTVec3 vLightDirModel = *(PVRTVec3*) vLightDir.ptr(); 576 vLightDirModel.normalize(); 577 578 glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x); 579 580 // Load the correct texture for the mesh using our texture lookup table 581 GLuint uiTex = 0; 582 583 if(Node.nIdxMaterial != -1) 584 uiTex = m_puiTextureIDs[Node.nIdxMaterial]; 585 586 glBindTexture(GL_TEXTURE_2D, uiTex); 587 588 /* 589 Now that the model-view matrix is set and the materials ready, 590 call another function to actually draw the mesh. 591 */ 592 DrawMesh(i); 593 } 594 595 // Safely disable the vertex attribute arrays 596 glDisableVertexAttribArray(VERTEX_ARRAY); 597 glDisableVertexAttribArray(NORMAL_ARRAY); 598 glDisableVertexAttribArray(TEXCOORD_ARRAY); 599 600 glBindBuffer(GL_ARRAY_BUFFER, 0); 601 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 602 603 // Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools 604 m_Print3D.DisplayDefaultTitle("DisplacementMapping", "", ePVRTPrint3DSDKLogo); 605 m_Print3D.Flush(); 606 607 return true; 608 } 609 610 /*!**************************************************************************** 611 @Function DrawMesh 612 @Input i32NodeIndex Node index of the mesh to draw 613 @Description Draws a SPODMesh after the model view matrix has been set and 614 the material prepared. 615 ******************************************************************************/ 616 void OGLES2DisplacementMap::DrawMesh(int i32NodeIndex) 617 { 618 int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx; 619 SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex]; 620 621 // bind the VBO for the mesh 622 glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]); 623 // bind the index buffer, won't hurt if the handle is 0 624 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]); 625 626 // Set the vertex attribute offsets 627 glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData); 628 glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData); 629 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData); 630 631 /* 632 The geometry can be exported in 4 ways: 633 - Indexed Triangle list 634 - Non-Indexed Triangle list 635 - Indexed Triangle strips 636 - Non-Indexed Triangle strips 637 */ 638 if(pMesh->nNumStrips == 0) 639 { 640 if(m_puiIndexVbo[i32MeshIndex]) 641 { 642 // Indexed Triangle list 643 glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0); 644 } 645 else 646 { 647 // Non-Indexed Triangle list 648 glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3); 649 } 650 } 651 else 652 { 653 int offset = 0; 654 655 for(int i = 0; i < (int)pMesh->nNumStrips; ++i) 656 { 657 if(m_puiIndexVbo[i32MeshIndex]) 658 { 659 // Indexed Triangle strips 660 glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]); 661 } 662 else 663 { 664 // Non-Indexed Triangle strips 665 glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2); 666 } 667 offset += pMesh->pnStripLength[i]+2; 668 } 669 } 670 } 671 672 /*!**************************************************************************** 673 @Function NewDemo 674 @Return PVRShell* The demo supplied by the user 675 @Description This function must be implemented by the user of the shell. 676 The user should return its PVRShell object defining the 677 behaviour of the application. 678 ******************************************************************************/ 679 PVRShell* NewDemo() 680 { 681 return new OGLES2DisplacementMap(); 682 } 683 684 /****************************************************************************** 685 End of file (OGLES2DisplacementMap.cpp) 686 ******************************************************************************/ 687 688