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