OGLES2PhantomMask.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. /******************************************************************************
  2. @File OGLES2PhantomMask.cpp
  3. @Title Introducing the POD 3D file format
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Shows how to load POD files and play the animation with basic
  8. lighting
  9. ******************************************************************************/
  10. #include <string.h>
  11. #include "PVRShell.h"
  12. #include "OGLES2Tools.h"
  13. /******************************************************************************
  14. shader attributes
  15. ******************************************************************************/
  16. // vertex attributes
  17. enum EVertexAttrib {
  18. VERTEX_ARRAY, NORMAL_ARRAY, TEXCOORD_ARRAY, eNumAttribs };
  19. const char* g_aszAttribNames[] = {
  20. "inVertex", "inNormal", "inTexCoord" };
  21. // shader uniforms
  22. enum ESHUniform {
  23. eSHMVPMatrix, eSHModel, ecAr, ecAg, ecAb, ecBr, ecBg, ecBb, ecC, eNumSHUniforms };
  24. const char* g_aszSHUniformNames[] = {
  25. "MVPMatrix", "Model", "cAr", "cAg", "cAb", "cBr", "cBg", "cBb", "cC" };
  26. enum EDifUniform {
  27. eDifMVPMatrix, eDifModel, eLightDir1, eLightDir2, eLightDir3, eLightDir4, eAmbient, eNumDifUniforms };
  28. const char* g_aszDifUniformNames[] = {
  29. "MVPMatrix", "Model", "LightDir1", "LightDir2", "LightDir3", "LightDir4", "Ambient" };
  30. /******************************************************************************
  31. Consts
  32. ******************************************************************************/
  33. // Camera constants. Used for making the projection matrix
  34. const float g_fCameraNear = 50.0f;
  35. const float g_fCameraFar = 5000.0f;
  36. const float g_fDemoFrameRate = 1.0f / 30.0f;
  37. // The camera to use from the pod file
  38. const int g_ui32Camera = 0;
  39. /******************************************************************************
  40. Content file names
  41. ******************************************************************************/
  42. // Source and binary shaders
  43. const char c_szFragShaderSrcFile[] = "FragShader.fsh";
  44. const char c_szFragShaderBinFile[] = "FragShader.fsc";
  45. const char c_szSHVertShaderSrcFile[] = "SHVertShader.vsh";
  46. const char c_szSHVertShaderBinFile[] = "SHVertShader.vsc";
  47. const char c_szDifVertShaderSrcFile[] = "DiffuseVertShader.vsh";
  48. const char c_szDifVertShaderBinFile[] = "DiffuseVertShader.vsc";
  49. // POD scene files
  50. const char c_szSceneFile[] = "PhantomMask.pod";
  51. // PVR texture files
  52. const char c_szMaskMainTexFile[] = "MaskMain.pvr";
  53. const char c_szRoomStillTexFile[] = "RoomStill.pvr";
  54. /*!****************************************************************************
  55. Class implementing the PVRShell functions.
  56. ******************************************************************************/
  57. class OGLES2PhantomMask : public PVRShell
  58. {
  59. // Print3D class used to display text
  60. CPVRTPrint3D m_Print3D;
  61. // 3D Model
  62. CPVRTModelPOD m_Scene;
  63. // OpenGL handles for shaders, textures and VBOs
  64. GLuint m_uiSHVertShader;
  65. GLuint m_uiDifVertShader;
  66. GLuint m_uiFragShader;
  67. GLuint* m_puiVbo;
  68. GLuint* m_puiIndexVbo;
  69. // Texture IDs
  70. GLuint m_ui32TexMask;
  71. GLuint m_ui32TexBackground;
  72. // The background
  73. CPVRTBackground m_Background;
  74. bool m_bEnableSH;
  75. // Group shader programs and their uniform locations together
  76. struct
  77. {
  78. GLuint uiId;
  79. GLuint auiLoc[eNumSHUniforms];
  80. }
  81. m_SHShaderProgram;
  82. struct
  83. {
  84. GLuint uiId;
  85. GLuint auiLoc[eNumDifUniforms];
  86. }
  87. m_DiffuseShaderProgram;
  88. // Variables to handle the animation in a time-based manner
  89. unsigned long m_ui32TimePrev;
  90. float m_fFrame;
  91. public:
  92. virtual bool InitApplication();
  93. virtual bool InitView();
  94. virtual bool ReleaseView();
  95. virtual bool QuitApplication();
  96. virtual bool RenderScene();
  97. bool LoadTextures(CPVRTString* pErrorStr);
  98. bool LoadShaders(CPVRTString* pErrorStr);
  99. bool LoadVbos(CPVRTString* pErrorStr);
  100. void DrawMesh(int i32NodeIndex);
  101. void ComputeAndSetSHIrradEnvMapConstants( float* pSHCoeffsRed, float* pSHCoeffsGreen, float* pSHCoeffsBlue );
  102. OGLES2PhantomMask() : m_bEnableSH(true),
  103. m_ui32TimePrev(0),
  104. m_fFrame(0.0f)
  105. {
  106. }
  107. };
  108. /*!****************************************************************************
  109. @Function LoadTextures
  110. @Return bool true if no error occured
  111. @Description Loads the textures required for this training course.
  112. For a more detailed explanation, see Texturing and
  113. IntroducingPVRTools.
  114. ******************************************************************************/
  115. bool OGLES2PhantomMask::LoadTextures(CPVRTString* pErrorStr)
  116. {
  117. if(PVRTTextureLoadFromPVR(c_szRoomStillTexFile, &m_ui32TexBackground) != PVR_SUCCESS)
  118. {
  119. *pErrorStr = "ERROR: Failed to load texture for Background.\n";
  120. return false;
  121. }
  122. if(PVRTTextureLoadFromPVR(c_szMaskMainTexFile, &m_ui32TexMask) != PVR_SUCCESS)
  123. {
  124. *pErrorStr = "ERROR: Failed to load texture for Mask.\n";
  125. return false;
  126. }
  127. return true;
  128. }
  129. /*!****************************************************************************
  130. @Function LoadShaders
  131. @Output pErrorStr A string describing the error on failure
  132. @Return bool true if no error occured
  133. @Description Loads and compiles the shaders and links the shader programs
  134. required for this training course
  135. ******************************************************************************/
  136. bool OGLES2PhantomMask::LoadShaders(CPVRTString* pErrorStr)
  137. {
  138. int i;
  139. // Load the common frag shader
  140. if (PVRTShaderLoadFromFile(
  141. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
  142. {
  143. return false;
  144. }
  145. // Load the vertex shader and create the program
  146. if(PVRTShaderLoadFromFile(
  147. c_szSHVertShaderBinFile, c_szSHVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSHVertShader, pErrorStr) != PVR_SUCCESS)
  148. {
  149. return false;
  150. }
  151. if(PVRTCreateProgram(
  152. &m_SHShaderProgram.uiId, m_uiSHVertShader, m_uiFragShader, g_aszAttribNames, 3, pErrorStr) != PVR_SUCCESS)
  153. {
  154. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  155. return false;
  156. }
  157. // Store the location of uniforms for later use
  158. for(i = 0; i < eNumSHUniforms; ++i)
  159. m_SHShaderProgram.auiLoc[i] = glGetUniformLocation(m_SHShaderProgram.uiId, g_aszSHUniformNames[i]);
  160. // Set the sampler2D variable to the first texture unit
  161. glUniform1i(glGetUniformLocation(m_SHShaderProgram.uiId, "sTexture"), 0);
  162. // Setup shader constants
  163. // Setup some base constants
  164. bool light0 = false;
  165. bool light1 = false;
  166. bool envlight = true;
  167. // SH Data Sets
  168. // Not all are used
  169. float SHCoeffsLight1Red[9] = {0.83409595f, -1.4446964f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, -1.6152197f};
  170. float SHCoeffsLight1Green[9] = {0.83409595f, -1.4446964f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, -1.6152197f};
  171. float SHCoeffsLight1Blue[9] = {0.83409595f, -1.4446964f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, -1.6152197f};
  172. float SHCoeffsLight2Red[9] = {0.83409595f, -1.2120811f, -0.24892779f, -0.74568230f, -1.3989232f, -0.46699628f, -0.84948879f, 0.28729999f, -0.70663643f};
  173. float SHCoeffsLight2Green[9] = {0.83409595f, -1.2120811f, -0.24892779f, -0.74568230f, -1.3989232f, -0.46699628f, -0.84948879f, 0.28729999f, -0.70663643f};
  174. float SHCoeffsLight2Blue[9] = {0.83409595f, -1.2120811f, -0.24892779f, -0.74568230f, -1.3989232f, -0.46699628f, -0.84948879f, 0.28729999f, -0.70663643f};
  175. float SHCoeffsLightEnvRed[9] = {1.2961891f, -0.42659417f, -0.10065936f, -8.4035477e-005f, -0.00021227333f, 0.10019236f, 0.011847760f, 0.00016783635f, -0.10584830f};
  176. float SHCoeffsLightEnvGreen[9] = {1.2506844f, -0.12775756f, 0.33325988f, -8.7283181e-005f, -0.00015105936f, -0.025249202f, -0.048718069f, 0.00026852929f, -0.28519103f};
  177. float SHCoeffsLightEnvBlue[9] = {1.6430428f, 0.098693930f, 0.071262904f, 0.00044371662f, 0.00027166531f, 0.056100018f, -0.23762819f, -0.00015725456f, -0.49318397f};
  178. float SHCoeffsLightSideRed[9] = { 0.83409595f, 0.00000000f, 0.00000000f, -1.4446964f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, 1.6152197f};
  179. float SHCoeffsLightSideGreen[9] = { 0.83409595f, 0.00000000f, 0.00000000f, -1.4446964f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, 1.6152197f};
  180. float SHCoeffsLightSideBlue[9] = { 0.83409595f, 0.00000000f, 0.00000000f, -1.4446964f, 0.00000000f, 0.00000000f, -0.93254757f, 0.00000000f, 1.6152197f};
  181. float SHCoeffsLightEnvGraceCrossRed[9] = {10.153550f, -5.0607910f, -4.3494077f, 3.7619650f, -1.4272760f, 3.3470039f, -2.0500889f, -7.1480651f, 2.7244451f};
  182. float SHCoeffsLightEnvGraceCrossGreen[9] = {5.6218147f, -4.4867749f, -2.3315217f, 0.71724868f, -0.65607071f, 2.8644383f, -1.2423282f, -2.7321301f, -0.70176142f};
  183. float SHCoeffsLightEnvGraceCrossBlue[9] = {6.9620109f, -7.7706318f, -3.4473803f, -0.12024292f, -1.5760463f, 6.0764866f, -1.9274533f, -1.7631743f, -3.9185245f};
  184. float SHCoeffsLightSummedRed[9];
  185. float SHCoeffsLightSummedGreen[9];
  186. float SHCoeffsLightSummedBlue[9];
  187. float LIGHT1WEIGHT,LIGHT2WEIGHT,LIGHTENVWEIGHT,LIGHTSIDEWEIGHT,LIGHTGRACECROSSWEIGHT;
  188. // SH Weights
  189. LIGHT1WEIGHT=0.0f;
  190. LIGHT2WEIGHT=0.0f;
  191. LIGHTENVWEIGHT=0.0f;
  192. LIGHTSIDEWEIGHT=0.0f;
  193. LIGHTGRACECROSSWEIGHT=0.0f;
  194. // Set weights based on scene info
  195. if(light0 && light1 && envlight)
  196. {
  197. LIGHT1WEIGHT=0.3f;
  198. LIGHT2WEIGHT=0.3f;
  199. LIGHTENVWEIGHT=1.0f;
  200. }
  201. else if(!light0 && !light1 && envlight)
  202. {
  203. LIGHTENVWEIGHT=1.0f;
  204. }
  205. // Calculate the final SH coefs using the different lights and weights
  206. for(i = 0; i < 9; ++i)
  207. {
  208. SHCoeffsLightSummedRed[i] = LIGHT1WEIGHT * SHCoeffsLight1Red[i]
  209. + LIGHT2WEIGHT * SHCoeffsLight2Red[i]
  210. + LIGHTENVWEIGHT* SHCoeffsLightEnvRed[i]
  211. + LIGHTSIDEWEIGHT * SHCoeffsLightSideRed[i]
  212. + LIGHTGRACECROSSWEIGHT * SHCoeffsLightEnvGraceCrossRed[i];
  213. SHCoeffsLightSummedGreen[i] = LIGHT1WEIGHT * SHCoeffsLight1Green[i]
  214. + LIGHT2WEIGHT * SHCoeffsLight2Green[i]
  215. + LIGHTENVWEIGHT * SHCoeffsLightEnvGreen[i]
  216. + LIGHTSIDEWEIGHT * SHCoeffsLightSideGreen[i]
  217. + LIGHTGRACECROSSWEIGHT * SHCoeffsLightEnvGraceCrossGreen[i];
  218. SHCoeffsLightSummedBlue[i] = LIGHT1WEIGHT * SHCoeffsLight1Blue[i]
  219. + LIGHT2WEIGHT * SHCoeffsLight2Blue[i]
  220. + LIGHTENVWEIGHT * SHCoeffsLightEnvBlue[i]
  221. + LIGHTSIDEWEIGHT * SHCoeffsLightSideBlue[i]
  222. + LIGHTGRACECROSSWEIGHT * SHCoeffsLightEnvGraceCrossBlue[i];
  223. }
  224. ComputeAndSetSHIrradEnvMapConstants(SHCoeffsLightSummedRed, SHCoeffsLightSummedGreen, SHCoeffsLightSummedBlue);
  225. // Setup the shaders we're going to use for Vertex lighting
  226. // Load the vertex shader and create the program
  227. if(PVRTShaderLoadFromFile(
  228. c_szDifVertShaderBinFile, c_szDifVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiDifVertShader, pErrorStr) != PVR_SUCCESS)
  229. {
  230. return false;
  231. }
  232. if(PVRTCreateProgram(
  233. &m_DiffuseShaderProgram.uiId, m_uiDifVertShader, m_uiFragShader, g_aszAttribNames, 3, pErrorStr) != PVR_SUCCESS)
  234. {
  235. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  236. return false;
  237. }
  238. // Store the location of uniforms for later use
  239. for(i = 0; i < eNumDifUniforms; ++i)
  240. m_DiffuseShaderProgram.auiLoc[i] = glGetUniformLocation(m_DiffuseShaderProgram.uiId, g_aszDifUniformNames[i]);
  241. // Setup constants
  242. // Light direction 1 : TOP
  243. glUniform3fv(m_DiffuseShaderProgram.auiLoc[eLightDir1], 1, PVRTVec3(0.0f,0.5f,0.0f).ptr());
  244. // Light direction 2 : BOTTOM
  245. glUniform3fv(m_DiffuseShaderProgram.auiLoc[eLightDir2], 1, PVRTVec3(0.0f,-0.5f,0.0f).ptr());
  246. // Light direction 3 : LEFT
  247. glUniform3fv(m_DiffuseShaderProgram.auiLoc[eLightDir3], 1, PVRTVec3(-0.5f,0.0f,0.0f).ptr());
  248. // Light direction 4 : RIGHT
  249. glUniform3fv(m_DiffuseShaderProgram.auiLoc[eLightDir4], 1, PVRTVec3(0.5f,0.0f,0.0f).ptr());
  250. // Ambient Light
  251. glUniform4fv(m_DiffuseShaderProgram.auiLoc[eAmbient], 1, PVRTVec4(0.05f,0.05f,0.05f,0.05f).ptr());
  252. // Set the sampler2D variable to the first texture unit
  253. glUniform1i(glGetUniformLocation(m_DiffuseShaderProgram.uiId, "sTexture"), 0);
  254. return true;
  255. }
  256. /*!****************************************************************************
  257. @Function LoadVbos
  258. @Description Loads the mesh data required for this training course into
  259. vertex buffer objects
  260. ******************************************************************************/
  261. bool OGLES2PhantomMask::LoadVbos(CPVRTString* pErrorStr)
  262. {
  263. if(!m_Scene.pMesh[0].pInterleaved)
  264. {
  265. *pErrorStr = "ERROR: IntroducingPOD requires the pod data to be interleaved. Please re-export with the interleaved option enabled.";
  266. return false;
  267. }
  268. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  269. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  270. /*
  271. Load vertex data of all meshes in the scene into VBOs
  272. The meshes have been exported with the "Interleave Vectors" option,
  273. so all data is interleaved in the buffer at pMesh->pInterleaved.
  274. Interleaving data improves the memory access pattern and cache efficiency,
  275. thus it can be read faster by the hardware.
  276. */
  277. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  278. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  279. {
  280. // Load vertex data into buffer object
  281. SPODMesh& Mesh = m_Scene.pMesh[i];
  282. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  283. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  284. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  285. // Load index data into buffer object if available
  286. m_puiIndexVbo[i] = 0;
  287. if (Mesh.sFaces.pData)
  288. {
  289. glGenBuffers(1, &m_puiIndexVbo[i]);
  290. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  291. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  292. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  293. }
  294. }
  295. glBindBuffer(GL_ARRAY_BUFFER, 0);
  296. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  297. return true;
  298. }
  299. /*!****************************************************************************
  300. @Function InitApplication
  301. @Return bool true if no error occured
  302. @Description Code in InitApplication() will be called by PVRShell once per
  303. run, before the rendering context is created.
  304. Used to initialize variables that are not dependant on it
  305. (e.g. external modules, loading meshes, etc.)
  306. If the rendering context is lost, InitApplication() will
  307. not be called again.
  308. ******************************************************************************/
  309. bool OGLES2PhantomMask::InitApplication()
  310. {
  311. m_puiVbo = 0;
  312. m_puiIndexVbo = 0;
  313. // Get and set the read path for content files
  314. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  315. // Load the scene
  316. if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  317. {
  318. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  319. return false;
  320. }
  321. // The cameras are stored in the file. We check it contains at least one.
  322. if(m_Scene.nNumCamera == 0)
  323. {
  324. PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera. Please add one and re-export.\n");
  325. return false;
  326. }
  327. // Initialise variables used for the animation
  328. m_ui32TimePrev = PVRShellGetTime();
  329. return true;
  330. }
  331. /*!****************************************************************************
  332. @Function QuitApplication
  333. @Return bool true if no error occured
  334. @Description Code in QuitApplication() will be called by PVRShell once per
  335. run, just before exiting the program.
  336. If the rendering context is lost, QuitApplication() will
  337. not be called.
  338. ******************************************************************************/
  339. bool OGLES2PhantomMask::QuitApplication()
  340. {
  341. // Free the memory allocated for the scene
  342. m_Scene.Destroy();
  343. delete[] m_puiVbo;
  344. delete[] m_puiIndexVbo;
  345. return true;
  346. }
  347. /*!****************************************************************************
  348. @Function InitView
  349. @Return bool true if no error occured
  350. @Description Code in InitView() will be called by PVRShell upon
  351. initialization or after a change in the rendering context.
  352. Used to initialize variables that are dependant on the rendering
  353. context (e.g. textures, vertex buffers, etc.)
  354. ******************************************************************************/
  355. bool OGLES2PhantomMask::InitView()
  356. {
  357. CPVRTString ErrorStr;
  358. // Initialise VBO data
  359. if(!LoadVbos(&ErrorStr))
  360. {
  361. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  362. return false;
  363. }
  364. // Load textures
  365. if(!LoadTextures(&ErrorStr))
  366. {
  367. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  368. return false;
  369. }
  370. // Load and compile the shaders & link programs
  371. if(!LoadShaders(&ErrorStr))
  372. {
  373. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  374. return false;
  375. }
  376. // Initialise Print3D
  377. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  378. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  379. {
  380. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  381. return false;
  382. }
  383. // Initalise the background
  384. if(m_Background.Init(0, bRotate, &ErrorStr) != PVR_SUCCESS)
  385. {
  386. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  387. return false;
  388. }
  389. // Use a nice bright blue as clear colour
  390. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  391. return true;
  392. }
  393. /*!****************************************************************************
  394. @Function ReleaseView
  395. @Return bool true if no error occured
  396. @Description Code in ReleaseView() will be called by PVRShell when the
  397. application quits or before a change in the rendering context.
  398. ******************************************************************************/
  399. bool OGLES2PhantomMask::ReleaseView()
  400. {
  401. // Release all Textures
  402. glDeleteTextures(1, &m_ui32TexMask);
  403. glDeleteTextures(1, &m_ui32TexBackground);
  404. // Delete program and shader objects
  405. glDeleteProgram(m_SHShaderProgram.uiId);
  406. glDeleteProgram(m_DiffuseShaderProgram.uiId);
  407. glDeleteShader(m_uiSHVertShader);
  408. glDeleteShader(m_uiDifVertShader);
  409. glDeleteShader(m_uiFragShader);
  410. // Delete buffer objects
  411. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  412. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  413. // Release Print3D Textures
  414. m_Print3D.ReleaseTextures();
  415. return true;
  416. }
  417. /*!****************************************************************************
  418. @Function RenderScene
  419. @Return bool true if no error occured
  420. @Description Main rendering loop function of the program. The shell will
  421. call this function every frame.
  422. eglSwapBuffers() will be performed by PVRShell automatically.
  423. PVRShell will also manage important OS events.
  424. Will also manage relevent OS events. The user has access to
  425. these events through an abstraction layer provided by PVRShell.
  426. ******************************************************************************/
  427. bool OGLES2PhantomMask::RenderScene()
  428. {
  429. if(PVRShellIsKeyPressed(PVRShellKeyNameACTION1))
  430. m_bEnableSH = !m_bEnableSH;
  431. // Clear the color and depth buffer
  432. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  433. // Draw the background
  434. m_Background.Draw(m_ui32TexBackground);
  435. // Enable culling
  436. glEnable(GL_CULL_FACE);
  437. // Enable depth testing
  438. glEnable(GL_DEPTH_TEST);
  439. // Use shader program
  440. GLuint ProgramID, MVPLoc, ModelLoc;
  441. if(m_bEnableSH)
  442. {
  443. ProgramID = m_SHShaderProgram.uiId;
  444. MVPLoc = m_SHShaderProgram.auiLoc[eSHMVPMatrix];
  445. ModelLoc = m_SHShaderProgram.auiLoc[eSHModel];
  446. }
  447. else
  448. {
  449. ProgramID = m_DiffuseShaderProgram.uiId;
  450. MVPLoc = m_DiffuseShaderProgram.auiLoc[eDifMVPMatrix];
  451. ModelLoc = m_DiffuseShaderProgram.auiLoc[eDifModel];
  452. }
  453. glUseProgram(ProgramID);
  454. /*
  455. Calculates the frame number to animate in a time-based manner.
  456. Uses the shell function PVRShellGetTime() to get the time in milliseconds.
  457. */
  458. unsigned long iTime = PVRShellGetTime();
  459. if(iTime > m_ui32TimePrev)
  460. {
  461. int iDeltaTime = iTime - m_ui32TimePrev;
  462. m_fFrame += (float)iDeltaTime * g_fDemoFrameRate;
  463. if(m_fFrame > m_Scene.nNumFrame - 1)
  464. m_fFrame = 0;
  465. // Sets the scene animation to this frame
  466. m_Scene.SetFrame(m_fFrame);
  467. }
  468. m_ui32TimePrev = iTime;
  469. /*
  470. Set up the view and projection matrices from the camera
  471. */
  472. PVRTMat4 mView, mProjection;
  473. PVRTVec3 vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f);
  474. float fFOV;
  475. // Setup the camera
  476. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  477. // Camera nodes are after the mesh and light nodes in the array
  478. int i32CamID = m_Scene.pNode[m_Scene.nNumMeshNode + m_Scene.nNumLight + g_ui32Camera].nIdx;
  479. // Get the camera position, target and field of view (fov)
  480. if(m_Scene.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target?
  481. fFOV = m_Scene.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node
  482. else
  483. fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, g_ui32Camera); // vTo is calculated from the rotation
  484. fFOV *= bRotate ? (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight) : (float)PVRShellGet(prefHeight)/(float)PVRShellGet(prefWidth);
  485. // We can build the model view matrix from the camera position, target and an up vector.
  486. // For this we usePVRTMat4LookAtRH()
  487. mView = PVRTMat4::LookAtRH(vFrom, vTo, vUp);
  488. // Calculate the projection matrix
  489. mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
  490. SPODNode& Node = m_Scene.pNode[0];
  491. // Get the node model matrix
  492. PVRTMat4 mWorld;
  493. mWorld = m_Scene.GetWorldMatrix(Node);
  494. // Set the model inverse transpose matrix
  495. PVRTMat3 mMat3 = PVRTMat3(mWorld);
  496. if(m_bEnableSH)
  497. mMat3 *= PVRTMat3::RotationY(-1.047197f);
  498. glUniformMatrix3fv(ModelLoc, 1, GL_FALSE, mMat3.f);
  499. // Pass the model-view-projection matrix (MVP) to the shader to transform the vertices
  500. PVRTMat4 mModelView, mMVP;
  501. mModelView = mView * mWorld;
  502. mMVP = mProjection * mModelView;
  503. glUniformMatrix4fv(MVPLoc, 1, GL_FALSE, mMVP.f);
  504. glBindTexture(GL_TEXTURE_2D, m_ui32TexMask);
  505. DrawMesh(Node.nIdx);
  506. // Print text on screen
  507. // Shadow
  508. m_Print3D.Print3D(0.0f, 1.0f, 1.205f, PVRTRGBA(0,0,0,255), "PhantomMask");
  509. if(m_bEnableSH)
  510. {
  511. // Shadow
  512. m_Print3D.Print3D(0.0f, 8.0f, 0.905f, PVRTRGBA(0,0,0,255), "Spherical Harmonics Lighting");
  513. // Base
  514. m_Print3D.DisplayDefaultTitle("PhantomMask", "Spherical Harmonics Lighting", ePVRTPrint3DSDKLogo);
  515. }
  516. else
  517. {
  518. // Shadow
  519. m_Print3D.Print3D(0.0f, 8.0f, 0.905f, PVRTRGBA(0,0,0,255), "Vertex Lighting");
  520. // Base
  521. m_Print3D.DisplayDefaultTitle("PhantomMask", "Vertex Lighting", ePVRTPrint3DSDKLogo);
  522. }
  523. m_Print3D.Flush();
  524. return true;
  525. }
  526. /*!****************************************************************************
  527. @Function DrawMesh
  528. @Input i32NodeIndex Node index of the mesh to draw
  529. @Description Draws a SPODMesh after the model view matrix has been set and
  530. the meterial prepared.
  531. ******************************************************************************/
  532. void OGLES2PhantomMask::DrawMesh(int i32MeshIndex)
  533. {
  534. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  535. // bind the VBO for the mesh
  536. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  537. // bind the index buffer, won't hurt if the handle is 0
  538. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  539. // Enable the vertex attribute arrays
  540. glEnableVertexAttribArray(VERTEX_ARRAY);
  541. glEnableVertexAttribArray(NORMAL_ARRAY);
  542. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  543. // Set the vertex attribute offsets
  544. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  545. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  546. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  547. /*
  548. The geometry can be exported in 4 ways:
  549. - Indexed Triangle list
  550. - Non-Indexed Triangle list
  551. - Indexed Triangle strips
  552. - Non-Indexed Triangle strips
  553. */
  554. if(pMesh->nNumStrips == 0)
  555. {
  556. if(m_puiIndexVbo[i32MeshIndex])
  557. {
  558. // Indexed Triangle list
  559. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  560. }
  561. else
  562. {
  563. // Non-Indexed Triangle list
  564. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  565. }
  566. }
  567. else
  568. {
  569. int offset = 0;
  570. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  571. {
  572. if(m_puiIndexVbo[i32MeshIndex])
  573. {
  574. // Indexed Triangle strips
  575. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
  576. }
  577. else
  578. {
  579. // Non-Indexed Triangle strips
  580. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  581. }
  582. offset += pMesh->pnStripLength[i]+2;
  583. }
  584. }
  585. // Safely disable the vertex attribute arrays
  586. glDisableVertexAttribArray(VERTEX_ARRAY);
  587. glDisableVertexAttribArray(NORMAL_ARRAY);
  588. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  589. glBindBuffer(GL_ARRAY_BUFFER, 0);
  590. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  591. }
  592. /*******************************************************************************
  593. @Function ComputeAndSetSHIrradEnvMapConstants
  594. @Description Function to pre-calculate and setup the Spherical Harmonics Constants
  595. *******************************************************************************/
  596. void OGLES2PhantomMask::ComputeAndSetSHIrradEnvMapConstants( float* pSHCoeffsRed, float* pSHCoeffsGreen, float* pSHCoeffsBlue )
  597. {
  598. float* fLight[3] = { pSHCoeffsRed, pSHCoeffsGreen, pSHCoeffsBlue };
  599. // Lighting environment coefficients
  600. float vCoefficients[3][4];
  601. int iChannel;
  602. // These constants are described in the article by Peter-Pike Sloan titled
  603. // "Efficient Evaluation of Irradiance Environment Maps" in the book
  604. // "ShaderX 2 - Shader Programming Tips and Tricks" by Wolfgang F. Engel.
  605. static const float s_fSqrtPI = 1.772453850905516027298167483341f;
  606. const float fC0 = 1.0f/(2.0f*s_fSqrtPI);
  607. const float fC1 = (float)1.7320508075688772935274463415059f / (3.0f * s_fSqrtPI);
  608. const float fC2 = (float)3.8729833462074168851792653997824f / (8.0f * s_fSqrtPI);
  609. const float fC3 = (float)2.2360679774997896964091736687313f / (16.0f* s_fSqrtPI);
  610. const float fC4 = 0.5f*fC2;
  611. for(iChannel = 0; iChannel < 3; ++iChannel)
  612. {
  613. vCoefficients[iChannel][0] = -fC1 * fLight[iChannel][3];
  614. vCoefficients[iChannel][1] = -fC1 * fLight[iChannel][1];
  615. vCoefficients[iChannel][2] = fC1 * fLight[iChannel][2];
  616. vCoefficients[iChannel][3] = fC0 * fLight[iChannel][0] - fC3*fLight[iChannel][6];
  617. }
  618. glUniform4fv(m_SHShaderProgram.auiLoc[ecAr], 1, vCoefficients[0]);
  619. glUniform4fv(m_SHShaderProgram.auiLoc[ecAg], 1, vCoefficients[1]);
  620. glUniform4fv(m_SHShaderProgram.auiLoc[ecAb], 1, vCoefficients[2]);
  621. for(iChannel = 0; iChannel < 3; ++iChannel)
  622. {
  623. vCoefficients[iChannel][0] = fC2 * fLight[iChannel][4];
  624. vCoefficients[iChannel][1] = -fC2 * fLight[iChannel][5];
  625. vCoefficients[iChannel][2] = 3.0f * fC3 * fLight[iChannel][6];
  626. vCoefficients[iChannel][3] = -fC2 * fLight[iChannel][7];
  627. }
  628. glUniform4fv(m_SHShaderProgram.auiLoc[ecBr], 1, vCoefficients[0]);
  629. glUniform4fv(m_SHShaderProgram.auiLoc[ecBg], 1, vCoefficients[1]);
  630. glUniform4fv(m_SHShaderProgram.auiLoc[ecBb], 1, vCoefficients[2]);
  631. vCoefficients[0][0] = fC4 * fLight[0][8];
  632. vCoefficients[0][1] = fC4 * fLight[1][8];
  633. vCoefficients[0][2] = fC4 * fLight[2][8];
  634. glUniform3fv(m_SHShaderProgram.auiLoc[ecC], 1, vCoefficients[0]);
  635. }
  636. /*!****************************************************************************
  637. @Function NewDemo
  638. @Return PVRShell* The demo supplied by the user
  639. @Description This function must be implemented by the user of the shell.
  640. The user should return its PVRShell object defining the
  641. behaviour of the application.
  642. ******************************************************************************/
  643. PVRShell* NewDemo()
  644. {
  645. return new OGLES2PhantomMask();
  646. }
  647. /******************************************************************************
  648. End of file (OGLES2PhantomMask.cpp)
  649. ******************************************************************************/