OGLES2Refraction.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /******************************************************************************
  2. @File OGLES2Refraction.cpp
  3. @Title Refraction
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Vertex-based refraction using a 2D environment map
  8. ******************************************************************************/
  9. #include "PVRShell.h"
  10. #include "OGLES2Tools.h"
  11. /******************************************************************************
  12. Constants
  13. ******************************************************************************/
  14. // Camera constants used to generate the projection matrix
  15. const float CAM_NEAR = 75.0f;
  16. const float CAM_FAR = 2000.0f;
  17. /******************************************************************************
  18. shader attributes
  19. ******************************************************************************/
  20. // vertex attributes
  21. enum EVertexAttrib {
  22. VERTEX_ARRAY, NORMAL_ARRAY, eNumAttribs };
  23. const char* g_aszAttribNames[] = {
  24. "inVertex", "inNormal" };
  25. // shader uniforms
  26. enum EUniform {
  27. eMVPMatrix, eLightDirModel, eEyePosModel, eSpecular, eRotate, eNumUniforms };
  28. const char* g_aszUniformNames[] = {
  29. "MVPMatrix", "LightDirModel", "EyePosModel", "bSpecular", "bRotate" };
  30. /******************************************************************************
  31. Content file names
  32. ******************************************************************************/
  33. // Source and binary shaders
  34. const char c_szFragShaderSrcFile[] = "FragShader.fsh";
  35. const char c_szFragShaderBinFile[] = "FragShader.fsc";
  36. const char c_szVertShaderSrcFile[] = "VertShader.vsh";
  37. const char c_szVertShaderBinFile[] = "VertShader.vsc";
  38. // PVR texture files
  39. const char c_szTextureFile[] = "Basetex.pvr";
  40. // POD scene files
  41. const char c_szSceneFile[] = "Mask.pod";
  42. /*!****************************************************************************
  43. Class implementing the PVRShell functions.
  44. ******************************************************************************/
  45. class OGLES2Refraction : public PVRShell
  46. {
  47. // Print3D class used to display text
  48. CPVRTPrint3D m_Print3D;
  49. // 3D Model
  50. CPVRTModelPOD m_Scene;
  51. // Projection and view matrices
  52. PVRTMat4 m_mProjection, m_mView;
  53. // OpenGL handles for shaders, textures and VBOs
  54. GLuint m_uiVertShader;
  55. GLuint m_uiFragShader;
  56. GLuint m_uiTexture;
  57. GLuint* m_puiVbo;
  58. GLuint* m_puiIndexVbo;
  59. // Group shader programs and their uniform locations together
  60. struct
  61. {
  62. GLuint uiId;
  63. GLuint auiLoc[eNumUniforms];
  64. }
  65. m_ShaderProgram;
  66. // Rotation angle for the model
  67. float m_fAngleX, m_fAngleY;
  68. // Flags (on/off)
  69. bool m_bSpecular;
  70. bool m_bRotate;
  71. // The background
  72. CPVRTBackground m_Background;
  73. public:
  74. virtual bool InitApplication();
  75. virtual bool InitView();
  76. virtual bool ReleaseView();
  77. virtual bool QuitApplication();
  78. virtual bool RenderScene();
  79. bool LoadTextures(CPVRTString* pErrorStr);
  80. bool LoadShaders(CPVRTString* pErrorStr);
  81. void LoadVbos();
  82. void DrawMesh(int i32NodeIndex);
  83. };
  84. /*!****************************************************************************
  85. @Function LoadTextures
  86. @Output pErrorStr A string describing the error on failure
  87. @Return bool true if no error occured
  88. @Description Loads the textures required for this training course
  89. ******************************************************************************/
  90. bool OGLES2Refraction::LoadTextures(CPVRTString* const pErrorStr)
  91. {
  92. if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS)
  93. {
  94. *pErrorStr = "ERROR: Failed to load texture.";
  95. return false;
  96. }
  97. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  98. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  99. return true;
  100. }
  101. /*!****************************************************************************
  102. @Function LoadShaders
  103. @Output pErrorStr A string describing the error on failure
  104. @Return bool true if no error occured
  105. @Description Loads and compiles the shaders and links the shader programs
  106. required for this training course
  107. ******************************************************************************/
  108. bool OGLES2Refraction::LoadShaders(CPVRTString* pErrorStr)
  109. {
  110. /*
  111. Load and compile the shaders from files.
  112. Binary shaders are tried first, source shaders
  113. are used as fallback.
  114. */
  115. if (PVRTShaderLoadFromFile(
  116. c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
  117. {
  118. return false;
  119. }
  120. if (PVRTShaderLoadFromFile(
  121. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
  122. {
  123. return false;
  124. }
  125. /*
  126. Set up and link the shader program
  127. */
  128. if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, g_aszAttribNames, eNumAttribs, pErrorStr) != PVR_SUCCESS)
  129. {
  130. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  131. return false;
  132. }
  133. // Store the location of uniforms for later use
  134. for (int i = 0; i < eNumUniforms; ++i)
  135. {
  136. m_ShaderProgram.auiLoc[i] = glGetUniformLocation(m_ShaderProgram.uiId, g_aszUniformNames[i]);
  137. }
  138. return true;
  139. }
  140. /*!****************************************************************************
  141. @Function LoadVbos
  142. @Description Loads the mesh data required for this training course into
  143. vertex buffer objects
  144. ******************************************************************************/
  145. void OGLES2Refraction::LoadVbos()
  146. {
  147. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  148. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  149. /*
  150. Load vertex data of all meshes in the scene into VBOs
  151. The meshes have been exported with the "Interleave Vectors" option,
  152. so all data is interleaved in the buffer at pMesh->pInterleaved.
  153. Interleaving data improves the memory access pattern and cache efficiency,
  154. thus it can be read faster by the hardware.
  155. */
  156. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  157. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  158. {
  159. // Load vertex data into buffer object
  160. SPODMesh& Mesh = m_Scene.pMesh[i];
  161. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  162. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  163. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  164. // Load index data into buffer object if available
  165. m_puiIndexVbo[i] = 0;
  166. if (Mesh.sFaces.pData)
  167. {
  168. glGenBuffers(1, &m_puiIndexVbo[i]);
  169. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  170. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  171. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  172. }
  173. }
  174. glBindBuffer(GL_ARRAY_BUFFER, 0);
  175. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  176. }
  177. /*!****************************************************************************
  178. @Function InitApplication
  179. @Return bool true if no error occured
  180. @Description Code in InitApplication() will be called by PVRShell once per
  181. run, before the rendering context is created.
  182. Used to initialize variables that are not dependant on it
  183. (e.g. external modules, loading meshes, etc.)
  184. If the rendering context is lost, InitApplication() will
  185. not be called again.
  186. ******************************************************************************/
  187. bool OGLES2Refraction::InitApplication()
  188. {
  189. m_puiVbo = 0;
  190. m_puiIndexVbo = 0;
  191. // Get and set the read path for content files
  192. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  193. // Load the scene
  194. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  195. {
  196. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  197. return false;
  198. }
  199. m_bSpecular = true;
  200. m_fAngleX = 0.0f;
  201. m_fAngleY = 0.0f;
  202. return true;
  203. }
  204. /*!****************************************************************************
  205. @Function QuitApplication
  206. @Return bool true if no error occured
  207. @Description Code in QuitApplication() will be called by PVRShell once per
  208. run, just before exiting the program.
  209. If the rendering context is lost, QuitApplication() will
  210. not be called.x
  211. ******************************************************************************/
  212. bool OGLES2Refraction::QuitApplication()
  213. {
  214. // Free the memory allocated for the scene
  215. m_Scene.Destroy();
  216. delete [] m_puiVbo;
  217. delete [] m_puiIndexVbo;
  218. return true;
  219. }
  220. /*!****************************************************************************
  221. @Function InitView
  222. @Return bool true if no error occured
  223. @Description Code in InitView() will be called by PVRShell upon
  224. initialization or after a change in the rendering context.
  225. Used to initialize variables that are dependant on the rendering
  226. context (e.g. textures, vertex buffers, etc.)
  227. ******************************************************************************/
  228. bool OGLES2Refraction::InitView()
  229. {
  230. CPVRTString ErrorStr;
  231. /*
  232. Initialize VBO data
  233. */
  234. LoadVbos();
  235. /*
  236. Load textures
  237. */
  238. if (!LoadTextures(&ErrorStr))
  239. {
  240. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  241. return false;
  242. }
  243. /*
  244. Load and compile the shaders & link programs
  245. */
  246. if (!LoadShaders(&ErrorStr))
  247. {
  248. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  249. return false;
  250. }
  251. // Set the sampler2D uniforms to corresponding texture units
  252. glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sTexture"), 0);
  253. // Is the screen rotated?
  254. m_bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  255. /*
  256. Initialize Print3D
  257. */
  258. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), m_bRotate) != PVR_SUCCESS)
  259. {
  260. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  261. return false;
  262. }
  263. /*
  264. Initalise the background
  265. */
  266. if(m_Background.Init(0, m_bRotate, &ErrorStr) != PVR_SUCCESS)
  267. {
  268. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  269. return false;
  270. }
  271. /*
  272. Calculate the projection and view matrices
  273. */
  274. m_mProjection = PVRTMat4::PerspectiveFovRH(PVRT_PI/6, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), CAM_NEAR, CAM_FAR, PVRTMat4::OGL, m_bRotate);
  275. m_mView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 150), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0));
  276. /*
  277. Set OpenGL ES render states needed for this training course
  278. */
  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 OGLES2Refraction::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 OGLES2Refraction::RenderScene()
  315. {
  316. // Keyboard input (cursor to change Reflection Flag)
  317. if (PVRShellIsKeyPressed(PVRShellKeyNameLEFT) || PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
  318. {
  319. m_bSpecular = !m_bSpecular;
  320. }
  321. // Clear the color and depth buffer
  322. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  323. m_Background.Draw(m_uiTexture);
  324. // Enable backface culling and depth test
  325. glCullFace(GL_BACK);
  326. glFrontFace(GL_CCW);
  327. glEnable(GL_CULL_FACE);
  328. glEnable(GL_DEPTH_TEST);
  329. // Use shader program
  330. glUseProgram(m_ShaderProgram.uiId);
  331. // Bind textures
  332. glActiveTexture(GL_TEXTURE0);
  333. glBindTexture(GL_TEXTURE_2D, m_uiTexture);
  334. // Calculate the model matrix
  335. PVRTMat4 mRotX, mRotY, mModel;
  336. mRotX = PVRTMat4::RotationX(m_fAngleX);
  337. mRotY = PVRTMat4::RotationY(m_fAngleY);
  338. mModel = mRotX * mRotY;
  339. m_fAngleX += PVRT_PI / 111;
  340. m_fAngleY += PVRT_PI / 150;
  341. // Set model view projection matrix
  342. PVRTMat4 mModelView, mMVP;
  343. mModelView = m_mView * mModel;
  344. mMVP = m_mProjection * mModelView;
  345. glUniformMatrix4fv(m_ShaderProgram.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr());
  346. // Set light direction in model space
  347. PVRTVec4 vLightDirModel;
  348. vLightDirModel = mModelView.inverse() * PVRTVec4(0.57735f, 0.57735f, 0.57735f, 0);
  349. glUniform3fv(m_ShaderProgram.auiLoc[eLightDirModel], 1, &vLightDirModel.x);
  350. // Set eye position in model space
  351. PVRTVec4 vEyePosModel;
  352. vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1);
  353. glUniform3fv(m_ShaderProgram.auiLoc[eEyePosModel], 1, &vEyePosModel.x);
  354. // Set specular flag
  355. glUniform1i(m_ShaderProgram.auiLoc[eSpecular], m_bSpecular);
  356. // Set rotation flag
  357. glUniform1i(m_ShaderProgram.auiLoc[eRotate], m_bRotate);
  358. /*
  359. Now that the uniforms are set, call another function to actually draw the mesh.
  360. */
  361. DrawMesh(0);
  362. // Displays the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  363. m_Print3D.DisplayDefaultTitle("Refraction", "", ePVRTPrint3DLogoIMG);
  364. m_Print3D.Print3D(0.3f, 7.5f, 0.75f, PVRTRGBA(255,255,255,255), "Specular reflection: %s", (m_bSpecular) ? "on" : "off" );
  365. m_Print3D.Flush();
  366. return true;
  367. }
  368. /*!****************************************************************************
  369. @Function DrawMesh
  370. @Input i32NodeIndex Node index of the mesh to draw
  371. @Description Draws a SPODMesh after the model view matrix has been set and
  372. the meterial prepared.
  373. ******************************************************************************/
  374. void OGLES2Refraction::DrawMesh(int i32NodeIndex)
  375. {
  376. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  377. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  378. // bind the VBO for the mesh
  379. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  380. // bind the index buffer, won't hurt if the handle is 0
  381. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  382. // Enable the vertex attribute arrays
  383. for (int i = 0; i < eNumAttribs; ++i) glEnableVertexAttribArray(i);
  384. // Set the vertex attribute offsets
  385. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  386. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  387. /*
  388. The geometry can be exported in 4 ways:
  389. - Indexed Triangle list
  390. - Non-Indexed Triangle list
  391. - Indexed Triangle strips
  392. - Non-Indexed Triangle strips
  393. */
  394. if(pMesh->nNumStrips == 0)
  395. {
  396. if(m_puiIndexVbo[i32MeshIndex])
  397. {
  398. // Indexed Triangle list
  399. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  400. }
  401. else
  402. {
  403. // Non-Indexed Triangle list
  404. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  405. }
  406. }
  407. else
  408. {
  409. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  410. {
  411. int offset = 0;
  412. if(m_puiIndexVbo[i32MeshIndex])
  413. {
  414. // Indexed Triangle strips
  415. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, (GLshort*)(offset*2));
  416. }
  417. else
  418. {
  419. // Non-Indexed Triangle strips
  420. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  421. }
  422. offset += pMesh->pnStripLength[i]+2;
  423. }
  424. }
  425. // Safely disable the vertex attribute arrays
  426. for (int i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
  427. glBindBuffer(GL_ARRAY_BUFFER, 0);
  428. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  429. }
  430. /*!****************************************************************************
  431. @Function NewDemo
  432. @Return PVRShell* The demo supplied by the user
  433. @Description This function must be implemented by the user of the shell.
  434. The user should return its PVRShell object defining the
  435. behaviour of the application.
  436. ******************************************************************************/
  437. PVRShell* NewDemo()
  438. {
  439. return new OGLES2Refraction();
  440. }
  441. /******************************************************************************
  442. End of file (OGLES2Refraction.cpp)
  443. ******************************************************************************/