/*!****************************************************************************
 @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 OGLESRenderToTexture::ReleaseView()
{
	// Delete the texture
	glDeleteTextures(1, &m_uiTextureID);
	glDeleteTextures(1, &m_uiTextureToRenderTo);

	// Release Print3D Textures
	m_Print3D.ReleaseTextures();

	// Destroy the FBO or PBuffer surface we were using
	switch(m_eR2TType)
	{
		case eFBO:
			// Delete frame buffer objects
			m_Extensions.glDeleteFramebuffersOES(1, &m_uFBO);

			// Delete our depth buffer
			m_Extensions.glDeleteRenderbuffersOES(1, &m_uDepthBuffer);
		break;
#if !defined(EGL_NOT_PRESENT)
		case ePBuffer:
			// Destroy the surfaces we created
			eglDestroySurface(m_CurrentDisplay,	m_PBufferSurface);
		break;
#endif
		default:
			break;
	}

	return true;
}
/*******************************************************************************
 * Function Name  : DrawModel
 * Description    : Draws the model
 *******************************************************************************/
void OGLESSkinning::DrawModel()
{
	//Set the frame number
	m_Scene.SetFrame(m_fFrame);

	// Enable lighting
	glEnable(GL_LIGHTING);

	// Enable States
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	//Iterate through all the mesh nodes in the scene
	for(int iNode = 0; iNode < (int)m_Scene.nNumMeshNode; ++iNode)
	{
		//Get the mesh node.
		SPODNode* pNode = &m_Scene.pNode[iNode];

		//Get the mesh that the mesh node uses.
		SPODMesh* pMesh = &m_Scene.pMesh[pNode->nIdx];

		// bind the VBO for the mesh
		glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[pNode->nIdx]);

		// bind the index buffer, won't hurt if the handle is 0
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[pNode->nIdx]);

		// Loads the correct texture using our texture lookup table
		if(pNode->nIdxMaterial == -1)
			glBindTexture(GL_TEXTURE_2D, 0); // It has no pMaterial defined. Use blank texture (0)
		else
			glBindTexture(GL_TEXTURE_2D, m_puiTextures[pNode->nIdxMaterial]);

		//If the mesh has bone weight data then we must be skinning.
		bool bSkinning = pMesh->sBoneWeight.n != 0;

		if(bSkinning)
		{
			//If we are skinning then enable the relevant states.
			glEnableClientState(GL_MATRIX_INDEX_ARRAY_OES);
			glEnableClientState(GL_WEIGHT_ARRAY_OES);
		}
		else
		{
			// If we're not using matrix palette then get the world matrix for the mesh
			// and transform the model view matrix by it.
			PVRTMat4 worldMatrix;
			m_Scene.GetWorldMatrix(worldMatrix, *pNode);

			//Push the modelview matrix
			glPushMatrix();

			glMultMatrixf(worldMatrix.f);
		}

		// Set Data Pointers
		// Used to display non interleaved geometry
		glVertexPointer(pMesh->sVertex.n, GL_FLOAT, pMesh->sVertex.nStride, pMesh->sVertex.pData);
		glNormalPointer(GL_FLOAT, pMesh->sNormals.nStride, pMesh->sNormals.pData);
		glTexCoordPointer(pMesh->psUVW[0].n, GL_FLOAT, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);

		if(bSkinning)
		{
			//Set up the indexes into the matrix palette.
			m_Extensions.glMatrixIndexPointerOES(pMesh->sBoneIdx.n, GL_UNSIGNED_BYTE, pMesh->sBoneIdx.nStride, pMesh->sBoneIdx.pData);
			m_Extensions.glWeightPointerOES(pMesh->sBoneWeight.n, GL_FLOAT, pMesh->sBoneWeight.nStride, pMesh->sBoneWeight.pData);
		}

		// Draw

		/*
			2 variables used by the indexed triangle-strip version of the drawing code that is included as an
			example but is unused as the .pod file supplied contains indexed triangle-list data.
		*/
		int i32Strip = 0;
		int i32Offset = 0;

		/*
			As we are using bone batching we don't want to draw all the faces contained within pMesh at once, we only
			want to draw the ones that are in the current batch. To do this we loop through the batches and pass to the
			the draw call the offser to the start of the current batch of triangles
			(pMesh->sBoneBatches.pnBatchOffset[i32Batch]) and the total number of triangles to draw (i32Tris)
		*/

		for(int i32Batch = 0; i32Batch < (bSkinning ? pMesh->sBoneBatches.nBatchCnt : 1); ++i32Batch)
		{
			// If the mesh is used for skining then set up the matrix palettes.
			if(bSkinning)
			{
				//Enable the matrix palette extension
				glEnable(GL_MATRIX_PALETTE_OES);
				/*
					Enables the matrix palette stack extension, and apply subsequent
					matrix operations to the matrix palette stack.
				*/
				glMatrixMode(GL_MATRIX_PALETTE_OES);

				PVRTMat4	mBoneWorld;
				int			i32NodeID;

				//	Iterate through all the bones in the batch
				for(int j = 0; j < pMesh->sBoneBatches.pnBatchBoneCnt[i32Batch]; ++j)
				{
					/*
						Set the current matrix palette that we wish to change. An error
						will be returned if the index (j) is not between 0 and
						GL_MAX_PALETTE_MATRICES_OES. The value of GL_MAX_PALETTE_MATRICES_OES
						can be retrieved using glGetIntegerv, the initial value is 9.

						GL_MAX_PALETTE_MATRICES_OES does not mean you need to limit
						your character to 9 bones as you can overcome this limitation
						by using bone batching which splits the mesh up into sub-meshes
						which use only a subset of the bones.
					*/

					m_Extensions.glCurrentPaletteMatrixOES(j);

					// Generates the world matrix for the given bone in this batch.
					i32NodeID = pMesh->sBoneBatches.pnBatches[i32Batch * pMesh->sBoneBatches.nBatchBoneMax + j];
					m_Scene.GetBoneWorldMatrix(mBoneWorld, *pNode, m_Scene.pNode[i32NodeID]);

					// Multiply the bone's world matrix by our transformation matrix and the view matrix
					mBoneWorld = m_mView * m_mTransform * mBoneWorld;

					// Load the bone matrix into the current palette matrix.
					glLoadMatrixf(mBoneWorld.f);
				}
			}
			else
			{
				//If we're not skinning then disable the matrix palette.
				glDisable(GL_MATRIX_PALETTE_OES);
			}

			//Switch to the modelview matrix.
			glMatrixMode(GL_MODELVIEW);

			// Calculate the number of triangles in the current batch
			int i32Tris;

			if(bSkinning)
			{
				if(i32Batch + 1 < pMesh->sBoneBatches.nBatchCnt)
					i32Tris = pMesh->sBoneBatches.pnBatchOffset[i32Batch+1] - pMesh->sBoneBatches.pnBatchOffset[i32Batch];
				else
					i32Tris = pMesh->nNumFaces - pMesh->sBoneBatches.pnBatchOffset[i32Batch];
			}
			else
				i32Tris = pMesh->nNumFaces;

			// Indexed Triangle list
			if(pMesh->nNumStrips == 0)
			{
				size_t offset = bSkinning ? sizeof(GLushort) * 3 * pMesh->sBoneBatches.pnBatchOffset[i32Batch] : 0;
				glDrawElements(GL_TRIANGLES, i32Tris * 3, GL_UNSIGNED_SHORT, (void*) offset);
			}
			else // Indexed Triangle strips
			{
				int i32TrisDrawn = 0;

				while(i32TrisDrawn < i32Tris)
				{
					glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i32Strip]+2, GL_UNSIGNED_SHORT, (void*) (i32Offset * sizeof(GLushort)));

					i32Offset += pMesh->pnStripLength[i32Strip]+2;
					i32TrisDrawn += pMesh->pnStripLength[i32Strip];

					++i32Strip;
				}
			}
		}

		if(bSkinning)
		{
			glDisableClientState(GL_MATRIX_INDEX_ARRAY_OES);
			glDisableClientState(GL_WEIGHT_ARRAY_OES);

			// We are finished with the matrix pallete so disable it.
			glDisable(GL_MATRIX_PALETTE_OES);
		}
		else
		{
			//Reset the modelview matrix back to what it was before we transformed by the mesh node.
			glPopMatrix();
		}
	}

	// Disable States
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	// unbind the vertex buffers as we don't need them bound anymore
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
/*******************************************************************************
 * Function Name  : InitView
 * Returns        : true if no error occured
 * Description    : Code in InitView() will be called by the Shell upon a change
 *					in the rendering context.
 *					Used to initialize variables that are dependant on the rendering
 *					context (e.g. textures, vertex buffers, etc.)
 *******************************************************************************/
