/*!****************************************************************************
 @Function		LoadShaders
 @Output		pErrorStr		A string describing the error on failure
 @Return		bool			true if no error occured
 @Description	Loads and compiles the shaders and links the shader programs
				required for this training course
******************************************************************************/
bool OGLES2PVRScopeRemote::LoadShaders(CPVRTString* pErrorStr, const char * const pszFrag, const char * const pszVert)
{
	CPPLProcessingScoped PPLProcessingScoped(m_psSPSCommsData,
		__FUNCTION__, static_cast<unsigned int>(strlen(__FUNCTION__)), m_i32FrameCounter);

	/*
		Load and compile the shaders from files.
		Binary shaders are tried first, source shaders
		are used as fallback.
	*/
	if (PVRTShaderLoadSourceFromMemory(
			pszVert, GL_VERTEX_SHADER, &m_uiVertShader, pErrorStr) != PVR_SUCCESS)
	{
		return false;
	}

	if (PVRTShaderLoadSourceFromMemory(
			pszFrag, GL_FRAGMENT_SHADER, &m_uiFragShader, pErrorStr) != PVR_SUCCESS)
	{
		return false;
	}

	/*
		Set up and link the shader program
	*/
	const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" };
	if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertShader, m_uiFragShader, aszAttribs, 3, pErrorStr))
	{
		PVRShellSet(prefExitMessage, pErrorStr->c_str());
		return false;
	}
	// Set the sampler2D variable to the first texture unit
	glUniform1i(glGetUniformLocation(m_ShaderProgram.uiId, "sThicknessTex"), 0);

	// Store the location of uniforms for later use
	m_ShaderProgram.uiMVPMatrixLoc		= glGetUniformLocation(m_ShaderProgram.uiId, "MVPMatrix");
	m_ShaderProgram.uiLightDirLoc		= glGetUniformLocation(m_ShaderProgram.uiId, "LightDirection");
	m_ShaderProgram.uiEyePosLoc			= glGetUniformLocation(m_ShaderProgram.uiId, "EyePosition");
	m_ShaderProgram.uiMinThicknessLoc	= glGetUniformLocation(m_ShaderProgram.uiId, "MinThickness");
	m_ShaderProgram.uiMaxVariationLoc	= glGetUniformLocation(m_ShaderProgram.uiId, "MaxVariation");

	return true;
}
unsigned createProgramFromSource(
        const char *    vss,        // vertex shader source
        const char *    fss,        // fragment shader source
        const char**    attribs,    // attribute list
        unsigned *      attrLocal,  // store attribute locations
        const unsigned  num         // attribute list size
    )
{
    unsigned id = 0;
    unsigned vs = 0;
    unsigned fs = 0;
    EPVRTError ret = PVR_SUCCESS;
    CPVRTString msg;
    int step = 0;
    do
    {
        if (!vss || !fss || (num && (!attribs || !attrLocal)))
        {
            Debug::logd("There's no shader source!!");
            break;
        }
        // 1 Compile vertex shader.
        step = 1;
        if (PVR_SUCCESS != PVRTShaderLoadSourceFromMemory(
                vss, GL_VERTEX_SHADER, &vs, &msg, 0, 0))
            break;
        // 2 Compile fragment shader.
        step = 2;
        if (PVR_SUCCESS != PVRTShaderLoadSourceFromMemory(
                fss, GL_FRAGMENT_SHADER, &fs, &msg, 0, 0))
            break;
        // 3 Link two shaders to program, and bind attribs to specific locations.
        step = 3;
        if (PVR_SUCCESS != PVRTCreateProgram( &id, vs, fs, attribs, num, &msg))
            break;
        for (unsigned i = 0; i < num; i++)  *(attrLocal + i) = i;
    } while (false);
    if (! id)
    {
        Debug::logd("(step:%d)%s", step, msg.c_str());
    }
    return id;
}
Beispiel #3
0
/*!***************************************************************************
 @Function		PVRTShaderLoadFromFile
 @Input			pszBinFile			binary shader filename
 @Input			pszSrcFile			source shader filename
 @Input			Type				type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER)
 @Input			Format				shader binary format, or 0 for source shader
 @Output		pObject				the resulting shader object
 @Output		pReturnError		the error message if it failed
 @Input			pContext			Context
 @Input			aszDefineArray		Array of defines to be pre-appended to shader string
 @Input			uiDefArraySize		Size of the define array
 @Return		PVR_SUCCESS on success and PVR_FAIL on failure (also fills pReturnError)
 @Description	Loads a shader file into memory and passes it to the GL. 
				It also passes defines that need to be pre-appended to the shader before compilation.
*****************************************************************************/
EPVRTError PVRTShaderLoadFromFile(	const char* const pszBinFile,
									const char* const pszSrcFile,
									const GLenum Type,
									const GLenum Format,
									GLuint* const pObject,
									CPVRTString* const pReturnError,
									const SPVRTContext* const pContext,
									const char* const* aszDefineArray, GLuint uiDefArraySize)
{
	PVRT_UNREFERENCED_PARAMETER(pContext);

	*pReturnError = "";

	/* 	
		Prepending defines relies on altering the source file that is loaded.
		For this reason, the function calls the source loader instead of the binary loader if defines have
		been passed in.
	*/
	if(Format && pszBinFile && uiDefArraySize == 0)
	{
		CPVRTResourceFile ShaderFile(pszBinFile);
		if (ShaderFile.IsOpen())
		{
			if(PVRTShaderLoadBinaryFromMemory(ShaderFile.DataPtr(), ShaderFile.Size(), Type, Format, pObject, pReturnError) == PVR_SUCCESS)
				return PVR_SUCCESS;
		}

		*pReturnError += CPVRTString("Failed to open shader ") + pszBinFile + "\n";
	}

	CPVRTResourceFile ShaderFile(pszSrcFile);
	if (!ShaderFile.IsOpen())
	{
		*pReturnError += CPVRTString("Failed to open shader ") + pszSrcFile + "\n";
		return PVR_FAIL;
	}
 
	CPVRTString ShaderFileString;
	const char* pShaderData = (const char*) ShaderFile.DataPtr();

	// Is our shader resource file data null terminated?
	if(pShaderData[ShaderFile.Size()-1] != '\0')
	{
		// If not create a temporary null-terminated string
		ShaderFileString.assign(pShaderData, ShaderFile.Size());
		pShaderData = ShaderFileString.c_str();
	}

	return PVRTShaderLoadSourceFromMemory(pShaderData, Type, pObject, pReturnError, aszDefineArray, uiDefArraySize);
}
Beispiel #4
0
/*!***************************************************************************
 @Function		Init
 @Input			pContext	A pointer to a PVRTContext
 @Input			bRotate		true to rotate texture 90 degrees.
 @Input			pszError	An option string for returning errors
 @Return 		PVR_SUCCESS on success
 @Description	Initialises the background
*****************************************************************************/
EPVRTError CPVRTBackground::Init(const SPVRTContext * const pContext, bool bRotate, CPVRTString *pszError)
{
	Destroy();

	m_pAPI = new SPVRTBackgroundAPI;

	if(!m_pAPI)
	{
		if(pszError)
			*pszError = "Error: Insufficient memory to allocate SCPVRTBackgroundAPI.";

		return PVR_FAIL;
	}

	m_pAPI->m_ui32VertexShader = 0;
	m_pAPI->m_ui32FragShader = 0;
	m_pAPI->m_ui32ProgramObject = 0;
	m_pAPI->m_ui32VertexBufferObject = 0;

	bool bResult;
	CPVRTString sTmpErrStr;

	// The shader loading code doesn't expect a null pointer for the error string
	if(!pszError)
		pszError = &sTmpErrStr;

	/* Compiles the shaders. For a more detailed explanation, see IntroducingPVRTools */

	// Try binary shaders first
	bResult = (PVRTShaderLoadBinaryFromMemory(_BackgroundFragShader_fsc, _BackgroundFragShader_fsc_size,
					GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_pAPI->m_ui32FragShader, pszError) == PVR_SUCCESS)
		       && (PVRTShaderLoadBinaryFromMemory(_BackgroundVertShader_vsc, _BackgroundVertShader_vsc_size,
					GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_pAPI->m_ui32VertexShader, pszError) == PVR_SUCCESS);
	if(!bResult)
	{
		// if binary shaders don't work, try source shaders
		bResult = (PVRTShaderLoadSourceFromMemory(_BackgroundFragShader_fsh, GL_FRAGMENT_SHADER, &m_pAPI->m_ui32FragShader, pszError) == PVR_SUCCESS) &&
				(PVRTShaderLoadSourceFromMemory(_BackgroundVertShader_vsh, GL_VERTEX_SHADER, &m_pAPI->m_ui32VertexShader, pszError)  == PVR_SUCCESS);
	}

	_ASSERT(bResult);

	if(!bResult)
		return PVR_FAIL;

	// Reset the error string
	if(pszError)
		*pszError = "";

	// Create the shader program
	m_pAPI->m_ui32ProgramObject = glCreateProgram();

	// Attach the fragment and vertex shaders to it
	glAttachShader(m_pAPI->m_ui32ProgramObject, m_pAPI->m_ui32FragShader);
	glAttachShader(m_pAPI->m_ui32ProgramObject, m_pAPI->m_ui32VertexShader);

	// Bind the custom vertex attribute "myVertex" to location VERTEX_ARRAY
	glBindAttribLocation(m_pAPI->m_ui32ProgramObject, VERTEX_ARRAY, "myVertex");

	// Bind the custom vertex attribute "myUV" to location TEXCOORD_ARRAY
	glBindAttribLocation(m_pAPI->m_ui32ProgramObject, TEXCOORD_ARRAY, "myUV");

	// Link the program
	glLinkProgram(m_pAPI->m_ui32ProgramObject);
	GLint Linked;
	glGetProgramiv(m_pAPI->m_ui32ProgramObject, GL_LINK_STATUS, &Linked);
	if (!Linked)
	{
		int i32InfoLogLength, i32CharsWritten;
		glGetProgramiv(m_pAPI->m_ui32ProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
		char* pszInfoLog = new char[i32InfoLogLength];
		glGetProgramInfoLog(m_pAPI->m_ui32ProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
		*pszError = CPVRTString("Failed to link: ") + pszInfoLog + "\n";
		delete [] pszInfoLog;
		bResult = false;
	}

	_ASSERT(bResult);

	if(!bResult)
		return PVR_FAIL;

	// Use the loaded shader program
	glUseProgram(m_pAPI->m_ui32ProgramObject);

	// Set the sampler2D variable to the first texture unit
	glUniform1i(glGetUniformLocation(m_pAPI->m_ui32ProgramObject, "sampler2d"), 0);

	// Create the vertex buffer object
	GLfloat *pVertexData = 0;

	// The vertex data for non-rotated
	GLfloat afVertexData[16] = { -1, -1, 1, -1, -1, 1, 1, 1,
						0, 0, 1, 0, 0, 1, 1, 1};

	// The vertex data for rotated
	GLfloat afVertexDataRotated[16] = {-1, 1, -1, -1, 1, 1, 1, -1,
						1, 1, 0, 1, 1, 0, 0, 0};

	if(!bRotate)
		pVertexData = &afVertexData[0];
	else
		pVertexData = &afVertexDataRotated[0];

	glGenBuffers(1, &m_pAPI->m_ui32VertexBufferObject);
	glBindBuffer(GL_ARRAY_BUFFER, m_pAPI->m_ui32VertexBufferObject);

	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, pVertexData, GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	m_bInit = true;

	return PVR_SUCCESS;
}
/*!****************************************************************************
 @Function		InitView
 @Return		bool		true if no error occured
 @Description	Code in InitView() will be called by PVRShell upon
				initialization or after a change in the rendering context.
				Used to initialize variables that are dependant on the rendering
				context (e.g. textures, vertex buffers, etc.)
******************************************************************************/
bool OGLESIntroducingPVRTools::InitView()
{
	/*
		Initialize the textures used by Print3D.
		To properly display text, Print3D needs to know the viewport dimensions
		and whether the text should be rotated. We get the dimensions using the
		shell function PVRShellGet(prefWidth/prefHeight). We can also get the
		rotate parameter by checking prefIsRotated and prefFullScreen.
	*/
	bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);

	if(m_Print3D.SetTextures(0, PVRShellGet(prefWidth), PVRShellGet(prefHeight), bRotate) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
		return false;
	}

	// Sets the clear color
	glClearColor(0.6f, 0.8f, 1.0f, 1.0f);

	/*
		Loads the texture using the tool function PVRTTextureLoadFromPVR.
		The first parameter is the name of the file and the
		second parameter returns the resulting texture handle.
		The third parameter is a CPVRTString for error message output.
		This function can also be used to conveniently set the filter modes. If
		those parameters are not given, OpenGL ES defaults are used.
		Setting a mipmap filter on a mipmap-less texture will result in an error.
	*/

	if(PVRTTextureLoadFromPVR(c_szTextureFile, &m_uiTexture) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, "ERROR: Cannot load the texture\n");
		return false;
	}

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	/*
		Compiles the shaders.
		First we use CPVRTResourceFile to load a file into memory. After construction with a
		file name, we just have to check whether the file is open or an error occured.
		We load both source and binary shaders, then try the binary shader first.
		The data of a CPVRTResourceFile will always be terminated with a 0 byte so it can
		safely be used as a C string.
	*/
	CPVRTResourceFile VertexShaderSrcFile(c_szVertShaderSrcFile);
	CPVRTResourceFile VertexShaderBinFile(c_szVertShaderBinFile);

	CPVRTString ErrorStr;
	/*
		PVRTShaderLoadBinaryFromMemory takes a pointer to the binary shader and the shader size as
		its first arguments. Then follows the shader type and binary format.
		On success, the handle to the new shader object is returned in the fifth parameter, while
		an error string is returned on failure.
	*/
	if (!VertexShaderBinFile.IsOpen() ||
		(PVRTShaderLoadBinaryFromMemory(VertexShaderBinFile.DataPtr(), VertexShaderBinFile.Size(),
			GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiVertexShader, &ErrorStr) != PVR_SUCCESS))
	{
		/*
			Fallback to source shader
			PVRTShaderLoadSourceFromMemory() takes the shader source code as its 1st argument.
			The shader type as 2nd argument (for now either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
			It returns the shader object in its 3rd argument.
			If an error occurs during compilation, the resulting log is returned in the 4th parameter.
			We could also use PVRTLoadAndCompileShaderFromFile() to load and
			compile a shader from an external text file
		*/

		CPVRTString vertexShaderSrc((const char*) VertexShaderSrcFile.DataPtr(), VertexShaderSrcFile.Size());

		if (!VertexShaderSrcFile.IsOpen() ||
			(PVRTShaderLoadSourceFromMemory(vertexShaderSrc.c_str(), GL_VERTEX_SHADER, &m_uiVertexShader, &ErrorStr) != PVR_SUCCESS))
		{
			PVRShellSet(prefExitMessage, ErrorStr.c_str());
			return false;
		}
	}

	/*
		PVRTShaderLoadFromFile can be used to try compiling/loading shaders from files. In this variant,
		two files are tried before failing (usually binary and source files). The type of shader is determined
		from the file extension (.fsh and .vsh for source, .fsc and .vsc for SGX binary shaders)
	*/
	if (PVRTShaderLoadFromFile(c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiFragShader, &ErrorStr) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, ErrorStr.c_str());
		return false;
	}

	/*
		PVRTCreateProgram creates a new program object, attaches the shaders, binds attributes (given as an array
		of strings and the size thereof), and makes the program current - or it returns an error string on failure.
	*/
	if (PVRTCreateProgram(&m_ShaderProgram.uiId, m_uiVertexShader, m_uiFragShader, g_aszAttribNames, eNumAttribs, &ErrorStr) != PVR_SUCCESS)
	{
		PVRShellSet(prefExitMessage, ErrorStr.c_str());
		return false;
	}

	// Store the location of uniforms for later use
	for (int i = 0; i < eNumUniforms; ++i)
	{
		m_ShaderProgram.auiLoc[i] = glGetUniformLocation(m_ShaderProgram.uiId, g_aszUniformNames[i]);
	}

	// Create VBO for the triangle from our data

	// Interleaved vertex data
	GLfloat afVertices[] = {-0.4f,-0.4f,0.0f, // Pos
							 0.0f,0.0f ,				 // UVs
							 0.4f,-0.4f,0.0f,
							 1.0f,0.0f ,
							 0.0f,0.4f ,0.0f,
							 0.5f,1.0f};

	glGenBuffers(1, &m_ui32Vbo);

	m_ui32VertexStride = 5 * sizeof(GLfloat); // 3 floats for the pos, 2 for the UVs

	// Bind the VBO
	glBindBuffer(GL_ARRAY_BUFFER, m_ui32Vbo);

	// Set the buffer's data
	glBufferData(GL_ARRAY_BUFFER, 3 * m_ui32VertexStride, afVertices, GL_STATIC_DRAW);

	// Unbind the VBO
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	return true;
}
/*!***************************************************************************
 @Function			APIInit
 @Description		Initialisation and texture upload. Should be called only once
					for a given context.
*****************************************************************************/
bool CPVRTPrint3D::APIInit(const SPVRTContext	* const pContext, bool bMakeCopy)
{
	PVRT_UNREFERENCED_PARAMETER(pContext);

	m_pAPI = new SPVRTPrint3DAPI;
	if(!m_pAPI)
		return false;

	if(bMakeCopy)
		m_pAPI->m_pInstanceData = new SPVRTPrint3DAPI::SInstanceData();

	SPVRTPrint3DAPI::SInstanceData& Data = (m_pAPI->m_pInstanceData ? *m_pAPI->m_pInstanceData : SPVRTPrint3DAPI::s_InstanceData);

	// Check to see if these shaders have already been loaded previously. Optimisation as we don't want to load many copies of the same shader!
	if(	Data.uFragmentShaderLogo != UNDEFINED_HANDLE && Data.uVertexShaderLogo != UNDEFINED_HANDLE && Data.uProgramLogo != UNDEFINED_HANDLE &&
		Data.uFragmentShaderFont != UNDEFINED_HANDLE && Data.uVertexShaderFont != UNDEFINED_HANDLE && Data.uProgramFont != UNDEFINED_HANDLE
	)
	{
		++SPVRTPrint3DAPI::s_iRefCount;
		return true;
	}

	// Compiles the shaders. For a more detailed explanation, see IntroducingPVRTools
	CPVRTString error;
	GLint Linked;
	bool bRes = true;

	bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DFragShaderLogo_fsh, GL_FRAGMENT_SHADER, &Data.uFragmentShaderLogo, &error) == PVR_SUCCESS);
	bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DVertShaderLogo_vsh, GL_VERTEX_SHADER, &Data.uVertexShaderLogo, &error)  == PVR_SUCCESS);

	_ASSERT(bRes);

	// Create the 'text' program
	Data.uProgramLogo = glCreateProgram();
	glAttachShader(Data.uProgramLogo, Data.uVertexShaderLogo);
	glAttachShader(Data.uProgramLogo, Data.uFragmentShaderLogo);
	glBindAttribLocation(Data.uProgramLogo, VERTEX_ARRAY, "myVertex");
	glBindAttribLocation(Data.uProgramLogo, UV_ARRAY, "myUV");

	glLinkProgram(Data.uProgramLogo);
	glGetProgramiv(Data.uProgramLogo, GL_LINK_STATUS, &Linked);

	if (!Linked)
		bRes = false;

	bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DFragShader_fsh, GL_FRAGMENT_SHADER, &Data.uFragmentShaderFont, &error) == PVR_SUCCESS);
	bRes &= (PVRTShaderLoadSourceFromMemory(_Print3DVertShader_vsh, GL_VERTEX_SHADER, &Data.uVertexShaderFont, &error)  == PVR_SUCCESS);

	_ASSERT(bRes);

	// Create the 'text' program
	Data.uProgramFont = glCreateProgram();
	glAttachShader(Data.uProgramFont, Data.uVertexShaderFont);
	glAttachShader(Data.uProgramFont, Data.uFragmentShaderFont);
	glBindAttribLocation(Data.uProgramFont, VERTEX_ARRAY, "myVertex");
	glBindAttribLocation(Data.uProgramFont, UV_ARRAY, "myUV");
	glBindAttribLocation(Data.uProgramFont, COLOR_ARRAY, "myColour");

	glLinkProgram(Data.uProgramFont);
	glGetProgramiv(Data.uProgramFont, GL_LINK_STATUS, &Linked);

	if (!Linked)
		bRes = false;

	Data.mvpLocationLogo = glGetUniformLocation(Data.uProgramFont, "myMVPMatrix");
	Data.mvpLocationFont = glGetUniformLocation(Data.uProgramLogo, "myMVPMatrix");

	_ASSERT(bRes && Data.mvpLocationLogo != -1 && Data.mvpLocationFont != -1);

	return bRes;
}
Beispiel #7
0
/*!***************************************************************************
 @Function			Load
 @Input				src					PFX Parser Object
 @Input				pszEffect			Effect name
 @Input				pszFileName			Effect file name
 @Output			pReturnError		Error string
 @Returns			EPVRTError			PVR_SUCCESS if load succeeded
 @Description		Loads the specified effect from the CPVRTPFXParser object.
					Compiles and links the shaders. Initialises texture data.
*****************************************************************************/
EPVRTError CPVRTPFXEffect::Load(CPVRTPFXParser &src, const char * const pszEffect, const char * const pszFileName, CPVRTString *pReturnError)
{
	GLuint				uiVertexShader = 0, uiFragShader = 0;
	int		i, j;

	if(!src.m_psEffect.GetSize())
		return PVR_FAIL;

	/*
		First find the named effect from the effect file
	*/
	if(pszEffect)
	{
		for(i = 0; i < src.m_psEffect.GetSize(); ++i)
		{
			if(strcmp(src.m_psEffect[i].pszName, pszEffect) == 0)
			{
				m_nEffect = i;
				break;
			}
		}
		if(i == src.m_psEffect.GetSize())
		{
			return PVR_FAIL;
		}
	}
	else
	{
		m_nEffect = 0;
	}

	/*
		Now load the effect
	*/
	m_pParser = &src;
	SPVRTPFXParserEffect *psParserEffect = &src.m_psEffect[m_nEffect];

	// Create room for per-texture data
	m_psTextures = new SPVRTPFXTexture[src.m_psTexture.GetSize()];

	// Initialise each Texture
	for(i = 0; i < src.m_psTexture.GetSize(); ++i)
	{
		m_psTextures[i].p	= src.m_psTexture[i].pszFile;
		m_psTextures[i].ui	= 0xFFFFFFFF;
	}

	// Initialise the effect
	{
		// initialise attributes to default values
		char *pszVertexShader = NULL;
		char *pszFragmentShader = NULL;
		bool bFreeVertexShader = false;
		bool bFreeFragmentShader = false;

		// find shaders requested
		for(i=0; i < src.m_psVertexShader.GetSize(); ++i)
		{
			if(strcmp(psParserEffect->pszVertexShaderName, src.m_psVertexShader[i].pszName) == 0)
			{
                if(src.m_psVertexShader[i].bUseFileName)
				{
					pszVertexShader = src.m_psVertexShader[i].pszGLSLcode;
				}
				else
				{
					// offset glsl code by nFirstLineNumber
					pszVertexShader = (char *)malloc((strlen(src.m_psVertexShader[i].pszGLSLcode) + (src.m_psVertexShader[i].nFirstLineNumber) + 1) * sizeof(char));
					pszVertexShader[0] = '\0';
					for(unsigned int n = 0; n < src.m_psVertexShader[i].nFirstLineNumber; n++)
						strcat(pszVertexShader, "\n");
					strcat(pszVertexShader, src.m_psVertexShader[i].pszGLSLcode);

					bFreeVertexShader = true;
				}

				break;
			}
		}
		for(i=0; i<src.m_psFragmentShader.GetSize(); ++i)
		{
			if(strcmp(psParserEffect->pszFragmentShaderName, src.m_psFragmentShader[i].pszName) == 0)
			{
				if(src.m_psFragmentShader[i].bUseFileName)
				{
					pszFragmentShader = src.m_psFragmentShader[i].pszGLSLcode;
				}
				else
				{
					// offset glsl code by nFirstLineNumber
					pszFragmentShader = (char *)malloc((strlen(src.m_psFragmentShader[i].pszGLSLcode) + (src.m_psFragmentShader[i].nFirstLineNumber) + 1) * sizeof(char));
					pszFragmentShader[0] = '\0';
					for(unsigned int n = 0; n < src.m_psFragmentShader[i].nFirstLineNumber; n++)
						strcat(pszFragmentShader, "\n");
					strcat(pszFragmentShader, src.m_psFragmentShader[i].pszGLSLcode);

					bFreeFragmentShader = true;
				}

				break;
			}
		}

		CPVRTString error;
		bool		bLoadSource = 1;

		// Try first to load from the binary block
		if (src.m_psVertexShader[i].pbGLSLBinary!=NULL)
		{
#if defined(GL_SGX_BINARY_IMG)
			if (PVRTShaderLoadBinaryFromMemory(src.m_psVertexShader[i].pbGLSLBinary, src.m_psVertexShader[i].nGLSLBinarySize,
												GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &uiVertexShader, &error) == PVR_SUCCESS)
			{
				// success loading the binary block so we do not need to load the source
				bLoadSource = 0;
			}
			else
#endif
			{
				bLoadSource = 1;
			}
		}

		// If it fails, load from source
		if (bLoadSource)
		{
			if(pszVertexShader)
			{
				if (PVRTShaderLoadSourceFromMemory(pszVertexShader, GL_VERTEX_SHADER, &uiVertexShader, &error) != PVR_SUCCESS)
				{
					*pReturnError = CPVRTString("Vertex Shader compile error in file '") + pszFileName + "':\n" + error;
					if(bFreeVertexShader)	FREE(pszVertexShader);
					if(bFreeFragmentShader)	FREE(pszFragmentShader);
					return PVR_FAIL;
				}
			}
			else // Shader not found or failed binary block
			{
				if (src.m_psVertexShader[i].pbGLSLBinary==NULL)
				{
					*pReturnError = CPVRTString("Vertex shader ") + psParserEffect->pszVertexShaderName + "  not found in " + pszFileName + ".\n";
				}
				else
				{
					*pReturnError = CPVRTString("Binary vertex shader ") + psParserEffect->pszVertexShaderName + " not supported.\n";
				}

				if(bFreeVertexShader)	FREE(pszVertexShader);
				if(bFreeFragmentShader)	FREE(pszFragmentShader);
				return PVR_FAIL;
			}
		}

		// Try first to load from the binary block
		if (src.m_psFragmentShader[i].pbGLSLBinary!=NULL)
		{
#if defined(GL_SGX_BINARY_IMG)
			if (PVRTShaderLoadBinaryFromMemory(src.m_psFragmentShader[i].pbGLSLBinary, src.m_psVertexShader[i].nGLSLBinarySize,
													GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &uiFragShader, &error) == PVR_SUCCESS)
			{
				// success loading the binary block so we do not need to load the source
				bLoadSource = 0;
			}
			else
#endif
			{
				bLoadSource = 1;
			}
		}

		// If it fails, load from source
		if (bLoadSource)
		{
			if(pszFragmentShader)
			{
				if (PVRTShaderLoadSourceFromMemory(pszFragmentShader, GL_FRAGMENT_SHADER, &uiFragShader, &error) != PVR_SUCCESS)
				{
					*pReturnError = CPVRTString("Fragment Shader compile error in file '") + pszFileName + "':\n" + error;
					if(bFreeVertexShader)	FREE(pszVertexShader);
					if(bFreeFragmentShader)	FREE(pszFragmentShader);
					return PVR_FAIL;
				}
			}
			else // Shader not found or failed binary block
			{
				if (src.m_psFragmentShader[i].pbGLSLBinary==NULL)
				{
					*pReturnError = CPVRTString("Fragment shader ") + psParserEffect->pszFragmentShaderName + "  not found in " + pszFileName + ".\n";
				}
				else
				{
					*pReturnError = CPVRTString("Binary Fragment shader ") + psParserEffect->pszFragmentShaderName + " not supported.\n";
				}

				if(bFreeVertexShader)
					FREE(pszVertexShader);
				if(bFreeFragmentShader)
					FREE(pszFragmentShader);

				return PVR_FAIL;
			}
		}

		if(bFreeVertexShader)
			FREE(pszVertexShader);

		if(bFreeFragmentShader)
			FREE(pszFragmentShader);

		// Create the shader program
		m_uiProgram = glCreateProgram();


		// Attach the fragment and vertex shaders to it
		glAttachShader(m_uiProgram, uiFragShader);
		glAttachShader(m_uiProgram, uiVertexShader);

		glDeleteShader(uiVertexShader);
		glDeleteShader(uiFragShader);

		// Bind vertex attributes
		for(i = 0; i < (int) psParserEffect->nNumAttributes; ++i)
		{
			glBindAttribLocation(m_uiProgram, i, psParserEffect->psAttribute[i].pszName);
		}

		//	Link the program.
		glLinkProgram(m_uiProgram);
		GLint Linked;
		glGetProgramiv(m_uiProgram, GL_LINK_STATUS, &Linked);
		if (!Linked)
		{
			int i32InfoLogLength, i32CharsWritten;
			glGetProgramiv(m_uiProgram, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
			char* pszInfoLog = new char[i32InfoLogLength];
			glGetProgramInfoLog(m_uiProgram, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
			*pReturnError = CPVRTString("Error Linking shaders in file '") + pszFileName + "':\n\n"
							+ CPVRTString("Failed to link: ") + pszInfoLog + "\n";
			delete [] pszInfoLog;
			return PVR_FAIL;
		}

		/*
			Textures
		*/
		m_pnTextureIdx = new unsigned int[psParserEffect->nNumTextures];
		for(i = 0; i < (int) psParserEffect->nNumTextures; ++i)
		{
			for(j = 0; j < src.m_psTexture.GetSize(); ++j)
			{
				if(strcmp(psParserEffect->psTextures[i].pszName, src.m_psTexture[j].pszName) == 0)
				{
					m_pnTextureIdx[i] = j;
					break;
				}
			}
			if(j == src.m_psTexture.GetSize())
			{
				*pReturnError = CPVRTString("Effect \"") +  psParserEffect->pszName + "\", requested non-existent texture: \""
								+ psParserEffect->psTextures[i].pszName + "\"\n";
				m_pnTextureIdx[i] = 0;
			}
		}
	}

	return PVR_SUCCESS;
}