/*!****************************************************************************
 @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;
}
Пример #4
0
/*!****************************************************************************
 @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;
}