bool OGLESSkinning::InitView()
{
	CPVRTString error;

	//	Check to see whether the matrix palette extension is supported.
	if(!CPVRTglesExt::IsGLExtensionSupported("GL_OES_matrix_palette"))
	{
		PVRShellSet(prefExitMessage, "ERROR: The extension GL_OES_matrix_palette is unsupported.\n");
		return false;
	}

	// Initialise the matrix palette extensions
	m_Extensions.LoadExtensions();

	// Load the textures
	if(!LoadTextures(&error))
	{
		PVRShellSet(prefExitMessage, error.c_str());
		return false;
	}

	// Init Print3D to display text on screen
	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;
	}

	// Model View Matrix
	CameraGetMatrix();

	// Projection Matrix
	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(m_mProjection.f);

	// GENERIC RENDER STATES

	// Enables Depth Testing
	glEnable(GL_DEPTH_TEST);

	// Enables Smooth Colour Shading
	glShadeModel(GL_SMOOTH);

	// Enable texturing
	glEnable(GL_TEXTURE_2D);

	// Define front faces
	glFrontFace(GL_CW);

	// Enables texture clamping
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

	// Reset the model view matrix to position the light
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	// Setup ambiant light
    glEnable(GL_LIGHTING);

	PVRTVec4 lightGlobalAmbient = PVRTVec4(1.0f, 1.0f, 1.0f, 1.0f);
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightGlobalAmbient.ptr());

	// Setup a directional light source
	PVRTVec4 lightPosition = PVRTVec4(-0.7f, -1.0f, 0.2f, 0.0f);
    PVRTVec4 lightAmbient  = PVRTVec4(1.0f, 1.0f, 1.0f, 1.0f);
    PVRTVec4 lightDiffuse  = PVRTVec4(1.0f, 1.0f, 1.0f, 1.0f);
    PVRTVec4 lightSpecular = PVRTVec4(0.2f, 0.2f, 0.2f, 1.0f);

    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.ptr());
    glLightfv(GL_LIGHT0, GL_AMBIENT,  lightAmbient.ptr());
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  lightDiffuse.ptr());
    glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular.ptr());

	LoadVbos();

	/*
		Initialise an array to lookup the textures
		for each material in the scene.
	*/
	m_puiTextures = new GLuint[m_Scene.nNumMaterial];

	for(unsigned int i = 0; i < m_Scene.nNumMaterial; ++i)
	{
		m_puiTextures[i] = m_uiLegTex;

		SPODMaterial* pMaterial = &m_Scene.pMaterial[i];
		if(strcmp(pMaterial->pszName, "Mat_body") == 0)
		{
			m_puiTextures[i] = m_uiBodyTex;
		}
		else if(strcmp(pMaterial->pszName, "Mat_legs") == 0)
		{
			m_puiTextures[i] = m_uiLegTex;
		}
		else if(strcmp(pMaterial->pszName, "Mat_belt") == 0)
		{
			m_puiTextures[i] = m_uiBeltTex;
		}
	}

	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 OGLESParticles::InitView()
{
	PVRTMat4		mProjection;
	SPVRTContext	sContext;

	bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);

	// Initialize Print3D textures
	if(m_Print3D.SetTextures(&sContext, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D.\n");
		return false;
	}

	// Initialize Extensions
	m_Extensions.LoadExtensions();

	//	Load textures.
	if(PVRTTextureLoadFromPVR(c_szLightTexFile, &m_ui32TexName) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot load light texture.\n");
		return false;
	}

	myglTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	myglTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	if(PVRTTextureLoadFromPVR(c_szFloorTexFile, &m_ui32FloorTexName) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot load floor texture.\n");
		return false;
	}

	myglTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	myglTexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	if(bRotate)
		myglRotate(f2vt(90), f2vt(0), f2vt(0), f2vt(1));

	// Creates the projection matrix.
	mProjection = PVRTMat4::PerspectiveFovRH(f2vt(45.0f*(PVRT_PIf/180.0f)), f2vt((float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight)), f2vt(10.0f), f2vt(1200.0f), PVRTMat4::OGL);
	
	myglMultMatrix(mProjection.f);

	//	Calculates the attenuation coefficient for the points drawn.
	double H = bRotate ? PVRShellGet(prefWidth) : PVRShellGet(prefHeight);
	double h = 2.0 / mProjection.f[5];
	double D0 = sqrt(2.0) * H / h;
	double k = 1.0/(1.0 + 2.0 * (1 / mProjection.f[5]) * (1 / mProjection.f[5]));
	
	m_fPointAttenuationCoef = (float)(1.0 / (D0 * D0) * k);

	//	Creates the model view matrix.
	m_mView = PVRTMat4::LookAtRH(m_fFrom, m_fTo, g_fUp);

	glMatrixMode(GL_MODELVIEW);
	myglLoadMatrix(m_mView.f);

	/*
		Pre-Set TexCoords since they never change.
		Pre-Set the Index Buffer.
	*/

	for(unsigned int i = 0; i < g_ui32MaxParticles; ++i)
	{
		m_sParticleVTXBuf[i*4+0].u = 0;
		m_sParticleVTXBuf[i*4+0].v = 0;

		m_sParticleVTXBuf[i*4+1].u = 1;
		m_sParticleVTXBuf[i*4+1].v = 0;

		m_sParticleVTXBuf[i*4+2].u = 0;
		m_sParticleVTXBuf[i*4+2].v = 1;

		m_sParticleVTXBuf[i*4+3].u = 1;
		m_sParticleVTXBuf[i*4+3].v = 1;

		m_ui16ParticleINDXBuf[i*6+0] = (i*4) + 0;
		m_ui16ParticleINDXBuf[i*6+1] = (i*4) + 1;
		m_ui16ParticleINDXBuf[i*6+2] = (i*4) + 2;
		m_ui16ParticleINDXBuf[i*6+3] = (i*4) + 2;
		m_ui16ParticleINDXBuf[i*6+4] = (i*4) + 1;
		m_ui16ParticleINDXBuf[i*6+5] = (i*4) + 3;
	}


	//	Create vertex buffers.
	glGenBuffers(1, &m_i32VertVboID);
	glGenBuffers(1, &m_i32ColAVboID);
	glGenBuffers(1, &m_i32ColBVboID);
	glGenBuffers(1, &m_i32QuadVboID);

	//	Preset the floor uvs and vertices as they never change.
	PVRTVec3 pos(0, 0, 0);

	float szby2 = 100;

	m_sQuadVTXBuf[0].x = m_fFloorQuadVerts[0]  = pos.x - f2vt(szby2);
	m_sQuadVTXBuf[0].y = m_fFloorQuadVerts[1]  = pos.y;
	m_sQuadVTXBuf[0].z = m_fFloorQuadVerts[2]  = pos.z - f2vt(szby2);

	m_sQuadVTXBuf[1].x = m_fFloorQuadVerts[3]  = pos.x + f2vt(szby2);
	m_sQuadVTXBuf[1].y = m_fFloorQuadVerts[4]  = pos.y;
	m_sQuadVTXBuf[1].z = m_fFloorQuadVerts[5]  = pos.z - f2vt(szby2);

	m_sQuadVTXBuf[2].x = m_fFloorQuadVerts[6]  = pos.x - f2vt(szby2);
	m_sQuadVTXBuf[2].y = m_fFloorQuadVerts[7]  = pos.y;
	m_sQuadVTXBuf[2].z = m_fFloorQuadVerts[8]  = pos.z + f2vt(szby2);

	m_sQuadVTXBuf[3].x = m_fFloorQuadVerts[9]  = pos.x + f2vt(szby2);
	m_sQuadVTXBuf[3].y = m_fFloorQuadVerts[10] = pos.y;
	m_sQuadVTXBuf[3].z = m_fFloorQuadVerts[11] = pos.z + f2vt(szby2);

	m_fFloorQuadUVs[0] = f2vt(0);
	m_fFloorQuadUVs[1] = f2vt(0);
	m_sQuadVTXBuf[0].u = 0;
	m_sQuadVTXBuf[0].v = 0;

	m_fFloorQuadUVs[2] = f2vt(1);
	m_fFloorQuadUVs[3] = f2vt(0);
	m_sQuadVTXBuf[1].u = 255;
	m_sQuadVTXBuf[1].v = 0;

	m_fFloorQuadUVs[4] = f2vt(0);
	m_fFloorQuadUVs[5] = f2vt(1);
	m_sQuadVTXBuf[2].u = 0;
	m_sQuadVTXBuf[2].v = 255;

	m_fFloorQuadUVs[6] = f2vt(1);
	m_fFloorQuadUVs[7] = f2vt(1);
	m_sQuadVTXBuf[3].u = 255;
	m_sQuadVTXBuf[3].v = 255;

	glBindBuffer(GL_ARRAY_BUFFER, m_i32QuadVboID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(SVtx) * 4, m_sQuadVTXBuf, GL_STATIC_DRAW);

	return true;
}
/*!****************************************************************************
 @Function		CreateFBOorPBuffer
 @Return		bool		true if no error occured
 @Description	Attempts to create our FBO if supported or a PBuffer if they
				are not.
******************************************************************************/
bool OGLESRenderToTexture::CreateFBOorPBuffer()
{
#if !defined(EGL_NOT_PRESENT)
	EGLConfig eglConfig = 0;
	EGLint list[9];
#endif

	// Find the largest square power of two texture that fits into the viewport
	m_i32TexSize = 1;
	int iSize = PVRT_MIN(PVRShellGet(prefWidth), PVRShellGet(prefHeight));
	while (m_i32TexSize * 2 < iSize) m_i32TexSize *= 2;

	// Check for FBO extension
	if(CPVRTglesExt::IsGLExtensionSupported("GL_OES_framebuffer_object"))
	{
		// FBOs are present so we're going to use them
		m_eR2TType = eFBO;

		// Load the extensions as they are required
		m_Extensions.LoadExtensions();

		// Check to see if the GL_EXT_discard_framebuffer extension is supported by seeing if
		// CPVRTglesExt has a valid pointer for glDiscardFramebufferEXT
		m_bDiscard = m_Extensions.glDiscardFramebufferEXT != 0;

		// Get the currently bound frame buffer object. On most platforms this just gives 0.
		glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &m_i32OriginalFbo);

		// Generate and bind a render buffer which will become a depth buffer shared between our two FBOs
		m_Extensions.glGenRenderbuffersOES(1, &m_uDepthBuffer);
		m_Extensions.glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_uDepthBuffer);

		/*
			Currently it is unknown to GL that we want our new render buffer to be a depth buffer.
			glRenderbufferStorage will fix this and in this case will allocate a depth buffer
			m_i32TexSize by m_i32TexSize.
		*/
		m_Extensions.glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, m_i32TexSize, m_i32TexSize);
	}
