• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2 
3  @File         OGLES2DisplacementMap.cpp
4 
5  @Title        Displacement Map
6 
7  @Version
8 
9  @Copyright    Copyright (c) Imagination Technologies Limited.
10 
11  @Platform     Independent
12 
13  @Description  Shows how to displace geometry in the vertex shader using a
14                texture.
15 
16 ******************************************************************************/
17 #include <string.h>
18 
19 #include "PVRShell.h"
20 #include "OGLES2Tools.h"
21 
22 /******************************************************************************
23  Defines
24 ******************************************************************************/
25 // Index to bind the attributes to vertex shaders
26 #define VERTEX_ARRAY	0
27 #define NORMAL_ARRAY	1
28 #define TEXCOORD_ARRAY	2
29 
30 /******************************************************************************
31  Consts
32 ******************************************************************************/
33 // Camera constants. Used for making the projection matrix
34 const float g_fCameraNear = 4.0f;
35 const float g_fCameraFar  = 2000.0f;
36 
37 const float g_fDemoFrameRate = 1.0f / 90.0f;
38 
39 // The camera to use from the pod file
40 const int g_ui32Camera = 0;
41 
42 /******************************************************************************
43  Content file names
44 ******************************************************************************/
45 
46 // Source and binary shaders
47 const char c_szFragShaderSrcFile[]	= "FragShader.fsh";
48 const char c_szFragShaderBinFile[]	= "FragShader.fsc";
49 const char c_szVertShaderSrcFile[]	= "VertShader.vsh";
50 const char c_szVertShaderBinFile[]	= "VertShader.vsc";
51 
52 // POD scene files
53 const char c_szSceneFile[]			= "DisMapScene.pod";
54 const char c_szDisMapFile[]			= "DisMap.pvr";
55 
56 /*!****************************************************************************
57  Class implementing the PVRShell functions.
58 ******************************************************************************/
59 class OGLES2DisplacementMap : public PVRShell
60 {
61 	// Print3D class used to display text
62 	CPVRTPrint3D	m_Print3D;
63 
64 	// 3D Model
65 	CPVRTModelPOD	m_Scene;
66 
67 	// OpenGL handles for shaders, textures and VBOs
68 	GLuint m_uiVertShader;
69 	GLuint m_uiFragShader;
70 	GLuint* m_puiVbo;
71 	GLuint* m_puiIndexVbo;
72 	GLuint* m_puiTextureIDs;
73 	GLuint  m_uiDisMapID;
74 
75 	// Group shader programs and their uniform locations together
76 	struct
77 	{
78 		GLuint uiId;
79 		GLuint uiMVPMatrixLoc;
80 		GLuint uiLightDirLoc;
81 		GLuint uiTexture;
82 		GLuint uiDisMap;
83 		GLuint uiDisplacementFactor;
84 	}
85 	m_ShaderProgram;
86 
87 	// Variables to handle the animation in a time-based manner
88 	unsigned long		m_ulTimePrev;
89 
90 	// App variables
91 	PVRTVec4		m_LightDir;
92 	PVRTMat4		m_View, m_Projection;
93 	float			m_DisplacementFactor;
94 	bool			m_bGrow;
95 
96 public:
97 	virtual bool InitApplication();
98 	virtual bool InitView();
99 	virtual bool ReleaseView();
100 	virtual bool QuitApplication();
101 	virtual bool RenderScene();
102 
103 	OGLES2DisplacementMap();
104 	bool LoadTextures(CPVRTString* pErrorStr);
105 	bool LoadShaders(CPVRTString* pErrorStr);
106 	bool LoadVbos(CPVRTString* pErrorStr);
107 
108 	void DrawMesh(int i32NodeIndex);
109 };
110 
111 /*!****************************************************************************
112  @Function		OGLES2DisplacementMap
113  @Description	Constructor
114 ******************************************************************************/
OGLES2DisplacementMap()115 OGLES2DisplacementMap::OGLES2DisplacementMap() :    m_puiVbo(0),
116 													m_puiIndexVbo(0),
117 													m_puiTextureIDs(0),
118 													m_ulTimePrev(0),
119 													m_DisplacementFactor(0),
120 													m_bGrow(false)
121 {
122 }
123 
124 /*!****************************************************************************
125  @Function		LoadTextures
126  @Return		bool			true if no error occurred
127  @Description	Loads the textures required for this training course
128 ******************************************************************************/
LoadTextures(CPVRTString * pErrorStr)129 bool OGLES2DisplacementMap::LoadTextures(CPVRTString* pErrorStr)
130 {
131 	/*
132 		Load the textures.
133 		For a more detailed explanation, see Texturing and IntroducingPVRTools
134 	*/
135 
136 	/*
137 		Initialises an array to lookup the textures
138 		for each material in the scene.
139 	*/
140 	m_puiTextureIDs = new GLuint[m_Scene.nNumMaterial];
141 
142 	if(!m_puiTextureIDs)
143 	{
144 		*pErrorStr = "ERROR: Insufficient memory.";
145 		return false;
146 	}
147 
148 	for(int i = 0; i < (int) m_Scene.nNumMaterial; ++i)
149 	{
150 		m_puiTextureIDs[i] = 0;
151 		SPODMaterial* pMaterial = &m_Scene.pMaterial[i];
152 
153 		if(pMaterial->nIdxTexDiffuse != -1)
154 		{
155 			/*
156 				Using the tools function PVRTTextureLoadFromPVR load the textures required by the pod file.
157 
158 				Note: This function only loads .pvr files. You can set the textures in 3D Studio Max to .pvr
159 				files using the PVRTexTool plug-in for max. Alternatively, the pod material properties can be
160 				modified in PVRShaman.
161 			*/
162 
163 			CPVRTString sTextureName = m_Scene.pTexture[pMaterial->nIdxTexDiffuse].pszName;
164 
165 			if(PVRTTextureLoadFromPVR(sTextureName.c_str(), &m_puiTextureIDs[i]) != PVR_SUCCESS)
166 			{
167 				*pErrorStr = "ERROR: Failed to load " + sTextureName + ".";
168 
169 				// Check to see if we're trying to load .pvr or not
170 				CPVRTString sFileExtension = PVRTStringGetFileExtension(sTextureName);
171 
172 				if(sFileExtension.toLower() == "pvr")
173 					*pErrorStr += "Note: Can only load pvr files.";
174 
175 				return false;
176 			}
177 		}
178 	}
179 
180 	// Load the texture used for the displacement map
181 	if(PVRTTextureLoadFromPVR(c_szDisMapFile, &m_uiDisMapID) != PVR_SUCCESS)
182 	{
183 		*pErrorStr = "ERROR: Failed to load " + CPVRTString(c_szDisMapFile) + ".";
184 		return false;
185 	}
186 
187 	// Define the wrapping to use for the displacement map
188 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
189 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
190 
191 	return true;
192 }
193 
194 /*!****************************************************************************
195  @Function		LoadShaders
196  @Output		pErrorStr		A string describing the error on failure
197  @Return		bool			true if no error occurred
198  @Description	Loads and compiles the shaders and links the shader programs
199 				required for this training course
200 ******************************************************************************/
LoadShaders(CPVRTString * pErrorStr)201 bool OGLES2DisplacementMap::LoadShaders(CPVRTString* pErrorStr)
202 {
203 	/*
204 		Load and compile the shaders from files.
205 		Binary shaders are tried first, source shaders
206 		are used as fallback.
207 	*/
208 	if(PVRTShaderLoadFromFile(
209 			c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
210 	{
211 		return false;
212 	}
213 
214 	if (PVRTShaderLoadFromFile(
215 			c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
216 	{
217 		return false;
218 	}
219 
220 	/*
221 		Set up and link the shader program
222 	*/
223 	const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" };
224 
225 	if(PVRTCreateProgram(
226 			&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS)
227 	{
228 		PVRShellSet(prefExitMessage, pErrorStr->c_str());
229 		return false;
230 	}
231 
232 	// Store the location of uniforms for later use
233 	m_ShaderProgram.uiMVPMatrixLoc	= glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix");
234 	m_ShaderProgram.uiLightDirLoc	= glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection");
235 	m_ShaderProgram.uiDisplacementFactor = glGetUniformLocation(m_ShaderProgram.uiId, "DisplacementFactor");
236 
237 	m_ShaderProgram.uiTexture = glGetUniformLocation(m_ShaderProgram.uiId, "sTexture");
238 	m_ShaderProgram.uiDisMap  = glGetUniformLocation(m_ShaderProgram.uiId, "sDisMap");
239 
240 	return true;
241 }
242 
243 /*!****************************************************************************
244  @Function		LoadVbos
245  @Description	Loads the mesh data required for this training course into
246 				vertex buffer objects
247 ******************************************************************************/
LoadVbos(CPVRTString * pErrorStr)248 bool OGLES2DisplacementMap::LoadVbos(CPVRTString* pErrorStr)
249 {
250 	if(!m_Scene.pMesh[0].pInterleaved)
251 	{
252 		*pErrorStr = "ERROR: IntroducingPOD requires the pod data to be interleaved. Please re-export with the interleaved option enabled.";
253 		return false;
254 	}
255 
256 	if (!m_puiVbo)      m_puiVbo = new GLuint[m_Scene.nNumMesh];
257 	if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
258 
259 	/*
260 		Load vertex data of all meshes in the scene into VBOs
261 
262 		The meshes have been exported with the "Interleave Vectors" option,
263 		so all data is interleaved in the buffer at pMesh->pInterleaved.
264 		Interleaving data improves the memory access pattern and cache efficiency,
265 		thus it can be read faster by the hardware.
266 	*/
267 	glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
268 	for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
269 	{
270 		// Load vertex data into buffer object
271 		SPODMesh& Mesh = m_Scene.pMesh[i];
272 		unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
273 		glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
274 		glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
275 
276 		// Load index data into buffer object if available
277 		m_puiIndexVbo[i] = 0;
278 		if (Mesh.sFaces.pData)
279 		{
280 			glGenBuffers(1, &m_puiIndexVbo[i]);
281 			uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
282 			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
283 			glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
284 		}
285 	}
286 	glBindBuffer(GL_ARRAY_BUFFER, 0);
287 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
288 
289 	return true;
290 }
291 
292 /*!****************************************************************************
293  @Function		InitApplication
294  @Return		bool		true if no error occurred
295  @Description	Code in InitApplication() will be called by PVRShell once per
296 				run, before the rendering context is created.
297 				Used to initialize variables that are not dependent on it
298 				(e.g. external modules, loading meshes, etc.)
299 				If the rendering context is lost, InitApplication() will
300 				not be called again.
301 ******************************************************************************/
InitApplication()302 bool OGLES2DisplacementMap::InitApplication()
303 {
304 	// Get and set the read path for content files
305 	CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
306 
307 	// Get and set the load/release functions for loading external files.
308 	// In the majority of cases the PVRShell will return NULL function pointers implying that
309 	// nothing special is required to load external files.
310 	CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc));
311 
312 	// Load the scene
313 	if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
314 	{
315 		PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
316 		return false;
317 	}
318 
319 	// The cameras are stored in the file. We check it contains at least one.
320 	if(m_Scene.nNumCamera == 0)
321 	{
322 		PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera. Please add one and re-export.\n");
323 		return false;
324 	}
325 
326 	// We also check that the scene contains at least one light
327 	if(m_Scene.nNumLight == 0)
328 	{
329 		PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light. Please add one and re-export.\n");
330 		return false;
331 	}
332 
333 	return true;
334 }
335 
336 /*!****************************************************************************
337  @Function		QuitApplication
338  @Return		bool		true if no error occurred
339  @Description	Code in QuitApplication() will be called by PVRShell once per
340 				run, just before exiting the program.
341 				If the rendering context is lost, QuitApplication() will
342 				not be called.
343 ******************************************************************************/
QuitApplication()344 bool OGLES2DisplacementMap::QuitApplication()
345 {
346 	// Free the memory allocated for the scene
347 	m_Scene.Destroy();
348 
349 	delete[] m_puiVbo;
350 	delete[] m_puiIndexVbo;
351 
352     return true;
353 }
354 
355 /*!****************************************************************************
356  @Function		InitView
357  @Return		bool		true if no error occurred
358  @Description	Code in InitView() will be called by PVRShell upon
359 				initialization or after a change in the rendering context.
360 				Used to initialize variables that are dependent on the rendering
361 				context (e.g. textures, vertex buffers, etc.)
362 ******************************************************************************/
InitView()363 bool OGLES2DisplacementMap::InitView()
364 {
365 	CPVRTString ErrorStr;
366 
367 	/*
368 		Initialize VBO data
369 	*/
370 	if(!LoadVbos(&ErrorStr))
371 	{
372 		PVRShellSet(prefExitMessage, ErrorStr.c_str());
373 		return false;
374 	}
375 
376 	/*
377 		Load textures
378 	*/
379 	if(!LoadTextures(&ErrorStr))
380 	{
381 		PVRShellSet(prefExitMessage, ErrorStr.c_str());
382 		return false;
383 	}
384 
385 	/*
386 		Load and compile the shaders & link programs
387 	*/
388 	if(!LoadShaders(&ErrorStr))
389 	{
390 		PVRShellSet(prefExitMessage, ErrorStr.c_str());
391 		return false;
392 	}
393 
394 	/*
395 		Initialize Print3D
396 	*/
397 	bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
398 
399 	if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
400 	{
401 		PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
402 		return false;
403 	}
404 
405 	/*
406 		Set OpenGL ES render states needed for this training course
407 	*/
408 	// Enable backface culling and depth test
409 	glCullFace(GL_BACK);
410 	glEnable(GL_CULL_FACE);
411 
412 	glEnable(GL_DEPTH_TEST);
413 
414 	// Use a nice bright blue as clear colour
415 	glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
416 
417 	//Get the direction of the first light from the scene.
418 	m_LightDir = m_Scene.GetLightDirection(0);
419 
420 	// For direction vectors, w should be 0
421 	m_LightDir.w = 0.0f;
422 
423 
424 	//	Set up the view and projection matrices from the camera
425 	PVRTVec3	vFrom, vTo(0.0f), vUp(0.0f, 1.0f, 0.0f);
426 	float fFOV;
427 
428 	// Setup the camera
429 
430 	// Camera nodes are after the mesh and light nodes in the array
431 	int i32CamID = m_Scene.pNode[m_Scene.nNumMeshNode + m_Scene.nNumLight + g_ui32Camera].nIdx;
432 
433 	// Get the camera position, target and field of view (fov)
434 	if(m_Scene.pCamera[i32CamID].nIdxTarget != -1) // Does the camera have a target?
435 		fFOV = m_Scene.GetCameraPos( vFrom, vTo, g_ui32Camera); // vTo is taken from the target node
436 	else
437 		fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, g_ui32Camera); // vTo is calculated from the rotation
438 
439 	// We can build the model view matrix from the camera position, target and an up vector.
440 	// For this we usePVRTMat4LookAtRH()
441 	m_View = PVRTMat4::LookAtRH(vFrom, vTo, vUp);
442 
443 	// Calculate the projection matrix
444 	m_Projection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
445 
446 	// Initialize variables used for the animation
447 	m_ulTimePrev = PVRShellGetTime();
448 
449 	return true;
450 }
451 
452 /*!****************************************************************************
453  @Function		ReleaseView
454  @Return		bool		true if no error occurred
455  @Description	Code in ReleaseView() will be called by PVRShell when the
456 				application quits or before a change in the rendering context.
457 ******************************************************************************/
ReleaseView()458 bool OGLES2DisplacementMap::ReleaseView()
459 {
460 	// Deletes the textures
461 	glDeleteTextures(m_Scene.nNumMaterial, &m_puiTextureIDs[0]);
462 	glDeleteTextures(1, &m_uiDisMapID);
463 
464 	// Frees the texture lookup array
465 	delete[] m_puiTextureIDs;
466 	m_puiTextureIDs = 0;
467 
468 	// Delete program and shader objects
469 	glDeleteProgram(m_ShaderProgram.uiId);
470 
471 	glDeleteShader(m_uiVertShader);
472 	glDeleteShader(m_uiFragShader);
473 
474 	// Delete buffer objects
475 	glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
476 	glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
477 
478 	// Release Print3D Textures
479 	m_Print3D.ReleaseTextures();
480 
481 	return true;
482 }
483 
484 /*!****************************************************************************
485  @Function		RenderScene
486  @Return		bool		true if no error occurred
487  @Description	Main rendering loop function of the program. The shell will
488 				call this function every frame.
489 				eglSwapBuffers() will be performed by PVRShell automatically.
490 				PVRShell will also manage important OS events.
491 				Will also manage relevant OS events. The user has access to
492 				these events through an abstraction layer provided by PVRShell.
493 ******************************************************************************/
RenderScene()494 bool OGLES2DisplacementMap::RenderScene()
495 {
496 	// Clear the color and depth buffer
497 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
498 
499 
500 	//	Calculates the the time since the last frame
501 	unsigned long ulTime = PVRShellGetTime();
502 	unsigned long ulDeltaTime = ulTime - m_ulTimePrev;
503 	m_ulTimePrev = ulTime;
504 
505 	// Use shader program
506 	glUseProgram(m_ShaderProgram.uiId);
507 
508 	// Enable 2D texturing for the first texture.
509 	glActiveTexture(GL_TEXTURE0);
510 
511 	// Set the sampler2D variable to the first texture unit
512 	glUniform1i(m_ShaderProgram.uiTexture, 0);
513 
514 	// Enable 2D texturing for the second texture.
515 	glActiveTexture(GL_TEXTURE1);
516 
517 	// Set the displacement map variable to the second texture unit
518 	glUniform1i(m_ShaderProgram.uiDisMap, 1);
519 
520 	// Calculate and set the displacement factor
521 	if(m_bGrow)
522 	{
523 		m_DisplacementFactor += (float)ulDeltaTime * g_fDemoFrameRate;
524 
525 		if(m_DisplacementFactor > 25.0f)
526 		{
527 			m_bGrow = false;
528 			m_DisplacementFactor = 25.0f;
529 		}
530 	}
531 	else
532 	{
533 		m_DisplacementFactor -= (float)ulDeltaTime * g_fDemoFrameRate;
534 
535 		if(m_DisplacementFactor < 0.0f)
536 		{
537 			m_bGrow = true;
538 			m_DisplacementFactor = 0.0f;
539 		}
540 	}
541 
542 	glUniform1f(m_ShaderProgram.uiDisplacementFactor, m_DisplacementFactor);
543 
544 	// Bind the displacement map texture
545 	glBindTexture(GL_TEXTURE_2D, m_uiDisMapID);
546 
547 	// Now the displacement map texture is bound set the active texture to texture 0
548 	glActiveTexture(GL_TEXTURE0);
549 
550 	// Draw the scene
551 
552 	// Enable the vertex attribute arrays
553 	glEnableVertexAttribArray(VERTEX_ARRAY);
554 	glEnableVertexAttribArray(NORMAL_ARRAY);
555 	glEnableVertexAttribArray(TEXCOORD_ARRAY);
556 
557 	for(unsigned int i = 0; i < m_Scene.nNumMeshNode; ++i)
558 	{
559 		SPODNode& Node = m_Scene.pNode[i];
560 
561 		// Get the node model matrix
562 		PVRTMat4 mWorld;
563 		mWorld = m_Scene.GetWorldMatrix(Node);
564 
565 		// Pass the model-view-projection matrix (MVP) to the shader to transform the vertices
566 		PVRTMat4 mModelView, mMVP;
567 		mModelView = m_View * mWorld;
568 		mMVP = m_Projection * mModelView;
569 		glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.f);
570 
571 		// Pass the light direction in model space to the shader
572 		PVRTVec4 vLightDir;
573 		vLightDir = mWorld.inverse() * m_LightDir;
574 
575 		PVRTVec3 vLightDirModel = *(PVRTVec3*) vLightDir.ptr();
576 		vLightDirModel.normalize();
577 
578 		glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x);
579 
580 		// Load the correct texture for the mesh using our texture lookup table
581 		GLuint uiTex = 0;
582 
583 		if(Node.nIdxMaterial != -1)
584 			uiTex = m_puiTextureIDs[Node.nIdxMaterial];
585 
586 		glBindTexture(GL_TEXTURE_2D, uiTex);
587 
588 		/*
589 			Now that the model-view matrix is set and the materials ready,
590 			call another function to actually draw the mesh.
591 		*/
592 		DrawMesh(i);
593 	}
594 
595 	// Safely disable the vertex attribute arrays
596 	glDisableVertexAttribArray(VERTEX_ARRAY);
597 	glDisableVertexAttribArray(NORMAL_ARRAY);
598 	glDisableVertexAttribArray(TEXCOORD_ARRAY);
599 
600 	glBindBuffer(GL_ARRAY_BUFFER, 0);
601 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
602 
603 	// Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
604 	m_Print3D.DisplayDefaultTitle("DisplacementMapping", "", ePVRTPrint3DSDKLogo);
605 	m_Print3D.Flush();
606 
607 	return true;
608 }
609 
610 /*!****************************************************************************
611  @Function		DrawMesh
612  @Input			i32NodeIndex		Node index of the mesh to draw
613  @Description	Draws a SPODMesh after the model view matrix has been set and
614 				the material prepared.
615 ******************************************************************************/
DrawMesh(int i32NodeIndex)616 void OGLES2DisplacementMap::DrawMesh(int i32NodeIndex)
617 {
618 	int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
619 	SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
620 
621 	// bind the VBO for the mesh
622 	glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
623 	// bind the index buffer, won't hurt if the handle is 0
624 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
625 
626 	// Set the vertex attribute offsets
627 	glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
628 	glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
629 	glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
630 
631 	/*
632 		The geometry can be exported in 4 ways:
633 		- Indexed Triangle list
634 		- Non-Indexed Triangle list
635 		- Indexed Triangle strips
636 		- Non-Indexed Triangle strips
637 	*/
638 	if(pMesh->nNumStrips == 0)
639 	{
640 		if(m_puiIndexVbo[i32MeshIndex])
641 		{
642 			// Indexed Triangle list
643 			glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
644 		}
645 		else
646 		{
647 			// Non-Indexed Triangle list
648 			glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
649 		}
650 	}
651 	else
652 	{
653 		int offset = 0;
654 
655 		for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
656 		{
657 			if(m_puiIndexVbo[i32MeshIndex])
658 			{
659 				// Indexed Triangle strips
660 				glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
661 			}
662 			else
663 			{
664 				// Non-Indexed Triangle strips
665 				glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
666 			}
667 			offset += pMesh->pnStripLength[i]+2;
668 		}
669 	}
670 }
671 
672 /*!****************************************************************************
673  @Function		NewDemo
674  @Return		PVRShell*		The demo supplied by the user
675  @Description	This function must be implemented by the user of the shell.
676 				The user should return its PVRShell object defining the
677 				behaviour of the application.
678 ******************************************************************************/
NewDemo()679 PVRShell* NewDemo()
680 {
681 	return new OGLES2DisplacementMap();
682 }
683 
684 /******************************************************************************
685  End of file (OGLES2DisplacementMap.cpp)
686 ******************************************************************************/
687 
688