Home | History | Annotate | Download | only in OGLES3
      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  ******************************************************************************/
    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  ******************************************************************************/
    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  ******************************************************************************/
    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 ******************************************************************************/
    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 
    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  ******************************************************************************/
    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  ******************************************************************************/
    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  ******************************************************************************/
    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 ******************************************************************************/
    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  ******************************************************************************/
    863 PVRShell* NewDemo()
    864 {
    865 	return new OGLES3ColourGrading();
    866 }
    867 
    868 /******************************************************************************
    869  End of file (OGLES3ColourGrading.cpp)
    870  ******************************************************************************/
    871 
    872