/*!**************************************************************************** @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 OGLES3PVRScopeRemote::RenderScene() { CPPLProcessingScoped PPLProcessingScoped(m_psSPSCommsData, __FUNCTION__, static_cast<unsigned int>(strlen(__FUNCTION__)), m_i32FrameCounter); if(m_psSPSCommsData) { // mark every N frames if(!(m_i32FrameCounter % 100)) { char buf[128]; const int nLen = sprintf(buf, "frame %u", m_i32FrameCounter); m_bCommsError |= !pplSendMark(m_psSPSCommsData, buf, nLen); } // Check for dirty items m_bCommsError |= !pplSendProcessingBegin(m_psSPSCommsData, "dirty", static_cast<unsigned int>(strlen("dirty")), m_i32FrameCounter); { unsigned int nItem, nNewDataLen; const char *pData; bool bRecompile = false; while(pplLibraryDirtyGetFirst(m_psSPSCommsData, &nItem, &nNewDataLen, &pData)) { PVRShellOutputDebug("dirty item %u %u 0x%08x\n", nItem, nNewDataLen, pData); switch(nItem) { case 0: delete [] m_pszFragShader; m_pszFragShader = new char [nNewDataLen+1]; strncpy(m_pszFragShader, (char*)pData, nNewDataLen); m_pszFragShader[nNewDataLen] = 0; bRecompile = true; break; case 1: delete [] m_pszVertShader; m_pszVertShader = new char [nNewDataLen+1]; strncpy(m_pszVertShader, (char*)pData, nNewDataLen); m_pszVertShader[nNewDataLen] = 0; bRecompile = true; break; case 2: if(nNewDataLen == sizeof(SSPSCommsLibraryTypeFloat)) { const SSPSCommsLibraryTypeFloat * const psData = (SSPSCommsLibraryTypeFloat*)pData; m_fMinThickness = psData->fCurrent; } break; case 3: if(nNewDataLen == sizeof(SSPSCommsLibraryTypeFloat)) { const SSPSCommsLibraryTypeFloat * const psData = (SSPSCommsLibraryTypeFloat*)pData; m_fMaxVariation = psData->fCurrent; } break; } } if(bRecompile) { CPVRTString ErrorStr; glDeleteProgram(m_ShaderProgram.uiId); glDeleteShader(m_uiVertShader); glDeleteShader(m_uiFragShader); if (!LoadShaders(&ErrorStr, m_pszFragShader, m_pszVertShader)) { PVRShellOutputDebug("%s", ErrorStr.c_str()); } } } m_bCommsError |= !pplSendProcessingEnd(m_psSPSCommsData); } if (m_psSPSCommsData) { m_bCommsError |= !pplSendProcessingBegin(m_psSPSCommsData, "draw", static_cast<unsigned int>(strlen("draw")), m_i32FrameCounter); } // Clear the color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use shader program glUseProgram(m_ShaderProgram.uiId); // Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_uiTexture); // Rotate and Translation the model matrix PVRTMat4 mModel; mModel = PVRTMat4::RotationY(m_fAngleY); m_fAngleY += (2*PVRT_PI/60)/7; // Set model view projection matrix PVRTMat4 mModelView, mMVP; mModelView = m_mView * mModel; mMVP = m_mProjection * mModelView; glUniformMatrix4fv(m_ShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr()); // Set light direction in model space PVRTVec4 vLightDirModel; vLightDirModel = mModel.inverse() * PVRTVec4(1, 1, 1, 0); glUniform3fv(m_ShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x); // Set eye position in model space PVRTVec4 vEyePosModel; vEyePosModel = mModelView.inverse() * PVRTVec4(0, 0, 0, 1); glUniform3fv(m_ShaderProgram.uiEyePosLoc, 1, &vEyePosModel.x); /* Set the iridescent shading parameters */ // Set the minimum thickness of the coating in nm glUniform1f(m_ShaderProgram.uiMinThicknessLoc, m_fMinThickness); // Set the maximum variation in thickness of the coating in nm glUniform1f(m_ShaderProgram.uiMaxVariationLoc, m_fMaxVariation); /* Now that the uniforms are set, call another function to actually draw the mesh. */ DrawMesh(0); if (m_psSPSCommsData) { m_bCommsError |= !pplSendProcessingEnd(m_psSPSCommsData); m_bCommsError |= !pplSendProcessingBegin(m_psSPSCommsData, "Print3D", static_cast<unsigned int>(strlen("Print3D")), m_i32FrameCounter); } // Displays the demo name using the tools. For a detailed explanation, see the example IntroducingPVRTools if(m_bCommsError) { m_Print3D.DisplayDefaultTitle("PVRScopeRemote", "Remote APIs\n\nError:\n PVRScopeComms failed\n Is PVRPerfServer connected?", ePVRTPrint3DSDKLogo); m_bCommsError = false; } else m_Print3D.DisplayDefaultTitle("PVRScopeRemote", "Remote APIs", ePVRTPrint3DSDKLogo); m_Print3D.Flush(); if (m_psSPSCommsData) { m_bCommsError |= !pplSendProcessingEnd(m_psSPSCommsData); } // send counters m_anCounterReadings[eCounter] = m_i32FrameCounter; m_anCounterReadings[eCounter10] = m_i32Frame10Counter; if(m_psSPSCommsData) { m_bCommsError |= !pplCountersUpdate(m_psSPSCommsData, m_anCounterReadings); } // update some counters ++m_i32FrameCounter; if(0 == (m_i32FrameCounter / 10) % 10) { m_i32Frame10Counter += 10; } return true; }
/*!**************************************************************************** @Function saveBinaryProgram @Return bool True if save succeeded. @Description This function takes as input the ID of a shader program object which should have been created prior to calling this function, as well as a filename to save the binary program to. The function will save out a file storing the binary shader program, and the enum value determining its format. ******************************************************************************/ bool OGLES3BinaryShader::saveBinaryProgram(const char* Filename, GLuint &ProgramObjectID) { //Quick check to make sure that the program actually exists. GLint linked; glGetProgramiv(ProgramObjectID, GL_LINK_STATUS, &linked); if (!linked) { //Shaders not linked correctly, no binary to retrieve. return false; } // Get the length of the shader binary program in memory. // Doing this ensures that a sufficient amount of memory is allocated for storing the binary program you retrieve. GLsizei length=0; glGetProgramiv(ProgramObjectID,GL_PROGRAM_BINARY_LENGTH, &length); // Pointer to the binary shader program in memory, needs to be allocated with the right size. GLvoid* ShaderBinary = (GLvoid*)malloc(length); // The format that the binary is retrieved in. GLenum binaryFormat=0; // Error checking variable - this should be greater than 0 after glGetProgramBinaryOES, otherwise there was an error. GLsizei lengthWritten=0; // Get the program binary from GL and save it out. glGetProgramBinary(ProgramObjectID,length,&lengthWritten,&binaryFormat,ShaderBinary); if(!lengthWritten) { // Save failed. Insufficient memory allocated to write binary shader. return false; } // Cache the program binary for future runs FILE* outfile = fopen(Filename, "wb"); if(!outfile) { PVRShellOutputDebug("Failed to open %s for writing to.\n", Filename); return false; } // Save the binary format. if(!fwrite((void*)&binaryFormat,sizeof(GLenum),1,outfile)) { fclose(outfile); return false; // Couldn't write binary format to file. } // Save the actual binary program. if(!fwrite(ShaderBinary, length,1,outfile)) { fclose(outfile); return false; // Couldn't write binary data to file. } // Close the file. fclose(outfile); // Free the memory used by Shader Binary. free(ShaderBinary); return true; }
/*!**************************************************************************** @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 OGLES3PVRScopeRemote::InitApplication() { // We want a data connection to PVRPerfServer { m_psSPSCommsData = pplInitialise("PVRScopeRemote", 14); m_bCommsError = false; // Demonstrate that there is a good chance of the initial data being // lost - the connection is normally completed asynchronously. pplSendMark(m_psSPSCommsData, "lost", static_cast<unsigned int>(strlen("lost"))); // This is entirely optional. Wait for the connection to succeed, it will // timeout if e.g. PVRPerfServer is not running. int nBoolConnected; pplWaitForConnection(m_psSPSCommsData, &nBoolConnected, 1, 200); } CPPLProcessingScoped PPLProcessingScoped(m_psSPSCommsData, __FUNCTION__, static_cast<unsigned int>(strlen(__FUNCTION__)), m_i32FrameCounter); // set thickness variation of the film m_fMaxVariation = 100.0f; // set the minimum thickness of the film m_fMinThickness = 100.0f; m_puiVbo = 0; m_puiIndexVbo = 0; m_i32FrameCounter = 0; m_i32Frame10Counter = 0; // Get and set the read path for content files CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath)); // Get and set the load/release functions for loading external files. // In the majority of cases the PVRShell will return NULL function pointers implying that // nothing special is required to load external files. CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc)); // Load the scene if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n"); return false; } // set angle of rotation m_fAngleY = 0.0f; /* Remotely editable library items */ if(m_psSPSCommsData) { SSPSCommsLibraryItem asItems[8]; unsigned int nItemCount = 0; /* Want editable shaders */ CPVRTResourceFile FragShaderFile(c_szFragShaderSrcFile); CPVRTResourceFile VertShaderFile(c_szVertShaderSrcFile); struct SLibList { const char * const pszName; const CPVRTResourceFile * const pFile; } aShaders[2] = { { c_szFragShaderSrcFile, &FragShaderFile }, { c_szVertShaderSrcFile, &VertShaderFile } }; for(unsigned int i = 0; i < sizeof(aShaders) / sizeof(*aShaders); ++i) { if(aShaders[i].pFile->IsOpen()) { asItems[nItemCount].pszName = aShaders[i].pszName; asItems[nItemCount].nNameLength = (unsigned int)strlen(aShaders[i].pszName); asItems[nItemCount].eType = eSPSCommsLibTypeString; asItems[nItemCount].pData = (const char*)aShaders[i].pFile->DataPtr(); asItems[nItemCount].nDataLength = (unsigned int)aShaders[i].pFile->Size(); ++nItemCount; } } // Want editable: min thickness m_sCommsLibMinThickness.fCurrent = m_fMinThickness; m_sCommsLibMinThickness.fMin = 0.0f; m_sCommsLibMinThickness.fMax = 500.0f; asItems[nItemCount].pszName = "min thickness"; asItems[nItemCount].nNameLength = (unsigned int)strlen(asItems[nItemCount].pszName); asItems[nItemCount].eType = eSPSCommsLibTypeFloat; asItems[nItemCount].pData = (const char*)&m_sCommsLibMinThickness; asItems[nItemCount].nDataLength = sizeof(m_sCommsLibMinThickness); ++nItemCount; // Want editable: max variation m_sCommsLibMaxVariation.fCurrent = m_fMaxVariation; m_sCommsLibMaxVariation.fMin = 50.0f; m_sCommsLibMaxVariation.fMax = 150.0f; asItems[nItemCount].pszName = "max variation"; asItems[nItemCount].nNameLength = (unsigned int)strlen(asItems[nItemCount].pszName); asItems[nItemCount].eType = eSPSCommsLibTypeFloat; asItems[nItemCount].pData = (const char*)&m_sCommsLibMaxVariation; asItems[nItemCount].nDataLength = sizeof(m_sCommsLibMaxVariation); ++nItemCount; _ASSERT(nItemCount < sizeof(asItems) / sizeof(*asItems)); /* Ok, submit our library */ if(!pplLibraryCreate(m_psSPSCommsData, asItems, nItemCount)) { PVRShellOutputDebug("PVRScopeRemote: pplLibraryCreate() failed\n"); } } /* User defined counters */ if(m_psSPSCommsData) { SSPSCommsCounterDef asDefs[eCounterNum]; for(unsigned int i = 0; i < eCounterNum; ++i) { asDefs[i].pszName = c_apszDefs[i]; asDefs[i].nNameLength = (unsigned int)strlen(c_apszDefs[i]); } if(!pplCountersCreate(m_psSPSCommsData, asDefs, eCounterNum)) { PVRShellOutputDebug("PVRScopeRemote: pplCountersCreate() failed\n"); } } 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 OGLESIntroducingPFX::InitView() { /* Initialize Print3D */ 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; } // Sets the clear color glClearColor(0.6f, 0.8f, 1.0f, 1.0f); // Enables depth test using the z-buffer glEnable(GL_DEPTH_TEST); /* Loads the light direction from the scene. */ // We check the scene contains at least one if (m_Scene.nNumLight == 0) { PVRShellSet(prefExitMessage, "ERROR: The scene does not contain a light\n"); return false; } /* Load the effect file */ { unsigned int nUnknownUniformCount; CPVRTString error; // Parse the file m_pEffectParser = new CPVRTPFXParser; if(m_pEffectParser->ParseFromFile(c_szPfxFile, &error) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, error.c_str()); return false; } // Load an effect from the file m_pEffect = new CPVRTPFXEffect(); if(m_pEffect->Load(*m_pEffectParser, "Effect", c_szPfxFile, &error) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, error.c_str()); return false; } // Generate uniform array if(m_pEffect->BuildUniformTable( &m_psUniforms, &m_nUniformCnt, &nUnknownUniformCount, c_psUniformSemantics, sizeof(c_psUniformSemantics) / sizeof(*c_psUniformSemantics), &error) != PVR_SUCCESS) { PVRShellOutputDebug(error.c_str()); return false; } if(nUnknownUniformCount) { PVRShellOutputDebug(error.c_str()); PVRShellOutputDebug("Unknown uniform semantic count: %d\n", nUnknownUniformCount); } } /* Loads the textures. For a more detailed explanation, see Texturing and IntroducingPVRTools */ { const SPVRTPFXTexture *psTex; unsigned int nCnt, i; GLuint ui; psTex = m_pEffect->GetTextureArray(nCnt); for(i = 0; i < nCnt; ++i) { if(strcmp(psTex[i].p, "Reflection.pvr") == 0) { if(PVRTTextureLoadFromPVR(c_szReflectTexFile, &ui) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot load the texture\n"); return false; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_pEffect->SetTexture(i, ui); } else if (strcmp(psTex[i].p, "Basetex.pvr") == 0) { if(PVRTTextureLoadFromPVR(c_szBaseTexFile, &ui) != PVR_SUCCESS) { PVRShellSet(prefExitMessage, "ERROR: Cannot load the texture\n"); return false; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); m_pEffect->SetTexture(i, ui); } else { PVRShellOutputDebug("Warning: effect file requested unrecognised texture: \"%s\"\n", psTex[i].p); m_pEffect->SetTexture(i, 0); } } } // Create buffer objects. m_aiVboID = new GLuint[m_Scene.nNumMeshNode]; glGenBuffers(m_Scene.nNumMeshNode, m_aiVboID); for(int i = 0; i < (int)m_Scene.nNumMeshNode ; i++) { SPODNode* pNode = &m_Scene.pNode[i]; // Gets pMesh referenced by the pNode SPODMesh* pMesh = &m_Scene.pMesh[pNode->nIdx]; // Generate a vertex buffer and set the interleaved vertex data. glBindBuffer(GL_ARRAY_BUFFER, m_aiVboID[i]); glBufferData(GL_ARRAY_BUFFER, pMesh->sVertex.nStride*pMesh->nNumVertex, pMesh->pInterleaved, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } return true; }