OGLES2FastTnL.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /******************************************************************************
  2. @File OGLES2FastTnL.cpp
  3. @Title Fast Transformation and Lighting
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Demonstrates fast transform and lighting in the vertex shader.
  8. ******************************************************************************/
  9. #include <math.h>
  10. #include "PVRShell.h"
  11. #include "OGLES2Tools.h"
  12. /******************************************************************************
  13. Constants
  14. ******************************************************************************/
  15. // Camera constants. Used for making the projection matrix
  16. const float CAM_FOV = PVRT_PI / 6;
  17. const float CAM_NEAR = 4.0f;
  18. // Index to bind the attributes to vertex shaders
  19. const int VERTEX_ARRAY = 0;
  20. const int NORMAL_ARRAY = 1;
  21. const int TEXCOORD_ARRAY = 2;
  22. /******************************************************************************
  23. Content file names
  24. ******************************************************************************/
  25. // Source and binary shaders
  26. const char c_szFragShaderSrcFile[] = "FragShader.fsh";
  27. const char c_szFragShaderBinFile[] = "FragShader.fsc";
  28. const char c_szVertShaderSrcFile[] = "VertShader.vsh";
  29. const char c_szVertShaderBinFile[] = "VertShader.vsc";
  30. // PVR texture files
  31. const char c_szTextureFile[] = "Basetex.pvr";
  32. // POD scene files
  33. const char c_szSceneFile[] = "Mask.pod";
  34. /*!****************************************************************************
  35. Class implementing the PVRShell functions.
  36. ******************************************************************************/
  37. class OGLES2FastTnL : public PVRShell
  38. {
  39. // Print3D class used to display text
  40. CPVRTPrint3D m_Print3D;
  41. // 3D Model
  42. CPVRTModelPOD m_Scene;
  43. // Projection and view matrices
  44. PVRTMat4 m_mViewProj;
  45. // OpenGL handles for shaders, textures and VBOs
  46. GLuint m_uiVertShader;
  47. GLuint m_uiFragShader;
  48. GLuint m_uiTexture;
  49. GLuint* m_puiVbo;
  50. GLuint* m_puiIndexVbo;
  51. // Group shader programs and their uniform locations together
  52. struct
  53. {
  54. GLuint uiId;
  55. GLuint uiMVPMatrixLoc;
  56. GLuint uiLightDirLoc;
  57. GLuint uiMaterialBiasLoc;
  58. GLuint uiMaterialScaleLoc;
  59. }
  60. m_ShaderProgram;
  61. // View Angle for animation
  62. float m_fAngleY;
  63. public:
  64. virtual bool InitApplication();
  65. virtual bool InitView();
  66. virtual bool ReleaseView();
  67. virtual bool QuitApplication();
  68. virtual bool RenderScene();
  69. bool LoadTextures(CPVRTString* pErrorStr);
  70. bool LoadShaders(CPVRTString* pErrorStr);
  71. void LoadVbos();
  72. void DrawMesh(int i32NodeIndex);
  73. };
  74. /*!****************************************************************************
  75. @Function LoadTextures
  76. @Output pErrorStr A string describing the error on failure
  77. @Return bool true if no error occured
  78. @Description Loads the textures required for this training course
  79. ******************************************************************************/
  80. bool OGLES2FastTnL::LoadTextures(CPVRTString* const pErrorStr)
  81. {
  82. if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS)
  83. {
  84. *pErrorStr = "ERROR: Failed to load texture.";
  85. return false;
  86. }
  87. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  88. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  89. return true;
  90. }
  91. /*!****************************************************************************
  92. @Function LoadShaders
  93. @Output pErrorStr A string describing the error on failure
  94. @Return bool true if no error occured
  95. @Description Loads and compiles the shaders and links the shader programs
  96. required for this training course
  97. ******************************************************************************/
  98. bool OGLES2FastTnL::LoadShaders(CPVRTString* pErrorStr)
  99. {
  100. /*
  101. Load and compile the shaders from files.
  102. Binary shaders are tried first, source shaders
  103. are used as fallback.
  104. */
  105. if (PVRTShaderLoadFromFile(
  106. c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
  107. {
  108. return false;
  109. }
  110. if (PVRTShaderLoadFromFile(
  111. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
  112. {
  113. return false;
  114. }
  115. /*
  116. Set up and link the shader program
  117. */
  118. const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" };
  119. if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS)
  120. {
  121. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  122. return false;
  123. }
  124. // Set the sampler2D variable to the first texture unit
  125. glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sTexture"), 0);
  126. // Store the location of uniforms for later use
  127. m_ShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix");
  128. m_ShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection");
  129. m_ShaderProgram.uiMaterialBiasLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MaterialBias");
  130. m_ShaderProgram.uiMaterialScaleLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MaterialScale");
  131. return true;
  132. }
  133. /*!****************************************************************************
  134. @Function LoadVbos
  135. @Description Loads the mesh data required for this training course into
  136. vertex buffer objects
  137. ******************************************************************************/
  138. void OGLES2FastTnL::LoadVbos()
  139. {
  140. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  141. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  142. /*
  143. Load vertex data of all meshes in the scene into VBOs
  144. The meshes have been exported with the "Interleave Vectors" option,
  145. so all data is interleaved in the buffer at pMesh->pInterleaved.
  146. Interleaving data improves the memory access pattern and cache efficiency,
  147. thus it can be read faster by the hardware.
  148. */
  149. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  150. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  151. {
  152. // Load vertex data into buffer object
  153. SPODMesh& Mesh = m_Scene.pMesh[i];
  154. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  155. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  156. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  157. // Load index data into buffer object if available
  158. m_puiIndexVbo[i] = 0;
  159. if (Mesh.sFaces.pData)
  160. {
  161. glGenBuffers(1, &m_puiIndexVbo[i]);
  162. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  163. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  164. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  165. }
  166. }
  167. glBindBuffer(GL_ARRAY_BUFFER, 0);
  168. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  169. }
  170. /*!****************************************************************************
  171. @Function InitApplication
  172. @Return bool true if no error occured
  173. @Description Code in InitApplication() will be called by PVRShell once per
  174. run, before the rendering context is created.
  175. Used to initialize variables that are not dependant on it
  176. (e.g. external modules, loading meshes, etc.)
  177. If the rendering context is lost, InitApplication() will
  178. not be called again.
  179. ******************************************************************************/
  180. bool OGLES2FastTnL::InitApplication()
  181. {
  182. m_puiVbo = 0;
  183. m_puiIndexVbo = 0;
  184. // Get and set the read path for content files
  185. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  186. // Load the scene
  187. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  188. {
  189. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  190. return false;
  191. }
  192. m_fAngleY = 0.0;
  193. return true;
  194. }
  195. /*!****************************************************************************
  196. @Function QuitApplication
  197. @Return bool true if no error occured
  198. @Description Code in QuitApplication() will be called by PVRShell once per
  199. run, just before exiting the program.
  200. If the rendering context is lost, QuitApplication() will
  201. not be called.x
  202. ******************************************************************************/
  203. bool OGLES2FastTnL::QuitApplication()
  204. {
  205. // Free the memory allocated for the scene
  206. m_Scene.Destroy();
  207. delete [] m_puiVbo;
  208. delete [] m_puiIndexVbo;
  209. return true;
  210. }
  211. /*!****************************************************************************
  212. @Function InitView
  213. @Return bool true if no error occured
  214. @Description Code in InitView() will be called by PVRShell upon
  215. initialization or after a change in the rendering context.
  216. Used to initialize variables that are dependant on the rendering
  217. context (e.g. textures, vertex buffers, etc.)
  218. ******************************************************************************/
  219. bool OGLES2FastTnL::InitView()
  220. {
  221. CPVRTString ErrorStr;
  222. /*
  223. Initialize VBO data
  224. */
  225. LoadVbos();
  226. /*
  227. Load textures
  228. */
  229. if (!LoadTextures(&ErrorStr))
  230. {
  231. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  232. return false;
  233. }
  234. /*
  235. Load and compile the shaders & link programs
  236. */
  237. if (!LoadShaders(&ErrorStr))
  238. {
  239. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  240. return false;
  241. }
  242. // Is the screen rotated?
  243. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  244. /*
  245. Initialize Print3D
  246. */
  247. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  248. {
  249. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  250. return false;
  251. }
  252. /*
  253. Calculate the projection and view matrices
  254. */
  255. float fAspect = PVRShellGet(prefWidth) / (float)PVRShellGet(prefHeight);
  256. m_mViewProj = PVRTMat4::PerspectiveFovFloatDepthRH(CAM_FOV, fAspect, CAM_NEAR, PVRTMat4::OGL, bRotate);
  257. m_mViewProj *= PVRTMat4::LookAtRH(PVRTVec3(0.f, 0.f, 150.f), PVRTVec3(0.f), PVRTVec3(0.f, 1.f, 0.f));
  258. /*
  259. Set default shader material uniforms
  260. */
  261. float fSpecularConcentration = 0.8f; // a value from 0 to 1 (wider, concetrated)
  262. float fSpecularIntensity = 0.5f; // a value from 0 to 1
  263. // Specular bias
  264. glUniform1f(m_ShaderProgram.uiMaterialBiasLoc, fSpecularConcentration);
  265. // Specular intensity scale
  266. glUniform1f(m_ShaderProgram.uiMaterialScaleLoc, fSpecularIntensity / (1.0f - fSpecularConcentration));
  267. /*
  268. Set OpenGL ES render states needed for this training course
  269. */
  270. // Enable backface culling and depth test
  271. glCullFace(GL_BACK);
  272. glEnable(GL_CULL_FACE);
  273. // Enable z-buffer test
  274. // We are using a projection matrix optimized for a floating point depth buffer,
  275. // so the depth test and clear value need to be inverted (1 becomes near, 0 becomes far).
  276. glEnable(GL_DEPTH_TEST);
  277. glDepthFunc(GL_GEQUAL);
  278. glClearDepthf(0.0f);
  279. // Use a nice bright blue as clear colour
  280. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  281. return true;
  282. }
  283. /*!****************************************************************************
  284. @Function ReleaseView
  285. @Return bool true if no error occured
  286. @Description Code in ReleaseView() will be called by PVRShell when the
  287. application quits or before a change in the rendering context.
  288. ******************************************************************************/
  289. bool OGLES2FastTnL::ReleaseView()
  290. {
  291. // Delete textures
  292. glDeleteTextures(1, &m_uiTexture);
  293. // Delete program and shader objects
  294. glDeleteProgram(m_ShaderProgram.uiId);
  295. glDeleteShader(m_uiVertShader);
  296. glDeleteShader(m_uiFragShader);
  297. // Delete buffer objects
  298. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  299. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  300. // Release Print3D Textures
  301. m_Print3D.ReleaseTextures();
  302. return true;
  303. }
  304. /*!****************************************************************************
  305. @Function RenderScene
  306. @Return bool true if no error occured
  307. @Description Main rendering loop function of the program. The shell will
  308. call this function every frame.
  309. eglSwapBuffers() will be performed by PVRShell automatically.
  310. PVRShell will also manage important OS events.
  311. Will also manage relevent OS events. The user has access to
  312. these events through an abstraction layer provided by PVRShell.
  313. ******************************************************************************/
  314. bool OGLES2FastTnL::RenderScene()
  315. {
  316. // Clear the color and depth buffer
  317. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  318. // Use shader program
  319. glUseProgram(m_ShaderProgram.uiId);
  320. // Bind texture
  321. glActiveTexture(GL_TEXTURE0);
  322. glBindTexture(GL_TEXTURE_2D, m_uiTexture);
  323. /*
  324. Now that the uniforms are set, call another function to actually draw the mesh.
  325. */
  326. DrawMesh(0);
  327. // Rotate the model matrix
  328. PVRTMat4 mModel = PVRTMat4::RotationY(m_fAngleY);
  329. m_fAngleY += 0.02f;
  330. // Calculate model view projection matrix
  331. PVRTMat4 mMVP = m_mViewProj * mModel;
  332. // Feeds Projection Model View matrix to the shaders
  333. glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr());
  334. /*
  335. The inverse of a rotation matrix is the transposed matrix
  336. Because of v * M = transpose(M) * v, this means:
  337. v * R == inverse(R) * v
  338. So we don't have to actually invert or transpose the matrix
  339. to transform back from world space to model space
  340. */
  341. PVRTVec3 vMsLightDir = (PVRTVec3(1, 1, 1) * PVRTMat3(mModel)).normalized();
  342. glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, vMsLightDir.ptr());
  343. // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  344. m_Print3D.DisplayDefaultTitle("FastTnL", "", ePVRTPrint3DLogoIMG);
  345. m_Print3D.Flush();
  346. return true;
  347. }
  348. /*!****************************************************************************
  349. @Function DrawMesh
  350. @Input i32NodeIndex Node index of the mesh to draw
  351. @Description Draws a SPODMesh after the model view matrix has been set and
  352. the meterial prepared.
  353. ******************************************************************************/
  354. void OGLES2FastTnL::DrawMesh(int i32NodeIndex)
  355. {
  356. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  357. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  358. // bind the VBO for the mesh
  359. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  360. // bind the index buffer, won't hurt if the handle is 0
  361. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  362. // Enable the vertex attribute arrays
  363. glEnableVertexAttribArray(VERTEX_ARRAY);
  364. glEnableVertexAttribArray(NORMAL_ARRAY);
  365. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  366. // Set the vertex attribute offsets
  367. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  368. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  369. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  370. /*
  371. The geometry can be exported in 4 ways:
  372. - Indexed Triangle list
  373. - Non-Indexed Triangle list
  374. - Indexed Triangle strips
  375. - Non-Indexed Triangle strips
  376. */
  377. if(pMesh->nNumStrips == 0)
  378. {
  379. if(m_puiIndexVbo[i32MeshIndex])
  380. {
  381. // Indexed Triangle list
  382. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  383. }
  384. else
  385. {
  386. // Non-Indexed Triangle list
  387. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  388. }
  389. }
  390. else
  391. {
  392. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  393. {
  394. int offset = 0;
  395. if(m_puiIndexVbo[i32MeshIndex])
  396. {
  397. // Indexed Triangle strips
  398. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, (GLshort*)(offset*2));
  399. }
  400. else
  401. {
  402. // Non-Indexed Triangle strips
  403. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  404. }
  405. offset += pMesh->pnStripLength[i]+2;
  406. }
  407. }
  408. // Safely disable the vertex attribute arrays
  409. glDisableVertexAttribArray(VERTEX_ARRAY);
  410. glDisableVertexAttribArray(NORMAL_ARRAY);
  411. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  412. glBindBuffer(GL_ARRAY_BUFFER, 0);
  413. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  414. }
  415. /*!****************************************************************************
  416. @Function NewDemo
  417. @Return PVRShell* The demo supplied by the user
  418. @Description This function must be implemented by the user of the shell.
  419. The user should return its PVRShell object defining the
  420. behaviour of the application.
  421. ******************************************************************************/
  422. PVRShell* NewDemo()
  423. {
  424. return new OGLES2FastTnL();
  425. }
  426. /******************************************************************************
  427. End of file (OGLES2FastTnL.cpp)
  428. ******************************************************************************/