1 /******************************************************************************
3 @File OGLES2ColourGrading.cpp
9 @Copyright Copyright (c) Imagination Technologies Limited.
13 @Description Demonstrates how to colour grade your render.
15 ******************************************************************************/
17 #include "OGLES2Tools.h"
19 /******************************************************************************
21 ******************************************************************************/
22 const char* const c_pszMaskTexture = "MaskTexture.pvr";
23 const char* const c_pszBackgroundTexture = "Background.pvr";
25 // Our colour lookup tables
26 const char* const c_pszLUTs[] =
35 "bluewhitegradient.pvr"
39 const char* const c_szFragShaderSrcFile = "FragShader.fsh";
40 const char* const c_szVertShaderSrcFile = "VertShader.vsh";
41 const char* const c_szSceneFragShaderSrcFile = "SceneFragShader.fsh";
42 const char* const c_szSceneVertShaderSrcFile = "SceneVertShader.vsh";
43 const char* const c_szBackgroundFragShaderSrcFile = "BackgroundFragShader.fsh";
46 const char c_szSceneFile[] = "Mask.pod";
48 // Camera constants. Used for making the projection matrix
49 const float CAM_FOV = PVRT_PI / 6;
50 const float CAM_NEAR = 4.0f;
51 const float CAM_FAR = 5000.0f;
53 // Index to bind the attributes to vertex shaders
54 const int VERTEX_ARRAY = 0;
55 const int TEXCOORD_ARRAY = 1;
56 const int NORMAL_ARRAY = 2;
58 // Look up table enumeration
71 // The range to cycle through
73 eB = eBlueWhiteGradient
76 const char* const c_pszLUTNames[] =
88 /*!****************************************************************************
89 Class implementing the PVRShell functions.
90 ******************************************************************************/
91 class OGLES2ColourGrading : public PVRShell
93 enum EMultisampleExtension
95 eMultisampleExtension_None,
96 eMultisampleExtension_IMG,
97 eMultisampleExtension_EXT
101 CPVRTPrint3D m_Print3D;
104 GLuint m_uiMaskTexture;
105 GLuint m_uiBackgroundTexture;
106 GLuint m_uiLUTs[eLast];
110 GLuint m_ui32FullScreenRectVBO;
112 // Stride for vertex data
113 unsigned int m_ui32VertexStride;
116 CPVRTModelPOD m_Mask;
117 GLuint* m_puiMaskVBO;
118 GLuint* m_puiMaskIBO;
120 GLuint m_ui32BackgroundVBO;
122 // Projection and view matrices
123 PVRTMat4 m_mViewProjection;
126 GLuint m_uiPostVertShader;
127 GLuint m_uiPostFragShader;
135 GLuint m_uiBackgroundFragShader;
141 m_BackgroundShaderProgram;
143 GLuint m_uiSceneVertShader;
144 GLuint m_uiSceneFragShader;
149 GLuint uiMVPMatrixLoc;
150 GLuint uiLightDirLoc;
151 GLuint uiMaterialBiasLoc;
152 GLuint uiMaterialScaleLoc;
154 m_SceneShaderProgram;
156 // Render contexts, etc
157 GLint m_i32OriginalFbo;
159 // Texture IDs used by the app
160 GLuint m_uiTextureToRenderTo;
161 GLuint m_uiDepthToRenderTo;
163 // Handle for our FBO and the depth buffer that it requires
166 // Handle for our multi-sampled FBO and the depth buffer that it requires
167 GLuint m_uiFBOMultisampled;
168 GLuint m_uiDepthBufferMultisampled;
169 GLuint m_uiColourBufferMultisampled;
172 unsigned long m_ulStartTime;
175 CPVRTgles2Ext m_Extensions;
177 // Discard the frame buffer attachments
179 bool m_bMultisampledSupported;
180 EMultisampleExtension m_eMultisampleMode;
183 OGLES2ColourGrading() :
185 m_uiBackgroundTexture(0),
187 m_ui32FullScreenRectVBO(0),
188 m_ui32VertexStride(0),
191 m_ui32BackgroundVBO(0),
192 m_uiPostVertShader(0),
193 m_uiPostFragShader(0),
194 m_uiBackgroundFragShader(0),
195 m_uiSceneVertShader(0),
196 m_uiSceneFragShader(0),
198 m_uiTextureToRenderTo(0),
199 m_uiDepthToRenderTo(0),
201 m_uiFBOMultisampled(0),
202 m_uiDepthBufferMultisampled(0),
203 m_uiColourBufferMultisampled(0),
206 m_bMultisampledSupported(false)
210 // PVRShell functions
211 virtual bool InitApplication();
212 virtual bool InitView();
213 virtual bool ReleaseView();
214 virtual bool QuitApplication();
215 virtual bool RenderScene();
218 bool LoadShaders(CPVRTString& ErrorStr);
220 void LoadVbos(const bool bRotated);
221 void DrawMesh(const int i32NodeIndex);
225 /*!****************************************************************************
226 @Function InitApplication
227 @Return bool true if no error occurred
228 @Description Code in InitApplication() will be called by PVRShell once per
229 run, before the rendering context is created.
230 Used to initialize variables that are not dependent on it
231 (e.g. external modules, loading meshes, etc.)
232 If the rendering context is lost, InitApplication() will
234 ******************************************************************************/
235 bool OGLES2ColourGrading::InitApplication()
237 // Get and set the read path for content files
238 CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
240 // Get and set the load/release functions for loading external files.
241 // In the majority of cases the PVRShell will return NULL function pointers implying that
242 // nothing special is required to load external files.
243 CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc));
246 if(m_Mask.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
248 PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
252 // Initialise some variables
253 m_puiMaskVBO = m_puiMaskIBO = 0;
258 /*!****************************************************************************
259 @Function QuitApplication
260 @Return bool true if no error occurred
261 @Description Code in QuitApplication() will be called by PVRShell once per
262 run, just before exiting the program.
263 If the rendering context is lost, QuitApplication() will
265 ******************************************************************************/
266 bool OGLES2ColourGrading::QuitApplication()
268 // Free the memory allocated for the scene
271 delete[] m_puiMaskVBO;
274 delete[] m_puiMaskIBO;
279 /*!****************************************************************************
280 @Function LoadEffects
281 @Output ErrorStr A description of an error, if one occurs.
282 @Return bool true if no error occurred
283 @Description Loads and parses the bundled PFX and generates the various
285 ******************************************************************************/
286 bool OGLES2ColourGrading::LoadShaders(CPVRTString& ErrorStr)
288 // Load and compile the shaders from files.
289 if(PVRTShaderLoadFromFile(NULL, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiPostVertShader, &ErrorStr) != PVR_SUCCESS)
294 if(PVRTShaderLoadFromFile(NULL, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiPostFragShader, &ErrorStr) != PVR_SUCCESS)
299 // Setup and link the shader program
300 const char* aszAttribs[] = { "inVertex", "inTexCoord" };
301 if(PVRTCreateProgram(&m_PostShaderProgram.uiId, m_uiPostVertShader, m_uiPostFragShader, aszAttribs, 2, &ErrorStr) != PVR_SUCCESS)
306 // Set the sampler variables to their respective texture unit
307 glUniform1i(glGetUniformLocation(m_PostShaderProgram.uiId, "sTexture"), 0);
308 glUniform1i(glGetUniformLocation(m_PostShaderProgram.uiId, "sColourLUT"), 1);
312 if(PVRTShaderLoadFromFile(NULL, c_szBackgroundFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiBackgroundFragShader, &ErrorStr) != PVR_SUCCESS)
317 // Set up and link the shader program re-using the vertex shader from the main shader program
318 const char* aszBackgroundAttribs[] = { "inVertex", "inTexCoord" };
319 if(PVRTCreateProgram(&m_BackgroundShaderProgram.uiId, m_uiPostVertShader, m_uiBackgroundFragShader, aszBackgroundAttribs, 2, &ErrorStr) != PVR_SUCCESS)
324 // Set the sampler2D variable to the first texture unit
325 glUniform1i(glGetUniformLocation(m_BackgroundShaderProgram.uiId, "sTexture"), 0);
327 // Scene shaders - Used for rendering the mask
328 if(PVRTShaderLoadFromFile(NULL, c_szSceneVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSceneVertShader, &ErrorStr) != PVR_SUCCESS)
333 if(PVRTShaderLoadFromFile(NULL, c_szSceneFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSceneFragShader, &ErrorStr) != PVR_SUCCESS)
338 // Setup and link the shader program
339 const char* aszSceneAttribs[] = { "inVertex", "inTexCoord", "inNormal" };
340 if (PVRTCreateProgram(&m_SceneShaderProgram.uiId, m_uiSceneVertShader, m_uiSceneFragShader, aszSceneAttribs, 3, &ErrorStr) != PVR_SUCCESS)
345 // Set the sampler2D variable to the first texture unit
346 glUniform1i(glGetUniformLocation(m_SceneShaderProgram.uiId, "sTexture"), 0);
348 // Store the location of uniforms for later use
349 m_SceneShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MVPMatrix");
350 m_SceneShaderProgram.uiLightDirLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "LightDirection");
351 m_SceneShaderProgram.uiMaterialBiasLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MaterialBias");
352 m_SceneShaderProgram.uiMaterialScaleLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MaterialScale");
354 // Set default shader material uniforms
355 float fSpecularConcentration = 0.6f; // a value from 0 to 1 (wider, concentrated)
356 float fSpecularIntensity = 0.3f; // a value from 0 to 1
359 glUniform1f(m_SceneShaderProgram.uiMaterialBiasLoc, fSpecularConcentration);
360 // Specular intensity scale
361 glUniform1f(m_SceneShaderProgram.uiMaterialScaleLoc, fSpecularIntensity / (1.0f - fSpecularConcentration));
366 /*!****************************************************************************
368 @Description Loads the mesh data required for this training course into
369 vertex buffer objects
370 ******************************************************************************/
371 void OGLES2ColourGrading::LoadVbos(const bool bRotated)
374 m_puiMaskVBO = new GLuint[m_Mask.nNumMesh];
377 m_puiMaskIBO = new GLuint[m_Mask.nNumMesh];
380 Load vertex data of all meshes in the scene into VBOs
382 The meshes have been exported with the "Interleave Vectors" option,
383 so all data is interleaved in the buffer at pMesh->pInterleaved.
384 Interleaving data improves the memory access pattern and cache efficiency,
385 thus it can be read faster by the hardware.
387 glGenBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
388 for(unsigned int i = 0; i < m_Mask.nNumMesh; ++i)
390 // Load vertex data into buffer object
391 SPODMesh& Mesh = m_Mask.pMesh[i];
392 unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
393 glBindBuffer(GL_ARRAY_BUFFER, m_puiMaskVBO[i]);
394 glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
396 // Load index data into buffer object if available
398 if (Mesh.sFaces.pData)
400 glGenBuffers(1, &m_puiMaskIBO[i]);
401 uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
402 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiMaskIBO[i]);
403 glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
407 // Create VBO for the fullscreen rect that we'll be rendering our FBO to
409 // Interleaved vertex data
410 GLfloat afVertices[] = {
412 -1.0f, 1.0f, 0.0f, 1.0f, // Pos
415 -1.0f, -1.0f, 0.0f, 1.0f,
418 0.0f, 1.0f, 0.0f, 1.0f,
421 0.0f, -1.0f, 0.0f, 1.0f,
424 1.0f, 1.0f, 0.0f, 1.0f,
427 1.0f, -1.0f, 0.0f, 1.0f,
431 if(bRotated) // If we're rotated then pre-process the fullscreen rect's geometry to compensate
433 for(unsigned int i = 0; i < 6; ++i)
435 float fTmp = afVertices[i * 6 + 1];
436 afVertices[i * 6 + 1] = afVertices[i * 6];
437 afVertices[i * 6] = fTmp;
439 fTmp = afVertices[i * 6 + 5];
440 afVertices[i * 6 + 5] = afVertices[i * 6 + 4];
441 afVertices[i * 6 + 4] = fTmp;
445 glGenBuffers(1, &m_ui32FullScreenRectVBO);
446 m_ui32VertexStride = 6 * sizeof(GLfloat); // 4 floats for the pos, 2 for the UVs
449 glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
451 // Set the buffer's data
452 glBufferData(GL_ARRAY_BUFFER, 6 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW);
454 // Create the VBO for the background
455 GLfloat afBackgroundVertices[] = {
457 -1.0f, 1.0f, 0.0f, 1.0f, // Pos
460 -1.0f, -1.0f, 0.0f, 1.0f,
463 1.0f, 1.0f, 0.0f, 1.0f,
466 1.0f, -1.0f, 0.0f, 1.0f,
470 if(bRotated) // If we're rotated then pre-process the background geometry
472 for(unsigned int i = 0; i < 4; ++i)
474 float fTmp = afBackgroundVertices[i * 6 + 1];
475 afBackgroundVertices[i * 6 + 1] = -afBackgroundVertices[i * 6];
476 afBackgroundVertices[i * 6] = -fTmp;
480 glGenBuffers(1, &m_ui32BackgroundVBO);
483 glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
485 // Set the buffer's data
486 glBufferData(GL_ARRAY_BUFFER, 4 * m_ui32VertexStride, afBackgroundVertices, GL_STATIC_DRAW);
488 // Unbind our buffers
489 glBindBuffer(GL_ARRAY_BUFFER, 0);
490 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
493 bool OGLES2ColourGrading::CreateFBO()
495 // Figure out if the platform supports either EXT or IMG extension
496 m_eMultisampleMode = eMultisampleExtension_IMG;
497 if(m_Extensions.glFramebufferTexture2DMultisampleEXT && m_Extensions.glRenderbufferStorageMultisampleEXT)
499 m_eMultisampleMode = eMultisampleExtension_EXT;
502 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
504 // Query the max amount of samples that are supported, we are going to use the max
506 glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
508 // Get the currently bound frame buffer object. On most platforms this just gives 0.
509 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo);
511 // Create a texture for rendering to
512 glGenTextures(1, &m_uiTextureToRenderTo);
513 glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
514 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, PVRShellGet(prefWidth), PVRShellGet(prefHeight), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
515 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
516 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
517 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
518 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
520 // Create the object that will allow us to render to the aforementioned texture
521 glGenFramebuffers(1, &m_uiFBO);
522 glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO);
524 // Attach the texture to the FBO
525 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureToRenderTo, 0);
526 if(!m_bMultisampledSupported)
528 glGenTextures(1, &m_uiDepthToRenderTo);
529 glBindTexture(GL_TEXTURE_2D, m_uiDepthToRenderTo);
\r
530 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
\r
531 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
\r
532 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, PVRShellGet(prefWidth), PVRShellGet(prefHeight), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0);
533 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiDepthToRenderTo, 0);
536 // Check that our FBO creation was successful
537 GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
538 if(uStatus != GL_FRAMEBUFFER_COMPLETE)
540 PVRShellSet(prefExitMessage, "ERROR: Failed to initialise FBO");
544 // Generate and bind a render buffer which will become a multisampled depth buffer shared between our two FBOs
545 if(m_bMultisampledSupported)
547 // Create and initialize the multi-sampled FBO.
549 // Create the object that will allow us to render to the aforementioned texture
550 glGenFramebuffers(1, &m_uiFBOMultisampled);
551 glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBOMultisampled);
553 glGenRenderbuffers(1, &m_uiDepthBufferMultisampled);
554 glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
556 if(m_eMultisampleMode == eMultisampleExtension_EXT)
557 m_Extensions.glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT16, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
559 m_Extensions.glRenderbufferStorageMultisampleIMG(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT16, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
561 glGenRenderbuffers(1, &m_uiColourBufferMultisampled);
562 glBindRenderbuffer(GL_RENDERBUFFER, m_uiColourBufferMultisampled);
563 if(m_eMultisampleMode == eMultisampleExtension_EXT)
564 m_Extensions.glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGB, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
566 m_Extensions.glRenderbufferStorageMultisampleIMG(GL_RENDERBUFFER, samples, GL_RGB, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
568 glBindRenderbuffer(GL_RENDERBUFFER, 0);
570 // Attach the multisampled depth buffer we created earlier to our FBO.
571 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
573 // Attach the multisampled colour renderbuffer to the FBO
574 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_uiColourBufferMultisampled);
576 // Check that our FBO creation was successful
577 uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
578 if(uStatus != GL_FRAMEBUFFER_COMPLETE)
580 PVRShellSet(prefExitMessage, "ERROR: Failed to initialise multisampled FBO");
585 // Unbind the frame buffer object so rendering returns back to the backbuffer
586 glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
591 /*!****************************************************************************
593 @Return bool true if no error occurred
594 @Description Code in InitView() will be called by PVRShell upon
595 initialization or after a change in the rendering context.
596 Used to initialize variables that are dependent on the rendering
597 context (e.g. textures, vertex buffers, etc.)
598 ******************************************************************************/
599 bool OGLES2ColourGrading::InitView()
601 m_Extensions.LoadExtensions();
603 // Initialize the textures used by Print3D.
604 bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
606 if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
608 PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
612 // Create the texture
613 if(PVRTTextureLoadFromPVR(c_pszMaskTexture, &m_uiMaskTexture) != PVR_SUCCESS)
615 PVRShellSet(prefExitMessage, "ERROR: Failed to load mask texture\n");
619 if(PVRTTextureLoadFromPVR(c_pszBackgroundTexture, &m_uiBackgroundTexture) != PVR_SUCCESS)
621 PVRShellSet(prefExitMessage, "ERROR: Failed to load background texture\n");
625 // Load our 3D texture look up tables
626 for(unsigned int i = 0; i < eLast; ++i)
628 if(PVRTTextureLoadFromPVR(c_pszLUTs[i], &m_uiLUTs[i]) != PVR_SUCCESS)
630 PVRShellSet(prefExitMessage, "ERROR: Failed to load a 3D texture\n");
634 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
635 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
636 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_WRAP_R_OES, GL_CLAMP_TO_EDGE);
638 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
639 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
643 CPVRTString ErrorStr;
644 if(!LoadShaders(ErrorStr))
646 PVRShellSet(prefExitMessage, ErrorStr.c_str());
650 // Create a multisampled FBO if the required extension is supported
651 m_eMultisampleMode = eMultisampleExtension_None;
652 m_bMultisampledSupported = false;
653 m_bMultisampledSupported |= CPVRTgles2Ext::IsGLExtensionSupported("GL_EXT_multisampled_render_to_texture");
654 m_bMultisampledSupported |= CPVRTgles2Ext::IsGLExtensionSupported("GL_IMG_multisampled_render_to_texture");
659 PVRShellSet(prefExitMessage, "Failed to create FBO");
663 // Check to see if the GL_EXT_discard_framebuffer extension is supported
664 m_bDiscard = CPVRTgles2Ext::IsGLExtensionSupported("GL_EXT_discard_framebuffer");
667 m_bDiscard = m_Extensions.glDiscardFramebufferEXT != 0;
670 // Initialise VBO data
673 // Calculate the projection and view matrices
674 float fAspect = PVRShellGet(prefWidth) / (float)PVRShellGet(prefHeight);
675 m_mViewProjection = PVRTMat4::PerspectiveFovRH(CAM_FOV, fAspect, CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
676 m_mViewProjection *= PVRTMat4::LookAtRH(PVRTVec3(0.f, 0.f, 150.f), PVRTVec3(0.f), PVRTVec3(0.f, 1.f, 0.f));
678 // Enable backface culling and depth test
679 glEnable(GL_CULL_FACE);
680 glEnable(GL_DEPTH_TEST);
682 // Set the clear colour
683 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
685 // Store initial time
686 m_ulStartTime = PVRShellGetTime();
691 /*!****************************************************************************
692 @Function ReleaseView
693 @Return bool true if no error occurred
694 @Description Code in ReleaseView() will be called by PVRShell when the
695 application quits or before a change in the rendering context.
696 ******************************************************************************/
697 bool OGLES2ColourGrading::ReleaseView()
700 glDeleteTextures(1, &m_uiMaskTexture);
701 glDeleteTextures(1, &m_uiBackgroundTexture);
702 glDeleteTextures(eLast, m_uiLUTs);
703 glDeleteTextures(1, &m_uiTextureToRenderTo);
704 glDeleteTextures(1, &m_uiDepthToRenderTo);
706 // Release Vertex buffer object.
707 glDeleteBuffers(1, &m_ui32FullScreenRectVBO);
708 glDeleteBuffers(1, &m_ui32BackgroundVBO);
711 glDeleteShader(m_uiPostVertShader);
712 glDeleteShader(m_uiPostFragShader);
713 glDeleteShader(m_uiBackgroundFragShader);
714 glDeleteShader(m_uiSceneVertShader);
715 glDeleteShader(m_uiSceneFragShader);
717 glDeleteProgram(m_PostShaderProgram.uiId);
718 glDeleteProgram(m_BackgroundShaderProgram.uiId);
719 glDeleteProgram(m_SceneShaderProgram.uiId);
721 // Tidy up the FBOs and renderbuffers
723 // Delete frame buffer objects
724 glDeleteFramebuffers(1, &m_uiFBO);
725 glDeleteFramebuffers(1, &m_uiFBOMultisampled);
727 // Delete our depth buffer
728 glDeleteRenderbuffers(1, &m_uiDepthBufferMultisampled);
729 glDeleteRenderbuffers(1, &m_uiColourBufferMultisampled);
731 // Delete buffer objects
732 glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
733 glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskIBO);
735 // Release Print3D Textures
736 m_Print3D.ReleaseTextures();
741 /*!****************************************************************************
742 @Function RenderScene
743 @Return bool true if no error occurred
744 @Description Main rendering loop function of the program. The shell will
745 call this function every frame.
746 eglSwapBuffers() will be performed by PVRShell automatically.
747 PVRShell will also manage important OS events.
748 Will also manage relevant OS events. The user has access to
749 these events through an abstraction layer provided by PVRShell.
750 ******************************************************************************/
751 bool OGLES2ColourGrading::RenderScene()
753 // Clears the colour buffer
754 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
756 unsigned long ulTime = PVRShellGetTime() - m_ulStartTime;
758 // Process input to switch between tone mapping operators
759 if(PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
763 if(m_iCurrentLUT > eB)
766 else if(PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
770 if(m_iCurrentLUT < eA)
774 // Render to our texture
777 glBindFramebuffer(GL_FRAMEBUFFER, m_bMultisampledSupported ? m_uiFBOMultisampled : m_uiFBO);
779 // Clear the colour and depth buffer of our FBO surface
780 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
782 glDisable(GL_CULL_FACE);
783 glDisable(GL_DEPTH_TEST);
786 glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
788 // Use shader program
789 glUseProgram(m_BackgroundShaderProgram.uiId);
791 // Enable the vertex attribute arrays
792 glEnableVertexAttribArray(VERTEX_ARRAY);
793 glEnableVertexAttribArray(TEXCOORD_ARRAY);
795 // Set the vertex attribute offsets
796 glVertexAttribPointer(VERTEX_ARRAY, 4, GL_FLOAT, GL_FALSE, m_ui32VertexStride, 0);
797 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, m_ui32VertexStride, (void*) (4 * sizeof(GLfloat)));
800 glActiveTexture(GL_TEXTURE0);
801 glBindTexture(GL_TEXTURE_2D, m_uiBackgroundTexture);
803 // Draw a screen-aligned quad.
805 // Draws a non-indexed triangle array
806 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
808 // Safely disable the vertex attribute arrays
809 glDisableVertexAttribArray(VERTEX_ARRAY);
810 glDisableVertexAttribArray(TEXCOORD_ARRAY);
812 glEnable(GL_CULL_FACE);
813 glEnable(GL_DEPTH_TEST);
815 // Use shader program
816 glUseProgram(m_SceneShaderProgram.uiId);
818 // Rotate the model matrix
819 PVRTMat4 mModel = PVRTMat4::RotationY(ulTime * 0.0015f);
821 // Calculate model view projection matrix
822 PVRTMat4 mMVP = m_mViewProjection * mModel;
824 // Feeds Projection Model View matrix to the shaders
825 glUniformMatrix4fv(m_SceneShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr());
827 PVRTVec3 vMsLightDir = (PVRTVec3(1, 1, 1) * PVRTMat3(mModel)).normalized();
828 glUniform3fv(m_SceneShaderProgram.uiLightDirLoc, 1, vMsLightDir.ptr());
830 glBindTexture(GL_TEXTURE_2D, m_uiMaskTexture);
832 // Now that the uniforms are set, call another function to actually draw the mesh.
836 glBindBuffer(GL_ARRAY_BUFFER, 0);
838 if(m_bDiscard) // Was GL_EXT_discard_framebuffer supported?
841 Give the drivers a hint that we don't want the depth and stencil information stored for future use.
843 Note: This training course doesn't have any stencil information so the STENCIL_ATTACHMENT enum
844 is used for demonstrations purposes only and will be ignored by the driver.
846 const GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
847 m_Extensions.glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
850 // Blit and resolve the multisampled render buffer to the non-multisampled FBO
851 if(m_bMultisampledSupported)
853 glBindFramebuffer(GL_READ_FRAMEBUFFER_NV, m_uiFBOMultisampled);
854 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_NV, m_uiFBO);
855 return false; // FIXME: fix the multisampling path by adding a blit function below
856 //glBlitFramebuffer(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), 0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), GL_COLOR_BUFFER_BIT, GL_NEAREST);
859 // We are done with rendering to our FBO so switch back to the back buffer.
860 glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
863 GLenum error = glGetError();
865 glDisable(GL_CULL_FACE);
866 glDisable(GL_DEPTH_TEST);
868 error = glGetError();
870 // Use shader program
871 glUseProgram(m_PostShaderProgram.uiId);
874 glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
876 error = glGetError();
878 // Enable the vertex attribute arrays
879 glEnableVertexAttribArray(VERTEX_ARRAY);
880 glEnableVertexAttribArray(TEXCOORD_ARRAY);
882 error = glGetError();
884 // Set the vertex attribute offsets
885 glVertexAttribPointer(VERTEX_ARRAY, 4, GL_FLOAT, GL_FALSE, m_ui32VertexStride, 0);
886 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, m_ui32VertexStride, (void*) (4 * sizeof(GLfloat)));
888 error = glGetError();
891 glActiveTexture(GL_TEXTURE0);
892 glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
894 error = glGetError();
896 glActiveTexture(GL_TEXTURE1);
897 glBindTexture(GL_TEXTURE_3D_OES, m_uiLUTs[m_iCurrentLUT]);
899 error = glGetError();
901 // Draw a screen-aligned quad.
903 // Draw the left-hand side that shows the scene with the colour grading applied
904 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
906 // Draw the right-hande side showing the scene how it looks without
907 glBindTexture(GL_TEXTURE_3D_OES, m_uiLUTs[eIdentity]);
908 glDrawArrays(GL_TRIANGLE_STRIP, 2, 4);
910 // Safely disable the vertex attribute arrays
911 glDisableVertexAttribArray(VERTEX_ARRAY);
912 glDisableVertexAttribArray(TEXCOORD_ARRAY);
915 glBindBuffer(GL_ARRAY_BUFFER, 0);
918 m_Print3D.DisplayDefaultTitle("Colour grading using 3D textures", c_pszLUTNames[m_iCurrentLUT], ePVRTPrint3DSDKLogo);
924 /*!****************************************************************************
926 @Input i32NodeIndex Node index of the mesh to draw
927 @Description Draws a SPODMesh after the model view matrix has been set and
928 the material prepared.
929 ******************************************************************************/
930 void OGLES2ColourGrading::DrawMesh(const int i32NodeIndex)
932 int i32MeshIndex = m_Mask.pNode[i32NodeIndex].nIdx;
933 SPODMesh* pMesh = &m_Mask.pMesh[i32MeshIndex];
935 // bind the VBO for the mesh
936 glBindBuffer(GL_ARRAY_BUFFER, m_puiMaskVBO[i32MeshIndex]);
937 // bind the index buffer, won't hurt if the handle is 0
938 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiMaskIBO[i32MeshIndex]);
940 // Enable the vertex attribute arrays
941 glEnableVertexAttribArray(VERTEX_ARRAY);
942 glEnableVertexAttribArray(NORMAL_ARRAY);
943 glEnableVertexAttribArray(TEXCOORD_ARRAY);
945 // Set the vertex attribute offsets
946 glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
947 glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
948 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
950 // Indexed Triangle list
951 glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
953 // Safely disable the vertex attribute arrays
954 glDisableVertexAttribArray(VERTEX_ARRAY);
955 glDisableVertexAttribArray(NORMAL_ARRAY);
956 glDisableVertexAttribArray(TEXCOORD_ARRAY);
958 glBindBuffer(GL_ARRAY_BUFFER, 0);
959 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
962 /*!****************************************************************************
964 @Return PVRShell* The demo supplied by the user
965 @Description This function must be implemented by the user of the shell.
966 The user should return its PVRShell object defining the
967 behaviour of the application.
968 ******************************************************************************/
971 return new OGLES2ColourGrading();
974 /******************************************************************************
975 End of file (OGLES2ColourGrading.cpp)
976 ******************************************************************************/