1 /******************************************************************************
2
3 @File OGLES3ColourGrading.cpp
4
5 @Title Colour grading
6
7 @Version
8
9 @Copyright Copyright (c) Imagination Technologies Limited.
10
11 @Platform Independent
12
13 @Description Demonstrates how to colour grade your render.
14
15 ******************************************************************************/
16 #include "PVRShell.h"
17 #include "OGLES3Tools.h"
18
19 /******************************************************************************
20 Constants
21 ******************************************************************************/
22 const char* const c_pszMaskTexture = "MaskTexture.pvr";
23 const char* const c_pszBackgroundTexture = "Background.pvr";
24
25 // Our colour lookup tables
26 const char* const c_pszLUTs[] =
27 {
28 "identity.pvr",
29 "bw.pvr",
30 "cooler.pvr",
31 "warmer.pvr",
32 "sepia.pvr",
33 "inverted.pvr",
34 "highcontrast.pvr",
35 "bluewhitegradient.pvr"
36 };
37
38 // Shader source
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";
44
45 // POD scene files
46 const char c_szSceneFile[] = "Mask.pod";
47
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;
52
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;
57
58 // Look up table enumeration
59 enum ELUTs
60 {
61 eIdentity,
62 eBW,
63 eCooler,
64 eWarmer,
65 eSepia,
66 eInverted,
67 eHighContrast,
68 eBlueWhiteGradient,
69 eLast,
70
71 // The range to cycle through
72 eA = eBW,
73 eB = eBlueWhiteGradient
74 };
75
76 const char* const c_pszLUTNames[] =
77 {
78 "Identity",
79 "Black and white",
80 "Cooler",
81 "Warmer",
82 "Sepia",
83 "Inverted",
84 "High Contrast",
85 "Blue White Gradient"
86 };
87
88 /*!****************************************************************************
89 Class implementing the PVRShell functions.
90 ******************************************************************************/
91 class OGLES3ColourGrading : public PVRShell
92 {
93 // Print3D object
94 CPVRTPrint3D m_Print3D;
95
96 // Texture handle
97 GLuint m_uiMaskTexture;
98 GLuint m_uiBackgroundTexture;
99 GLuint m_uiLUTs[eLast];
100 int m_iCurrentLUT;
101
102 // VBO handle
103 GLuint m_ui32FullScreenRectVBO;
104
105 // Stride for vertex data
106 unsigned int m_ui32VertexStride;
107
108 // 3D Model
109 CPVRTModelPOD m_Mask;
110 GLuint* m_puiMaskVBO;
111 GLuint* m_puiMaskIBO;
112
113 GLuint m_ui32BackgroundVBO;
114
115 // Projection and view matrices
116 PVRTMat4 m_mViewProjection;
117
118 // Shaders
119 GLuint m_uiPostVertShader;
120 GLuint m_uiPostFragShader;
121
122 struct
123 {
124 GLuint uiId;
125 }
126 m_PostShaderProgram;
127
128 GLuint m_uiBackgroundFragShader;
129
130 struct
131 {
132 GLuint uiId;
133 }
134 m_BackgroundShaderProgram;
135
136 GLuint m_uiSceneVertShader;
137 GLuint m_uiSceneFragShader;
138
139 struct
140 {
141 GLuint uiId;
142 GLuint uiMVPMatrixLoc;
143 GLuint uiLightDirLoc;
144 GLuint uiMaterialBiasLoc;
145 GLuint uiMaterialScaleLoc;
146 }
147 m_SceneShaderProgram;
148
149 // Render contexts, etc
150 GLint m_i32OriginalFbo;
151
152 // Texture IDs used by the app
153 GLuint m_uiTextureToRenderTo;
154
155 // Handle for our FBO and the depth buffer that it requires
156 GLuint m_uiFBO;
157
158 // Handle for our multi-sampled FBO and the depth buffer that it requires
159 GLuint m_uiFBOMultisampled;
160 GLuint m_uiDepthBufferMultisampled;
161 GLuint m_uiColourBufferMultisampled;
162
163 // Start time
164 unsigned long m_ulStartTime;
165
166 public:
167 // PVRShell functions
168 virtual bool InitApplication();
169 virtual bool InitView();
170 virtual bool ReleaseView();
171 virtual bool QuitApplication();
172 virtual bool RenderScene();
173
174 private:
175 bool LoadShaders(CPVRTString& ErrorStr);
176 bool CreateFBO();
177 void LoadVbos(const bool bRotated);
178 void DrawMesh(const int i32NodeIndex);
179 };
180
181
182 /*!****************************************************************************
183 @Function InitApplication
184 @Return bool true if no error occurred
185 @Description Code in InitApplication() will be called by PVRShell once per
186 run, before the rendering context is created.
187 Used to initialize variables that are not dependent on it
188 (e.g. external modules, loading meshes, etc.)
189 If the rendering context is lost, InitApplication() will
190 not be called again.
191 ******************************************************************************/
InitApplication()192 bool OGLES3ColourGrading::InitApplication()
193 {
194 // Get and set the read path for content files
195 CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
196
197 // Get and set the load/release functions for loading external files.
198 // In the majority of cases the PVRShell will return NULL function pointers implying that
199 // nothing special is required to load external files.
200 CPVRTResourceFile::SetLoadReleaseFunctions(PVRShellGet(prefLoadFileFunc), PVRShellGet(prefReleaseFileFunc));
201
202 // Load the scene
203 if(m_Mask.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
204 {
205 PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
206 return false;
207 }
208
209 // Initialise some variables
210 m_puiMaskVBO = m_puiMaskIBO = 0;
211 m_iCurrentLUT = eA;
212 return true;
213 }
214
215 /*!****************************************************************************
216 @Function QuitApplication
217 @Return bool true if no error occurred
218 @Description Code in QuitApplication() will be called by PVRShell once per
219 run, just before exiting the program.
220 If the rendering context is lost, QuitApplication() will
221 not be called.
222 ******************************************************************************/
QuitApplication()223 bool OGLES3ColourGrading::QuitApplication()
224 {
225 // Free the memory allocated for the scene
226 m_Mask.Destroy();
227
228 delete[] m_puiMaskVBO;
229 m_puiMaskVBO = 0;
230
231 delete[] m_puiMaskIBO;
232 m_puiMaskIBO = 0;
233 return true;
234 }
235
236 /*!****************************************************************************
237 @Function LoadEffects
238 @Output ErrorStr A description of an error, if one occurs.
239 @Return bool true if no error occurred
240 @Description Loads and parses the bundled PFX and generates the various
241 effect objects.
242 ******************************************************************************/
LoadShaders(CPVRTString & ErrorStr)243 bool OGLES3ColourGrading::LoadShaders(CPVRTString& ErrorStr)
244 {
245 // Load and compile the shaders from files.
246 if(PVRTShaderLoadFromFile(NULL, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiPostVertShader, &ErrorStr) != PVR_SUCCESS)
247 {
248 return false;
249 }
250
251 if(PVRTShaderLoadFromFile(NULL, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiPostFragShader, &ErrorStr) != PVR_SUCCESS)
252 {
253 return false;
254 }
255
256 // Setup and link the shader program
257 const char* aszAttribs[] = { "inVertex", "inTexCoord" };
258 if(PVRTCreateProgram(&m_PostShaderProgram.uiId, m_uiPostVertShader, m_uiPostFragShader, aszAttribs, 2, &ErrorStr) != PVR_SUCCESS)
259 {
260 return false;
261 }
262
263 // Set the sampler variables to their respective texture unit
264 glUniform1i(glGetUniformLocation(m_PostShaderProgram.uiId, "sTexture"), 0);
265 glUniform1i(glGetUniformLocation(m_PostShaderProgram.uiId, "sColourLUT"), 1);
266
267 // Background shader
268
269 if(PVRTShaderLoadFromFile(NULL, c_szBackgroundFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiBackgroundFragShader, &ErrorStr) != PVR_SUCCESS)
270 {
271 return false;
272 }
273
274 // Set up and link the shader program re-using the vertex shader from the main shader program
275 const char* aszBackgroundAttribs[] = { "inVertex", "inTexCoord" };
276 if(PVRTCreateProgram(&m_BackgroundShaderProgram.uiId, m_uiPostVertShader, m_uiBackgroundFragShader, aszBackgroundAttribs, 2, &ErrorStr) != PVR_SUCCESS)
277 {
278 return false;
279 }
280
281 // Set the sampler2D variable to the first texture unit
282 glUniform1i(glGetUniformLocation(m_BackgroundShaderProgram.uiId, "sTexture"), 0);
283
284 // Scene shaders - Used for rendering the mask
285 if(PVRTShaderLoadFromFile(NULL, c_szSceneVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSceneVertShader, &ErrorStr) != PVR_SUCCESS)
286 {
287 return false;
288 }
289
290 if(PVRTShaderLoadFromFile(NULL, c_szSceneFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSceneFragShader, &ErrorStr) != PVR_SUCCESS)
291 {
292 return false;
293 }
294
295 // Setup and link the shader program
296 const char* aszSceneAttribs[] = { "inVertex", "inTexCoord", "inNormal" };
297 if (PVRTCreateProgram(&m_SceneShaderProgram.uiId, m_uiSceneVertShader, m_uiSceneFragShader, aszSceneAttribs, 3, &ErrorStr) != PVR_SUCCESS)
298 {
299 return false;
300 }
301
302 // Set the sampler2D variable to the first texture unit
303 glUniform1i(glGetUniformLocation(m_SceneShaderProgram.uiId, "sTexture"), 0);
304
305 // Store the location of uniforms for later use
306 m_SceneShaderProgram.uiMVPMatrixLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MVPMatrix");
307 m_SceneShaderProgram.uiLightDirLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "LightDirection");
308 m_SceneShaderProgram.uiMaterialBiasLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MaterialBias");
309 m_SceneShaderProgram.uiMaterialScaleLoc = glGetUniformLocation(m_SceneShaderProgram.uiId, "MaterialScale");
310
311 // Set default shader material uniforms
312 float fSpecularConcentration = 0.6f; // a value from 0 to 1 (wider, concentrated)
313 float fSpecularIntensity = 0.3f; // a value from 0 to 1
314
315 // Specular bias
316 glUniform1f(m_SceneShaderProgram.uiMaterialBiasLoc, fSpecularConcentration);
317 // Specular intensity scale
318 glUniform1f(m_SceneShaderProgram.uiMaterialScaleLoc, fSpecularIntensity / (1.0f - fSpecularConcentration));
319
320 return true;
321 }
322
323 /*!****************************************************************************
324 @Function LoadVbos
325 @Description Loads the mesh data required for this training course into
326 vertex buffer objects
327 ******************************************************************************/
LoadVbos(const bool bRotated)328 void OGLES3ColourGrading::LoadVbos(const bool bRotated)
329 {
330 if(!m_puiMaskVBO)
331 m_puiMaskVBO = new GLuint[m_Mask.nNumMesh];
332
333 if(!m_puiMaskIBO)
334 m_puiMaskIBO = new GLuint[m_Mask.nNumMesh];
335
336 /*
337 Load vertex data of all meshes in the scene into VBOs
338
339 The meshes have been exported with the "Interleave Vectors" option,
340 so all data is interleaved in the buffer at pMesh->pInterleaved.
341 Interleaving data improves the memory access pattern and cache efficiency,
342 thus it can be read faster by the hardware.
343 */
344 glGenBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
345 for(unsigned int i = 0; i < m_Mask.nNumMesh; ++i)
346 {
347 // Load vertex data into buffer object
348 SPODMesh& Mesh = m_Mask.pMesh[i];
349 unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
350 glBindBuffer(GL_ARRAY_BUFFER, m_puiMaskVBO[i]);
351 glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
352
353 // Load index data into buffer object if available
354 m_puiMaskIBO[i] = 0;
355 if (Mesh.sFaces.pData)
356 {
357 glGenBuffers(1, &m_puiMaskIBO[i]);
358 uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
359 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiMaskIBO[i]);
360 glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
361 }
362 }
363
364 // Create VBO for the fullscreen rect that we'll be rendering our FBO to
365
366 // Interleaved vertex data
367 GLfloat afVertices[] = {
368 // Left quad
369 -1.0f, 1.0f, 0.0f, 1.0f, // Pos
370 0.0f, 1.0f, // UVs
371
372 -1.0f, -1.0f, 0.0f, 1.0f,
373 0.0f, 0.0f,
374
375 0.0f, 1.0f, 0.0f, 1.0f,
376 0.5f, 1.0f,
377
378 0.0f, -1.0f, 0.0f, 1.0f,
379 0.5f, 0.0f,
380
381 1.0f, 1.0f, 0.0f, 1.0f,
382 1.0f, 1.0f,
383
384 1.0f, -1.0f, 0.0f, 1.0f,
385 1.0f, 0.0f,
386 };
387
388 if(bRotated) // If we're rotated then pre-process the fullscreen rect's geometry to compensate
389 {
390 for(unsigned int i = 0; i < 6; ++i)
391 {
392 float fTmp = afVertices[i * 6 + 1];
393 afVertices[i * 6 + 1] = afVertices[i * 6];
394 afVertices[i * 6] = fTmp;
395
396 fTmp = afVertices[i * 6 + 5];
397 afVertices[i * 6 + 5] = afVertices[i * 6 + 4];
398 afVertices[i * 6 + 4] = fTmp;
399 }
400 }
401
402 glGenBuffers(1, &m_ui32FullScreenRectVBO);
403 m_ui32VertexStride = 6 * sizeof(GLfloat); // 4 floats for the pos, 2 for the UVs
404
405 // Bind the VBO
406 glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
407
408 // Set the buffer's data
409 glBufferData(GL_ARRAY_BUFFER, 6 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW);
410
411 // Create the VBO for the background
412 GLfloat afBackgroundVertices[] = {
413 // Left quad
414 -1.0f, 1.0f, 0.0f, 1.0f, // Pos
415 0.0f, 1.0f, // UVs
416
417 -1.0f, -1.0f, 0.0f, 1.0f,
418 0.0f, 0.0f,
419
420 1.0f, 1.0f, 0.0f, 1.0f,
421 1.0f, 1.0f,
422
423 1.0f, -1.0f, 0.0f, 1.0f,
424 1.0f, 0.0f,
425 };
426
427 if(bRotated) // If we're rotated then pre-process the background geometry
428 {
429 for(unsigned int i = 0; i < 4; ++i)
430 {
431 float fTmp = afBackgroundVertices[i * 6 + 1];
432 afBackgroundVertices[i * 6 + 1] = -afBackgroundVertices[i * 6];
433 afBackgroundVertices[i * 6] = -fTmp;
434 }
435 }
436
437 glGenBuffers(1, &m_ui32BackgroundVBO);
438
439 // Bind the VBO
440 glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
441
442 // Set the buffer's data
443 glBufferData(GL_ARRAY_BUFFER, 4 * m_ui32VertexStride, afBackgroundVertices, GL_STATIC_DRAW);
444
445 // Unbind our buffers
446 glBindBuffer(GL_ARRAY_BUFFER, 0);
447 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
448 }
449
CreateFBO()450 bool OGLES3ColourGrading::CreateFBO()
451 {
452 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
453
454 // Query the max amount of samples that are supported, we are going to use the max
455 GLint samples;
456 glGetIntegerv(GL_MAX_SAMPLES, &samples);
457
458 // Get the currently bound frame buffer object. On most platforms this just gives 0.
459 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo);
460
461 // Create a texture for rendering to
462 glGenTextures(1, &m_uiTextureToRenderTo);
463 glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
464 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, PVRShellGet(prefWidth), PVRShellGet(prefHeight), 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
465 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
466 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
467 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
468 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
469
470 // Create the object that will allow us to render to the aforementioned texture
471 glGenFramebuffers(1, &m_uiFBO);
472 glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBO);
473
474 glDrawBuffers(1, drawBuffers);
475 glReadBuffer(GL_COLOR_ATTACHMENT0);
476
477 // Attach the texture to the FBO
478 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureToRenderTo, 0);
479
480 // Check that our FBO creation was successful
481 GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
482 if(uStatus != GL_FRAMEBUFFER_COMPLETE)
483 {
484 PVRShellSet(prefExitMessage, "ERROR: Failed to initialise FBO");
485 return false;
486 }
487
488 // Create and initialize the multi-sampled FBO.
489
490 // Create the object that will allow us to render to the aforementioned texture
491 glGenFramebuffers(1, &m_uiFBOMultisampled);
492 glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBOMultisampled);
493
494 glDrawBuffers(1, drawBuffers);
495 glReadBuffer(GL_COLOR_ATTACHMENT0);
496
497 // Generate and bind a render buffer which will become a multisampled depth buffer shared between our two FBOs
498 glGenRenderbuffers(1, &m_uiDepthBufferMultisampled);
499 glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
500 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT24, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
501
502 glGenRenderbuffers(1, &m_uiColourBufferMultisampled);
503 glBindRenderbuffer(GL_RENDERBUFFER, m_uiColourBufferMultisampled);
504 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGB8, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
505 glBindRenderbuffer(GL_RENDERBUFFER, 0);
506
507 // Attach the multisampled depth buffer we created earlier to our FBO.
508 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
509
510 // Attach the multisampled colour renderbuffer to the FBO
511 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_uiColourBufferMultisampled);
512
513 // Check that our FBO creation was successful
514 uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
515 if(uStatus != GL_FRAMEBUFFER_COMPLETE)
516 {
517 PVRShellSet(prefExitMessage, "ERROR: Failed to initialise multisampled FBO");
518 return false;
519 }
520
521 // Unbind the frame buffer object so rendering returns back to the backbuffer
522 glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
523
524 return true;
525 }
526
527 /*!****************************************************************************
528 @Function InitView
529 @Return bool true if no error occurred
530 @Description Code in InitView() will be called by PVRShell upon
531 initialization or after a change in the rendering context.
532 Used to initialize variables that are dependent on the rendering
533 context (e.g. textures, vertex buffers, etc.)
534 ******************************************************************************/
InitView()535 bool OGLES3ColourGrading::InitView()
536 {
537 // Initialize the textures used by Print3D.
538 bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
539
540 if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
541 {
542 PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
543 return false;
544 }
545
546 // Create the texture
547 if(PVRTTextureLoadFromPVR(c_pszMaskTexture, &m_uiMaskTexture) != PVR_SUCCESS)
548 {
549 PVRShellSet(prefExitMessage, "ERROR: Failed to load mask texture\n");
550 return false;
551 }
552
553 if(PVRTTextureLoadFromPVR(c_pszBackgroundTexture, &m_uiBackgroundTexture) != PVR_SUCCESS)
554 {
555 PVRShellSet(prefExitMessage, "ERROR: Failed to load background texture\n");
556 return false;
557 }
558
559 // Load our 3D texture look up tables
560 for(unsigned int i = 0; i < eLast; ++i)
561 {
562 if(PVRTTextureLoadFromPVR(c_pszLUTs[i], &m_uiLUTs[i]) != PVR_SUCCESS)
563 {
564 PVRShellSet(prefExitMessage, "ERROR: Failed to load a 3D texture\n");
565 return false;
566 }
567
568 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
569 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
570 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
571
572 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
573 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
574 }
575
576 // Load the effects
577 CPVRTString ErrorStr;
578 if(!LoadShaders(ErrorStr))
579 {
580 PVRShellSet(prefExitMessage, ErrorStr.c_str());
581 return false;
582 }
583
584 // Create FBOs
585 if(!CreateFBO())
586 {
587 PVRShellSet(prefExitMessage, "Failed to create FBO");
588 return false;
589 }
590
591 // Initialise VBO data
592 LoadVbos(bRotate);
593
594 // Calculate the projection and view matrices
595 float fAspect = PVRShellGet(prefWidth) / (float)PVRShellGet(prefHeight);
596 m_mViewProjection = PVRTMat4::PerspectiveFovRH(CAM_FOV, fAspect, CAM_NEAR, CAM_FAR, PVRTMat4::OGL, bRotate);
597 m_mViewProjection *= PVRTMat4::LookAtRH(PVRTVec3(0.f, 0.f, 150.f), PVRTVec3(0.f), PVRTVec3(0.f, 1.f, 0.f));
598
599 // Enable backface culling and depth test
600 glEnable(GL_CULL_FACE);
601 glEnable(GL_DEPTH_TEST);
602
603 // Set the clear colour
604 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
605
606 // Store initial time
607 m_ulStartTime = PVRShellGetTime();
608
609 return true;
610 }
611
612 /*!****************************************************************************
613 @Function ReleaseView
614 @Return bool true if no error occurred
615 @Description Code in ReleaseView() will be called by PVRShell when the
616 application quits or before a change in the rendering context.
617 ******************************************************************************/
ReleaseView()618 bool OGLES3ColourGrading::ReleaseView()
619 {
620 // Frees the texture
621 glDeleteTextures(1, &m_uiMaskTexture);
622 glDeleteTextures(1, &m_uiBackgroundTexture);
623 glDeleteTextures(eLast, m_uiLUTs);
624 glDeleteTextures(1, &m_uiTextureToRenderTo);
625
626 // Release Vertex buffer object.
627 glDeleteBuffers(1, &m_ui32FullScreenRectVBO);
628 glDeleteBuffers(1, &m_ui32BackgroundVBO);
629
630 // Release effects
631 glDeleteShader(m_uiPostVertShader);
632 glDeleteShader(m_uiPostFragShader);
633 glDeleteShader(m_uiBackgroundFragShader);
634 glDeleteShader(m_uiSceneVertShader);
635 glDeleteShader(m_uiSceneFragShader);
636
637 glDeleteProgram(m_PostShaderProgram.uiId);
638 glDeleteProgram(m_BackgroundShaderProgram.uiId);
639 glDeleteProgram(m_SceneShaderProgram.uiId);
640
641 // Tidy up the FBOs and renderbuffers
642
643 // Delete frame buffer objects
644 glDeleteFramebuffers(1, &m_uiFBO);
645 glDeleteFramebuffers(1, &m_uiFBOMultisampled);
646
647 // Delete our depth buffer
648 glDeleteRenderbuffers(1, &m_uiDepthBufferMultisampled);
649 glDeleteRenderbuffers(1, &m_uiColourBufferMultisampled);
650
651 // Delete buffer objects
652 glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
653 glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskIBO);
654
655 // Release Print3D Textures
656 m_Print3D.ReleaseTextures();
657
658 return true;
659 }
660
661 /*!****************************************************************************
662 @Function RenderScene
663 @Return bool true if no error occurred
664 @Description Main rendering loop function of the program. The shell will
665 call this function every frame.
666 eglSwapBuffers() will be performed by PVRShell automatically.
667 PVRShell will also manage important OS events.
668 Will also manage relevant OS events. The user has access to
669 these events through an abstraction layer provided by PVRShell.
670 ******************************************************************************/
RenderScene()671 bool OGLES3ColourGrading::RenderScene()
672 {
673 // Clears the colour buffer
674 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
675
676 unsigned long ulTime = PVRShellGetTime() - m_ulStartTime;
677
678 // Process input to switch between tone mapping operators
679 if(PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
680 {
681 ++m_iCurrentLUT;
682
683 if(m_iCurrentLUT > eB)
684 m_iCurrentLUT = eA;
685 }
686 else if(PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
687 {
688 --m_iCurrentLUT;
689
690 if(m_iCurrentLUT < eA)
691 m_iCurrentLUT = eB;
692 }
693
694 // Render to our texture
695 {
696 // Bind our FBO
697 glBindFramebuffer(GL_FRAMEBUFFER, m_uiFBOMultisampled);
698
699 // Clear the colour and depth buffer of our FBO surface
700 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
701
702 glDisable(GL_CULL_FACE);
703 glDisable(GL_DEPTH_TEST);
704
705 // Bind the VBO
706 glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
707
708 // Use shader program
709 glUseProgram(m_BackgroundShaderProgram.uiId);
710
711 // Enable the vertex attribute arrays
712 glEnableVertexAttribArray(VERTEX_ARRAY);
713 glEnableVertexAttribArray(TEXCOORD_ARRAY);
714
715 // Set the vertex attribute offsets
716 glVertexAttribPointer(VERTEX_ARRAY, 4, GL_FLOAT, GL_FALSE, m_ui32VertexStride, 0);
717 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, m_ui32VertexStride, (void*) (4 * sizeof(GLfloat)));
718
719 // Bind texture
720 glActiveTexture(GL_TEXTURE0);
721 glBindTexture(GL_TEXTURE_2D, m_uiBackgroundTexture);
722
723 // Draw a screen-aligned quad.
724
725 // Draws a non-indexed triangle array
726 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
727
728 // Safely disable the vertex attribute arrays
729 glDisableVertexAttribArray(VERTEX_ARRAY);
730 glDisableVertexAttribArray(TEXCOORD_ARRAY);
731
732 glEnable(GL_CULL_FACE);
733 glEnable(GL_DEPTH_TEST);
734
735 // Use shader program
736 glUseProgram(m_SceneShaderProgram.uiId);
737
738 // Rotate the model matrix
739 PVRTMat4 mModel = PVRTMat4::RotationY(ulTime * 0.0015f);
740
741 // Calculate model view projection matrix
742 PVRTMat4 mMVP = m_mViewProjection * mModel;
743
744 // Feeds Projection Model View matrix to the shaders
745 glUniformMatrix4fv(m_SceneShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr());
746
747 PVRTVec3 vMsLightDir = (PVRTVec3(1, 1, 1) * PVRTMat3(mModel)).normalized();
748 glUniform3fv(m_SceneShaderProgram.uiLightDirLoc, 1, vMsLightDir.ptr());
749
750 glBindTexture(GL_TEXTURE_2D, m_uiMaskTexture);
751
752 // Now that the uniforms are set, call another function to actually draw the mesh.
753 DrawMesh(0);
754
755 // Unbind the VBO
756 glBindBuffer(GL_ARRAY_BUFFER, 0);
757
758 // Give the drivers a hint that we don't want the depth and stencil information stored for future use.
759 const GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
760 glInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
761
762 // Blit and resolve the multisampled render buffer to the non-multisampled FBO
763 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_uiFBOMultisampled);
764 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_uiFBO);
765 glBlitFramebuffer(0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), 0, 0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), GL_COLOR_BUFFER_BIT, GL_NEAREST);
766
767 // We are done with rendering to our FBO so switch back to the back buffer.
768 glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
769 }
770
771 glDisable(GL_CULL_FACE);
772 glDisable(GL_DEPTH_TEST);
773
774 // Use shader program
775 glUseProgram(m_PostShaderProgram.uiId);
776
777 // Bind the VBO
778 glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
779
780 // Enable the vertex attribute arrays
781 glEnableVertexAttribArray(VERTEX_ARRAY);
782 glEnableVertexAttribArray(TEXCOORD_ARRAY);
783
784 // Set the vertex attribute offsets
785 glVertexAttribPointer(VERTEX_ARRAY, 4, GL_FLOAT, GL_FALSE, m_ui32VertexStride, 0);
786 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, m_ui32VertexStride, (void*) (4 * sizeof(GLfloat)));
787
788 // Bind texture
789 glActiveTexture(GL_TEXTURE0);
790 glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
791
792 glActiveTexture(GL_TEXTURE1);
793 glBindTexture(GL_TEXTURE_3D, m_uiLUTs[m_iCurrentLUT]);
794
795 // Draw a screen-aligned quad.
796
797 // Draw the left-hand side that shows the scene with the colour grading applied
798 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
799
800 // Draw the right-hande side showing the scene how it looks without
801 glBindTexture(GL_TEXTURE_3D, m_uiLUTs[eIdentity]);
802 glDrawArrays(GL_TRIANGLE_STRIP, 2, 4);
803
804 // Safely disable the vertex attribute arrays
805 glDisableVertexAttribArray(VERTEX_ARRAY);
806 glDisableVertexAttribArray(TEXCOORD_ARRAY);
807
808 // Unbind the VBO
809 glBindBuffer(GL_ARRAY_BUFFER, 0);
810
811 // Render title
812 m_Print3D.DisplayDefaultTitle("Colour grading using 3D textures", c_pszLUTNames[m_iCurrentLUT], ePVRTPrint3DSDKLogo);
813 m_Print3D.Flush();
814
815 return true;
816 }
817
818 /*!****************************************************************************
819 @Function DrawMesh
820 @Input i32NodeIndex Node index of the mesh to draw
821 @Description Draws a SPODMesh after the model view matrix has been set and
822 the material prepared.
823 ******************************************************************************/
DrawMesh(const int i32NodeIndex)824 void OGLES3ColourGrading::DrawMesh(const int i32NodeIndex)
825 {
826 int i32MeshIndex = m_Mask.pNode[i32NodeIndex].nIdx;
827 SPODMesh* pMesh = &m_Mask.pMesh[i32MeshIndex];
828
829 // bind the VBO for the mesh
830 glBindBuffer(GL_ARRAY_BUFFER, m_puiMaskVBO[i32MeshIndex]);
831 // bind the index buffer, won't hurt if the handle is 0
832 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiMaskIBO[i32MeshIndex]);
833
834 // Enable the vertex attribute arrays
835 glEnableVertexAttribArray(VERTEX_ARRAY);
836 glEnableVertexAttribArray(NORMAL_ARRAY);
837 glEnableVertexAttribArray(TEXCOORD_ARRAY);
838
839 // Set the vertex attribute offsets
840 glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
841 glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
842 glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
843
844 // Indexed Triangle list
845 glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
846
847 // Safely disable the vertex attribute arrays
848 glDisableVertexAttribArray(VERTEX_ARRAY);
849 glDisableVertexAttribArray(NORMAL_ARRAY);
850 glDisableVertexAttribArray(TEXCOORD_ARRAY);
851
852 glBindBuffer(GL_ARRAY_BUFFER, 0);
853 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
854 }
855
856 /*!****************************************************************************
857 @Function NewDemo
858 @Return PVRShell* The demo supplied by the user
859 @Description This function must be implemented by the user of the shell.
860 The user should return its PVRShell object defining the
861 behaviour of the application.
862 ******************************************************************************/
NewDemo()863 PVRShell* NewDemo()
864 {
865 return new OGLES3ColourGrading();
866 }
867
868 /******************************************************************************
869 End of file (OGLES3ColourGrading.cpp)
870 ******************************************************************************/
871
872