/*!*************************************************************************** @Function PVRTPFXOnLoadTexture @Input TextureName @Output uiHandle @Output uiFlags @Return EPVRTError PVR_SUCCESS on success. @Description Callback function on texture load. *****************************************************************************/ EPVRTError OGLES3MagicLantern::PVRTPFXOnLoadTexture(const CPVRTStringHash& TextureName, GLuint& uiHandle, unsigned int& uiFlags) { /* Because we have multiple effects being loaded yet the textures remain the same we can efficiently cache texture IDs and only load a texture once but assign it to multiple effects. */ // Check if the texture already exists in the map if(m_TextureCache.Exists(TextureName)) { const STextureData& TexData = m_TextureCache[TextureName]; uiHandle = TexData.uiHandle; uiFlags = TexData.uiFlags; return PVR_SUCCESS; } // Texture is not loaded. Load and add to the map. PVRTextureHeaderV3 sHeader; if(PVRTTextureLoadFromPVR(TextureName.c_str(), &uiHandle, &sHeader) != PVR_SUCCESS) return PVR_FAIL; uiFlags = 0; if(sHeader.u32NumFaces == 6) uiFlags |= PVRTEX_CUBEMAP; STextureData& TexData = m_TextureCache[TextureName]; TexData.uiFlags = uiFlags; TexData.uiHandle = uiHandle; return PVR_SUCCESS; }
/*!**************************************************************************** @Function LoadTextures @Output pErrorStr A CPVRTString describing the error on failure @Return bool true if no error occured @Description Loads the textures required for this training course ******************************************************************************/ bool OGLES3ShadowMapping::LoadTextures(CPVRTString* const pszErrorStr) { for (unsigned int i=0; i < c_uiNumTextureNames; i++) { // Check if the texture already exists in the map if(m_TextureCache.Exists(c_sTextureNames[i])) continue; CPVRTString filename = c_sTextureNames[i].String() + CPVRTString(".pvr"); // Texture is not loaded. Load and add to the map. GLuint uiHandle; PVRTextureHeaderV3 sHeader; if(PVRTTextureLoadFromPVR(filename.c_str(), &uiHandle, &sHeader) != PVR_SUCCESS) { *pszErrorStr = CPVRTString("Failed to load texture: ") + filename; return false; } m_TextureCache[c_sTextureNames[i]] = uiHandle; } return true; }
/*!**************************************************************************** @Function RenderSceneWithEffect @Return bool true if no error occured @Description Renders the whole scene with a single effect. ******************************************************************************/ bool OGLES3ShadowMapping::RenderSceneWithEffect(const int uiEffectId, const PVRTMat4 &mProjection, const PVRTMat4 &mView) { CPVRTPFXEffect *pEffect = m_ppPFXEffects[uiEffectId]; // Activate the passed effect pEffect->Activate(); for (unsigned int i=0; i < m_Scene.nNumMeshNode; i++) { SPODNode* pNode = &m_Scene.pNode[i]; SPODMesh* pMesh = &m_Scene.pMesh[pNode->nIdx]; SPODMaterial *pMaterial = 0; if (pNode->nIdxMaterial != -1) { pMaterial = &m_Scene.pMaterial[pNode->nIdxMaterial]; // Bind the texture if there is one bound to this object if (pMaterial->nIdxTexDiffuse != -1) { CPVRTString texname = CPVRTString(m_Scene.pTexture[pMaterial->nIdxTexDiffuse].pszName).substitute(".png", ""); CPVRTStringHash hashedName(texname); if (m_TextureCache.Exists(hashedName)) glBindTexture(GL_TEXTURE_2D, m_TextureCache[hashedName]); } } glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]); // Pre-calculate commonly used matrices PVRTMat4 mWorld; m_Scene.GetWorldMatrix(mWorld, *pNode); PVRTMat4 mWorldView = mView * mWorld; // Bind semantics const CPVRTArray<SPVRTPFXUniform>& Uniforms = pEffect->GetUniformArray(); for(unsigned int j = 0; j < Uniforms.GetSize(); ++j) { switch(Uniforms[j].nSemantic) { case ePVRTPFX_UsPOSITION: { glVertexAttribPointer(Uniforms[j].nLocation, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData); glEnableVertexAttribArray(Uniforms[j].nLocation); } break; case ePVRTPFX_UsNORMAL: { glVertexAttribPointer(Uniforms[j].nLocation, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData); glEnableVertexAttribArray(Uniforms[j].nLocation); } break; case ePVRTPFX_UsUV: { glVertexAttribPointer(Uniforms[j].nLocation, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData); glEnableVertexAttribArray(Uniforms[j].nLocation); } break; case ePVRTPFX_UsMATERIALCOLORDIFFUSE: { if (pMaterial) glUniform4f(Uniforms[j].nLocation, pMaterial->pfMatDiffuse[0], pMaterial->pfMatDiffuse[1], pMaterial->pfMatDiffuse[2], 1.0f); } break; case ePVRTPFX_UsWORLDVIEWPROJECTION: { PVRTMat4 mWorldViewProj = mProjection * mWorldView; glUniformMatrix4fv(Uniforms[j].nLocation, 1, GL_FALSE, mWorldViewProj.f); } break; case ePVRTPFX_UsWORLDI: { PVRTMat3 mWorldI3x3(mWorld.inverse()); glUniformMatrix3fv(Uniforms[j].nLocation, 1, GL_FALSE, mWorldI3x3.f); } break; case ePVRTPFX_UsWORLDVIEWIT: { PVRTMat3 mWorldViewIT3x3(mWorldView.inverse().transpose()); glUniformMatrix3fv(Uniforms[j].nLocation, 1, GL_FALSE, mWorldViewIT3x3.f); } break; case ePVRTPFX_UsTEXTURE: { // Set the sampler variable to the texture unit glUniform1i(Uniforms[j].nLocation, Uniforms[j].nIdx); } break; case ePVRTPFX_UsLIGHTPOSWORLD: { glUniform3fv(Uniforms[j].nLocation, 1, m_vLightPosition.ptr()); } break; case eCUSTOMSEMANTIC_SHADOWTRANSMATRIX: { // We need to calculate the texture projection matrix. This matrix takes the pixels from world space to previously rendered light projection space //where we can look up values from our saved depth buffer. The matrix is constructed from the light view and projection matrices as used for the previous render and //then multiplied by the inverse of the current view matrix. //PVRTMat4 mTextureMatrix = m_mBiasMatrix * m_mLightProjection * m_mLightView * mView.inverse(); PVRTMat4 mTextureMatrix = m_mBiasMatrix * m_mLightProjection * m_mLightView * mWorld; glUniformMatrix4fv(Uniforms[j].nLocation, 1, GL_FALSE, mTextureMatrix.f); } break; case ePVRTPFX_UsRANDOM: { glUniform1f(Uniforms[j].nLocation, m_fBias); } break; default: { PVRShellOutputDebug("Error: Unhandled semantic in RenderSceneWithEffect()\n"); return false; } } } // Now that all uniforms are set and the materials ready, draw the mesh. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0); // Disable all vertex attributes for(unsigned int j = 0; j < Uniforms.GetSize(); ++j) { switch(Uniforms[j].nSemantic) { case ePVRTPFX_UsPOSITION: case ePVRTPFX_UsNORMAL: case ePVRTPFX_UsUV: glDisableVertexAttribArray(Uniforms[j].nLocation); break; } } } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); return true; }