OGLES2ShadowVolume.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /******************************************************************************
  2. @File OGLES2ShadowVolume.cpp
  3. @Title Shadow Volumes
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Shows how to use PVRTools to generate shadow volumes for stencil
  8. shadows.
  9. ******************************************************************************/
  10. #include <string.h>
  11. #include "PVRShell.h"
  12. #include "OGLES2Tools.h"
  13. /******************************************************************************
  14. Constants
  15. ******************************************************************************/
  16. // Camera constants used to generate the projection matrix
  17. const float CAM_NEAR = 75.0f;
  18. const float CAM_FAR = 2000.0f;
  19. /******************************************************************************
  20. shader attributes
  21. ******************************************************************************/
  22. // vertex attributes
  23. enum EVertexAttrib {
  24. VERTEX_ARRAY, NORMAL_ARRAY, TEXCOORD_ARRAY, eNumAttribs };
  25. // shader uniforms
  26. enum EUniform {
  27. eMVPMatrix, eLightPosModel, eVolumeScale, eColor, eNumUniforms };
  28. const char* g_aszUniformNames[] = {
  29. "MVPMatrix", "LightPosModel", "VolumeScale", "Color" };
  30. // Enum to decide which cog is which
  31. enum eCog
  32. {
  33. eBigCog = 1,
  34. eSmallCog = 2,
  35. eNumMeshes
  36. };
  37. enum eObjectType
  38. {
  39. eDoesntCast, // This object type doesn't cast shadows
  40. eStaticObject, // This object type doesn't move so we only need to calculate its volume once (as long as the light doesn't move)
  41. eDynamicObject // This object type changes every frame so we need to calculate its volume every frame also.
  42. };
  43. /******************************************************************************
  44. Content file names
  45. ******************************************************************************/
  46. // Source and binary shaders
  47. const char c_szBaseFragSrcFile[] = "BaseFragShader.fsh";
  48. const char c_szBaseFragBinFile[] = "BaseFragShader.fsc";
  49. const char c_szConstFragSrcFile[] = "ConstFragShader.fsh";
  50. const char c_szConstFragBinFile[] = "ConstFragShader.fsc";
  51. const char c_szBaseVertSrcFile[] = "BaseVertShader.vsh";
  52. const char c_szBaseVertBinFile[] = "BaseVertShader.vsc";
  53. const char c_szShadowVolVertSrcFile[] = "ShadowVolVertShader.vsh";
  54. const char c_szShadowVolVertBinFile[] = "ShadowVolVertShader.vsc";
  55. const char c_szFullscreenVertSrcFile[] = "FullscreenVertShader.vsh";
  56. const char c_szFullscreenVertBinFile[] = "FullscreenVertShader.vsc";
  57. // PVR texture files
  58. const char c_szBackgroundTexFile[] = "Background.pvr";
  59. const char c_szRustTexFile[] = "Rust.pvr";
  60. // POD scene files
  61. const char c_szSceneFile[] = "scene.pod";
  62. /*!****************************************************************************
  63. Class implementing the PVRShell functions.
  64. ******************************************************************************/
  65. class OGLES2ShadowVolumes : public PVRShell
  66. {
  67. // Print3D class used to display text
  68. CPVRTPrint3D m_Print3D;
  69. // 3D Model
  70. CPVRTModelPOD m_Scene;
  71. PVRTVec4 m_vLightPosWorld;
  72. // Projection and view matrices
  73. PVRTMat4 m_mProjection, m_mView;
  74. // OpenGL handles for shaders, textures and VBOs
  75. GLuint m_uiBaseVertShader;
  76. GLuint m_uiShadowVolVertShader;
  77. GLuint m_uiFullscreenVertShader;
  78. GLuint m_uiBaseFragShader;
  79. GLuint m_uiConstFragShader;
  80. GLuint m_uiBackgroundTex;
  81. GLuint m_uiRustTex;
  82. GLuint* m_puiVbo;
  83. GLuint* m_puiIndexVbo;
  84. // Group shader programs and their uniform locations together
  85. struct
  86. {
  87. GLuint uiId;
  88. GLuint auiLoc[eNumUniforms];
  89. }
  90. m_BaseShader, m_FullscreenShader, m_ShadowVolShader;
  91. // Array to lookup the textures for each material in the scene
  92. GLuint* m_puiTextures;
  93. // Variables to handle the animation in a time-based manner
  94. unsigned long m_i32TimePrev;
  95. float m_fBigCogAngle;
  96. float m_fSmallCogAngle;
  97. PVRTShadowVolShadowMesh *m_pShadowMesh; // Model definition suitable for shadow volumes
  98. PVRTShadowVolShadowVol *m_pShadowVol; // Geometry of actual shadow volume
  99. // The number of shadows we have in the scene
  100. unsigned int m_ui32NoOfShadows;
  101. // An array that will store the ID of the SPODMesh that the shadows are cast from
  102. unsigned int* m_pui32MeshIndex;
  103. // An array to store the mesh type. It stores eObjectType values.
  104. int m_i32ObjectType[eNumMeshes];
  105. // A boolean used to decide whether to display the shadow volumes
  106. bool m_bDisplayVolumes;
  107. public:
  108. virtual bool InitApplication();
  109. virtual bool InitView();
  110. virtual bool ReleaseView();
  111. virtual bool QuitApplication();
  112. virtual bool RenderScene();
  113. bool LoadTextures(CPVRTString* pErrorStr);
  114. bool LoadShaders(CPVRTString* pErrorStr);
  115. void LoadVbos();
  116. void DrawMesh(int i32NodeIndex);
  117. void DoStencilTest();
  118. bool BuildShadowVolume(PVRTShadowVolShadowMesh *pShadowMesh, PVRTShadowVolShadowVol *pVolume, SPODMesh* pMesh);
  119. void DrawScene();
  120. void DrawShadowVolumes(PVRTVec4 *pLightPos);
  121. void DrawFullScreenQuad();
  122. bool BuildVolume(unsigned int ui32ShadowVol, PVRTVec4 *pLightPos);
  123. };
  124. /*!****************************************************************************
  125. @Function LoadTextures
  126. @Output pErrorStr A string describing the error on failure
  127. @Return bool true if no error occured
  128. @Description Loads the textures required for this training course
  129. ******************************************************************************/
  130. bool OGLES2ShadowVolumes::LoadTextures(CPVRTString* const pErrorStr)
  131. {
  132. if(PVRTTextureLoadFromPVR(c_szBackgroundTexFile, &m_uiBackgroundTex) != PVR_SUCCESS)
  133. {
  134. *pErrorStr = "ERROR: Failed to load texture.";
  135. return false;
  136. }
  137. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  138. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  139. if(PVRTTextureLoadFromPVR(c_szRustTexFile, &m_uiRustTex) != PVR_SUCCESS)
  140. {
  141. *pErrorStr = "ERROR: Failed to load texture.";
  142. return false;
  143. }
  144. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  145. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  146. return true;
  147. }
  148. /*!****************************************************************************
  149. @Function LoadShaders
  150. @Output pErrorStr A string describing the error on failure
  151. @Return bool true if no error occured
  152. @Description Loads and compiles the shaders and links the shader programs
  153. required for this training course
  154. ******************************************************************************/
  155. bool OGLES2ShadowVolumes::LoadShaders(CPVRTString* pErrorStr)
  156. {
  157. /*
  158. Load and compile the shaders from files.
  159. Binary shaders are tried first, source shaders
  160. are used as fallback.
  161. */
  162. if (
  163. (PVRTShaderLoadFromFile(c_szBaseFragBinFile, c_szBaseFragSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiBaseFragShader, pErrorStr) != PVR_SUCCESS) ||
  164. (PVRTShaderLoadFromFile(c_szConstFragBinFile, c_szConstFragSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiConstFragShader, pErrorStr) != PVR_SUCCESS) ||
  165. (PVRTShaderLoadFromFile(c_szBaseVertBinFile, c_szBaseVertSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiBaseVertShader, pErrorStr) != PVR_SUCCESS) ||
  166. (PVRTShaderLoadFromFile(c_szShadowVolVertBinFile, c_szShadowVolVertSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiShadowVolVertShader, pErrorStr) != PVR_SUCCESS) ||
  167. (PVRTShaderLoadFromFile(c_szFullscreenVertBinFile, c_szFullscreenVertSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiFullscreenVertShader, pErrorStr) != PVR_SUCCESS))
  168. {
  169. return false;
  170. }
  171. /*
  172. Set up and link the shader program
  173. */
  174. const char* aszBaseAttribNames[] = { "inVertex", "inNormal", "inTexCoord" };
  175. const char* aszFullscreenAttribNames[] = { "inVertex" };
  176. const char* aszShadowVolAttribNames[] = { "inVertex", "inExtrude" };
  177. if (
  178. (PVRTCreateProgram(&m_BaseShader.uiId, m_uiBaseVertShader, m_uiBaseFragShader, aszBaseAttribNames, 3, pErrorStr) != PVR_SUCCESS) ||
  179. (PVRTCreateProgram(&m_FullscreenShader.uiId, m_uiFullscreenVertShader, m_uiConstFragShader, aszFullscreenAttribNames, 1, pErrorStr) != PVR_SUCCESS) ||
  180. (PVRTCreateProgram(&m_ShadowVolShader.uiId, m_uiShadowVolVertShader, m_uiConstFragShader, aszShadowVolAttribNames, 2, pErrorStr) != PVR_SUCCESS))
  181. {
  182. return false;
  183. }
  184. // Store the location of uniforms for later use
  185. for (int i = 0; i < eNumUniforms; ++i)
  186. {
  187. m_BaseShader.auiLoc[i] = glGetUniformLocation(m_BaseShader.uiId, g_aszUniformNames[i]);
  188. m_FullscreenShader.auiLoc[i] = glGetUniformLocation(m_FullscreenShader.uiId, g_aszUniformNames[i]);
  189. m_ShadowVolShader.auiLoc[i] = glGetUniformLocation(m_ShadowVolShader.uiId, g_aszUniformNames[i]);
  190. }
  191. return true;
  192. }
  193. /*!****************************************************************************
  194. @Function LoadVbos
  195. @Description Loads the mesh data required for this training course into
  196. vertex buffer objects
  197. ******************************************************************************/
  198. void OGLES2ShadowVolumes::LoadVbos()
  199. {
  200. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  201. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  202. /*
  203. Load vertex data of all meshes in the scene into VBOs
  204. The meshes have been exported with the "Interleave Vectors" option,
  205. so all data is interleaved in the buffer at pMesh->pInterleaved.
  206. Interleaving data improves the memory access pattern and cache efficiency,
  207. thus it can be read faster by the hardware.
  208. */
  209. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  210. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  211. {
  212. // Load vertex data into buffer object
  213. SPODMesh& Mesh = m_Scene.pMesh[i];
  214. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  215. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  216. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  217. // Load index data into buffer object if available
  218. m_puiIndexVbo[i] = 0;
  219. if (Mesh.sFaces.pData)
  220. {
  221. glGenBuffers(1, &m_puiIndexVbo[i]);
  222. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  223. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  224. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  225. }
  226. }
  227. glBindBuffer(GL_ARRAY_BUFFER, 0);
  228. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  229. }
  230. /*!****************************************************************************
  231. @Function InitApplication
  232. @Return bool true if no error occured
  233. @Description Code in InitApplication() will be called by PVRShell once per
  234. run, before the rendering context is created.
  235. Used to initialize variables that are not dependant on it
  236. (e.g. external modules, loading meshes, etc.)
  237. If the rendering context is lost, InitApplication() will
  238. not be called again.
  239. ******************************************************************************/
  240. bool OGLES2ShadowVolumes::InitApplication()
  241. {
  242. m_puiVbo = 0;
  243. m_puiIndexVbo = 0;
  244. // Get and set the read path for content files
  245. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  246. // Load the scene
  247. if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  248. {
  249. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  250. return false;
  251. }
  252. // The cameras are stored in the file. We check it contains at least one.
  253. if(m_Scene.nNumCamera == 0)
  254. {
  255. PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera\n");
  256. return false;
  257. }
  258. // The scene must contain at least one light
  259. if(m_Scene.nNumLight == 0)
  260. {
  261. PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light\n");
  262. return false;
  263. }
  264. // Get the Light Position
  265. m_vLightPosWorld = m_Scene.GetLightPosition(0);
  266. m_vLightPosWorld.w = 1.0f;
  267. // Initialise variables
  268. m_bDisplayVolumes = false;
  269. m_fBigCogAngle = 0.0f;
  270. m_fSmallCogAngle = 0.0f;
  271. // Set up the object type for each mesh in the scene
  272. m_i32ObjectType[0] = eDoesntCast; // The mesh that makes up the background
  273. m_i32ObjectType[1] = eDynamicObject; // The big cog
  274. m_i32ObjectType[2] = eStaticObject; // The small cog
  275. // Request Stencil Buffer support
  276. PVRShellSet(prefStencilBufferContext, true);
  277. return true;
  278. }
  279. /*!****************************************************************************
  280. @Function QuitApplication
  281. @Return bool true if no error occured
  282. @Description Code in QuitApplication() will be called by PVRShell once per
  283. run, just before exiting the program.
  284. If the rendering context is lost, QuitApplication() will
  285. not be called.
  286. ******************************************************************************/
  287. bool OGLES2ShadowVolumes::QuitApplication()
  288. {
  289. // Free the memory allocated for the scene
  290. m_Scene.Destroy();
  291. delete [] m_puiVbo;
  292. delete [] m_puiIndexVbo;
  293. return true;
  294. }
  295. /*!****************************************************************************
  296. @Function InitView
  297. @Return bool true if no error occured
  298. @Description Code in InitView() will be called by PVRShell upon
  299. initialization or after a change in the rendering context.
  300. Used to initialize variables that are dependant on the rendering
  301. context (e.g. textures, vertex buffers, etc.)
  302. ******************************************************************************/
  303. bool OGLES2ShadowVolumes::InitView()
  304. {
  305. CPVRTString ErrorStr;
  306. /*
  307. Initialize VBO data
  308. */
  309. LoadVbos();
  310. /*
  311. Load textures
  312. */
  313. if (!LoadTextures(&ErrorStr))
  314. {
  315. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  316. return false;
  317. }
  318. /*
  319. Load and compile the shaders & link programs
  320. */
  321. if (!LoadShaders(&ErrorStr))
  322. {
  323. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  324. return false;
  325. }
  326. // Set the sampler2D uniforms to corresponding texture units
  327. glUseProgram(m_BaseShader.uiId);
  328. glUniform1i(glGetUniformLocation(m_BaseShader.uiId, "sTexture"), 0);
  329. /*
  330. Initialise an array to lookup the textures
  331. for each material in the scene.
  332. */
  333. m_puiTextures = new GLuint[m_Scene.nNumMaterial];
  334. for(unsigned int i = 0; i < m_Scene.nNumMaterial; ++i)
  335. {
  336. m_puiTextures[i] = 0;
  337. SPODMaterial* pMaterial = &m_Scene.pMaterial[i];
  338. if (!strcmp(pMaterial->pszName, "background"))
  339. {
  340. m_puiTextures[i] = m_uiBackgroundTex;
  341. }
  342. else if (!strcmp(pMaterial->pszName, "rust"))
  343. {
  344. m_puiTextures[i] = m_uiRustTex;
  345. }
  346. }
  347. // Go through the object type and find out how many shadows we are going to need
  348. m_ui32NoOfShadows = 0;
  349. for (int i = 0; i < eNumMeshes; ++i)
  350. {
  351. if(m_i32ObjectType[i] != eDoesntCast) ++m_ui32NoOfShadows;
  352. }
  353. // Build the shadow volumes and meshes
  354. // Create the number of shadow meshes and volumes we require
  355. m_pShadowMesh = new PVRTShadowVolShadowMesh[m_ui32NoOfShadows];
  356. m_pShadowVol = new PVRTShadowVolShadowVol [m_ui32NoOfShadows];
  357. // Create the array that stores the SPODNode ID for each shadow
  358. m_pui32MeshIndex = new unsigned int[m_ui32NoOfShadows];
  359. // Go through the meshes and initialise the shadow meshes, volumes and mesh index for each requried shadow
  360. int i32Index = 0;
  361. for (int i = 0; i < eNumMeshes; ++i)
  362. {
  363. if(m_i32ObjectType[i] != eDoesntCast)
  364. {
  365. m_pui32MeshIndex[i32Index] = i;
  366. SPODNode* pNode = &m_Scene.pNode[i];
  367. /*
  368. This function will take the POD mesh referenced by the current node and generate a
  369. new mesh suitable for creating shadow volumes and the shadow volume itself.
  370. */
  371. BuildShadowVolume(&m_pShadowMesh[i32Index], &m_pShadowVol[i32Index], &m_Scene.pMesh[pNode->nIdx]);
  372. /*
  373. The function will initialise the shadow volume with regard to the meshes current transformation
  374. and the light position.
  375. As the light position is fixed this is only done once for static objects where as dynamic objects
  376. are updated every frame.
  377. */
  378. BuildVolume(i32Index, &m_vLightPosWorld);
  379. ++i32Index;
  380. }
  381. }
  382. // Is the screen rotated?
  383. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  384. /*
  385. Initialize Print3D
  386. */
  387. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
  388. {
  389. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  390. return false;
  391. }
  392. // Calculate the view matrix
  393. PVRTVec3 vFrom, vTo;
  394. float fFOV;
  395. // We can get the camera position, target and field of view (fov) with GetCamera()
  396. fFOV = m_Scene.GetCameraPos( vFrom, vTo, 0);
  397. m_mView = PVRTMat4::LookAtRH(vFrom, vTo, PVRTVec3(0, 1, 0));
  398. // Calculate the projection matrix
  399. m_mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
  400. /*
  401. Set OpenGL ES render states needed for this training course
  402. */
  403. // Enable backface culling and depth test
  404. glCullFace(GL_BACK);
  405. glEnable(GL_CULL_FACE);
  406. glEnable(GL_DEPTH_TEST);
  407. // Use a nice bright blue as clear colour
  408. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  409. glClearStencil(0);
  410. m_i32TimePrev = PVRShellGetTime();
  411. return true;
  412. }
  413. /*!****************************************************************************
  414. @Function ReleaseView
  415. @Return bool true if no error occured
  416. @Description Code in ReleaseView() will be called by PVRShell when the
  417. application quits or before a change in the rendering context.
  418. ******************************************************************************/
  419. bool OGLES2ShadowVolumes::ReleaseView()
  420. {
  421. // Frees the texture lookup array
  422. delete[] m_puiTextures;
  423. // Delete textures
  424. glDeleteTextures(1, &m_uiBackgroundTex);
  425. glDeleteTextures(1, &m_uiRustTex);
  426. // Delete program and shader objects
  427. glDeleteProgram(m_BaseShader.uiId);
  428. glDeleteProgram(m_ShadowVolShader.uiId);
  429. glDeleteProgram(m_FullscreenShader.uiId);
  430. glDeleteShader(m_uiBaseVertShader);
  431. glDeleteShader(m_uiShadowVolVertShader);
  432. glDeleteShader(m_uiFullscreenVertShader);
  433. glDeleteShader(m_uiBaseFragShader);
  434. glDeleteShader(m_uiConstFragShader);
  435. // Delete buffer objects
  436. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  437. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  438. // Release Print3D Textures
  439. m_Print3D.ReleaseTextures();
  440. // Free the shadow volumes and meshes
  441. for(unsigned int i = 0; i < m_ui32NoOfShadows; ++i)
  442. {
  443. PVRTShadowVolMeshReleaseVol(&m_pShadowVol[i]);
  444. PVRTShadowVolMeshReleaseMesh(&m_pShadowMesh[i]);
  445. PVRTShadowVolMeshDestroyMesh(&m_pShadowMesh[i]);
  446. }
  447. delete[] m_pShadowMesh;
  448. delete[] m_pShadowVol;
  449. delete[] m_pui32MeshIndex;
  450. return true;
  451. }
  452. /*!****************************************************************************
  453. @Function BuildVolume
  454. @Return bool true if no error occured
  455. @Description This function will create the volume that we will be drawn
  456. in the stenciltest.
  457. ******************************************************************************/
  458. bool OGLES2ShadowVolumes::BuildVolume(unsigned int ui32ShadowVol, PVRTVec4 *pLightPos)
  459. {
  460. SPODNode* pNode;
  461. PVRTMat4 mWorld;
  462. PVRTVec4 vModelLightPos;
  463. int i32MeshIndex = m_pui32MeshIndex[ui32ShadowVol];
  464. pNode = &m_Scene.pNode[i32MeshIndex];
  465. // Get the world matrix for this particular node.
  466. switch(i32MeshIndex)
  467. {
  468. case eBigCog:
  469. mWorld = PVRTMat4::RotationZ(m_fBigCogAngle);
  470. break;
  471. case eSmallCog:
  472. mWorld = PVRTMat4::RotationZ(m_fSmallCogAngle);
  473. break;
  474. default:
  475. mWorld = m_Scene.GetWorldMatrix(*pNode);
  476. }
  477. /*
  478. Convert the light position into model space for the current Node.
  479. */
  480. vModelLightPos = mWorld.inverse() * (*pLightPos);
  481. /*
  482. Using the light position set up the shadow volume so it can be extruded in the shader.
  483. */
  484. unsigned int ui32Flags = PVRTSHADOWVOLUME_VISIBLE | PVRTSHADOWVOLUME_NEED_CAP_FRONT | PVRTSHADOWVOLUME_NEED_CAP_BACK;
  485. PVRTShadowVolSilhouetteProjectedBuild(&m_pShadowVol[ui32ShadowVol], ui32Flags , &m_pShadowMesh[ui32ShadowVol], (PVRTVec3*) &vModelLightPos, true);
  486. return true;
  487. }
  488. /*!****************************************************************************
  489. @Function RenderScene
  490. @Return bool true if no error occured
  491. @Description Main rendering loop function of the program. The shell will
  492. call this function every frame.
  493. eglSwapBuffers() will be performed by PVRShell automatically.
  494. PVRShell will also manage important OS events.
  495. Will also manage relevent OS events. The user has access to
  496. these events through an abstraction layer provided by PVRShell.
  497. ******************************************************************************/
  498. bool OGLES2ShadowVolumes::RenderScene()
  499. {
  500. //Calculate the time passes since the last frame so we can rotate the cogs in a time-based manner
  501. int i32Time = PVRShellGetTime();
  502. int i32DeltaTime = i32Time - m_i32TimePrev;
  503. m_i32TimePrev = i32Time;
  504. // If the cog is classed as dynamic then we need to update its angle of rotation
  505. if(m_i32ObjectType[eBigCog] == eDynamicObject)
  506. {
  507. m_fBigCogAngle += i32DeltaTime * 0.001f;
  508. while(m_fBigCogAngle > PVRT_TWO_PI)
  509. m_fBigCogAngle -= PVRT_TWO_PI;
  510. }
  511. if(m_i32ObjectType[eSmallCog] == eDynamicObject)
  512. {
  513. m_fSmallCogAngle -= i32DeltaTime * 0.004f;
  514. while(m_fSmallCogAngle > PVRT_TWO_PI)
  515. m_fSmallCogAngle -= PVRT_TWO_PI;
  516. }
  517. // If the action key has been pressed then switch between drawing and not drawing the shadow volumes
  518. if (PVRShellIsKeyPressed(PVRShellKeyNameACTION1))
  519. m_bDisplayVolumes = !m_bDisplayVolumes;
  520. // Clear the colour, stencil and depth buffers
  521. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  522. /*
  523. To create shadows we are going to do the following steps
  524. 1) Using the tools we are going to update any of the shadow volumes for the dynamic objects
  525. 2) Draw the scene as we would any other.
  526. 3) Enable the stencil test.
  527. 4) Draw Shadow Volumes to fill the stencil buffer with data.
  528. 5) Then we are going to draw a fullscreen quad which will only appear where the stencil buffer is not zero.
  529. 6) Disable the stencil test
  530. */
  531. /*
  532. Update the shadow volumes for any dynamic objects as they have moved so we requrie a different
  533. shadow volume. If the light position was also dynamic we would have to update volumes for all
  534. the static objects as well.
  535. */
  536. for(unsigned int i = 0; i < m_ui32NoOfShadows; ++i)
  537. {
  538. if(m_i32ObjectType[m_pui32MeshIndex[i]] == eDynamicObject)
  539. {
  540. BuildVolume(i, &m_vLightPosWorld);
  541. }
  542. }
  543. // Draw the scene lit.
  544. DrawScene();
  545. // Enable the stencil test
  546. glEnable(GL_STENCIL_TEST);
  547. // Do the stencil test
  548. DoStencilTest();
  549. // Draw a full screen quad
  550. DrawFullScreenQuad();
  551. // Disable the stencil test as it is no longer needed.
  552. glDisable(GL_STENCIL_TEST);
  553. // Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
  554. m_Print3D.DisplayDefaultTitle("ShadowVolumes", "", ePVRTPrint3DLogoIMG);
  555. m_Print3D.Flush();
  556. return true;
  557. }
  558. /*!****************************************************************************
  559. @Function DrawFullScreenQuad
  560. @Description Draws a fullscreen quad
  561. ******************************************************************************/
  562. void OGLES2ShadowVolumes::DrawFullScreenQuad()
  563. {
  564. glEnable(GL_BLEND);
  565. glBlendFunc(GL_DST_COLOR, GL_ZERO);
  566. // Use the shader program for the scene
  567. glUseProgram(m_FullscreenShader.uiId);
  568. const float afColor[] = { 0.4f, 0.4f, 0.4f, 1.0f };
  569. glUniform4fv(m_FullscreenShader.auiLoc[eColor], 1, afColor);
  570. // Enable vertex arributes
  571. glEnableVertexAttribArray(VERTEX_ARRAY);
  572. const float afVertexData[] = { -1, -1, 1, -1, -1, 1, 1, 1 };
  573. glVertexAttribPointer(VERTEX_ARRAY, 2, GL_FLOAT, GL_FALSE, 0, afVertexData);
  574. // Draw the quad
  575. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  576. // Disable vertex arributes
  577. glDisableVertexAttribArray(VERTEX_ARRAY);
  578. // Disable blending
  579. glDisable(GL_BLEND);
  580. }
  581. /*!****************************************************************************
  582. @Function DrawScene
  583. @Input bLight If true then the scene is drawn lit, otherwise it isn't
  584. @Description Draws the scene
  585. ******************************************************************************/
  586. void OGLES2ShadowVolumes::DrawScene()
  587. {
  588. SPODNode* pNode;
  589. PVRTMat4 mWorld;
  590. PVRTMat4 mModelView, mMVP;
  591. // Use the shader program for the scene
  592. glUseProgram(m_BaseShader.uiId);
  593. // Go through the meshes drawing each one
  594. for(unsigned int i = 0; i < m_Scene.nNumMeshNode; ++i)
  595. {
  596. pNode = &m_Scene.pNode[i];
  597. // Get the world matrix for this particular node.
  598. switch(i)
  599. {
  600. case eBigCog:
  601. mWorld = PVRTMat4::RotationZ(m_fBigCogAngle);
  602. break;
  603. case eSmallCog:
  604. mWorld = PVRTMat4::RotationZ(m_fSmallCogAngle);
  605. break;
  606. default:
  607. mWorld = m_Scene.GetWorldMatrix(*pNode);
  608. }
  609. // Pass the model-view-projection matrix (MVP) to the shader to transform the vertices
  610. mMVP = m_mProjection * m_mView * mWorld;
  611. glUniformMatrix4fv(m_BaseShader.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr());
  612. // Pass the light position in model space to the shader
  613. PVRTVec4 vLightPosModel;
  614. vLightPosModel = mWorld.inverse() * m_vLightPosWorld;
  615. glUniform3fv(m_BaseShader.auiLoc[eLightPosModel], 1, &vLightPosModel.x);
  616. // Loads the correct texture using our texture lookup table
  617. glBindTexture(GL_TEXTURE_2D, m_puiTextures[pNode->nIdxMaterial]);
  618. // Draw the mesh node
  619. DrawMesh(i);
  620. }
  621. }
  622. /*!****************************************************************************
  623. @Function DoStencilTest
  624. @Description Performs the Stencil test
  625. ******************************************************************************/
  626. void OGLES2ShadowVolumes::DoStencilTest()
  627. {
  628. /*
  629. For a detailed explanation on how to use the Stencil Buffer see the training course
  630. Stencil Buffer.
  631. */
  632. // Use the shader program that is used for the shadow volumes
  633. glUseProgram(m_ShadowVolShader.uiId);
  634. // Set the VolumeScale variable in the shader to say how much to extrude the volume by
  635. glUniform1f(m_ShadowVolShader.auiLoc[eVolumeScale], 1000.0f);
  636. const float afColor[] = { 0.4f, 1.0f, 0.0f, 0.2f };
  637. glUniform4fv(m_ShadowVolShader.auiLoc[eColor], 1, afColor);
  638. //If we want to display the shadow volumes don't disable the colour mask and enable blending
  639. if(m_bDisplayVolumes)
  640. {
  641. glEnable(GL_BLEND);
  642. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  643. }
  644. else // Disable the colour mask so we don't draw to the colour buffer
  645. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  646. // Disable writing to the depth buffer
  647. glDepthMask(GL_FALSE);
  648. // disable culling as we will want the front and back faces
  649. glDisable(GL_CULL_FACE);
  650. // Setup the stencil function
  651. glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
  652. /*
  653. Setup the stencil operations for front facing triangles and for the back facing triangles
  654. Note:
  655. We are using INCR_WRAP and DECR_WRAP since we are submitting the front and back faces
  656. together so we won't be rendering all the INCR faces first. This way it stops the
  657. stencil value getting clamped at 0 or the maximum possible value.
  658. */
  659. glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
  660. glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
  661. DrawShadowVolumes(&m_vLightPosWorld);
  662. // Enable Culling as we would like it back
  663. glEnable(GL_CULL_FACE);
  664. // Set the stencil function so we only draw where the stencil buffer isn't 0
  665. glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
  666. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  667. // Enable writing to the depth buffer
  668. glDepthMask(GL_TRUE);
  669. // If we're displaying the volumes disable blending else enable the colour buffer
  670. if(m_bDisplayVolumes)
  671. glDisable(GL_BLEND);
  672. else
  673. #if defined(__PALMPDK__)
  674. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // The alpha part is false as we don't want to blend with the video layer on the Palm Pre
  675. #else
  676. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  677. #endif
  678. }
  679. /*!****************************************************************************
  680. @Function DrawShadowVolumes
  681. @Input pLightPos
  682. @Description Draw the shadow volumes
  683. ******************************************************************************/
  684. void OGLES2ShadowVolumes::DrawShadowVolumes(PVRTVec4 *pLightPos)
  685. {
  686. PVRTMat4 mModelView, mMVP, mWorld;
  687. SPODNode *pNode;
  688. PVRTVec4 vModelLightPos;
  689. for(unsigned int i = 0; i < m_ui32NoOfShadows; ++i)
  690. {
  691. // Get the node
  692. pNode = &m_Scene.pNode[m_pui32MeshIndex[i]];
  693. // Get the world matrix for this particular node.
  694. switch (m_pui32MeshIndex[i])
  695. {
  696. case eBigCog:
  697. mWorld = PVRTMat4::RotationZ(m_fBigCogAngle);
  698. break;
  699. case eSmallCog:
  700. mWorld = PVRTMat4::RotationZ(m_fSmallCogAngle);
  701. break;
  702. default:
  703. mWorld = m_Scene.GetWorldMatrix(*pNode);
  704. }
  705. // Set the modeil view projection matrix
  706. mModelView = m_mView * mWorld;
  707. mMVP = m_mProjection * mModelView;
  708. glUniformMatrix4fv(m_ShadowVolShader.auiLoc[eMVPMatrix], 1, GL_FALSE, mMVP.ptr());
  709. // Convert the light position into model space
  710. vModelLightPos = mWorld.inverse() * (*pLightPos);
  711. glUniform3fv(m_ShadowVolShader.auiLoc[eLightPosModel], 1, &vModelLightPos.x);
  712. // Use the tools functions to draw the shadow volumes
  713. PVRTShadowVolSilhouetteProjectedRender(&m_pShadowMesh[i], &m_pShadowVol[i], 0);
  714. }
  715. }
  716. /*!****************************************************************************
  717. @Function DrawMesh
  718. @Input i32NodeIndex Node index of the mesh to draw
  719. @Description Draws a SPODMesh after the model view matrix has been set and
  720. the meterial prepared.
  721. ******************************************************************************/
  722. void OGLES2ShadowVolumes::DrawMesh(int i32NodeIndex)
  723. {
  724. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  725. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  726. // bind the VBO for the mesh
  727. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  728. // bind the index buffer, won't hurt if the handle is 0
  729. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  730. // Enable the vertex attribute arrays
  731. for (int i = 0; i < eNumAttribs; ++i) glEnableVertexAttribArray(i);
  732. // Set the vertex attribute offsets
  733. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  734. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  735. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  736. /*
  737. The geometry can be exported in 4 ways:
  738. - Indexed Triangle list
  739. - Non-Indexed Triangle list
  740. - Indexed Triangle strips
  741. - Non-Indexed Triangle strips
  742. */
  743. if(pMesh->nNumStrips == 0)
  744. {
  745. if(m_puiIndexVbo[i32MeshIndex])
  746. {
  747. // Indexed Triangle list
  748. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  749. }
  750. else
  751. {
  752. // Non-Indexed Triangle list
  753. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  754. }
  755. }
  756. else
  757. {
  758. for (int i = 0; i < (int)pMesh->nNumStrips; ++i)
  759. {
  760. int offset = 0;
  761. if(m_puiIndexVbo[i32MeshIndex])
  762. {
  763. // Indexed Triangle strips
  764. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
  765. }
  766. else
  767. {
  768. // Non-Indexed Triangle strips
  769. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  770. }
  771. offset += pMesh->pnStripLength[i]+2;
  772. }
  773. }
  774. // Safely disable the vertex attribute arrays
  775. for (int i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
  776. glBindBuffer(GL_ARRAY_BUFFER, 0);
  777. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  778. }
  779. /*!****************************************************************************
  780. @Function BuildShadowVolume
  781. @Output pShadowMesh The shadow mesh to be returned
  782. @Output pVolume The shadow volume to return
  783. @Input pMesh The mesh to build the shadow volume from
  784. @Description Build the shadow mesh and shadow volumes from a SPODMesh
  785. ******************************************************************************/
  786. bool OGLES2ShadowVolumes::BuildShadowVolume(PVRTShadowVolShadowMesh *pShadowMesh, PVRTShadowVolShadowVol *pVolume, SPODMesh* pMesh)
  787. {
  788. if(!pMesh || !pShadowMesh)
  789. return false;
  790. PVRTVec3 *pVertices;
  791. // If the data is interleaved then we need to copy the vertex positions into a temporary array for ShadowMesh creation
  792. if(pMesh->pInterleaved)
  793. {
  794. pVertices = new PVRTVec3[pMesh->nNumVertex];
  795. if(pVertices)
  796. {
  797. unsigned char* pData = pMesh->pInterleaved + (size_t) pMesh->sVertex.pData;
  798. for(unsigned int i = 0; i < pMesh->nNumVertex; ++i)
  799. {
  800. pVertices[i] = *((PVRTVec3*) pData);
  801. pData += pMesh->sVertex.nStride;
  802. }
  803. }
  804. else
  805. {
  806. return false;
  807. }
  808. }
  809. else
  810. {
  811. // The data isn't interleaved so just use the vertex data as is.
  812. pVertices = (PVRTVec3 *) pMesh->sVertex.pData;
  813. }
  814. // Create a mesh format suitable for generating shadow volumes.
  815. PVRTShadowVolMeshCreateMesh(pShadowMesh, (float*) pVertices, pMesh->nNumVertex, (unsigned short*) pMesh->sFaces.pData, pMesh->nNumFaces);
  816. // If the data was interleaved then we created a tmp array which we can now delete.
  817. if(pMesh->pInterleaved)
  818. {
  819. delete[] pVertices;
  820. }
  821. // Init the mesh
  822. PVRTShadowVolMeshInitMesh(pShadowMesh, 0);
  823. if(pVolume)
  824. {
  825. // Create the shadow volume
  826. PVRTShadowVolMeshInitVol(pVolume, pShadowMesh, 0);
  827. }
  828. return true;
  829. }
  830. /*!****************************************************************************
  831. @Function NewDemo
  832. @Return PVRShell* The demo supplied by the user
  833. @Description This function must be implemented by the user of the shell.
  834. The user should return its PVRShell object defining the
  835. behaviour of the application.
  836. ******************************************************************************/
  837. PVRShell* NewDemo()
  838. {
  839. return new OGLES2ShadowVolumes();
  840. }
  841. /******************************************************************************
  842. End of file (OGLES2ShadowVolumes.cpp)
  843. ******************************************************************************/