OGLES2CellShading.cpp 16 KB

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