#if !defined(EGL_NOT_PRESENT)
	else
	{
		// FBOs aren't present so we're going to use PBuffers
		m_eR2TType = ePBuffer;

		// Set up a configuration and attribute list used for creating a PBuffer surface.
		eglConfig = SelectEGLConfig();

		// First we specify the width of the surface...
		list[0] = EGL_WIDTH;
		list[1] = m_i32TexSize;
		// ...then the height of the surface...
		list[2] = EGL_HEIGHT;
		list[3] = m_i32TexSize;
		/* ... then we specifiy the target for the texture
			that will be created when the pbuffer is created...*/
		list[4] = EGL_TEXTURE_TARGET;
		list[5] = EGL_TEXTURE_2D;
		/*..then the format of the texture that will be created
			when the pBuffer is bound to a texture...*/
		list[6] = EGL_TEXTURE_FORMAT;
		list[7] = EGL_TEXTURE_RGB;
		// The final thing is EGL_NONE which signifies the end.
		list[8] = EGL_NONE;

		/*
			Get the current display, context and surface so we can switch between the
			PBuffer surface and the main render surface.
		*/

		m_CurrentDisplay = eglGetCurrentDisplay();
		m_CurrentContext = eglGetCurrentContext();
		m_CurrentSurface = eglGetCurrentSurface(EGL_DRAW);
	}
#else
	else
	{