OSDN Git Service

Fixed depth test for 3D texture test
[android-x86/external-swiftshader.git] / tests / third_party / PowerVR / Examples / Intermediate / ColourGrading / OGLES2 / OGLES2ColourGrading.cpp
1 /******************************************************************************
2  
3  @File         OGLES2ColourGrading.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 "OGLES2Tools.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 OGLES2ColourGrading : public PVRShell
92 {
93         enum EMultisampleExtension
94         {
95                 eMultisampleExtension_None,
96                 eMultisampleExtension_IMG,
97                 eMultisampleExtension_EXT
98         };
99
100         // Print3D object
101         CPVRTPrint3D                    m_Print3D;
102         
103         // Texture handle
104         GLuint                                  m_uiMaskTexture;
105         GLuint                                  m_uiBackgroundTexture;
106         GLuint                                  m_uiLUTs[eLast];
107         int                                             m_iCurrentLUT;
108
109         // VBO handle
110         GLuint                                  m_ui32FullScreenRectVBO;
111         
112         // Stride for vertex data
113         unsigned int                    m_ui32VertexStride;
114         
115         // 3D Model
116         CPVRTModelPOD   m_Mask;
117         GLuint* m_puiMaskVBO;
118         GLuint* m_puiMaskIBO;
119
120         GLuint m_ui32BackgroundVBO;
121
122         // Projection and view matrices
123         PVRTMat4 m_mViewProjection;
124
125         // Shaders
126         GLuint m_uiPostVertShader;
127         GLuint m_uiPostFragShader;
128
129         struct
130         {
131                 GLuint uiId;
132         }
133         m_PostShaderProgram;
134
135         GLuint m_uiBackgroundFragShader;
136
137         struct
138         {
139                 GLuint uiId;
140         }
141         m_BackgroundShaderProgram;
142
143         GLuint m_uiSceneVertShader;
144         GLuint m_uiSceneFragShader;
145
146         struct
147         {
148                 GLuint uiId;
149                 GLuint uiMVPMatrixLoc;
150                 GLuint uiLightDirLoc;
151                 GLuint uiMaterialBiasLoc;
152                 GLuint uiMaterialScaleLoc;
153         }
154         m_SceneShaderProgram;
155
156         // Render contexts, etc
157         GLint     m_i32OriginalFbo;
158
159         // Texture IDs used by the app
160         GLuint  m_uiTextureToRenderTo;
161         GLuint  m_uiDepthToRenderTo;
162
163         // Handle for our FBO and the depth buffer that it requires
164         GLuint m_uiFBO;
165
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;    
170
171         // Start time
172         unsigned long m_ulStartTime;
173
174         // Extensions
175         CPVRTgles2Ext m_Extensions;
176
177         // Discard the frame buffer attachments
178         bool m_bDiscard;
179         bool m_bMultisampledSupported;
180         EMultisampleExtension m_eMultisampleMode;
181
182 public:
183         OGLES2ColourGrading() :
184                 m_uiMaskTexture(0),
185                 m_uiBackgroundTexture(0),
186                 m_iCurrentLUT(0),
187                 m_ui32FullScreenRectVBO(0),
188                 m_ui32VertexStride(0),
189                 m_puiMaskVBO(0),
190                 m_puiMaskIBO(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),
197                 m_i32OriginalFbo(0),
198                 m_uiTextureToRenderTo(0),
199                 m_uiDepthToRenderTo(0),
200                 m_uiFBO(0),
201                 m_uiFBOMultisampled(0),
202                 m_uiDepthBufferMultisampled(0),
203                 m_uiColourBufferMultisampled(0),
204                 m_ulStartTime(0),
205                 m_bDiscard(false),
206                 m_bMultisampledSupported(false)
207         {
208         }
209
210         // PVRShell functions
211         virtual bool InitApplication();
212         virtual bool InitView();
213         virtual bool ReleaseView();
214         virtual bool QuitApplication();
215         virtual bool RenderScene();
216
217 private:
218         bool LoadShaders(CPVRTString& ErrorStr);
219         bool CreateFBO();
220         void LoadVbos(const bool bRotated);
221         void DrawMesh(const int i32NodeIndex);
222 };
223
224
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
233                 not be called again.
234  ******************************************************************************/
235 bool OGLES2ColourGrading::InitApplication()
236 {
237         // Get and set the read path for content files
238         CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
239         
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));
244
245         // Load the scene
246         if(m_Mask.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
247         {
248                 PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
249                 return false;
250         }
251
252         // Initialise some variables
253         m_puiMaskVBO = m_puiMaskIBO = 0;
254         m_iCurrentLUT = eA;
255         return true;
256 }
257
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
264                 not be called.
265  ******************************************************************************/
266 bool OGLES2ColourGrading::QuitApplication()
267 {
268         // Free the memory allocated for the scene
269         m_Mask.Destroy();
270
271         delete[] m_puiMaskVBO;
272         m_puiMaskVBO = 0;
273
274         delete[] m_puiMaskIBO;
275         m_puiMaskIBO = 0;
276     return true;
277 }
278
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
284                 effect objects.
285  ******************************************************************************/
286 bool OGLES2ColourGrading::LoadShaders(CPVRTString& ErrorStr)
287 {
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)
290         {
291                 return false;
292         }
293
294         if(PVRTShaderLoadFromFile(NULL, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiPostFragShader, &ErrorStr) != PVR_SUCCESS)
295         {
296                 return false;
297         }
298
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)
302         {
303                 return false;
304         }
305
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);
309
310         // Background shader
311
312         if(PVRTShaderLoadFromFile(NULL, c_szBackgroundFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiBackgroundFragShader, &ErrorStr) != PVR_SUCCESS)
313         {
314                 return false;
315         }
316
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)
320         {
321                 return false;
322         }
323
324         // Set the sampler2D variable to the first texture unit
325         glUniform1i(glGetUniformLocation(m_BackgroundShaderProgram.uiId, "sTexture"), 0);
326
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)
329         {
330                 return false;
331         }
332
333         if(PVRTShaderLoadFromFile(NULL, c_szSceneFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSceneFragShader, &ErrorStr) != PVR_SUCCESS)
334         {
335                 return false;
336         }
337
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)
341         {
342                 return false;
343         }
344
345         // Set the sampler2D variable to the first texture unit
346         glUniform1i(glGetUniformLocation(m_SceneShaderProgram.uiId, "sTexture"), 0);
347
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");
353
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
357
358         // Specular bias
359         glUniform1f(m_SceneShaderProgram.uiMaterialBiasLoc, fSpecularConcentration);
360         // Specular intensity scale
361         glUniform1f(m_SceneShaderProgram.uiMaterialScaleLoc, fSpecularIntensity / (1.0f - fSpecularConcentration));
362
363         return true;
364 }
365
366 /*!****************************************************************************
367  @Function              LoadVbos
368  @Description   Loads the mesh data required for this training course into
369                                 vertex buffer objects
370 ******************************************************************************/
371 void OGLES2ColourGrading::LoadVbos(const bool bRotated)
372 {
373         if(!m_puiMaskVBO)      
374                 m_puiMaskVBO = new GLuint[m_Mask.nNumMesh];
375
376         if(!m_puiMaskIBO) 
377                 m_puiMaskIBO = new GLuint[m_Mask.nNumMesh];
378
379         /*
380                 Load vertex data of all meshes in the scene into VBOs
381
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.
386         */
387         glGenBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
388         for(unsigned int i = 0; i < m_Mask.nNumMesh; ++i)
389         {
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);
395
396                 // Load index data into buffer object if available
397                 m_puiMaskIBO[i] = 0;
398                 if (Mesh.sFaces.pData)
399                 {
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);
404                 }
405         }
406
407         // Create VBO for the fullscreen rect that we'll be rendering our FBO to
408
409         // Interleaved vertex data
410         GLfloat afVertices[] = {
411                 // Left quad
412                 -1.0f,  1.0f, 0.0f,     1.0f,   // Pos
413                 0.0f,  1.0f,                        // UVs
414
415                 -1.0f, -1.0f, 0.0f,     1.0f,
416                 0.0f,  0.0f,
417
418                 0.0f,  1.0f, 0.0f,      1.0f,
419                 0.5f,  1.0f,
420
421                 0.0f, -1.0f, 0.0f,      1.0f,
422                 0.5f,  0.0f,
423
424                 1.0f,  1.0f, 0.0f,      1.0f,
425                 1.0f,  1.0f,
426
427                 1.0f, -1.0f, 0.0f,      1.0f,
428                 1.0f,  0.0f,
429         };
430
431         if(bRotated) // If we're rotated then pre-process the fullscreen rect's geometry to compensate
432         {
433                 for(unsigned int i = 0; i < 6; ++i)
434                 {
435                         float fTmp = afVertices[i * 6 + 1];
436                         afVertices[i * 6 + 1] = afVertices[i * 6];
437                         afVertices[i * 6] = fTmp;
438
439                         fTmp = afVertices[i * 6 + 5];
440                         afVertices[i * 6 + 5] = afVertices[i * 6 + 4];
441                         afVertices[i * 6 + 4] = fTmp;
442                 }
443         }
444
445         glGenBuffers(1, &m_ui32FullScreenRectVBO);
446         m_ui32VertexStride = 6 * sizeof(GLfloat); // 4 floats for the pos, 2 for the UVs
447
448         // Bind the VBO
449         glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
450
451         // Set the buffer's data
452         glBufferData(GL_ARRAY_BUFFER, 6 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW);
453
454         // Create the VBO for the background
455         GLfloat afBackgroundVertices[] = {
456                 // Left quad
457                 -1.0f,  1.0f, 0.0f,     1.0f,   // Pos
458                 0.0f,  1.0f,                        // UVs
459
460                 -1.0f, -1.0f, 0.0f,     1.0f,
461                 0.0f,  0.0f,
462
463                 1.0f,  1.0f, 0.0f,      1.0f,
464                 1.0f,  1.0f,
465
466                 1.0f, -1.0f, 0.0f,      1.0f,
467                 1.0f,  0.0f,
468         };
469
470         if(bRotated) // If we're rotated then pre-process the background geometry
471         {
472                 for(unsigned int i = 0; i < 4; ++i)
473                 {
474                         float fTmp = afBackgroundVertices[i * 6 + 1];
475                         afBackgroundVertices[i * 6 + 1] = -afBackgroundVertices[i * 6];
476                         afBackgroundVertices[i * 6] = -fTmp;
477                 }
478         }
479
480         glGenBuffers(1, &m_ui32BackgroundVBO);
481
482         // Bind the VBO
483         glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
484
485         // Set the buffer's data
486         glBufferData(GL_ARRAY_BUFFER, 4 * m_ui32VertexStride, afBackgroundVertices, GL_STATIC_DRAW);
487
488         // Unbind our buffers
489         glBindBuffer(GL_ARRAY_BUFFER, 0);
490         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
491 }
492
493 bool OGLES2ColourGrading::CreateFBO()
494 {
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)
498         {
499                 m_eMultisampleMode = eMultisampleExtension_EXT;
500         }
501
502         GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
503
504         // Query the max amount of samples that are supported, we are going to use the max
505         GLint samples;
506         glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples);
507
508         // Get the currently bound frame buffer object. On most platforms this just gives 0.
509         glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo);
510
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);
519
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);
523
524         // Attach the texture to the FBO
525         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_uiTextureToRenderTo, 0);
526         if(!m_bMultisampledSupported)
527         {
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);
534         }
535
536         // Check that our FBO creation was successful
537         GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
538         if(uStatus != GL_FRAMEBUFFER_COMPLETE)
539         {
540                 PVRShellSet(prefExitMessage, "ERROR: Failed to initialise FBO");
541                 return false;
542         }
543
544         // Generate and bind a render buffer which will become a multisampled depth buffer shared between our two FBOs
545         if(m_bMultisampledSupported)
546         {
547                 // Create and initialize the multi-sampled FBO.
548
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);
552
553                 glGenRenderbuffers(1, &m_uiDepthBufferMultisampled);
554                 glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
555
556                 if(m_eMultisampleMode == eMultisampleExtension_EXT)
557                         m_Extensions.glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT16, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
558                 else
559                         m_Extensions.glRenderbufferStorageMultisampleIMG(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT16, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
560
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));
565                 else
566                         m_Extensions.glRenderbufferStorageMultisampleIMG(GL_RENDERBUFFER, samples, GL_RGB, PVRShellGet(prefWidth), PVRShellGet(prefHeight));
567
568                 glBindRenderbuffer(GL_RENDERBUFFER, 0);
569
570                 // Attach the multisampled depth buffer we created earlier to our FBO.
571                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthBufferMultisampled);
572
573                 // Attach the multisampled colour renderbuffer to the FBO
574                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_uiColourBufferMultisampled);
575
576                 // Check that our FBO creation was successful
577                 uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
578                 if(uStatus != GL_FRAMEBUFFER_COMPLETE)
579                 {
580                         PVRShellSet(prefExitMessage, "ERROR: Failed to initialise multisampled FBO");
581                         return false;
582                 }
583         }
584
585         // Unbind the frame buffer object so rendering returns back to the backbuffer
586         glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
587
588         return true;
589 }
590
591 /*!****************************************************************************
592  @Function              InitView
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()
600 {
601         m_Extensions.LoadExtensions();
602
603         // Initialize the textures used by Print3D.
604         bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
605         
606         if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
607         {
608                 PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
609                 return false;
610         }       
611                 
612         // Create the texture
613         if(PVRTTextureLoadFromPVR(c_pszMaskTexture, &m_uiMaskTexture) != PVR_SUCCESS)
614         {
615                 PVRShellSet(prefExitMessage, "ERROR: Failed to load mask texture\n");
616                 return false;
617         }
618         
619         if(PVRTTextureLoadFromPVR(c_pszBackgroundTexture, &m_uiBackgroundTexture) != PVR_SUCCESS)
620         {
621                 PVRShellSet(prefExitMessage, "ERROR: Failed to load background texture\n");
622                 return false;
623         }
624         
625         // Load our 3D texture look up tables
626         for(unsigned int i = 0; i < eLast; ++i)
627         {
628                 if(PVRTTextureLoadFromPVR(c_pszLUTs[i], &m_uiLUTs[i]) != PVR_SUCCESS)
629                 {
630                         PVRShellSet(prefExitMessage, "ERROR: Failed to load a 3D texture\n");
631                         return false;
632                 }
633
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);
637
638                 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
639                 glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
640         }
641
642         // Load the effects
643         CPVRTString ErrorStr;
644         if(!LoadShaders(ErrorStr))
645         {
646                 PVRShellSet(prefExitMessage, ErrorStr.c_str());
647                 return false;
648         }
649         
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");
655
656         // Create FBOs
657         if(!CreateFBO())
658         {
659                 PVRShellSet(prefExitMessage, "Failed to create FBO");
660                 return false;
661         }
662
663         // Check to see if the GL_EXT_discard_framebuffer extension is supported
664         m_bDiscard = CPVRTgles2Ext::IsGLExtensionSupported("GL_EXT_discard_framebuffer");
665         if(m_bDiscard)
666         {
667                 m_bDiscard = m_Extensions.glDiscardFramebufferEXT != 0;
668         }
669
670         // Initialise VBO data
671         LoadVbos(bRotate);
672
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));
677
678         // Enable backface culling and depth test
679         glEnable(GL_CULL_FACE);
680         glEnable(GL_DEPTH_TEST);
681
682         // Set the clear colour
683         glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
684
685         // Store initial time
686         m_ulStartTime = PVRShellGetTime();
687
688         return true;
689 }
690
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()
698 {
699         // Frees the texture
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);
705
706         // Release Vertex buffer object.
707         glDeleteBuffers(1, &m_ui32FullScreenRectVBO);
708         glDeleteBuffers(1, &m_ui32BackgroundVBO);
709
710         // Release effects
711         glDeleteShader(m_uiPostVertShader);
712         glDeleteShader(m_uiPostFragShader);
713         glDeleteShader(m_uiBackgroundFragShader);
714         glDeleteShader(m_uiSceneVertShader);
715         glDeleteShader(m_uiSceneFragShader);
716
717         glDeleteProgram(m_PostShaderProgram.uiId);
718         glDeleteProgram(m_BackgroundShaderProgram.uiId);
719         glDeleteProgram(m_SceneShaderProgram.uiId);
720
721         // Tidy up the FBOs and renderbuffers
722
723         // Delete frame buffer objects
724         glDeleteFramebuffers(1, &m_uiFBO);
725         glDeleteFramebuffers(1, &m_uiFBOMultisampled);
726
727         // Delete our depth buffer
728         glDeleteRenderbuffers(1, &m_uiDepthBufferMultisampled);
729         glDeleteRenderbuffers(1, &m_uiColourBufferMultisampled);
730
731         // Delete buffer objects
732         glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskVBO);
733         glDeleteBuffers(m_Mask.nNumMesh, m_puiMaskIBO);
734
735         // Release Print3D Textures
736         m_Print3D.ReleaseTextures();
737
738         return true;
739 }
740
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()
752 {
753         // Clears the colour buffer
754         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
755                 
756         unsigned long ulTime = PVRShellGetTime() - m_ulStartTime;
757
758         // Process input to switch between tone mapping operators
759         if(PVRShellIsKeyPressed(PVRShellKeyNameRIGHT))
760         {
761                 ++m_iCurrentLUT;
762
763                 if(m_iCurrentLUT > eB)
764                         m_iCurrentLUT = eA;
765         }
766         else if(PVRShellIsKeyPressed(PVRShellKeyNameLEFT))
767         {
768                 --m_iCurrentLUT;
769
770                 if(m_iCurrentLUT < eA)
771                         m_iCurrentLUT = eB;
772         }
773         
774         // Render to our texture
775         {
776                 // Bind our FBO
777                 glBindFramebuffer(GL_FRAMEBUFFER, m_bMultisampledSupported ? m_uiFBOMultisampled : m_uiFBO);
778
779                 // Clear the colour and depth buffer of our FBO surface
780                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
781
782                 glDisable(GL_CULL_FACE);
783                 glDisable(GL_DEPTH_TEST);
784
785                 // Bind the VBO
786                 glBindBuffer(GL_ARRAY_BUFFER, m_ui32BackgroundVBO);
787
788                 // Use shader program
789                 glUseProgram(m_BackgroundShaderProgram.uiId);
790
791                 // Enable the vertex attribute arrays
792                 glEnableVertexAttribArray(VERTEX_ARRAY);
793                 glEnableVertexAttribArray(TEXCOORD_ARRAY);
794
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)));
798
799                 // Bind texture
800                 glActiveTexture(GL_TEXTURE0);
801                 glBindTexture(GL_TEXTURE_2D, m_uiBackgroundTexture);
802
803                 // Draw a screen-aligned quad.
804
805                 // Draws a non-indexed triangle array
806                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
807
808                 // Safely disable the vertex attribute arrays
809                 glDisableVertexAttribArray(VERTEX_ARRAY);
810                 glDisableVertexAttribArray(TEXCOORD_ARRAY);
811
812                 glEnable(GL_CULL_FACE);
813                 glEnable(GL_DEPTH_TEST);
814
815                 // Use shader program
816                 glUseProgram(m_SceneShaderProgram.uiId);
817
818                 // Rotate the model matrix
819                 PVRTMat4 mModel = PVRTMat4::RotationY(ulTime * 0.0015f);
820
821                 // Calculate model view projection matrix
822                 PVRTMat4 mMVP = m_mViewProjection * mModel;
823
824                 // Feeds Projection Model View matrix to the shaders
825                 glUniformMatrix4fv(m_SceneShaderProgram.uiMVPMatrixLoc, 1, GL_FALSE, mMVP.ptr());
826
827                 PVRTVec3 vMsLightDir = (PVRTVec3(1, 1, 1) * PVRTMat3(mModel)).normalized();
828                 glUniform3fv(m_SceneShaderProgram.uiLightDirLoc, 1, vMsLightDir.ptr());
829
830                 glBindTexture(GL_TEXTURE_2D, m_uiMaskTexture);
831
832                 // Now that the uniforms are set, call another function to actually draw the mesh.
833                 DrawMesh(0);
834
835                 // Unbind the VBO
836                 glBindBuffer(GL_ARRAY_BUFFER, 0);
837
838                 if(m_bDiscard) // Was GL_EXT_discard_framebuffer supported?
839                 {
840                         /*
841                         Give the drivers a hint that we don't want the depth and stencil information stored for future use.
842
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.
845                         */
846                         const GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
847                         m_Extensions.glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
848                 }
849
850                 // Blit and resolve the multisampled render buffer to the non-multisampled FBO
851                 if(m_bMultisampledSupported)
852                 {
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);
857                 }
858
859                 // We are done with rendering to our FBO so switch back to the back buffer.
860                 glBindFramebuffer(GL_FRAMEBUFFER, m_i32OriginalFbo);
861         }
862
863         GLenum error = glGetError();
864
865         glDisable(GL_CULL_FACE);
866         glDisable(GL_DEPTH_TEST);
867
868         error = glGetError();
869
870         // Use shader program
871         glUseProgram(m_PostShaderProgram.uiId);
872
873         // Bind the VBO
874         glBindBuffer(GL_ARRAY_BUFFER, m_ui32FullScreenRectVBO);
875
876         error = glGetError();
877
878         // Enable the vertex attribute arrays
879         glEnableVertexAttribArray(VERTEX_ARRAY);
880         glEnableVertexAttribArray(TEXCOORD_ARRAY);
881
882         error = glGetError();
883
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)));
887
888         error = glGetError();
889
890         // Bind texture
891         glActiveTexture(GL_TEXTURE0);
892         glBindTexture(GL_TEXTURE_2D, m_uiTextureToRenderTo);
893
894         error = glGetError();
895
896         glActiveTexture(GL_TEXTURE1);
897         glBindTexture(GL_TEXTURE_3D_OES, m_uiLUTs[m_iCurrentLUT]);
898
899         error = glGetError();
900
901         // Draw a screen-aligned quad.
902
903         // Draw the left-hand side that shows the scene with the colour grading applied
904         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
905         
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);
909
910         // Safely disable the vertex attribute arrays
911         glDisableVertexAttribArray(VERTEX_ARRAY);
912         glDisableVertexAttribArray(TEXCOORD_ARRAY);
913         
914         // Unbind the VBO
915         glBindBuffer(GL_ARRAY_BUFFER, 0);
916
917         // Render title
918         m_Print3D.DisplayDefaultTitle("Colour grading using 3D textures", c_pszLUTNames[m_iCurrentLUT], ePVRTPrint3DSDKLogo);
919         m_Print3D.Flush();
920         
921         return true;
922 }
923
924 /*!****************************************************************************
925  @Function              DrawMesh
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)
931 {
932         int i32MeshIndex = m_Mask.pNode[i32NodeIndex].nIdx;
933         SPODMesh* pMesh = &m_Mask.pMesh[i32MeshIndex];
934
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]);
939
940         // Enable the vertex attribute arrays
941         glEnableVertexAttribArray(VERTEX_ARRAY);
942         glEnableVertexAttribArray(NORMAL_ARRAY);
943         glEnableVertexAttribArray(TEXCOORD_ARRAY);
944
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);
949
950         // Indexed Triangle list
951         glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
952         
953         // Safely disable the vertex attribute arrays
954         glDisableVertexAttribArray(VERTEX_ARRAY);
955         glDisableVertexAttribArray(NORMAL_ARRAY);
956         glDisableVertexAttribArray(TEXCOORD_ARRAY);
957
958         glBindBuffer(GL_ARRAY_BUFFER, 0);
959         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
960 }
961
962 /*!****************************************************************************
963  @Function              NewDemo
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  ******************************************************************************/
969 PVRShell* NewDemo()
970 {
971         return new OGLES2ColourGrading();
972 }
973
974 /******************************************************************************
975  End of file (OGLES2ColourGrading.cpp)
976  ******************************************************************************/
977