123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851 |
- /******************************************************************************
- @File OGLES2ChameleonMan.cpp
- @Title OGLES2ChameleonMan
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform Independent
- @Description Shows how to perform skinning combined with Dot3 lighting
- ******************************************************************************/
- #include "PVRShell.h"
- #include "OGLES2Tools.h"
- /******************************************************************************
- Constants
- ******************************************************************************/
- // Camera constants used to generate the projection matrix
- const float g_fCameraNear = 4.0f;
- const float g_fCameraFar = 30000.0f;
- const float g_fDemoFrameRate = 0.02f;
- /******************************************************************************
- shader attributes
- ******************************************************************************/
- // Skinned
- // vertex attributes
- enum EVertexAttrib {
- VERTEX_ARRAY, NORMAL_ARRAY, TANGENT_ARRAY, BINORMAL_ARRAY, TEXCOORD_ARRAY, BONEWEIGHT_ARRAY, BONEINDEX_ARRAY, eNumAttribs };
- const char* g_aszAttribNames[] = {
- "inVertex", "inNormal", "inTangent", "inBiNormal", "inTexCoord", "inBoneWeight", "inBoneIndex" };
- // shader uniforms
- enum ESkinnnedUniform {
- eViewProj, eLightPos, eBoneCount, eBoneMatrices, eBoneMatricesIT, ebUseDot3, eNumSkinnedUniforms };
- const char* g_aszSkinnedUniformNames[] = {
- "ViewProjMatrix", "LightPos", "BoneCount", "BoneMatrixArray[0]", "BoneMatrixArrayIT[0]", "bUseDot3" };
- // Default
- // vertex attributes
- enum EDefaultVertexAttrib {
- DEFAULT_VERTEX_ARRAY, DEFAULT_TEXCOORD_ARRAY, eNumDefaultAttribs };
- const char* g_aszDefaultAttribNames[] = {
- "inVertex", "inTexCoord"};
- // shader uniforms
- enum EDefaultUniform {
- eDefaultMVPMatrix, eDefaultUOffset, eNumDefaultUniforms };
- const char* g_aszDefaultUniformNames[] = {
- "MVPMatrix", "fUOffset" };
- /******************************************************************************
- Content file names
- ******************************************************************************/
- // Source and binary shaders
- const char c_szSkinnedFragShaderSrcFile[] = "SkinnedFragShader.fsh";
- const char c_szSkinnedFragShaderBinFile[] = "SkinnedFragShader.fsc";
- const char c_szSkinnedVertShaderSrcFile[] = "SkinnedVertShader.vsh";
- const char c_szSkinnedVertShaderBinFile[] = "SkinnedVertShader.vsc";
- const char c_szDefaultFragShaderSrcFile[] = "DefaultFragShader.fsh";
- const char c_szDefaultFragShaderBinFile[] = "DefaultFragShader.fsc";
- const char c_szDefaultVertShaderSrcFile[] = "DefaultVertShader.vsh";
- const char c_szDefaultVertShaderBinFile[] = "DefaultVertShader.vsc";
- // Base Textures
- const char c_szFinalChameleonManHeadBodyTexFile[] = "FinalChameleonManHeadBody.pvr";
- const char c_szFinalChameleonManLegsTexFile[] = "FinalChameleonManLegs.pvr";
- const char c_szLampTexFile[] = "lamp.pvr";
- const char c_szChameleonBeltTexFile[] = "ChameleonBelt.pvr";
- const char c_szSkylineTexFile[] = "skyline.pvr";
- const char c_szWallDiffuseBakedTexFile[] = "Wall_diffuse_baked.pvr";
- // Tangent Space BumpMap Textures
- const char c_szTang_space_BodyMapTexFile[] = "Tang_space_BodyMap.pvr";
- const char c_szTang_space_LegsMapTexFile[] = "Tang_space_LegsMap.pvr";
- const char c_szTang_space_BeltMapTexFile[] = "Tang_space_BeltMap.pvr";
- // POD scene files
- const char c_szSceneFile[] = "ChameleonScene.pod";
- /****************************************************************************
- ** Enums **
- ****************************************************************************/
- enum EMeshes
- {
- eBody,
- eLegs,
- eBelt,
- eWall,
- eBackground,
- eLights
- };
- /****************************************************************************
- ** Structures
- ****************************************************************************/
- /*!****************************************************************************
- Class implementing the PVRShell functions.
- ******************************************************************************/
- class OGLES2ChameleonMan : public PVRShell
- {
- // Print3D class used to display text
- CPVRTPrint3D m_Print3D;
- // 3D Model
- CPVRTModelPOD m_Scene;
- // Model transformation variables
- float m_fWallPos;
- float m_fBackgroundPos;
- float m_fLightPos;
- // OpenGL handles for shaders and VBOs
- GLuint m_uiSkinnedVertShader;
- GLuint m_uiDefaultVertShader;
- GLuint m_uiSkinnedFragShader;
- GLuint m_uiDefaultFragShader;
- GLuint* m_puiVbo;
- GLuint* m_puiIndexVbo;
- // Texture IDs
- GLuint m_ui32TexHeadBody;
- GLuint m_ui32TexLegs;
- GLuint m_ui32TexBeltNormalMap;
- GLuint m_ui32TexHeadNormalMap;
- GLuint m_ui32TexLegsNormalMap;
- GLuint m_ui32TexSkyLine;
- GLuint m_ui32TexWall;
- GLuint m_ui32TexLamp;
- GLuint m_ui32TexBelt;
- // Group shader programs and their uniform locations together
- struct
- {
- GLuint uiId;
- GLuint auiLoc[eNumSkinnedUniforms];
- }
- m_SkinnedShaderProgram;
- struct
- {
- GLuint uiId;
- GLuint auiLoc[eNumDefaultUniforms];
- }
- m_DefaultShaderProgram;
- bool m_bEnableDOT3;
- // Variables to handle the animation in a time-based manner
- unsigned long m_iTimePrev;
- float m_fFrame;
- public:
- OGLES2ChameleonMan() : m_fWallPos(0),
- m_fBackgroundPos(0),
- m_fLightPos(0),
- m_puiVbo(0),
- m_puiIndexVbo(0),
- m_bEnableDOT3(true),
- m_fFrame(0)
- {
- }
- virtual bool InitApplication();
- virtual bool InitView();
- virtual bool ReleaseView();
- virtual bool QuitApplication();
- virtual bool RenderScene();
- bool LoadTextures(CPVRTString* pErrorStr);
- bool LoadShaders(CPVRTString* pErrorStr);
- void LoadVbos();
- void DrawSkinnedMesh(int i32NodeIndex);
- };
- /*!****************************************************************************
- @Function LoadTextures
- @Output pErrorStr A string describing the error on failure
- @Return bool true if no error occured
- @Description Loads the textures required for this training course
- ******************************************************************************/
- bool OGLES2ChameleonMan::LoadTextures(CPVRTString* const pErrorStr)
- {
- // Load Textures
- if(PVRTTextureLoadFromPVR(c_szFinalChameleonManHeadBodyTexFile, &m_ui32TexHeadBody) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for Upper Body.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szFinalChameleonManLegsTexFile, &m_ui32TexLegs) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for Legs.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szTang_space_BodyMapTexFile, &m_ui32TexHeadNormalMap) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Upper Body.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szTang_space_LegsMapTexFile, &m_ui32TexLegsNormalMap) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Legs.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szTang_space_BeltMapTexFile, &m_ui32TexBeltNormalMap) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load normalmap texture for Belt.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szSkylineTexFile, &m_ui32TexSkyLine) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for SkyLine.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szWallDiffuseBakedTexFile, &m_ui32TexWall) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for Wall.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szLampTexFile, &m_ui32TexLamp) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for Lamps.\n");
- return false;
- }
- if(PVRTTextureLoadFromPVR(c_szChameleonBeltTexFile, &m_ui32TexBelt) != PVR_SUCCESS)
- {
- *pErrorStr = CPVRTString("ERROR: Failed to load texture for Belt.\n");
- return false;
- }
- return true;
- }
- /*!****************************************************************************
- @Function LoadShaders
- @Output pErrorStr A string describing the error on failure
- @Return bool true if no error occured
- @Description Loads and compiles the shaders and links the shader programs
- required for this training course
- ******************************************************************************/
- bool OGLES2ChameleonMan::LoadShaders(CPVRTString* pErrorStr)
- {
- int i;
- /*
- Load and compile the shaders from files.
- Binary shaders are tried first, source shaders
- are used as fallback.
- */
- // Create the skinned program
- if(PVRTShaderLoadFromFile(
- c_szSkinnedVertShaderBinFile, c_szSkinnedVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSkinnedVertShader, pErrorStr) != PVR_SUCCESS)
- {
- return false;
- }
- if(PVRTShaderLoadFromFile(
- c_szSkinnedFragShaderBinFile, c_szSkinnedFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSkinnedFragShader, pErrorStr) != PVR_SUCCESS)
- {
- return false;
- }
- if(PVRTCreateProgram(&m_SkinnedShaderProgram.uiId, m_uiSkinnedVertShader, m_uiSkinnedFragShader, g_aszAttribNames, eNumAttribs, pErrorStr) != PVR_SUCCESS)
- {
- PVRShellSet(prefExitMessage, pErrorStr->c_str());
- return false;
- }
- // Store the location of uniforms for later use
- for(i = 0; i < eNumSkinnedUniforms; ++i)
- {
- m_SkinnedShaderProgram.auiLoc[i] = glGetUniformLocation(m_SkinnedShaderProgram.uiId, g_aszSkinnedUniformNames[i]);
- }
- glUniform1i(m_SkinnedShaderProgram.auiLoc[ebUseDot3], m_bEnableDOT3);
- // Set the sampler2D uniforms to corresponding texture units
- glUniform1i(glGetUniformLocation(m_SkinnedShaderProgram.uiId, "sTexture"), 0);
- glUniform1i(glGetUniformLocation(m_SkinnedShaderProgram.uiId, "sNormalMap"), 1);
- // Create the non-skinned program
- if(PVRTShaderLoadFromFile(
- c_szDefaultVertShaderBinFile, c_szDefaultVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiDefaultVertShader, pErrorStr) != PVR_SUCCESS)
- {
- return false;
- }
- if(PVRTShaderLoadFromFile(
- c_szDefaultFragShaderBinFile, c_szDefaultFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiDefaultFragShader, pErrorStr) != PVR_SUCCESS)
- {
- return false;
- }
- if(PVRTCreateProgram(&m_DefaultShaderProgram.uiId, m_uiDefaultVertShader, m_uiDefaultFragShader, g_aszDefaultAttribNames, eNumDefaultAttribs, pErrorStr) != PVR_SUCCESS)
- {
- PVRShellSet(prefExitMessage, pErrorStr->c_str());
- return false;
- }
- // Store the location of uniforms for later use
- for(i = 0; i < eNumDefaultUniforms; ++i)
- {
- m_DefaultShaderProgram.auiLoc[i] = glGetUniformLocation(m_DefaultShaderProgram.uiId, g_aszDefaultUniformNames[i]);
- }
- // Set the sampler2D uniforms to corresponding texture units
- glUniform1i(glGetUniformLocation(m_DefaultShaderProgram.uiId, "sTexture"), 0);
- return true;
- }
- /*!****************************************************************************
- @Function LoadVbos
- @Description Loads the mesh data required for this training course into
- vertex buffer objects
- ******************************************************************************/
- void OGLES2ChameleonMan::LoadVbos()
- {
- if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
- if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
- /*
- Load vertex data of all meshes in the scene into VBOs
- The meshes have been exported with the "Interleave Vectors" option,
- so all data is interleaved in the buffer at pMesh->pInterleaved.
- Interleaving data improves the memory access pattern and cache efficiency,
- thus it can be read faster by the hardware.
- */
- glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
- for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
- {
- // Load vertex data into buffer object
- SPODMesh& Mesh = m_Scene.pMesh[i];
- unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
- glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
- glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
- // Load index data into buffer object if available
- m_puiIndexVbo[i] = 0;
- if (Mesh.sFaces.pData)
- {
- glGenBuffers(1, &m_puiIndexVbo[i]);
- uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
- }
- }
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
- /*!****************************************************************************
- @Function InitApplication
- @Return bool true if no error occured
- @Description Code in InitApplication() will be called by PVRShell once per
- run, before the rendering context is created.
- Used to initialize variables that are not dependant on it
- (e.g. external modules, loading meshes, etc.)
- If the rendering context is lost, InitApplication() will
- not be called again.
- ******************************************************************************/
- bool OGLES2ChameleonMan::InitApplication()
- {
- // Get and set the read path for content files
- CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
- // Load the scene
- if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
- {
- PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
- return false;
- }
- // The cameras are stored in the file. We check it contains at least one.
- if (m_Scene.nNumCamera == 0)
- {
- PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a camera\n");
- return false;
- }
- // Check the scene contains at least one light
- if (m_Scene.nNumLight == 0)
- {
- PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light\n");
- return false;
- }
- return true;
- }
- /*!****************************************************************************
- @Function QuitApplication
- @Return bool true if no error occured
- @Description Code in QuitApplication() will be called by PVRShell once per
- run, just before exiting the program.
- If the rendering context is lost, QuitApplication() will
- not be called.
- ******************************************************************************/
- bool OGLES2ChameleonMan::QuitApplication()
- {
- // Free the memory allocated for the scene
- m_Scene.Destroy();
- delete [] m_puiVbo;
- delete [] m_puiIndexVbo;
- return true;
- }
- /*!****************************************************************************
- @Function InitView
- @Return bool true if no error occured
- @Description Code in InitView() will be called by PVRShell upon
- initialization or after a change in the rendering context.
- Used to initialize variables that are dependant on the rendering
- context (e.g. textures, vertex buffers, etc.)
- ******************************************************************************/
- bool OGLES2ChameleonMan::InitView()
- {
- CPVRTString ErrorStr;
- /*
- Initialize VBO data
- */
- LoadVbos();
- /*
- Load textures
- */
- if (!LoadTextures(&ErrorStr))
- {
- PVRShellSet(prefExitMessage, ErrorStr.c_str());
- return false;
- }
- /*
- Load and compile the shaders & link programs
- */
- if (!LoadShaders(&ErrorStr))
- {
- PVRShellSet(prefExitMessage, ErrorStr.c_str());
- return false;
- }
- /*
- Initialize Print3D
- */
- // Is the screen rotated?
- bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
- if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
- {
- PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
- return false;
- }
- /*
- Set OpenGL ES render states needed for this training course
- */
- // Enable backface culling and depth test
- glCullFace(GL_BACK);
- glEnable(GL_CULL_FACE);
- glEnable(GL_DEPTH_TEST);
- // Use a nice bright blue as clear colour
- glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
- // Initialise variables used for the animation
- m_iTimePrev = PVRShellGetTime();
- return true;
- }
- /*!****************************************************************************
- @Function ReleaseView
- @Return bool true if no error occured
- @Description Code in ReleaseView() will be called by PVRShell when the
- application quits or before a change in the rendering context.
- ******************************************************************************/
- bool OGLES2ChameleonMan::ReleaseView()
- {
- // Delete textures
- glDeleteTextures(1, &m_ui32TexLegs);
- glDeleteTextures(1, &m_ui32TexBeltNormalMap);
- glDeleteTextures(1, &m_ui32TexHeadNormalMap);
- glDeleteTextures(1, &m_ui32TexLegsNormalMap);
- glDeleteTextures(1, &m_ui32TexSkyLine);
- glDeleteTextures(1, &m_ui32TexWall);
- glDeleteTextures(1, &m_ui32TexLamp);
- glDeleteTextures(1, &m_ui32TexBelt);
- // Delete program and shader objects
- glDeleteProgram(m_SkinnedShaderProgram.uiId);
- glDeleteProgram(m_DefaultShaderProgram.uiId);
- glDeleteShader(m_uiSkinnedVertShader);
- glDeleteShader(m_uiDefaultVertShader);
- glDeleteShader(m_uiSkinnedFragShader);
- glDeleteShader(m_uiDefaultFragShader);
- // Delete buffer objects
- glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
- glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
- // Release Print3D Textures
- m_Print3D.ReleaseTextures();
- return true;
- }
- /*!****************************************************************************
- @Function RenderScene
- @Return bool true if no error occured
- @Description Main rendering loop function of the program. The shell will
- call this function every frame.
- eglSwapBuffers() will be performed by PVRShell automatically.
- PVRShell will also manage important OS events.
- Will also manage relevent OS events. The user has access to
- these events through an abstraction layer provided by PVRShell.
- ******************************************************************************/
- bool OGLES2ChameleonMan::RenderScene()
- {
- // Clear the color and depth buffer
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // Use shader program
- glUseProgram(m_SkinnedShaderProgram.uiId);
-
- if(PVRShellIsKeyPressed(PVRShellKeyNameACTION1))
- {
- m_bEnableDOT3 = !m_bEnableDOT3;
- glUniform1i(m_SkinnedShaderProgram.auiLoc[ebUseDot3], m_bEnableDOT3);
- }
- /*
- Calculates the frame number to animate in a time-based manner.
- Uses the shell function PVRShellGetTime() to get the time in milliseconds.
- */
- unsigned long iTime = PVRShellGetTime();
- if(iTime > m_iTimePrev)
- {
- float fDelta = (float) (iTime - m_iTimePrev);
- m_fFrame += fDelta * g_fDemoFrameRate;
- // Increment the counters to make sure our animation works
- m_fLightPos += fDelta * 0.0034f;
- m_fWallPos += fDelta * 0.00027f;
- m_fBackgroundPos += fDelta * -0.000027f;
- // Wrap the Animation back to the Start
- if(m_fLightPos >= PVRT_TWO_PI)
- m_fLightPos -= PVRT_TWO_PI;
- if(m_fWallPos >= PVRT_TWO_PI)
- m_fWallPos -= PVRT_TWO_PI;
- if(m_fBackgroundPos <= 0)
- m_fBackgroundPos += 1.0f;
- if(m_fFrame > m_Scene.nNumFrame - 1)
- m_fFrame = 0;
- }
- m_iTimePrev = iTime;
- // Set the scene animation to the current frame
- m_Scene.SetFrame(m_fFrame);
- // Set up camera
- PVRTVec3 vFrom, vTo, vUp(0.0f, 1.0f, 0.0f);
- PVRTMat4 mView, mProjection;
- PVRTVec3 LightPos;
- float fFOV;
- int i;
- bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
- // Get the camera position, target and field of view (fov)
- if(m_Scene.pCamera[0].nIdxTarget != -1) // Does the camera have a target?
- fFOV = m_Scene.GetCameraPos( vFrom, vTo, 0); // vTo is taken from the target node
- else
- fFOV = m_Scene.GetCamera( vFrom, vTo, vUp, 0); // vTo is calculated from the rotation
- fFOV *= bRotate ? (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight) : (float)PVRShellGet(prefHeight)/(float)PVRShellGet(prefWidth);
- /*
- We can build the model view matrix from the camera position, target and an up vector.
- For this we use PVRTMat4::LookAtRH().
- */
- mView = PVRTMat4::LookAtRH(vFrom, vTo, vUp);
- // Calculate the projection matrix
- mProjection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
- // Update Light Position and related VGP Program constant
- LightPos.x = 200.0f;
- LightPos.y = 350.0f;
- LightPos.z = 200.0f * PVRTABS(sin((PVRT_PI / 4.0f) + m_fLightPos));
- glUniform3fv(m_SkinnedShaderProgram.auiLoc[eLightPos], 1, LightPos.ptr());
- // Set up the View * Projection Matrix
- PVRTMat4 mViewProjection;
-
- mViewProjection = mProjection * mView;
- glUniformMatrix4fv(m_SkinnedShaderProgram.auiLoc[eViewProj], 1, GL_FALSE, mViewProjection.ptr());
- // Enable the vertex attribute arrays
- for(i = 0; i < eNumAttribs; ++i) glEnableVertexAttribArray(i);
- // Draw skinned meshes
- for(unsigned int i32NodeIndex = 0; i32NodeIndex < 3; ++i32NodeIndex)
- {
- // Bind correct texture
- switch(i32NodeIndex)
- {
- case eBody:
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexHeadNormalMap);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexHeadBody);
- break;
- case eLegs:
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexLegsNormalMap);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexLegs);
- break;
- default:
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexBeltNormalMap);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, m_ui32TexBelt);
- break;
- }
- DrawSkinnedMesh(i32NodeIndex);
- }
- // Safely disable the vertex attribute arrays
- for(i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
- // Draw non-skinned meshes
- glUseProgram(m_DefaultShaderProgram.uiId);
- // Enable the vertex attribute arrays
- for(i = 0; i < eNumDefaultAttribs; ++i) glEnableVertexAttribArray(i);
- for(unsigned int i32NodeIndex = 3; i32NodeIndex < m_Scene.nNumMeshNode; ++i32NodeIndex)
- {
- SPODNode& Node = m_Scene.pNode[i32NodeIndex];
- SPODMesh& Mesh = m_Scene.pMesh[Node.nIdx];
- // bind the VBO for the mesh
- glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[Node.nIdx]);
- // bind the index buffer, won't hurt if the handle is 0
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[Node.nIdx]);
- // Get the node model matrix
- PVRTMat4 mWorld;
- mWorld = m_Scene.GetWorldMatrix(Node);
- // Setup the appropriate texture and transformation (if needed)
- switch(i32NodeIndex)
- {
- case eWall:
- glBindTexture(GL_TEXTURE_2D, m_ui32TexWall);
- // Rotate the wall mesh which is circular
- mWorld *= PVRTMat4::RotationY(m_fWallPos);
- glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], 0);
- break;
- case eBackground:
- glBindTexture(GL_TEXTURE_2D, m_ui32TexSkyLine);
- glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], m_fBackgroundPos);
- break;
- case eLights:
- {
- glBindTexture(GL_TEXTURE_2D, m_ui32TexLamp);
- PVRTMat4 mWallWorld = m_Scene.GetWorldMatrix(m_Scene.pNode[eWall]);
- mWorld = mWallWorld * PVRTMat4::RotationY(m_fWallPos) * mWallWorld.inverse() * mWorld;
- glUniform1f(m_DefaultShaderProgram.auiLoc[eDefaultUOffset], 0);
- }
- break;
- default:
- break;
- };
- // Set up shader uniforms
- PVRTMat4 mModelViewProj;
- mModelViewProj = mViewProjection * mWorld;
- glUniformMatrix4fv(m_DefaultShaderProgram.auiLoc[eDefaultMVPMatrix], 1, GL_FALSE, mModelViewProj.ptr());
- // Set the vertex attribute offsets
- glVertexAttribPointer(DEFAULT_VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sVertex.nStride, Mesh.sVertex.pData);
- glVertexAttribPointer(DEFAULT_TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, Mesh.psUVW[0].nStride, Mesh.psUVW[0].pData);
-
- // Indexed Triangle list
- glDrawElements(GL_TRIANGLES, Mesh.nNumFaces*3, GL_UNSIGNED_SHORT, 0);
- }
- // Safely disable the vertex attribute arrays
- for(i = 0; i < eNumAttribs; ++i) glDisableVertexAttribArray(i);
- // unbind the VBOs
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- // Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
- const char * pDescription;
- if(m_bEnableDOT3)
- pDescription = "Skinning with DOT3 Per Pixel Lighting";
- else
- pDescription = "Skinning with Vertex Lighting";
- m_Print3D.DisplayDefaultTitle("Chameleon Man", pDescription, ePVRTPrint3DSDKLogo);
- m_Print3D.Flush();
- return true;
- }
- /*!****************************************************************************
- @Function DrawSkinnedMesh
- @Input i32NodeIndex Node index of the mesh to draw
- @Description Draws a SPODMesh after the model view matrix has been set and
- the meterial prepared.
- ******************************************************************************/
- void OGLES2ChameleonMan::DrawSkinnedMesh(int i32NodeIndex)
- {
- SPODNode& Node = m_Scene.pNode[i32NodeIndex];
- SPODMesh& Mesh = m_Scene.pMesh[Node.nIdx];
- // bind the VBO for the mesh
- glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[Node.nIdx]);
- // bind the index buffer, won't hurt if the handle is 0
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[Node.nIdx]);
- // Set the vertex attribute offsets
- glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sVertex.nStride, Mesh.sVertex.pData);
- glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sNormals.nStride, Mesh.sNormals.pData);
- glVertexAttribPointer(TANGENT_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sTangents.nStride, Mesh.sTangents.pData);
- glVertexAttribPointer(BINORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, Mesh.sBinormals.nStride, Mesh.sBinormals.pData);
- glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, Mesh.psUVW[0].nStride, Mesh.psUVW[0].pData);
- glVertexAttribPointer(BONEINDEX_ARRAY, Mesh.sBoneIdx.n, GL_UNSIGNED_BYTE, GL_FALSE, Mesh.sBoneIdx.nStride, Mesh.sBoneIdx.pData);
- glVertexAttribPointer(BONEWEIGHT_ARRAY, Mesh.sBoneWeight.n, GL_UNSIGNED_BYTE, GL_TRUE, Mesh.sBoneWeight.nStride, Mesh.sBoneWeight.pData);
- for(int i32Batch = 0; i32Batch < Mesh.sBoneBatches.nBatchCnt; ++i32Batch)
- {
- /*
- If the current mesh has bone index and weight data then we need to
- set up some additional variables in the shaders.
- */
- // Set the number of bones that will influence each vertex in the mesh
- glUniform1i(m_SkinnedShaderProgram.auiLoc[eBoneCount], Mesh.sBoneIdx.n);
- // Go through the bones for the current bone batch
- PVRTMat4 amBoneWorld[8];
- PVRTMat3 afBoneWorldIT[8], mBoneIT;
- int i32Count = Mesh.sBoneBatches.pnBatchBoneCnt[i32Batch];
- for(int i = 0; i < i32Count; ++i)
- {
- // Get the Node of the bone
- int i32NodeID = Mesh.sBoneBatches.pnBatches[i32Batch * Mesh.sBoneBatches.nBatchBoneMax + i];
- // Get the World transformation matrix for this bone and combine it with our app defined
- // transformation matrix
- amBoneWorld[i] = m_Scene.GetBoneWorldMatrix(Node, m_Scene.pNode[i32NodeID]);
- // Calculate the inverse transpose of the 3x3 rotation/scale part for correct lighting
- afBoneWorldIT[i] = PVRTMat3(amBoneWorld[i]).inverse().transpose();
- }
- glUniformMatrix4fv(m_SkinnedShaderProgram.auiLoc[eBoneMatrices], i32Count, GL_FALSE, amBoneWorld[0].ptr());
- glUniformMatrix3fv(m_SkinnedShaderProgram.auiLoc[eBoneMatricesIT], i32Count, GL_FALSE, afBoneWorldIT[0].ptr());
- /*
- As we are using bone batching we don't want to draw all the faces contained within pMesh, we only want
- to draw the ones that are in the current batch. To do this we pass to the drawMesh function the offset
- to the start of the current batch of triangles (Mesh.sBoneBatches.pnBatchOffset[i32Batch]) and the
- total number of triangles to draw (i32Tris)
- */
- int i32Tris;
- if(i32Batch+1 < Mesh.sBoneBatches.nBatchCnt)
- i32Tris = Mesh.sBoneBatches.pnBatchOffset[i32Batch+1] - Mesh.sBoneBatches.pnBatchOffset[i32Batch];
- else
- i32Tris = Mesh.nNumFaces - Mesh.sBoneBatches.pnBatchOffset[i32Batch];
- // Draw the mesh
- glDrawElements(GL_TRIANGLES, i32Tris * 3, GL_UNSIGNED_SHORT, &((unsigned short*)0)[3 * Mesh.sBoneBatches.pnBatchOffset[i32Batch]]);
- }
- }
- /*!****************************************************************************
- @Function NewDemo
- @Return PVRShell* The demo supplied by the user
- @Description This function must be implemented by the user of the shell.
- The user should return its PVRShell object defining the
- behaviour of the application.
- ******************************************************************************/
- PVRShell* NewDemo()
- {
- return new OGLES2ChameleonMan();
- }
- /******************************************************************************
- End of file (OGLES2ChameleonMan.cpp)
- ******************************************************************************/
|