Skip to content

Instantly share code, notes, and snippets.

@CartBlanche
Created October 7, 2011 22:44
Show Gist options
  • Save CartBlanche/1271517 to your computer and use it in GitHub Desktop.
Save CartBlanche/1271517 to your computer and use it in GitHub Desktop.
Render To Texture iOS
/******************************************************************************
@File OGLESRenderToTexture.cpp
@Title RenderToTexture
@Version
@Copyright Copyright (C) Imagination Technologies Limited.
@Platform Independant
@Description Shows how to render to a pBuffer surface or FBO and bind that to a
texture.
******************************************************************************/
#include "PVRShell.h"
#include "OGLESTools.h"
/******************************************************************************
Content file names
******************************************************************************/
// Scene
/*
The .pod file was exported from 3DSMax using PVRGeoPOD.
*/
const char c_szSceneFile[] = "RenderToTexture.pod";
const char c_szMaskTex[] = "YellowWood.pvr";
/******************************************************************************
Defines
******************************************************************************/
#if !defined(EGL_VERSION_1_0) // Do we have access to EGL?
#if !defined(EGL_NOT_PRESENT)
#define EGL_NOT_PRESENT 1
#endif
#endif
/******************************************************************************
Consts
******************************************************************************/
// Camera constants. Used for making the projection matrix
const float g_fCameraNear = 4.0f;
const float g_fCameraFar = 500.0f;
const char* m_pFBODescription = "Using FBOs";
#if !defined(EGL_NOT_PRESENT)
const char *m_pPBufferDescription = "Using PBuffers";
#endif
/*****************************************************************************
Class implementing the PVRShell functions.
******************************************************************************/
class OGLESRenderToTexture : public PVRShell
{
// Print3D class used to display text
CPVRTPrint3D m_Print3D;
// Vertex Buffer Object (VBO) handles
GLuint* m_puiVbo;
GLuint* m_puiIndexVbo;
// 3D Model
CPVRTModelPOD m_Scene;
// Projection and Model View matrices
PVRTMat4 m_mProjection, m_mView;
PVRTMat4 m_mR2TProjection, m_mR2TView;
// Texture IDs used by the app
GLuint m_uiTextureID;
GLuint m_uiTextureToRenderTo;
// Variables used for the animation
float m_fAngleY;
// App Variables
int m_i32TexSize;
// Render contexts, etc
GLint m_i32OriginalFbo;
#if !defined(EGL_NOT_PRESENT)
EGLDisplay m_CurrentDisplay;
EGLContext m_CurrentContext;
EGLSurface m_CurrentSurface;
// We require a PBuffer surface.
EGLSurface m_PBufferSurface;
#endif
// If supported we require an FBO, which itself will require a depth buffer
GLuint m_uFBO;
GLuint m_uDepthBuffer;
enum
{
eNone,
#if !defined(EGL_NOT_PRESENT)
ePBuffer,
#endif
eFBO
} m_eR2TType;
CPVRTglesExt m_Extensions;
const char * m_pDescription;
// Discard the frame buffer attachments
bool m_bDiscard;
public:
OGLESRenderToTexture() : m_puiVbo(0),
m_puiIndexVbo(0),
m_uiTextureID(0),
m_uiTextureToRenderTo(0),
m_fAngleY(0),
m_i32OriginalFbo(0),
m_pDescription(0),
m_bDiscard(false)
{
}
// PVRShell functions
virtual bool InitApplication();
virtual bool InitView();
virtual bool ReleaseView();
virtual bool QuitApplication();
virtual bool RenderScene();
bool LoadVbos(CPVRTString* pErrorStr);
void DrawMesh(unsigned int ui32MeshID);
bool LoadTextures(CPVRTString* pErrorStr);
bool CreateFBOorPBuffer();
#if !defined(EGL_NOT_PRESENT)
EGLConfig SelectEGLConfig();
#endif
bool StartRenderToTexture();
bool EndRenderToTexture();
};
/*!****************************************************************************
@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 OGLESRenderToTexture::InitApplication()
{
// Get and set the read path for content files
CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
/*
Loads the scene from the .pod file into a CPVRTModelPOD object.
We could also export the scene as a header file and
load it with ReadFromMemory().
*/
if(m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
{
CPVRTString ErrorStr = "ERROR: Couldn't load '" + CPVRTString(c_szSceneFile) + "'.";
PVRShellSet(prefExitMessage, ErrorStr.c_str());
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 OGLESRenderToTexture::QuitApplication()
{
// Frees 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 OGLESRenderToTexture::InitView()
{
CPVRTString ErrorStr;
/*
Initialise 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;
}
// Enables texturing
glEnable(GL_TEXTURE_2D);
// Initialize VBO data
if(!LoadVbos(&ErrorStr))
{
PVRShellSet(prefExitMessage, ErrorStr.c_str());
return false;
}
/*
Load textures
*/
if(!LoadTextures(&ErrorStr))
{
PVRShellSet(prefExitMessage, ErrorStr.c_str());
return false;
}
// Create a FBO or PBuffer
if(!CreateFBOorPBuffer())
return false;
// Setup some render states
// Enable the depth test
glEnable(GL_DEPTH_TEST);
// Enable culling
glEnable(GL_CULL_FACE);
// Setup the material parameters our meshes will use
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, PVRTVec4(1.0f).ptr());
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, PVRTVec4(1.0f).ptr());
// Setup view and projection matrices used for when rendering to the texture
// Caculate the view matrix
m_mR2TView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 60), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0));
// Calculate the projection matrix
// Note: As we'll be rendering to a texture we don't need to take the screen rotation into account
m_mR2TProjection = PVRTMat4::PerspectiveFovRH(1, 1, g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, false);
// Setup view and projection matrices used for when rendering the main scene
// Caculate the view matrix
m_mView = PVRTMat4::LookAtRH(PVRTVec3(0, 0, 125), PVRTVec3(0, 0, 0), PVRTVec3(0, 1, 0));
// Calculate the projection matrix
m_mProjection = PVRTMat4::PerspectiveFovRH(PVRT_PI/6, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
return true;
}
/*!****************************************************************************
@Function LoadTextures
@Return bool true if no error occured
@Description Loads the textures required for this training course
******************************************************************************/
bool OGLESRenderToTexture::LoadTextures(CPVRTString* pErrorStr)
{
// Load the texture that our mask will have
if(PVRTTextureLoadFromPVR(c_szMaskTex, &m_uiTextureID) != PVR_SUCCESS)
{
*pErrorStr += "Failed to open ";
*pErrorStr += c_szMaskTex;
return false;
}
return true;
}
/*!****************************************************************************
@Function LoadVbos
@Description Loads the mesh data required for this training course into
vertex buffer objects
******************************************************************************/
bool OGLESRenderToTexture::LoadVbos(CPVRTString* pErrorStr)
{
if(m_Scene.nNumMesh == 0) // If there are no VBO to create return
return true;
if(!m_Scene.pMesh[0].pInterleaved)
{
*pErrorStr = "ERROR: RenderToTexture requires the pod data to be interleaved. Please re-export with the interleaved option enabled.";
return false;
}
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);
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 OGLESRenderToTexture::ReleaseView()
{
// Delete the texture
glDeleteTextures(1, &m_uiTextureID);
glDeleteTextures(1, &m_uiTextureToRenderTo);
// Release Print3D Textures
m_Print3D.ReleaseTextures();
// Tidy up 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 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
{
PVRShellSet(prefExitMessage, "ERROR: Required extension \"GL_OES_framebuffer_object\" not present.");
return false;
}
#endif
// Create a texture for rendering to
glGenTextures(1, &m_uiTextureToRenderTo);
glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_i32TexSize, m_i32TexSize, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create the surface or object that will allow us to render to the aforementioned texture
switch(m_eR2TType)
{
case eFBO: // Create FBO
{
m_Extensions.glGenFramebuffersOES(1, &m_uFBO);
m_Extensions.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_uFBO);
// Attach the texture to the FBO
m_Extensions.glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, m_uiTextureToRenderTo, 0);
// Attach the depth buffer we created earlier to our FBO.
m_Extensions.glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, m_uDepthBuffer);
// Check that our FBO creation was successful
GLuint uStatus = m_Extensions.glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if(uStatus != GL_FRAMEBUFFER_COMPLETE_OES)
{
PVRShellSet(prefExitMessage, "ERROR: Failed to initialise FBO");
return false;
}
// Clear the colour and depth buffers for the FBO
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Unbind the FBO now we are done with it
m_Extensions.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_i32OriginalFbo);
// Set the description used by Print3D later on
m_pDescription = m_pFBODescription;
}
break;
#if !defined(EGL_NOT_PRESENT)
case ePBuffer: // Create a PBuffer surface
{
//Using our attribute list and our egl configuration setup our PBuffer.
m_PBufferSurface = eglCreatePbufferSurface(m_CurrentDisplay, eglConfig, list);
// If we don't have a surface return false.
if(m_PBufferSurface == EGL_NO_SURFACE)
{
PVRShellSet(prefExitMessage, "ERROR: Failed to create pbuffer.");
return false;
}
// Switch the render target to the pBuffer
if(!eglMakeCurrent(m_CurrentDisplay, m_PBufferSurface, m_PBufferSurface, m_CurrentContext))
{
PVRShellSet(prefExitMessage, "ERROR: Unable to make the pbuffer context current.");
return false;
}
// Bind the texture to this surface
eglBindTexImage(m_CurrentDisplay, m_PBufferSurface, EGL_BACK_BUFFER);
// Set the description used by Print3D later on
m_pDescription = m_pPBufferDescription;
// Clear the colour and depth buffers for the PBuffer surface
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
break;
#endif
default: {}
}
return true;
}
/*!****************************************************************************
@Function StartRenderToTexture
@Return bool true if no error occured
@Description Setup the render to texture
******************************************************************************/
bool OGLESRenderToTexture::StartRenderToTexture()
{
switch(m_eR2TType)
{
case eFBO:
// Bind our FBO
m_Extensions.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_uFBO);
break;
#if !defined(EGL_NOT_PRESENT)
case ePBuffer:
// Switch the render target to the pBuffer
if(!eglMakeCurrent(m_CurrentDisplay, m_PBufferSurface, m_PBufferSurface, m_CurrentContext))
{
PVRShellSet(prefExitMessage, "ERROR: Unable to make the pbuffer context current.\n");
return false;
}
/*
As we would like to render to the surface we need to release it from
all the textures it is bound to. Once released the textures no longer
contain the contents of the surface.
*/
if(!eglReleaseTexImage(m_CurrentDisplay, m_PBufferSurface, EGL_BACK_BUFFER))
{
PVRShellSet(prefExitMessage, "ERROR: Failed to release m_PBufferSurface.\n");
return false;
}
break;
#endif
default: {}
}
return true;
}
/*!****************************************************************************
@Function EndRenderToTexture
@Return bool true if no error occured
@Description We have finished rendering to our texture. Switch rendering
back to the backbuffer.
******************************************************************************/
bool OGLESRenderToTexture::EndRenderToTexture()
{
switch(m_eR2TType)
{
case eFBO:
if(m_bDiscard) // Was GL_EXT_discard_framebuffer supported?
{
/*
Give the drivers a hint that we don't want the depth and stencil information stored for future use.
Note: This training course doesn't have any stencil information so the STENCIL_ATTACHMENT enum
is used for demonstrations purposes only and will be ignored by the driver.
*/
const GLenum attachments[] = { GL_DEPTH_ATTACHMENT_OES, GL_STENCIL_ATTACHMENT_OES };
m_Extensions.glDiscardFramebufferEXT(GL_FRAMEBUFFER_OES, 2, attachments);
}
// We are done with rendering to our FBO so switch back to the back buffer.
m_Extensions.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_i32OriginalFbo);
break;
#if !defined(EGL_NOT_PRESENT)
case ePBuffer:
// We are done with rendering to our PBuffer so we now switch back to the backbuffer.
if(!eglMakeCurrent(m_CurrentDisplay, m_CurrentSurface, m_CurrentSurface, m_CurrentContext))
{
PVRShellOutputDebug("ERROR: Unable to make the main context current.\n");
return false;
}
// To use the contents of our PBuffer as a texture we need to bind the two together
glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
if(!eglBindTexImage(m_CurrentDisplay, m_PBufferSurface, EGL_BACK_BUFFER))
{
PVRShellOutputDebug("ERROR: Failed to bind m_PBufferSurface.\n");
return false;
}
break;
#endif
default: {}
}
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 OGLESRenderToTexture::RenderScene()
{
// Enable the attribute arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
// Setup the lighting direction
// Enables lighting. See BasicTnL for a detailed explanation
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// Reads the light direction from the scene.
PVRTVec4 vLightDirection;
PVRTVec3 vPos;
m_Scene.GetLight(vPos, *(PVRTVec3*)&vLightDirection, 0);
vLightDirection.x = -vLightDirection.x;
vLightDirection.y = -vLightDirection.y;
vLightDirection.z = -vLightDirection.z;
vLightDirection.w = 0;
// Update out angle used for rotating the mask
PVRTMat4 mModel;
m_fAngleY += (2*PVRT_PI/60)/7;
// Setup everything needed to render to our texture
if(StartRenderToTexture())
{
// Setup the Viewport to the dimensions of the texture
glViewport(0, 0, m_i32TexSize, m_i32TexSize);
// Set the colour to clear our texture to
glClearColor(0.8f, 1.0f, 0.6f, 1.0f);
// Clear the colour and depth buffer of our FBO / PBuffer surface
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render our objects as we usually would
// Load the projection matrix we would like to use
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m_mR2TProjection.f);
// Switch to the MODELVIEW matrix mode
glMatrixMode(GL_MODELVIEW);
// Specify the view matrix to OpenGL ES so we can specify the light in world space
glLoadMatrixf(m_mR2TView.f);
// Set the light direction
glLightfv(GL_LIGHT0, GL_POSITION, vLightDirection.ptr());
// Set the model-view matrix
PVRTMat4 mModelView;
mModelView = m_mR2TView * PVRTMat4::RotationY(m_fAngleY);
glLoadMatrixf(mModelView.f);
// Bind the mask's texture
glBindTexture(GL_TEXTURE_2D, m_uiTextureID);
// Draw our mask
DrawMesh(m_Scene.pNode[0].nIdx);
// We're done rendering to texture so revert back to rendering to the back buffer
EndRenderToTexture();
}
// Set the clear colour
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
// Clear the colour and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Load the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m_mProjection.f);
glMatrixMode(GL_MODELVIEW);
// Specify the view matrix to OpenGL ES so we can specify the light in world space
glLoadMatrixf(m_mView.f);
// Set the light direction
glLightfv(GL_LIGHT0, GL_POSITION, vLightDirection.ptr());
// Setup the Viewport to the dimensions of the screen
glViewport(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
// Get the node model matrix
PVRTMat4 mWorld = m_Scene.GetWorldMatrix(m_Scene.pNode[1]);
// Set the model-view matrix
PVRTMat4 mModelView;
mModelView = m_mView * mWorld ;
glLoadMatrixf(mModelView.f);
// Bind our texture that we have rendered to
glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
// Draw our textured cube
DrawMesh(m_Scene.pNode[1].nIdx);
// Disable the vertex attribute arrays
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// Display the demo name using the tools. For a detailed explanation, see the training course IntroducingPVRTools
m_Print3D.DisplayDefaultTitle("RenderToTexture", m_pDescription, ePVRTPrint3DSDKLogo);
m_Print3D.Flush();
return true;
}
/*!****************************************************************************
@Function DrawMesh
@Input mesh The mesh to draw
@Description Draws a SPODMesh after the model view matrix has been set and
the meterial prepared.
******************************************************************************/
void OGLESRenderToTexture::DrawMesh(unsigned int ui32MeshID)
{
SPODMesh& Mesh = m_Scene.pMesh[ui32MeshID];
// bind the VBO for the mesh
glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[ui32MeshID]);
// bind the index buffer, won't hurt if the handle is 0
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[ui32MeshID]);
// Setup pointers
glVertexPointer(Mesh.sVertex.n, GL_FLOAT, Mesh.sVertex.nStride, Mesh.sVertex.pData);
glTexCoordPointer(Mesh.psUVW[0].n, GL_FLOAT, Mesh.psUVW[0].nStride, Mesh.psUVW[0].pData);
glNormalPointer(GL_FLOAT, Mesh.sNormals.nStride, Mesh.sNormals.pData);
// Indexed Triangle list
glDrawElements(GL_TRIANGLES, Mesh.nNumFaces * 3, GL_UNSIGNED_SHORT, 0);
}
#if !defined(EGL_NOT_PRESENT)
/*!****************************************************************************
@Function SelectEGLConfig
@Description Finds an EGL config with required options based on Mode Requested - for PBuffer
******************************************************************************/
EGLConfig OGLESRenderToTexture::SelectEGLConfig()
{
EGLConfig EglConfig = 0;
EGLint i32ConfigID;
EGLint i32BufferSize;
EGLint i32SampleBuffers;
EGLint i32Samples;
// Get the colour buffer size and the anti-aliasing parameters of the current surface so we can create
// a PBuffer surface that matches.
EGLDisplay eglDisplay = eglGetCurrentDisplay();
eglQueryContext(eglDisplay, eglGetCurrentContext(), EGL_CONFIG_ID, &i32ConfigID);
eglGetConfigAttrib(eglDisplay, (EGLConfig) (size_t) i32ConfigID, EGL_BUFFER_SIZE,&i32BufferSize);
eglGetConfigAttrib(eglDisplay, (EGLConfig) (size_t) i32ConfigID, EGL_SAMPLE_BUFFERS,&i32SampleBuffers);
eglGetConfigAttrib(eglDisplay, (EGLConfig) (size_t) i32ConfigID, EGL_SAMPLES,&i32Samples);
EGLint i32ConfigNo;
// Setup the configuration list for our surface.
EGLint conflist[] =
{
EGL_CONFIG_CAVEAT, EGL_NONE,
/*
Tell it the minimum size we want for our colour buffer, depth size and
anti-aliasing settings so eglChooseConfig will choose a config that is
a good match for our window context so we only need a single context.
*/
EGL_BUFFER_SIZE, i32BufferSize,
EGL_DEPTH_SIZE, 16,
EGL_SAMPLE_BUFFERS, i32SampleBuffers,
EGL_SAMPLES, i32Samples,
// The PBuffer bit is the important part as it shows we want a PBuffer
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
EGL_NONE
};
// Find and return the config
if(!eglChooseConfig(eglDisplay, conflist, &EglConfig, 1, &i32ConfigNo) || i32ConfigNo != 1)
{
PVRShellOutputDebug("Error: Failed to find a suitable config.\n");
return 0;
}
return EglConfig;
}
#endif
/*!****************************************************************************
@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 OGLESRenderToTexture();
}
/******************************************************************************
End of file (OGLESRenderToTexture.cpp)
******************************************************************************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment