OGLES2Iridescence.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /******************************************************************************
  2. @File OGLES2Iridescence.cpp
  3. @Title Iridescence
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Shows how to implement an iridescent effect on an object by
  8. simulating the effects of a thin transparent coating.
  9. ******************************************************************************/
  10. #include "PVRShell.h"
  11. #include "OGLES2Tools.h"
  12. /******************************************************************************
  13. Defines
  14. ******************************************************************************/
  15. // Camera constants. Used for making the projection matrix
  16. #define CAM_NEAR (1.0f)
  17. #define CAM_FAR (5000.0f)
  18. // Index to bind the attributes to vertex shaders
  19. #define VERTEX_ARRAY 0
  20. #define NORMAL_ARRAY 1
  21. #define 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[] = "Thickness.pvr";
  32. // POD scene files
  33. const char c_szSceneFile[] = "Mask.pod";
  34. /*!****************************************************************************
  35. Class implementing the PVRShell functions.
  36. ******************************************************************************/
  37. class OGLES2Iridescence : 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_mProjection, m_mView;
  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 uiEyePosLoc;
  58. GLuint uiMinThicknessLoc;
  59. GLuint uiMaxVariationLoc;
  60. }
  61. m_ShaderProgram;
  62. // The translation and Rotate parameter of Model
  63. float m_fAngleY;
  64. float m_fMinThickness;
  65. float m_fMaxVariation;
  66. public:
  67. virtual bool InitApplication();
  68. virtual bool InitView();
  69. virtual bool ReleaseView();
  70. virtual bool QuitApplication();
  71. virtual bool RenderScene();
  72. bool LoadTextures(CPVRTString* pErrorStr);
  73. bool LoadShaders(CPVRTString* pErrorStr);
  74. void LoadVbos();
  75. void DrawMesh(int i32NodeIndex);
  76. };
  77. /*!****************************************************************************
  78. @Function LoadTextures
  79. @Output pErrorStr A string describing the error on failure
  80. @Return bool true if no error occured
  81. @Description Loads the textures required for this training course
  82. ******************************************************************************/
  83. bool OGLES2Iridescence::LoadTextures(CPVRTString* const pErrorStr)
  84. {
  85. if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS)
  86. {
  87. *pErrorStr = "ERROR: Failed to load texture.";
  88. return false;
  89. }
  90. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  91. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  92. return true;
  93. }
  94. /*!****************************************************************************
  95. @Function LoadShaders
  96. @Output pErrorStr A string describing the error on failure
  97. @Return bool true if no error occured
  98. @Description Loads and compiles the shaders and links the shader programs
  99. required for this training course
  100. ******************************************************************************/
  101. bool OGLES2Iridescence::LoadShaders(CPVRTString* pErrorStr)
  102. {
  103. /*
  104. Load and compile the shaders from files.
  105. Binary shaders are tried first, source shaders
  106. are used as fallback.
  107. */
  108. if (PVRTShaderLoadFromFile(
  109. c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
  110. {
  111. return false;
  112. }
  113. if (PVRTShaderLoadFromFile(
  114. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
  115. {
  116. return false;
  117. }
  118. /*
  119. Set up and link the shader program
  120. */
  121. const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" };
  122. if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr))
  123. {
  124. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  125. return false;
  126. }
  127. // Set the sampler2D variable to the first texture unit
  128. glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sThicknessTex"), 0);
  129. // Store the location of uniforms for later use
  130. m_ShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix");
  131. m_ShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection");
  132. m_ShaderProgram.uiEyePosLoc = glGetUniformLocation(m_ShaderProgram.uiId, "EyePosition");
  133. m_ShaderProgram.uiMinThicknessLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MinThickness");
  134. m_ShaderProgram.uiMaxVariationLoc = glGetUniformLocation(m_ShaderProgram.uiId, "MaxVariation");
  135. return true;
  136. }
  137. /*!****************************************************************************
  138. @Function LoadVbos
  139. @Description Loads the mesh data required for this training course into
  140. vertex buffer objects
  141. ******************************************************************************/
  142. void OGLES2Iridescence::LoadVbos()
  143. {
  144. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  145. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  146. /*
  147. Load vertex data of all meshes in the scene into VBOs
  148. The meshes have been exported with the "Interleave Vectors" option,
  149. so all data is interleaved in the buffer at pMesh->pInterleaved.
  150. Interleaving data improves the memory access pattern and cache efficiency,
  151. thus it can be read faster by the hardware.
  152. */
  153. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  154. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  155. {
  156. // Load vertex data into buffer object
  157. SPODMesh& Mesh = m_Scene.pMesh[i];
  158. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  159. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  160. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  161. // Load index data into buffer object if available
  162. m_puiIndexVbo[i] = 0;
  163. if (Mesh.sFaces.pData)
  164. {
  165. glGenBuffers(1, &m_puiIndexVbo[i]);
  166. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  167. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  168. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  169. }
  170. }
  171. glBindBuffer(GL_ARRAY_BUFFER, 0);
  172. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  173. }
  174. /*!****************************************************************************
  175. @Function InitApplication
  176. @Return bool true if no error occured
  177. @Description Code in InitApplication() will be called by PVRShell once per
  178. run, before the rendering context is created.
  179. Used to initialize variables that are not dependant on it
  180. (e.g. external modules, loading meshes, etc.)
  181. If the rendering context is lost, InitApplication() will
  182. not be called again.
  183. ******************************************************************************/
  184. bool OGLES2Iridescence::InitApplication()
  185. {
  186. m_puiVbo = 0;
  187. m_puiIndexVbo = 0;
  188. // Get and set the read path for content files
  189. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  190. // Load the scene
  191. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  192. {
  193. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  194. return false;
  195. }
  196. // set angle of rotation
  197. m_fAngleY = 0.0f;
  198. return true;
  199. }
  200. /*!****************************************************************************
  201. @Function QuitApplication
  202. @Return bool true if no error occured
  203. @Description Code in QuitApplication() will be called by PVRShell once per
  204. run, just before exiting the program.
  205. If the rendering context is lost, QuitApplication() will
  206. not be called.x
  207. ******************************************************************************/
  208. bool OGLES2Iridescence::QuitApplication()
  209. {
  210. // Free the memory allocated for the scene
  211. m_Scene.Destroy();
  212. delete [] m_puiVbo;
  213. delete [] m_puiIndexVbo;
  214. return true;
  215. }
  216. /*!****************************************************************************
  217. @Function InitView
  218. @Return bool true if no error occured
  219. @Description Code in InitView() will be called by PVRShell upon
  220. initialization or after a change in the rendering context.
  221. Used to initialize variables that are dependant on the rendering
  222. context (e.g. textures, vertex buffers, etc.)
  223. ******************************************************************************/
  224. bool OGLES2Iridescence::InitView()
  225. {
  226. CPVRTString ErrorStr;
  227. /*
  228. Initialize VBO data
  229. */
  230. LoadVbos();
  231. /*
  232. Load textures
  233. */
  234. if (!LoadTextures(&ErrorStr))
  235. {
  236. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  237. return false;
  238. }
  239. /*
  240. Load and compile the shaders & link programs
  241. */
  242. if (!LoadShaders(&ErrorStr))
  243. {
  244. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  245. return false;
  246. }
  247. // Is the screen rotated?
  248. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  249. /*
  250. Initialize Print3D
  251. */
  252. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  253. {
  254. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  255. return false;
  256. }
  257. /*
  258. Calculate the projection and view matrices
  259. */
  260. m_mProjection = PVRTMat4::PerspectiveFovRH(PVRT_PI/6, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
  261. m_mView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 125), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0));
  262. /*
  263. Set OpenGL ES render states needed for this training course
  264. */
  265. // Enable backface culling and depth test
  266. glCullFace(GL_BACK);
  267. glEnable(GL_CULL_FACE);
  268. glEnable(GL_DEPTH_TEST);
  269. // Use a nice bright blue as clear colour
  270. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  271. // set thickness variation of the film
  272. m_fMaxVariation = 100.0f;
  273. // set the minimum thickness of the film
  274. m_fMinThickness = 100.0f;
  275. return true;
  276. }
  277. /*!****************************************************************************
  278. @Function ReleaseView
  279. @Return bool true if no error occured
  280. @Description Code in ReleaseView() will be called by PVRShell when the
  281. application quits or before a change in the rendering context.
  282. ******************************************************************************/
  283. bool OGLES2Iridescence::ReleaseView()
  284. {
  285. // Delete textures
  286. glDeleteTextures(1, &m_uiTexture);
  287. // Delete program and shader objects
  288. glDeleteProgram(m_ShaderProgram.uiId);
  289. glDeleteShader(m_uiVertShader);
  290. glDeleteShader(m_uiFragShader);
  291. // Delete buffer objects
  292. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  293. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  294. // Release Print3D Textures
  295. m_Print3D.ReleaseTextures();
  296. return true;
  297. }
  298. /*!****************************************************************************
  299. @Function RenderScene
  300. @Return bool true if no error occured
  301. @Description Main rendering loop function of the program. The shell will
  302. call this function every frame.
  303. eglSwapBuffers() will be performed by PVRShell automatically.
  304. PVRShell will also manage important OS events.
  305. Will also manage relevent OS events. The user has access to
  306. these events through an abstraction layer provided by PVRShell.
  307. ******************************************************************************/
  308. bool OGLES2Iridescence::RenderScene()
  309. {
  310. // Keyboard input (cursor up/down to change thickness variation)
  311. if (PVRShellIsKeyPressed(PVRShellKeyNameUP))
  312. {
  313. m_fMaxVariation += 1.0f;
  314. }
  315. else if (PVRShellIsKeyPressed(PVRShellKeyNameDOWN))
  316. {
  317. m_fMaxVariation = PVRT_MAX(0.0f, m_fMaxVariation - 1.0f);
  318. }
  319. // Keyboard input (cursor left/right to change minimum thickness)
  320. if (PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
  321. {
  322. m_fMinThickness += 1.0f;
  323. }
  324. else if (PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
  325. {
  326. m_fMinThickness = PVRT_MAX(0.0f, m_fMinThickness - 1.0f);
  327. }
  328. // Clear the color and depth buffer
  329. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  330. // Use shader program
  331. glUseProgram(m_ShaderProgram.uiId);
  332. // Bind texture
  333. glActiveTexture(GL_TEXTURE0);
  334. glBindTexture(GL_TEXTURE_2D, m_uiTexture);
  335. // Rotate and Translation the model matrix
  336. PVRTMat4 mModel;
  337. mModel = PVRTMat4::RotationY(m_fAngleY);
  338. m_fAngleY += (2*PVRT_PI/60)/7;
  339. // Set model view projection matrix
  340. PVRTMat4 mModelView, mMVP;
  341. mModelView = m_mView * mModel;
  342. mMVP = m_mProjection * mModelView;
  343. glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr());
  344. // Set light direction in model space
  345. PVRTVec4 vLightDirModel;
  346. vLightDirModel = mModel.inverse() * PVRTVec4(1, 1, 1, 0);
  347. glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x);
  348. // Set eye position in model space
  349. PVRTVec4 vEyePosModel;
  350. vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1);
  351. glUniform3fv(m_ShaderProgram.uiEyePosLoc, 1, &vEyePosModel.x);
  352. /*
  353. Set the iridescent shading parameters
  354. */
  355. // Set the minimum thickness of the coating in nm
  356. glUniform1f(m_ShaderProgram.uiMinThicknessLoc, m_fMinThickness);
  357. // Set the maximum variation in thickness of the coating in nm
  358. glUniform1f(m_ShaderProgram.uiMaxVariationLoc, m_fMaxVariation);
  359. /*
  360. Now that the uniforms are set, call another function to actually draw the mesh.
  361. */
  362. DrawMesh(0);
  363. m_Print3D.Print3D(2.0f, 10.0f, 0.75f, 0xffffffff, "Minimum Thickness:");
  364. m_Print3D.Print3D(2.0f, 15.0f, 0.75f, 0xffffffff, "%8.0f nm", m_fMinThickness);
  365. m_Print3D.Print3D(2.0f, 20.0f, 0.75f, 0xffffffff, "Maximum Variation:");
  366. m_Print3D.Print3D(2.0f, 25.0f, 0.75f, 0xffffffff, "%8.0f nm", m_fMaxVariation);
  367. // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  368. m_Print3D.DisplayDefaultTitle("Iridescence", "", ePVRTPrint3DLogoIMG);
  369. m_Print3D.Flush();
  370. return true;
  371. }
  372. /*!****************************************************************************
  373. @Function DrawMesh
  374. @Input i32NodeIndex Node index of the mesh to draw
  375. @Description Draws a SPODMesh after the model view matrix has been set and
  376. the meterial prepared.
  377. ******************************************************************************/
  378. void OGLES2Iridescence::DrawMesh(int i32NodeIndex)
  379. {
  380. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  381. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  382. // bind the VBO for the mesh
  383. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  384. // bind the index buffer, won't hurt if the handle is 0
  385. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  386. // Enable the vertex attribute arrays
  387. glEnableVertexAttribArray(VERTEX_ARRAY);
  388. glEnableVertexAttribArray(NORMAL_ARRAY);
  389. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  390. // Set the vertex attribute offsets
  391. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  392. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  393. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  394. /*
  395. The geometry can be exported in 4 ways:
  396. - Indexed Triangle list
  397. - Non-Indexed Triangle list
  398. - Indexed Triangle strips
  399. - Non-Indexed Triangle strips
  400. */
  401. if(pMesh->nNumStrips == 0)
  402. {
  403. if(m_puiIndexVbo[i32MeshIndex])
  404. {
  405. // Indexed Triangle list
  406. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  407. }
  408. else
  409. {
  410. // Non-Indexed Triangle list
  411. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  412. }
  413. }
  414. else
  415. {
  416. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  417. {
  418. int offset = 0;
  419. if(m_puiIndexVbo[i32MeshIndex])
  420. {
  421. // Indexed Triangle strips
  422. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, (GLshort*)(offset*2));
  423. }
  424. else
  425. {
  426. // Non-Indexed Triangle strips
  427. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  428. }
  429. offset += pMesh->pnStripLength[i]+2;
  430. }
  431. }
  432. // Safely disable the vertex attribute arrays
  433. glDisableVertexAttribArray(VERTEX_ARRAY);
  434. glDisableVertexAttribArray(NORMAL_ARRAY);
  435. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  436. glBindBuffer(GL_ARRAY_BUFFER, 0);
  437. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  438. }
  439. /*!****************************************************************************
  440. @Function NewDemo
  441. @Return PVRShell* The demo supplied by the user
  442. @Description This function must be implemented by the user of the shell.
  443. The user should return its PVRShell object defining the
  444. behaviour of the application.
  445. ******************************************************************************/
  446. PVRShell* NewDemo()
  447. {
  448. return new OGLES2Iridescence();
  449. }
  450. /******************************************************************************
  451. End of file (OGLES2Iridescence.cpp)
  452. ******************************************************************************/