OGLES2LevelOfDetail.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /******************************************************************************
  2. @File OGLES2LevelOfDetail.cpp
  3. @Title Level of detail
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Demonstrates the use of different shader detail levels
  8. ******************************************************************************/
  9. #include <math.h>
  10. #include "PVRShell.h"
  11. #include "OGLES2Tools.h"
  12. /******************************************************************************
  13. Constants
  14. ******************************************************************************/
  15. // Camera constants used to generate the projection matrix
  16. const float CAM_NEAR = 75.0f;
  17. const float CAM_FAR = 3000.0f;
  18. /******************************************************************************
  19. shader attributes
  20. ******************************************************************************/
  21. // vertex attributes
  22. enum EVertexAttrib {
  23. VERTEX_ARRAY, NORMAL_ARRAY, TEXCOORD_ARRAY, TANGENT_ARRAY, eNumAttribs };
  24. const char* g_aszAttribNames[] = {
  25. "inVertex", "inNormal", "inTexCoord", "inTangent" };
  26. // shader uniforms
  27. enum EUniform {
  28. eMVPMatrix, eModelWorld, eEyePosModel, eHighDetail, eNumUniforms };
  29. const char* g_aszUniformNames[] = {
  30. "MVPMatrix", "ModelWorld", "EyePosModel", "bHighDetail" };
  31. /******************************************************************************
  32. Content file names
  33. ******************************************************************************/
  34. // Source and binary shaders
  35. const char c_szFragShaderSrcFile[] = "FragShader.fsh";
  36. const char c_szFragShaderBinFile[] = "FragShader.fsc";
  37. const char c_szVertShaderSrcFile[] = "VertShader.vsh";
  38. const char c_szVertShaderBinFile[] = "VertShader.vsc";
  39. // PVR texture files
  40. const char c_szReflectTexFile[] = "Reflection.pvr";
  41. const char c_szNormalTexFile[] = "NormalMap.pvr";
  42. // POD scene files
  43. const char c_szSceneFile[] = "Mask.pod";
  44. const char* g_Detail[] = {"Detail: High", "Detail: Low"};
  45. /*!****************************************************************************
  46. Class implementing the PVRShell functions.
  47. ******************************************************************************/
  48. class OGLES2LevelOfDetail : public PVRShell
  49. {
  50. // Print3D class used to display text
  51. CPVRTPrint3D m_Print3D;
  52. // 3D Model
  53. CPVRTModelPOD m_Scene;
  54. // Projection and view matrices
  55. PVRTMat4 m_mProjection, m_mView;
  56. // OpenGL handles for shaders, textures and VBOs
  57. GLuint m_uiVertShader;
  58. GLuint m_uiFragShader;
  59. GLuint m_uiReflectTex;
  60. GLuint m_uiNormalTex;
  61. GLuint* m_puiVbo;
  62. GLuint* m_puiIndexVbo;
  63. // Group shader programs and their uniform locations together
  64. struct
  65. {
  66. GLuint uiId;
  67. GLuint auiLoc[eNumUniforms];
  68. }
  69. m_ShaderProgram;
  70. // Rotation angle for the model
  71. float m_fAngleY;
  72. // Z position of the model
  73. float m_fPositionZ;
  74. // Level of detail flag
  75. bool m_bHighDetail;
  76. // The mesh bounding box
  77. PVRTVec4 m_avBoundingBox[8];
  78. public:
  79. virtual bool InitApplication();
  80. virtual bool InitView();
  81. virtual bool ReleaseView();
  82. virtual bool QuitApplication();
  83. virtual bool RenderScene();
  84. bool LoadTextures(CPVRTString* pErrorStr);
  85. bool LoadShaders(CPVRTString* pErrorStr);
  86. void LoadVbos();
  87. void ProjectVertex(PVRTVec4& Vector, PVRTMat4& Matrix, float& fX, float& fY);
  88. void DrawMesh(int i32NodeIndex);
  89. };
  90. /*!****************************************************************************
  91. @Function LoadTextures
  92. @Output pErrorStr A string describing the error on failure
  93. @Return bool true if no error occured
  94. @Description Loads the textures required for this training course
  95. ******************************************************************************/
  96. bool OGLES2LevelOfDetail::LoadTextures(CPVRTString* const pErrorStr)
  97. {
  98. if(PVRTTextureLoadFromPVR(c_szReflectTexFile, &m_uiReflectTex) != PVR_SUCCESS)
  99. {
  100. *pErrorStr = "ERROR: Failed to load texture.";
  101. return false;
  102. }
  103. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  104. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  105. if(PVRTTextureLoadFromPVR(c_szNormalTexFile, &m_uiNormalTex) != PVR_SUCCESS)
  106. {
  107. *pErrorStr = "ERROR: Failed to load texture.";
  108. return false;
  109. }
  110. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  111. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  112. return true;
  113. }
  114. /*!****************************************************************************
  115. @Function LoadShaders
  116. @Output pErrorStr A string describing the error on failure
  117. @Return bool true if no error occured
  118. @Description Loads and compiles the shaders and links the shader programs
  119. required for this training course
  120. ******************************************************************************/
  121. bool OGLES2LevelOfDetail::LoadShaders(CPVRTString* pErrorStr)
  122. {
  123. /*
  124. Load and compile the shaders from files.
  125. Binary shaders are tried first, source shaders
  126. are used as fallback.
  127. */
  128. if (PVRTShaderLoadFromFile(
  129. c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
  130. {
  131. return false;
  132. }
  133. if (PVRTShaderLoadFromFile(
  134. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
  135. {
  136. return false;
  137. }
  138. /*
  139. Set up and link the shader program
  140. */
  141. if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, g_aszAttribNames, eNumAttribs, pErrorStr) != PVR_SUCCESS)
  142. {
  143. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  144. return false;
  145. }
  146. // Store the location of uniforms for later use
  147. for (int i = 0; i < eNumUniforms; ++i)
  148. {
  149. m_ShaderProgram.auiLoc[i] = glGetUniformLocation(m_ShaderProgram.uiId, g_aszUniformNames[i]);
  150. }
  151. return true;
  152. }
  153. /*!****************************************************************************
  154. @Function LoadVbos
  155. @Description Loads the mesh data required for this training course into
  156. vertex buffer objects
  157. ******************************************************************************/
  158. void OGLES2LevelOfDetail::LoadVbos()
  159. {
  160. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  161. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  162. /*
  163. Load vertex data of all meshes in the scene into VBOs
  164. The meshes have been exported with the "Interleave Vectors" option,
  165. so all data is interleaved in the buffer at pMesh->pInterleaved.
  166. Interleaving data improves the memory access pattern and cache efficiency,
  167. thus it can be read faster by the hardware.
  168. */
  169. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  170. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  171. {
  172. // Load vertex data into buffer object
  173. SPODMesh& Mesh = m_Scene.pMesh[i];
  174. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  175. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  176. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  177. // Load index data into buffer object if available
  178. m_puiIndexVbo[i] = 0;
  179. if (Mesh.sFaces.pData)
  180. {
  181. glGenBuffers(1, &m_puiIndexVbo[i]);
  182. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  183. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  184. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  185. }
  186. if (i == 0)
  187. {
  188. PVRTVec3 vBoundingBoxMin, vBoundingBoxMax;
  189. // calculate bounding box for mesh 0
  190. float* pfData = (float*)Mesh.pInterleaved;
  191. vBoundingBoxMin.x = vBoundingBoxMax.x = pfData[0];
  192. vBoundingBoxMin.y = vBoundingBoxMax.y = pfData[1];
  193. vBoundingBoxMin.z = vBoundingBoxMax.z = pfData[2];
  194. for(unsigned int i = 1; i < Mesh.nNumVertex; ++i)
  195. {
  196. pfData = (float*)(((char*)pfData) + Mesh.sVertex.nStride);
  197. vBoundingBoxMin.x = PVRT_MIN(vBoundingBoxMin.x, pfData[0]);
  198. vBoundingBoxMin.y = PVRT_MIN(vBoundingBoxMin.y, pfData[1]);
  199. vBoundingBoxMin.z = PVRT_MIN(vBoundingBoxMin.z, pfData[2]);
  200. vBoundingBoxMax.x = PVRT_MAX(vBoundingBoxMax.x, pfData[0]);
  201. vBoundingBoxMax.y = PVRT_MAX(vBoundingBoxMax.y, pfData[1]);
  202. vBoundingBoxMax.z = PVRT_MAX(vBoundingBoxMax.z, pfData[2]);
  203. }
  204. for (int i = 0; i < 8; ++i)
  205. {
  206. m_avBoundingBox[i].x = (i & 1) ? vBoundingBoxMin.x : vBoundingBoxMax.x;
  207. m_avBoundingBox[i].y = (i & 2) ? vBoundingBoxMin.y : vBoundingBoxMax.y;
  208. m_avBoundingBox[i].z = (i & 4) ? vBoundingBoxMin.z : vBoundingBoxMax.z;
  209. m_avBoundingBox[i].w = 1.0f;
  210. }
  211. }
  212. }
  213. glBindBuffer(GL_ARRAY_BUFFER, 0);
  214. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  215. }
  216. /*!****************************************************************************
  217. @Function InitApplication
  218. @Return bool true if no error occured
  219. @Description Code in InitApplication() will be called by PVRShell once per
  220. run, before the rendering context is created.
  221. Used to initialize variables that are not dependant on it
  222. (e.g. external modules, loading meshes, etc.)
  223. If the rendering context is lost, InitApplication() will
  224. not be called again.
  225. ******************************************************************************/
  226. bool OGLES2LevelOfDetail::InitApplication()
  227. {
  228. m_puiVbo = 0;
  229. m_puiIndexVbo = 0;
  230. // Get and set the read path for content files
  231. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  232. // Load the scene
  233. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  234. {
  235. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  236. return false;
  237. }
  238. m_fAngleY = 0.0f;
  239. m_fPositionZ = 0.0f;
  240. m_bHighDetail = true;
  241. return true;
  242. }
  243. /*!****************************************************************************
  244. @Function QuitApplication
  245. @Return bool true if no error occured
  246. @Description Code in QuitApplication() will be called by PVRShell once per
  247. run, just before exiting the program.
  248. If the rendering context is lost, QuitApplication() will
  249. not be called.x
  250. ******************************************************************************/
  251. bool OGLES2LevelOfDetail::QuitApplication()
  252. {
  253. // Free the memory allocated for the scene
  254. m_Scene.Destroy();
  255. delete [] m_puiVbo;
  256. delete [] m_puiIndexVbo;
  257. return true;
  258. }
  259. /*!****************************************************************************
  260. @Function InitView
  261. @Return bool true if no error occured
  262. @Description Code in InitView() will be called by PVRShell upon
  263. initialization or after a change in the rendering context.
  264. Used to initialize variables that are dependant on the rendering
  265. context (e.g. textures, vertex buffers, etc.)
  266. ******************************************************************************/
  267. bool OGLES2LevelOfDetail::InitView()
  268. {
  269. CPVRTString ErrorStr;
  270. /*
  271. Initialize VBO data
  272. */
  273. LoadVbos();
  274. /*
  275. Load textures
  276. */
  277. if (!LoadTextures(&ErrorStr))
  278. {
  279. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  280. return false;
  281. }
  282. /*
  283. Load and compile the shaders & link programs
  284. */
  285. if (!LoadShaders(&ErrorStr))
  286. {
  287. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  288. return false;
  289. }
  290. // Set the sampler2D uniforms to corresponding texture units
  291. glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sReflectTex"), 0);
  292. glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sNormalMap"), 1);
  293. // Is the screen rotated?
  294. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  295. /*
  296. Initialize Print3D
  297. */
  298. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  299. {
  300. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  301. return false;
  302. }
  303. /*
  304. Calculate the projection and view matrices
  305. */
  306. m_mProjection = PVRTMat4::PerspectiveFovRH(PVRT_PI/6, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
  307. m_mView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 150), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0));
  308. /*
  309. Set OpenGL ES render states needed for this training course
  310. */
  311. // Enable backface culling and depth test
  312. glCullFace(GL_BACK);
  313. glEnable(GL_CULL_FACE);
  314. glEnable(GL_DEPTH_TEST);
  315. // Use a nice bright blue as clear colour
  316. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  317. return true;
  318. }
  319. /*!****************************************************************************
  320. @Function ReleaseView
  321. @Return bool true if no error occured
  322. @Description Code in ReleaseView() will be called by PVRShell when the
  323. application quits or before a change in the rendering context.
  324. ******************************************************************************/
  325. bool OGLES2LevelOfDetail::ReleaseView()
  326. {
  327. // Delete textures
  328. glDeleteTextures(1, &m_uiReflectTex);
  329. glDeleteTextures(1, &m_uiNormalTex);
  330. // Delete program and shader objects
  331. glDeleteProgram(m_ShaderProgram.uiId);
  332. glDeleteShader(m_uiVertShader);
  333. glDeleteShader(m_uiFragShader);
  334. // Delete buffer objects
  335. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  336. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  337. // Release Print3D Textures
  338. m_Print3D.ReleaseTextures();
  339. return true;
  340. }
  341. /*!****************************************************************************
  342. @Function RenderScene
  343. @Return bool true if no error occured
  344. @Description Main rendering loop function of the program. The shell will
  345. call this function every frame.
  346. eglSwapBuffers() will be performed by PVRShell automatically.
  347. PVRShell will also manage important OS events.
  348. Will also manage relevent OS events. The user has access to
  349. these events through an abstraction layer provided by PVRShell.
  350. ******************************************************************************/
  351. bool OGLES2LevelOfDetail::RenderScene()
  352. {
  353. // Clear the color and depth buffer
  354. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  355. // Use shader program
  356. glUseProgram(m_ShaderProgram.uiId);
  357. // Bind textures
  358. glActiveTexture(GL_TEXTURE0);
  359. glBindTexture(GL_TEXTURE_2D, m_uiReflectTex);
  360. glActiveTexture(GL_TEXTURE1);
  361. glBindTexture(GL_TEXTURE_2D, m_uiNormalTex);
  362. // Rotate and Translate the model matrix
  363. PVRTMat4 mModel, mRotY, mTrans;
  364. float fDistance = 1400.0f * cos(m_fPositionZ) - 1350.0f;
  365. mTrans = PVRTMat4::Translation(0.0, 0.0, fDistance);
  366. mRotY = PVRTMat4::RotationY(m_fAngleY);
  367. mModel = mTrans * mRotY;
  368. m_fAngleY += PVRT_PI / 210;
  369. m_fPositionZ += 2 * PVRT_PI * 0.0008f;
  370. // Set model view projection matrix
  371. PVRTMat4 mModelView, mMVP;
  372. mModelView = m_mView * mModel;
  373. mMVP = m_mProjection * mModelView;
  374. glUniformMatrix4fv(m_ShaderProgram.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr());
  375. // Set model matrix
  376. PVRTMat3 Model3x3 = PVRTMat3(mModel);
  377. glUniformMatrix3fv(m_ShaderProgram.auiLoc[eModelWorld], 1, GL_FALSE, Model3x3.ptr());
  378. // Set eye position in model space
  379. PVRTVec4 vEyePosModel;
  380. vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1);
  381. glUniform3fv(m_ShaderProgram.auiLoc[eEyePosModel], 1, &vEyePosModel.x);
  382. // Calculate the square of the pixel area that the mesh takes up on screen
  383. // This is done by projecting the vertices of the bounding box to screen space
  384. // then taking the axis aligned 2D bounding box of the projected vertices.
  385. // This is a very conservative estimate
  386. float fMinX, fMaxX, fMinY, fMaxY, fX, fY;
  387. ProjectVertex(m_avBoundingBox[0], mMVP, fX, fY);
  388. fMinX = fMaxX = fX;
  389. fMinY = fMaxY = fY;
  390. for (int i = 1; i < 8; ++i)
  391. {
  392. ProjectVertex(m_avBoundingBox[i], mMVP, fX, fY);
  393. fMinX = PVRT_MIN(fMinX, fX);
  394. fMinY = PVRT_MIN(fMinY, fY);
  395. fMaxX = PVRT_MAX(fMaxX, fX);
  396. fMaxY = PVRT_MAX(fMaxY, fY);
  397. }
  398. // Choose high detail if the mesh bounding box covers more than 2% of the screen
  399. m_bHighDetail = ((fMaxX - fMinX) * (fMaxY - fMinY) > 0.02);
  400. glUniform1i(m_ShaderProgram.auiLoc[eHighDetail], m_bHighDetail);
  401. /*
  402. Now that the uniforms are set, call another function to actually draw the mesh.
  403. */
  404. DrawMesh(m_bHighDetail ? 0 : 1);
  405. // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  406. m_Print3D.DisplayDefaultTitle("Level of detail", (m_bHighDetail) ? "Detail: high" : "Detail: low", ePVRTPrint3DLogoIMG);
  407. m_Print3D.Flush();
  408. return true;
  409. }
  410. void OGLES2LevelOfDetail::ProjectVertex(PVRTVec4& Vector, PVRTMat4& Matrix, float& fX, float& fY)
  411. {
  412. PVRTVec4 vProj;
  413. vProj = Matrix * Vector;
  414. float fRcpW = 1 / vProj.w;
  415. fX = vProj.x * fRcpW;
  416. fY = vProj.y * fRcpW;
  417. }
  418. /*!****************************************************************************
  419. @Function DrawMesh
  420. @Input i32NodeIndex Node index of the mesh to draw
  421. @Description Draws a SPODMesh after the model view matrix has been set and
  422. the meterial prepared.
  423. ******************************************************************************/
  424. void OGLES2LevelOfDetail::DrawMesh(int i32NodeIndex)
  425. {
  426. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  427. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  428. // bind the VBO for the mesh
  429. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  430. // bind the index buffer, won't hurt if the handle is 0
  431. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  432. // Enable the vertex attribute arrays
  433. for (int i = 0; i < eNumAttribs; ++i) glEnableVertexAttribArray(i);
  434. // Set the vertex attribute offsets
  435. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  436. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  437. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  438. glVertexAttribPointer(TANGENT_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sTangents.nStride, pMesh->sTangents.pData);
  439. /*
  440. The geometry can be exported in 4 ways:
  441. - Indexed Triangle list
  442. - Non-Indexed Triangle list
  443. - Indexed Triangle strips
  444. - Non-Indexed Triangle strips
  445. */
  446. if(pMesh->nNumStrips == 0)
  447. {
  448. if(m_puiIndexVbo[i32MeshIndex])
  449. {
  450. // Indexed Triangle list
  451. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  452. }
  453. else
  454. {
  455. // Non-Indexed Triangle list
  456. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  457. }
  458. }
  459. else
  460. {
  461. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  462. {
  463. int offset = 0;
  464. if(m_puiIndexVbo[i32MeshIndex])
  465. {
  466. // Indexed Triangle strips
  467. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
  468. }
  469. else
  470. {
  471. // Non-Indexed Triangle strips
  472. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  473. }
  474. offset += pMesh->pnStripLength[i]+2;
  475. }
  476. }
  477. // Safely disable the vertex attribute arrays
  478. for (int i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
  479. glBindBuffer(GL_ARRAY_BUFFER, 0);
  480. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  481. }
  482. /*!****************************************************************************
  483. @Function NewDemo
  484. @Return PVRShell* The demo supplied by the user
  485. @Description This function must be implemented by the user of the shell.
  486. The user should return its PVRShell object defining the
  487. behaviour of the application.
  488. ******************************************************************************/
  489. PVRShell* NewDemo()
  490. {
  491. return new OGLES2LevelOfDetail();
  492. }
  493. /******************************************************************************
  494. End of file (OGLES2LevelOfDetail.cpp)
  495. ******************************************************************************/