OGLES2ChameleonMan.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. /******************************************************************************
  2. @File OGLES2ChameleonMan.cpp
  3. @Title OGLES2ChameleonMan
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Shows how to perform skinning combined with Dot3 lighting
  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 g_fCameraNear = 4.0f;
  16. const float g_fCameraFar = 30000.0f;
  17. const float g_fDemoFrameRate = 0.02f;
  18. /******************************************************************************
  19. shader attributes
  20. ******************************************************************************/
  21. // Skinned
  22. // vertex attributes
  23. enum EVertexAttrib {
  24. VERTEX_ARRAY, NORMAL_ARRAY, TANGENT_ARRAY, BINORMAL_ARRAY, TEXCOORD_ARRAY, BONEWEIGHT_ARRAY, BONEINDEX_ARRAY, eNumAttribs };
  25. const char* g_aszAttribNames[] = {
  26. "inVertex", "inNormal", "inTangent", "inBiNormal", "inTexCoord", "inBoneWeight", "inBoneIndex" };
  27. // shader uniforms
  28. enum ESkinnnedUniform {
  29. eViewProj, eLightPos, eBoneCount, eBoneMatrices, eBoneMatricesIT, ebUseDot3, eNumSkinnedUniforms };
  30. const char* g_aszSkinnedUniformNames[] = {
  31. "ViewProjMatrix", "LightPos", "BoneCount", "BoneMatrixArray[0]", "BoneMatrixArrayIT[0]", "bUseDot3" };
  32. // Default
  33. // vertex attributes
  34. enum EDefaultVertexAttrib {
  35. DEFAULT_VERTEX_ARRAY, DEFAULT_TEXCOORD_ARRAY, eNumDefaultAttribs };
  36. const char* g_aszDefaultAttribNames[] = {
  37. "inVertex", "inTexCoord"};
  38. // shader uniforms
  39. enum EDefaultUniform {
  40. eDefaultMVPMatrix, eDefaultUOffset, eNumDefaultUniforms };
  41. const char* g_aszDefaultUniformNames[] = {
  42. "MVPMatrix", "fUOffset" };
  43. /******************************************************************************
  44. Content file names
  45. ******************************************************************************/
  46. // Source and binary shaders
  47. const char c_szSkinnedFragShaderSrcFile[] = "SkinnedFragShader.fsh";
  48. const char c_szSkinnedFragShaderBinFile[] = "SkinnedFragShader.fsc";
  49. const char c_szSkinnedVertShaderSrcFile[] = "SkinnedVertShader.vsh";
  50. const char c_szSkinnedVertShaderBinFile[] = "SkinnedVertShader.vsc";
  51. const char c_szDefaultFragShaderSrcFile[] = "DefaultFragShader.fsh";
  52. const char c_szDefaultFragShaderBinFile[] = "DefaultFragShader.fsc";
  53. const char c_szDefaultVertShaderSrcFile[] = "DefaultVertShader.vsh";
  54. const char c_szDefaultVertShaderBinFile[] = "DefaultVertShader.vsc";
  55. // Base Textures
  56. const char c_szFinalChameleonManHeadBodyTexFile[] = "FinalChameleonManHeadBody.pvr";
  57. const char c_szFinalChameleonManLegsTexFile[] = "FinalChameleonManLegs.pvr";
  58. const char c_szLampTexFile[] = "lamp.pvr";
  59. const char c_szChameleonBeltTexFile[] = "ChameleonBelt.pvr";
  60. const char c_szSkylineTexFile[] = "skyline.pvr";
  61. const char c_szWallDiffuseBakedTexFile[] = "Wall_diffuse_baked.pvr";
  62. // Tangent Space BumpMap Textures
  63. const char c_szTang_space_BodyMapTexFile[] = "Tang_space_BodyMap.pvr";
  64. const char c_szTang_space_LegsMapTexFile[] = "Tang_space_LegsMap.pvr";
  65. const char c_szTang_space_BeltMapTexFile[] = "Tang_space_BeltMap.pvr";
  66. // POD scene files
  67. const char c_szSceneFile[] = "ChameleonScene.pod";
  68. /****************************************************************************
  69. ** Enums **
  70. ****************************************************************************/
  71. enum EMeshes
  72. {
  73. eBody,
  74. eLegs,
  75. eBelt,
  76. eWall,
  77. eBackground,
  78. eLights
  79. };
  80. /****************************************************************************
  81. ** Structures
  82. ****************************************************************************/
  83. /*!****************************************************************************
  84. Class implementing the PVRShell functions.
  85. ******************************************************************************/
  86. class OGLES2ChameleonMan : public PVRShell
  87. {
  88. // Print3D class used to display text
  89. CPVRTPrint3D m_Print3D;
  90. // 3D Model
  91. CPVRTModelPOD m_Scene;
  92. // Model transformation variables
  93. float m_fWallPos;
  94. float m_fBackgroundPos;
  95. float m_fLightPos;
  96. // OpenGL handles for shaders and VBOs
  97. GLuint m_uiSkinnedVertShader;
  98. GLuint m_uiDefaultVertShader;
  99. GLuint m_uiSkinnedFragShader;
  100. GLuint m_uiDefaultFragShader;
  101. GLuint* m_puiVbo;
  102. GLuint* m_puiIndexVbo;
  103. // Texture IDs
  104. GLuint m_ui32TexHeadBody;
  105. GLuint m_ui32TexLegs;
  106. GLuint m_ui32TexBeltNormalMap;
  107. GLuint m_ui32TexHeadNormalMap;
  108. GLuint m_ui32TexLegsNormalMap;
  109. GLuint m_ui32TexSkyLine;
  110. GLuint m_ui32TexWall;
  111. GLuint m_ui32TexLamp;
  112. GLuint m_ui32TexBelt;
  113. // Group shader programs and their uniform locations together
  114. struct
  115. {
  116. GLuint uiId;
  117. GLuint auiLoc[eNumSkinnedUniforms];
  118. }
  119. m_SkinnedShaderProgram;
  120. struct
  121. {
  122. GLuint uiId;
  123. GLuint auiLoc[eNumDefaultUniforms];
  124. }
  125. m_DefaultShaderProgram;
  126. bool m_bEnableDOT3;
  127. // Variables to handle the animation in a time-based manner
  128. unsigned long m_iTimePrev;
  129. float m_fFrame;
  130. public:
  131. OGLES2ChameleonMan() : m_fWallPos(0),
  132. m_fBackgroundPos(0),
  133. m_fLightPos(0),
  134. m_puiVbo(0),
  135. m_puiIndexVbo(0),
  136. m_bEnableDOT3(true),
  137. m_fFrame(0)
  138. {
  139. }
  140. virtual bool InitApplication();
  141. virtual bool InitView();
  142. virtual bool ReleaseView();
  143. virtual bool QuitApplication();
  144. virtual bool RenderScene();
  145. bool LoadTextures(CPVRTString* pErrorStr);
  146. bool LoadShaders(CPVRTString* pErrorStr);
  147. void LoadVbos();
  148. void DrawSkinnedMesh(int i32NodeIndex);
  149. };
  150. /*!****************************************************************************
  151. @Function LoadTextures
  152. @Output pErrorStr A string describing the error on failure
  153. @Return bool true if no error occured
  154. @Description Loads the textures required for this training course
  155. ******************************************************************************/
  156. bool OGLES2ChameleonMan::LoadTextures(CPVRTString* const pErrorStr)
  157. {
  158. // Load Textures
  159. if(PVRTTextureLoadFromPVR(c_szFinalChameleonManHeadBodyTexFile, &m_ui32TexHeadBody) != PVR_SUCCESS)
  160. {
  161. *pErrorStr = CPVRTString("ERROR: Failed to load texture for Upper Body.\n");
  162. return false;
  163. }
  164. if(PVRTTextureLoadFromPVR(c_szFinalChameleonManLegsTexFile, &m_ui32TexLegs) != PVR_SUCCESS)
  165. {
  166. *pErrorStr = CPVRTString("ERROR: Failed to load texture for Legs.\n");
  167. return false;
  168. }
  169. if(PVRTTextureLoadFromPVR(c_szTang_space_BodyMapTexFile, &m_ui32TexHeadNormalMap) != PVR_SUCCESS)
  170. {
  171. *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Upper Body.\n");
  172. return false;
  173. }
  174. if(PVRTTextureLoadFromPVR(c_szTang_space_LegsMapTexFile, &m_ui32TexLegsNormalMap) != PVR_SUCCESS)
  175. {
  176. *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Legs.\n");
  177. return false;
  178. }
  179. if(PVRTTextureLoadFromPVR(c_szTang_space_BeltMapTexFile, &m_ui32TexBeltNormalMap) != PVR_SUCCESS)
  180. {
  181. *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Belt.\n");
  182. return false;
  183. }
  184. if(PVRTTextureLoadFromPVR(c_szSkylineTexFile, &m_ui32TexSkyLine) != PVR_SUCCESS)
  185. {
  186. *pErrorStr = CPVRTString("ERROR: Failed to load texture for SkyLine.\n");
  187. return false;
  188. }
  189. if(PVRTTextureLoadFromPVR(c_szWallDiffuseBakedTexFile, &m_ui32TexWall) != PVR_SUCCESS)
  190. {
  191. *pErrorStr = CPVRTString("ERROR: Failed to load texture for Wall.\n");
  192. return false;
  193. }
  194. if(PVRTTextureLoadFromPVR(c_szLampTexFile, &m_ui32TexLamp) != PVR_SUCCESS)
  195. {
  196. *pErrorStr = CPVRTString("ERROR: Failed to load texture for Lamps.\n");
  197. return false;
  198. }
  199. if(PVRTTextureLoadFromPVR(c_szChameleonBeltTexFile, &m_ui32TexBelt) != PVR_SUCCESS)
  200. {
  201. *pErrorStr = CPVRTString("ERROR: Failed to load texture for Belt.\n");
  202. return false;
  203. }
  204. return true;
  205. }
  206. /*!****************************************************************************
  207. @Function LoadShaders
  208. @Output pErrorStr A string describing the error on failure
  209. @Return bool true if no error occured
  210. @Description Loads and compiles the shaders and links the shader programs
  211. required for this training course
  212. ******************************************************************************/
  213. bool OGLES2ChameleonMan::LoadShaders(CPVRTString* pErrorStr)
  214. {
  215. int i;
  216. /*
  217. Load and compile the shaders from files.
  218. Binary shaders are tried first, source shaders
  219. are used as fallback.
  220. */
  221. // Create the skinned program
  222. if(PVRTShaderLoadFromFile(
  223. c_szSkinnedVertShaderBinFile, c_szSkinnedVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSkinnedVertShader, pErrorStr) != PVR_SUCCESS)
  224. {
  225. return false;
  226. }
  227. if(PVRTShaderLoadFromFile(
  228. c_szSkinnedFragShaderBinFile, c_szSkinnedFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSkinnedFragShader, pErrorStr) != PVR_SUCCESS)
  229. {
  230. return false;
  231. }
  232. if(PVRTCreateProgram(&m_SkinnedShaderProgram.uiId, m_uiSkinnedVertShader, m_uiSkinnedFragShader, g_aszAttribNames, eNumAttribs, pErrorStr) != PVR_SUCCESS)
  233. {
  234. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  235. return false;
  236. }
  237. // Store the location of uniforms for later use
  238. for(i = 0; i < eNumSkinnedUniforms; ++i)
  239. {
  240. m_SkinnedShaderProgram.auiLoc[i] = glGetUniformLocation(m_SkinnedShaderProgram.uiId, g_aszSkinnedUniformNames[i]);
  241. }
  242. glUniform1i(m_SkinnedShaderProgram.auiLoc[ebUseDot3], m_bEnableDOT3);
  243. // Set the sampler2D uniforms to corresponding texture units
  244. glUniform1i(glGetUniformLocation(m_SkinnedShaderProgram.uiId, "sTexture"), 0);
  245. glUniform1i(glGetUniformLocation(m_SkinnedShaderProgram.uiId, "sNormalMap"), 1);
  246. // Create the non-skinned program
  247. if(PVRTShaderLoadFromFile(
  248. c_szDefaultVertShaderBinFile, c_szDefaultVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiDefaultVertShader, pErrorStr) != PVR_SUCCESS)
  249. {
  250. return false;
  251. }
  252. if(PVRTShaderLoadFromFile(
  253. c_szDefaultFragShaderBinFile, c_szDefaultFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiDefaultFragShader, pErrorStr) != PVR_SUCCESS)
  254. {
  255. return false;
  256. }
  257. if(PVRTCreateProgram(&m_DefaultShaderProgram.uiId, m_uiDefaultVertShader, m_uiDefaultFragShader, g_aszDefaultAttribNames, eNumDefaultAttribs, pErrorStr) != PVR_SUCCESS)
  258. {
  259. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  260. return false;
  261. }
  262. // Store the location of uniforms for later use
  263. for(i = 0; i < eNumDefaultUniforms; ++i)
  264. {
  265. m_DefaultShaderProgram.auiLoc[i] = glGetUniformLocation(m_DefaultShaderProgram.uiId, g_aszDefaultUniformNames[i]);
  266. }
  267. // Set the sampler2D uniforms to corresponding texture units
  268. glUniform1i(glGetUniformLocation(m_DefaultShaderProgram.uiId, "sTexture"), 0);
  269. return true;
  270. }
  271. /*!****************************************************************************
  272. @Function LoadVbos
  273. @Description Loads the mesh data required for this training course into
  274. vertex buffer objects
  275. ******************************************************************************/
  276. void OGLES2ChameleonMan::LoadVbos()
  277. {
  278. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  279. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  280. /*
  281. Load vertex data of all meshes in the scene into VBOs
  282. The meshes have been exported with the "Interleave Vectors" option,
  283. so all data is interleaved in the buffer at pMesh->pInterleaved.
  284. Interleaving data improves the memory access pattern and cache efficiency,
  285. thus it can be read faster by the hardware.
  286. */
  287. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  288. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  289. {
  290. // Load vertex data into buffer object
  291. SPODMesh& Mesh = m_Scene.pMesh[i];
  292. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  293. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  294. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  295. // Load index data into buffer object if available
  296. m_puiIndexVbo[i] = 0;
  297. if (Mesh.sFaces.pData)
  298. {
  299. glGenBuffers(1, &m_puiIndexVbo[i]);
  300. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  301. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  302. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  303. }
  304. }
  305. glBindBuffer(GL_ARRAY_BUFFER, 0);
  306. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  307. }
  308. /*!****************************************************************************
  309. @Function InitApplication
  310. @Return bool true if no error occured
  311. @Description Code in InitApplication() will be called by PVRShell once per
  312. run, before the rendering context is created.
  313. Used to initialize variables that are not dependant on it
  314. (e.g. external modules, loading meshes, etc.)
  315. If the rendering context is lost, InitApplication() will
  316. not be called again.
  317. ******************************************************************************/
  318. bool OGLES2ChameleonMan::InitApplication()
  319. {
  320. // Get and set the read path for content files
  321. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  322. // Load the scene
  323. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  324. {
  325. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  326. return false;
  327. }
  328. // The cameras are stored in the file. We check it contains at least one.
  329. if (m_Scene.nNumCamera == 0)
  330. {
  331. PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera\n");
  332. return false;
  333. }
  334. // Check the scene contains at least one light
  335. if (m_Scene.nNumLight == 0)
  336. {
  337. PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light\n");
  338. return false;
  339. }
  340. return true;
  341. }
  342. /*!****************************************************************************
  343. @Function QuitApplication
  344. @Return bool true if no error occured
  345. @Description Code in QuitApplication() will be called by PVRShell once per
  346. run, just before exiting the program.
  347. If the rendering context is lost, QuitApplication() will
  348. not be called.
  349. ******************************************************************************/
  350. bool OGLES2ChameleonMan::QuitApplication()
  351. {
  352. // Free the memory allocated for the scene
  353. m_Scene.Destroy();
  354. delete [] m_puiVbo;
  355. delete [] m_puiIndexVbo;
  356. return true;
  357. }
  358. /*!****************************************************************************
  359. @Function InitView
  360. @Return bool true if no error occured
  361. @Description Code in InitView() will be called by PVRShell upon
  362. initialization or after a change in the rendering context.
  363. Used to initialize variables that are dependant on the rendering
  364. context (e.g. textures, vertex buffers, etc.)
  365. ******************************************************************************/
  366. bool OGLES2ChameleonMan::InitView()
  367. {
  368. CPVRTString ErrorStr;
  369. /*
  370. Initialize VBO data
  371. */
  372. LoadVbos();
  373. /*
  374. Load textures
  375. */
  376. if (!LoadTextures(&ErrorStr))
  377. {
  378. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  379. return false;
  380. }
  381. /*
  382. Load and compile the shaders & link programs
  383. */
  384. if (!LoadShaders(&ErrorStr))
  385. {
  386. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  387. return false;
  388. }
  389. /*
  390. Initialize Print3D
  391. */
  392. // Is the screen rotated?
  393. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  394. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  395. {
  396. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  397. return false;
  398. }
  399. /*
  400. Set OpenGL ES render states needed for this training course
  401. */
  402. // Enable backface culling and depth test
  403. glCullFace(GL_BACK);
  404. glEnable(GL_CULL_FACE);
  405. glEnable(GL_DEPTH_TEST);
  406. // Use a nice bright blue as clear colour
  407. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  408. // Initialise variables used for the animation
  409. m_iTimePrev = PVRShellGetTime();
  410. return true;
  411. }
  412. /*!****************************************************************************
  413. @Function ReleaseView
  414. @Return bool true if no error occured
  415. @Description Code in ReleaseView() will be called by PVRShell when the
  416. application quits or before a change in the rendering context.
  417. ******************************************************************************/
  418. bool OGLES2ChameleonMan::ReleaseView()
  419. {
  420. // Delete textures
  421. glDeleteTextures(1, &m_ui32TexLegs);
  422. glDeleteTextures(1, &m_ui32TexBeltNormalMap);
  423. glDeleteTextures(1, &m_ui32TexHeadNormalMap);
  424. glDeleteTextures(1, &m_ui32TexLegsNormalMap);
  425. glDeleteTextures(1, &m_ui32TexSkyLine);
  426. glDeleteTextures(1, &m_ui32TexWall);
  427. glDeleteTextures(1, &m_ui32TexLamp);
  428. glDeleteTextures(1, &m_ui32TexBelt);
  429. // Delete program and shader objects
  430. glDeleteProgram(m_SkinnedShaderProgram.uiId);
  431. glDeleteProgram(m_DefaultShaderProgram.uiId);
  432. glDeleteShader(m_uiSkinnedVertShader);
  433. glDeleteShader(m_uiDefaultVertShader);
  434. glDeleteShader(m_uiSkinnedFragShader);
  435. glDeleteShader(m_uiDefaultFragShader);
  436. // Delete buffer objects
  437. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  438. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  439. // Release Print3D Textures
  440. m_Print3D.ReleaseTextures();
  441. return true;
  442. }
  443. /*!****************************************************************************
  444. @Function RenderScene
  445. @Return bool true if no error occured
  446. @Description Main rendering loop function of the program. The shell will
  447. call this function every frame.
  448. eglSwapBuffers() will be performed by PVRShell automatically.
  449. PVRShell will also manage important OS events.
  450. Will also manage relevent OS events. The user has access to
  451. these events through an abstraction layer provided by PVRShell.
  452. ******************************************************************************/
  453. bool OGLES2ChameleonMan::RenderScene()
  454. {
  455. // Clear the color and depth buffer
  456. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  457. // Use shader program
  458. glUseProgram(m_SkinnedShaderProgram.uiId);
  459. if(PVRShellIsKeyPressed(PVRShellKeyNameACTION1))
  460. {
  461. m_bEnableDOT3 = !m_bEnableDOT3;
  462. glUniform1i(m_SkinnedShaderProgram.auiLoc[ebUseDot3], m_bEnableDOT3);
  463. }
  464. /*
  465. Calculates the frame number to animate in a time-based manner.
  466. Uses the shell function PVRShellGetTime() to get the time in milliseconds.
  467. */
  468. unsigned long iTime = PVRShellGetTime();
  469. if(iTime > m_iTimePrev)
  470. {
  471. float fDelta = (float) (iTime - m_iTimePrev);
  472. m_fFrame += fDelta * g_fDemoFrameRate;
  473. // Increment the counters to make sure our animation works
  474. m_fLightPos += fDelta * 0.0034f;
  475. m_fWallPos += fDelta * 0.00027f;
  476. m_fBackgroundPos += fDelta * -0.000027f;
  477. // Wrap the Animation back to the Start
  478. if(m_fLightPos >= PVRT_TWO_PI)
  479. m_fLightPos -= PVRT_TWO_PI;
  480. if(m_fWallPos >= PVRT_TWO_PI)
  481. m_fWallPos -= PVRT_TWO_PI;
  482. if(m_fBackgroundPos <= 0)
  483. m_fBackgroundPos += 1.0f;
  484. if(m_fFrame > m_Scene.nNumFrame - 1)
  485. m_fFrame = 0;
  486. }
  487. m_iTimePrev = iTime;
  488. // Set the scene animation to the current frame
  489. m_Scene.SetFrame(m_fFrame);
  490. // Set up camera
  491. PVRTVec3 vFrom, vTo, vUp(0.0f, 1.0f, 0.0f);
  492. PVRTMat4 mView, mProjection;
  493. PVRTVec3 LightPos;
  494. float fFOV;
  495. int i;
  496. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  497. // Get the camera position, target and field of view (fov)
  498. if(m_Scene.pCamera[0].nIdxTarget != -1) // Does the camera have a target?
  499. fFOV = m_Scene.GetCameraPos( vFrom, vTo, 0); // vTo is taken from the target node
  500. else
  501. fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, 0); // vTo is calculated from the rotation
  502. fFOV *= bRotate ? (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight) : (float)PVRShellGet(prefHeight)/(float)PVRShellGet(prefWidth);
  503. /*
  504. We can build the model view matrix from the camera position, target and an up vector.
  505. For this we use PVRTMat4::LookAtRH().
  506. */
  507. mView = PVRTMat4::LookAtRH(vFrom, vTo, vUp);
  508. // Calculate the projection matrix
  509. mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
  510. // Update Light Position and related VGP Program constant
  511. LightPos.x = 200.0f;
  512. LightPos.y = 350.0f;
  513. LightPos.z = 200.0f * PVRTABS(sin((PVRT_PI / 4.0f) + m_fLightPos));
  514. glUniform3fv(m_SkinnedShaderProgram.auiLoc[eLightPos], 1, LightPos.ptr());
  515. // Set up the View * Projection Matrix
  516. PVRTMat4 mViewProjection;
  517. mViewProjection = mProjection * mView;
  518. glUniformMatrix4fv(m_SkinnedShaderProgram.auiLoc[eViewProj], 1, GL_FALSE, mViewProjection.ptr());
  519. // Enable the vertex attribute arrays
  520. for(i = 0; i < eNumAttribs; ++i) glEnableVertexAttribArray(i);
  521. // Draw skinned meshes
  522. for(unsigned int i32NodeIndex = 0; i32NodeIndex < 3; ++i32NodeIndex)
  523. {
  524. // Bind correct texture
  525. switch(i32NodeIndex)
  526. {
  527. case eBody:
  528. glActiveTexture(GL_TEXTURE1);
  529. glBindTexture(GL_TEXTURE_2D, m_ui32TexHeadNormalMap);
  530. glActiveTexture(GL_TEXTURE0);
  531. glBindTexture(GL_TEXTURE_2D, m_ui32TexHeadBody);
  532. break;
  533. case eLegs:
  534. glActiveTexture(GL_TEXTURE1);
  535. glBindTexture(GL_TEXTURE_2D, m_ui32TexLegsNormalMap);
  536. glActiveTexture(GL_TEXTURE0);
  537. glBindTexture(GL_TEXTURE_2D, m_ui32TexLegs);
  538. break;
  539. default:
  540. glActiveTexture(GL_TEXTURE1);
  541. glBindTexture(GL_TEXTURE_2D, m_ui32TexBeltNormalMap);
  542. glActiveTexture(GL_TEXTURE0);
  543. glBindTexture(GL_TEXTURE_2D, m_ui32TexBelt);
  544. break;
  545. }
  546. DrawSkinnedMesh(i32NodeIndex);
  547. }
  548. // Safely disable the vertex attribute arrays
  549. for(i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
  550. // Draw non-skinned meshes
  551. glUseProgram(m_DefaultShaderProgram.uiId);
  552. // Enable the vertex attribute arrays
  553. for(i = 0; i < eNumDefaultAttribs; ++i) glEnableVertexAttribArray(i);
  554. for(unsigned int i32NodeIndex = 3; i32NodeIndex < m_Scene.nNumMeshNode; ++i32NodeIndex)
  555. {
  556. SPODNode& Node = m_Scene.pNode[i32NodeIndex];
  557. SPODMesh& Mesh = m_Scene.pMesh[Node.nIdx];
  558. // bind the VBO for the mesh
  559. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[Node.nIdx]);
  560. // bind the index buffer, won't hurt if the handle is 0
  561. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[Node.nIdx]);
  562. // Get the node model matrix
  563. PVRTMat4 mWorld;
  564. mWorld = m_Scene.GetWorldMatrix(Node);
  565. // Setup the appropriate texture and transformation (if needed)
  566. switch(i32NodeIndex)
  567. {
  568. case eWall:
  569. glBindTexture(GL_TEXTURE_2D, m_ui32TexWall);
  570. // Rotate the wall mesh which is circular
  571. mWorld *= PVRTMat4::RotationY(m_fWallPos);
  572. glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], 0);
  573. break;
  574. case eBackground:
  575. glBindTexture(GL_TEXTURE_2D, m_ui32TexSkyLine);
  576. glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], m_fBackgroundPos);
  577. break;
  578. case eLights:
  579. {
  580. glBindTexture(GL_TEXTURE_2D, m_ui32TexLamp);
  581. PVRTMat4 mWallWorld = m_Scene.GetWorldMatrix(m_Scene.pNode[eWall]);
  582. mWorld = mWallWorld * PVRTMat4::RotationY(m_fWallPos) * mWallWorld.inverse() * mWorld;
  583. glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], 0);
  584. }
  585. break;
  586. default:
  587. break;
  588. };
  589. // Set up shader uniforms
  590. PVRTMat4 mModelViewProj;
  591. mModelViewProj = mViewProjection * mWorld;
  592. glUniformMatrix4fv(m_DefaultShaderProgram.auiLoc[eDefaultMVPMatrix], 1, GL_FALSE, mModelViewProj.ptr());
  593. // Set the vertex attribute offsets
  594. glVertexAttribPointer(DEFAULT_VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sVertex.nStride, Mesh.sVertex.pData);
  595. glVertexAttribPointer(DEFAULT_TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, Mesh.psUVW[0].nStride, Mesh.psUVW[0].pData);
  596. // Indexed Triangle list
  597. glDrawElements(GL_TRIANGLES, Mesh.nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  598. }
  599. // Safely disable the vertex attribute arrays
  600. for(i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
  601. // unbind the VBOs
  602. glBindBuffer(GL_ARRAY_BUFFER, 0);
  603. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  604. // Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  605. const char * pDescription;
  606. if(m_bEnableDOT3)
  607. pDescription = "Skinning with DOT3 Per Pixel Lighting";
  608. else
  609. pDescription = "Skinning with Vertex Lighting";
  610. m_Print3D.DisplayDefaultTitle("Chameleon Man", pDescription, ePVRTPrint3DSDKLogo);
  611. m_Print3D.Flush();
  612. return true;
  613. }
  614. /*!****************************************************************************
  615. @Function DrawSkinnedMesh
  616. @Input i32NodeIndex Node index of the mesh to draw
  617. @Description Draws a SPODMesh after the model view matrix has been set and
  618. the meterial prepared.
  619. ******************************************************************************/
  620. void OGLES2ChameleonMan::DrawSkinnedMesh(int i32NodeIndex)
  621. {
  622. SPODNode& Node = m_Scene.pNode[i32NodeIndex];
  623. SPODMesh& Mesh = m_Scene.pMesh[Node.nIdx];
  624. // bind the VBO for the mesh
  625. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[Node.nIdx]);
  626. // bind the index buffer, won't hurt if the handle is 0
  627. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[Node.nIdx]);
  628. // Set the vertex attribute offsets
  629. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sVertex.nStride, Mesh.sVertex.pData);
  630. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sNormals.nStride, Mesh.sNormals.pData);
  631. glVertexAttribPointer(TANGENT_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sTangents.nStride, Mesh.sTangents.pData);
  632. glVertexAttribPointer(BINORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sBinormals.nStride, Mesh.sBinormals.pData);
  633. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, Mesh.psUVW[0].nStride, Mesh.psUVW[0].pData);
  634. glVertexAttribPointer(BONEINDEX_ARRAY, Mesh.sBoneIdx.n, GL_UNSIGNED_BYTE, GL_FALSE, Mesh.sBoneIdx.nStride, Mesh.sBoneIdx.pData);
  635. glVertexAttribPointer(BONEWEIGHT_ARRAY, Mesh.sBoneWeight.n, GL_UNSIGNED_BYTE, GL_TRUE, Mesh.sBoneWeight.nStride, Mesh.sBoneWeight.pData);
  636. for(int i32Batch = 0; i32Batch < Mesh.sBoneBatches.nBatchCnt; ++i32Batch)
  637. {
  638. /*
  639. If the current mesh has bone index and weight data then we need to
  640. set up some additional variables in the shaders.
  641. */
  642. // Set the number of bones that will influence each vertex in the mesh
  643. glUniform1i(m_SkinnedShaderProgram.auiLoc[eBoneCount], Mesh.sBoneIdx.n);
  644. // Go through the bones for the current bone batch
  645. PVRTMat4 amBoneWorld[8];
  646. PVRTMat3 afBoneWorldIT[8], mBoneIT;
  647. int i32Count = Mesh.sBoneBatches.pnBatchBoneCnt[i32Batch];
  648. for(int i = 0; i < i32Count; ++i)
  649. {
  650. // Get the Node of the bone
  651. int i32NodeID = Mesh.sBoneBatches.pnBatches[i32Batch * Mesh.sBoneBatches.nBatchBoneMax + i];
  652. // Get the World transformation matrix for this bone and combine it with our app defined
  653. // transformation matrix
  654. amBoneWorld[i] = m_Scene.GetBoneWorldMatrix(Node, m_Scene.pNode[i32NodeID]);
  655. // Calculate the inverse transpose of the 3x3 rotation/scale part for correct lighting
  656. afBoneWorldIT[i] = PVRTMat3(amBoneWorld[i]).inverse().transpose();
  657. }
  658. glUniformMatrix4fv(m_SkinnedShaderProgram.auiLoc[eBoneMatrices], i32Count, GL_FALSE, amBoneWorld[0].ptr());
  659. glUniformMatrix3fv(m_SkinnedShaderProgram.auiLoc[eBoneMatricesIT], i32Count, GL_FALSE, afBoneWorldIT[0].ptr());
  660. /*
  661. As we are using bone batching we don't want to draw all the faces contained within pMesh, we only want
  662. to draw the ones that are in the current batch. To do this we pass to the drawMesh function the offset
  663. to the start of the current batch of triangles (Mesh.sBoneBatches.pnBatchOffset[i32Batch]) and the
  664. total number of triangles to draw (i32Tris)
  665. */
  666. int i32Tris;
  667. if(i32Batch+1 < Mesh.sBoneBatches.nBatchCnt)
  668. i32Tris = Mesh.sBoneBatches.pnBatchOffset[i32Batch+1] - Mesh.sBoneBatches.pnBatchOffset[i32Batch];
  669. else
  670. i32Tris = Mesh.nNumFaces - Mesh.sBoneBatches.pnBatchOffset[i32Batch];
  671. // Draw the mesh
  672. glDrawElements(GL_TRIANGLES, i32Tris * 3, GL_UNSIGNED_SHORT, &((unsigned short*)0)[3 * Mesh.sBoneBatches.pnBatchOffset[i32Batch]]);
  673. }
  674. }
  675. /*!****************************************************************************
  676. @Function NewDemo
  677. @Return PVRShell* The demo supplied by the user
  678. @Description This function must be implemented by the user of the shell.
  679. The user should return its PVRShell object defining the
  680. behaviour of the application.
  681. ******************************************************************************/
  682. PVRShell* NewDemo()
  683. {
  684. return new OGLES2ChameleonMan();
  685. }
  686. /******************************************************************************
  687. End of file (OGLES2ChameleonMan.cpp)
  688. ******************************************************************************/