Home | History | Annotate | Download | only in OGLES2
      1 /******************************************************************************
      2 
      3  @File         OGLES2/PVRTPFXParserAPI.cpp
      4 
      5  @Title        OGLES2/PVRTPFXParserAPI
      6 
      7  @Version
      8 
      9  @Copyright    Copyright (c) Imagination Technologies Limited.
     10 
     11  @Platform     ANSI compatible
     12 
     13  @Description  PFX file parser.
     14 
     15 ******************************************************************************/
     16 
     17 /*****************************************************************************
     18 ** Includes
     19 *****************************************************************************/
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <stdlib.h>
     23 
     24 #include "PVRTContext.h"
     25 #include "PVRTMatrix.h"
     26 #include "PVRTFixedPoint.h"
     27 #include "PVRTString.h"
     28 #include "PVRTShader.h"
     29 #include "PVRTPFXParser.h"
     30 #include "PVRTPFXParserAPI.h"
     31 #include "PVRTPFXSemantics.h"
     32 #include "PVRTTexture.h"
     33 #include "PVRTTextureAPI.h"
     34 
     35 /*!***************************************************************************
     36  @Function			CPVRTPFXEffect Constructor
     37  @Description		Sets the context and initialises the member variables to zero.
     38 *****************************************************************************/
     39 CPVRTPFXEffect::CPVRTPFXEffect():
     40 	m_bLoaded(false), m_psContext(NULL), m_pParser(NULL), m_nEffect(0), m_uiProgram(0), m_Semantics(PVRTPFXSemanticsGetSemanticList(), ePVRTPFX_NumSemantics)
     41 {
     42 }
     43 
     44 /*!***************************************************************************
     45  @Function			CPVRTPFXEffect Constructor
     46  @Description		Sets the context and initialises the member variables to zero.
     47 *****************************************************************************/
     48 CPVRTPFXEffect::CPVRTPFXEffect(SPVRTContext &sContext):
     49 	m_bLoaded(false), m_psContext(&sContext), m_pParser(NULL), m_nEffect(0), m_uiProgram(0), m_Semantics(PVRTPFXSemanticsGetSemanticList(), ePVRTPFX_NumSemantics)
     50 {
     51 }
     52 
     53 /*!***************************************************************************
     54  @Function			CPVRTPFXEffect Destructor
     55  @Description		Calls Destroy().
     56 *****************************************************************************/
     57 CPVRTPFXEffect::~CPVRTPFXEffect()
     58 {
     59 	Destroy();
     60 
     61 	// Free allocated strings
     62 	for(unsigned int uiIndex = ePVRTPFX_NumSemantics; uiIndex < m_Semantics.GetSize(); ++uiIndex)
     63 	{
     64 		delete [] m_Semantics[uiIndex].p;
     65 		m_Semantics[uiIndex].p = NULL;
     66 	}
     67 }
     68 
     69 /*!***************************************************************************
     70  @Function			Load
     71  @Input				src					PFX Parser Object
     72  @Input				pszEffect			Effect name
     73  @Input				pszFileName			Effect file name
     74  @Output			pReturnError		Error string
     75  @Returns			EPVRTError			PVR_SUCCESS if load succeeded
     76  @Description		Loads the specified effect from the CPVRTPFXParser object.
     77 					Compiles and links the shaders. Initialises texture data.
     78 *****************************************************************************/
     79 EPVRTError CPVRTPFXEffect::Load(CPVRTPFXParser &src, const char * const pszEffect, const char * const pszFileName,
     80 								PVRTPFXEffectDelegate* pDelegate, unsigned int& uiUnknownUniforms, CPVRTString *pReturnError)
     81 {
     82 	unsigned int	 i;
     83 
     84 	if(!src.GetNumberEffects())
     85 		return PVR_FAIL;
     86 
     87 	// --- First find the named effect from the effect file
     88 	if(pszEffect)
     89 	{
     90 		int iEffect = src.FindEffectByName(CPVRTStringHash(pszEffect));
     91 		if(iEffect == -1)
     92 			return PVR_FAIL;
     93 
     94 		m_nEffect = (unsigned int)iEffect;
     95 	}
     96 	else
     97 	{
     98 		m_nEffect = 0;
     99 	}
    100 
    101 	// --- Now load the effect
    102 	m_pParser = &src;
    103 	const SPVRTPFXParserEffect &ParserEffect = src.GetEffect(m_nEffect);
    104 
    105 	// Create room for per-texture data
    106 	const CPVRTArray<SPVRTPFXParserEffectTexture>& EffectTextures = src.GetEffect(m_nEffect).Textures;
    107 	unsigned int uiNumTexturesForEffect = EffectTextures.GetSize();
    108 	m_Textures.SetCapacity(uiNumTexturesForEffect);
    109 
    110 	// Initialise each Texture
    111 	for(i = 0; i < uiNumTexturesForEffect; ++i)
    112 	{
    113 		int iTexIdx = src.FindTextureByName(EffectTextures[i].Name);
    114 		if(iTexIdx < 0)
    115 		{
    116 			*pReturnError += PVRTStringFromFormattedStr("ERROR: Effect '%s' requests non-existent texture: %s\n", ParserEffect.Name.c_str(), EffectTextures[i].Name.c_str());
    117 			return PVR_FAIL;
    118 		}
    119 
    120 		unsigned int uiTexIdx = m_Textures.Append();
    121 		m_Textures[uiTexIdx].Name	= src.GetTexture((unsigned int)iTexIdx)->Name;
    122 		m_Textures[uiTexIdx].ui		= 0xFFFFFFFF;
    123 		m_Textures[uiTexIdx].flags	= 0;
    124 		m_Textures[uiTexIdx].unit	= 0;
    125 	}
    126 
    127 	// Load the shaders
    128 	if(LoadShadersForEffect(src, pszFileName, pReturnError) != PVR_SUCCESS)
    129 		return PVR_FAIL;
    130 
    131 	// Build uniform table
    132 	if(RebuildUniformTable(uiUnknownUniforms, pReturnError) != PVR_SUCCESS)
    133 		return PVR_FAIL;
    134 
    135 	// Load the requested textures
    136 	if(pDelegate)
    137 	{
    138 		if(LoadTexturesForEffect(pDelegate, pReturnError) != PVR_SUCCESS)
    139 			return PVR_FAIL;
    140 	}
    141 
    142 	m_bLoaded = true;
    143 
    144 	return PVR_SUCCESS;
    145 }
    146 
    147 /*!***************************************************************************
    148 @Function		LoadTexturesForEffect
    149 @Output			pReturnError
    150 @Return			EPVRTError
    151 @Description	Loads all of the textures for this effect.
    152 *****************************************************************************/
    153 EPVRTError CPVRTPFXEffect::LoadTexturesForEffect(PVRTPFXEffectDelegate* pDelegate, CPVRTString *pReturnError)
    154 {
    155 	GLuint			uiHandle;
    156 	unsigned int	uiFlags;
    157 
    158 	for(unsigned int i = 0; i < m_Textures.GetSize(); ++i)
    159 	{
    160 		int iTexID = m_pParser->FindTextureByName(m_Textures[i].Name);
    161 		if(iTexID == -1)
    162 		{
    163 			*pReturnError += PVRTStringFromFormattedStr("ERROR: Cannot find texture '%s' in any TEXTURE block.\n", m_Textures[i].Name.c_str());
    164 			return PVR_FAIL;
    165 		}
    166 
    167 		const SPVRTPFXParserTexture* pTexDesc = m_pParser->GetTexture(iTexID);
    168 
    169 
    170 		uiHandle = 0xBADF00D;
    171 		uiFlags  = 0;
    172 
    173 		if(pDelegate->PVRTPFXOnLoadTexture(pTexDesc->FileName, uiHandle, uiFlags) != PVR_SUCCESS)
    174 		{
    175 			*pReturnError += PVRTStringFromFormattedStr("ERROR: Failed to load texture: %s.\n", pTexDesc->FileName.c_str());
    176 			return PVR_FAIL;
    177 		}
    178 
    179 		// Make sure uiHandle was written.
    180 		if(uiHandle == 0xBADF00D)
    181 		{
    182 			*pReturnError += PVRTStringFromFormattedStr("ERROR: GL handle for texture '%s' not set!\n", pTexDesc->FileName.c_str());
    183 			return PVR_FAIL;
    184 		}
    185 
    186 		SetTexture(i, uiHandle, uiFlags);
    187 	}
    188 
    189 	return PVR_SUCCESS;
    190 }
    191 
    192 /*!***************************************************************************
    193 @Function		LoadShadersForEffect
    194 @Input			pszFileName
    195 @Output			pReturnError
    196 @Return			EPVRTError
    197 @Description	Loads all of the GLSL shaders for an effect.
    198 *****************************************************************************/
    199 EPVRTError CPVRTPFXEffect::LoadShadersForEffect(CPVRTPFXParser &src, const char * const pszFileName, CPVRTString *pReturnError)
    200 {
    201 	// initialise attributes to default values
    202 	char *pszVertexShader		= NULL;
    203 	char *pszFragmentShader		= NULL;
    204 	bool bFreeVertexShader		= false;
    205 	bool bFreeFragmentShader	= false;
    206 	unsigned int uiVertIdx		= 0;
    207 	unsigned int uiFragIdx		= 0;
    208 	unsigned int uiVertexShader	= 0;
    209 	unsigned int uiFragShader	= 0;
    210 
    211 	const SPVRTPFXParserEffect &ParserEffect = src.GetEffect(m_nEffect);
    212 
    213 	// find shaders requested
    214 	for(uiVertIdx = 0; uiVertIdx < src.GetNumberVertexShaders(); ++uiVertIdx)
    215 	{
    216 		const SPVRTPFXParserShader& VertexShader = src.GetVertexShader(uiVertIdx);
    217 		if(ParserEffect.VertexShaderName == VertexShader.Name)
    218 		{
    219 			if(VertexShader.bUseFileName)
    220 			{
    221 				pszVertexShader = VertexShader.pszGLSLcode;
    222 			}
    223 			else
    224 			{
    225 				if(!VertexShader.pszGLSLcode)
    226 					continue;			// No code specified.
    227 #if 0
    228 				// offset glsl code by nFirstLineNumber
    229 				pszVertexShader = (char *)malloc((strlen(VertexShader.pszGLSLcode) + (VertexShader.nFirstLineNumber) + 1) * sizeof(char));
    230 				pszVertexShader[0] = '\0';
    231 			 	for(unsigned int n = 0; n < VertexShader.nFirstLineNumber; n++)
    232 					strcat(pszVertexShader, "\n");
    233 				strcat(pszVertexShader, VertexShader.pszGLSLcode);
    234 #else
    235 				pszVertexShader = (char *)malloc(strlen(VertexShader.pszGLSLcode) + 1);
    236 				pszVertexShader[0] = '\0';
    237 				strcat(pszVertexShader, VertexShader.pszGLSLcode);
    238 #endif
    239 				bFreeVertexShader = true;
    240 			}
    241 
    242 			break;
    243 		}
    244 	}
    245 	for(uiFragIdx = 0; uiFragIdx < src.GetNumberFragmentShaders(); ++uiFragIdx)
    246 	{
    247 		const SPVRTPFXParserShader& FragmentShader = src.GetFragmentShader(uiFragIdx);
    248 		if(ParserEffect.FragmentShaderName == FragmentShader.Name)
    249 		{
    250 			if(FragmentShader.bUseFileName)
    251 			{
    252 				pszFragmentShader = FragmentShader.pszGLSLcode;
    253 			}
    254 			else
    255 			{
    256 				if(!FragmentShader.pszGLSLcode)
    257 					continue;			// No code specified.
    258 
    259 #if 0
    260 				// offset glsl code by nFirstLineNumber
    261 				pszFragmentShader = (char *)malloc((strlen(FragmentShader.pszGLSLcode) + (FragmentShader.nFirstLineNumber) + 1) * sizeof(char));
    262 				pszFragmentShader[0] = '\0';
    263 				for(unsigned int n = 0; n < FragmentShader.nFirstLineNumber; n++)
    264 					strcat(pszFragmentShader, "\n");
    265 				strcat(pszFragmentShader, FragmentShader.pszGLSLcode);
    266 #else
    267 				pszFragmentShader = (char *)malloc(strlen(FragmentShader.pszGLSLcode) + 1);
    268 				pszFragmentShader[0] = '\0';
    269 				strcat(pszFragmentShader, FragmentShader.pszGLSLcode);
    270 #endif
    271 				bFreeFragmentShader = true;
    272 			}
    273 
    274 			break;
    275 		}
    276 	}
    277 
    278 	CPVRTString error;
    279 	bool		bLoadSource = 1;
    280 
    281 	// Try first to load from the binary block
    282 	if (src.GetVertexShader(uiVertIdx).pbGLSLBinary!=NULL)
    283 	{
    284 #if defined(GL_SGX_BINARY_IMG)
    285 		if (PVRTShaderLoadBinaryFromMemory(src.GetVertexShader(uiVertIdx).pbGLSLBinary, src.GetVertexShader(uiVertIdx).nGLSLBinarySize,
    286 			GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &uiVertexShader, &error) == PVR_SUCCESS)
    287 		{
    288 			// success loading the binary block so we do not need to load the source
    289 			bLoadSource = 0;
    290 		}
    291 		else
    292 #endif
    293 		{
    294 			bLoadSource = 1;
    295 		}
    296 	}
    297 
    298 	// If it fails, load from source
    299 	if (bLoadSource)
    300 	{
    301 		if(pszVertexShader)
    302 		{
    303 			if (PVRTShaderLoadSourceFromMemory(pszVertexShader, GL_VERTEX_SHADER, &uiVertexShader, &error) != PVR_SUCCESS)
    304 			{
    305 				*pReturnError = CPVRTString("ERROR: Vertex Shader compile error in file '") + pszFileName + "':\n" + error;
    306 				if(bFreeVertexShader)	FREE(pszVertexShader);
    307 				if(bFreeFragmentShader)	FREE(pszFragmentShader);
    308 				return PVR_FAIL;
    309 			}
    310 		}
    311 		else // Shader not found or failed binary block
    312 		{
    313 			if (src.GetVertexShader(uiVertIdx).pbGLSLBinary==NULL)
    314 			{
    315 				*pReturnError = CPVRTString("ERROR: Vertex shader ") + ParserEffect.VertexShaderName.String() + "  not found in " + pszFileName + ".\n";
    316 			}
    317 			else
    318 			{
    319 				*pReturnError = CPVRTString("ERROR: Binary vertex shader ") + ParserEffect.VertexShaderName.String() + " not supported.\n";
    320 			}
    321 
    322 			if(bFreeVertexShader)	FREE(pszVertexShader);
    323 			if(bFreeFragmentShader)	FREE(pszFragmentShader);
    324 			return PVR_FAIL;
    325 		}
    326 	}
    327 
    328 	// Try first to load from the binary block
    329 	if (src.GetFragmentShader(uiFragIdx).pbGLSLBinary!=NULL)
    330 	{
    331 #if defined(GL_SGX_BINARY_IMG)
    332 		if (PVRTShaderLoadBinaryFromMemory(src.GetFragmentShader(uiFragIdx).pbGLSLBinary, src.GetFragmentShader(uiFragIdx).nGLSLBinarySize,
    333 			GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &uiFragShader, &error) == PVR_SUCCESS)
    334 		{
    335 			// success loading the binary block so we do not need to load the source
    336 			bLoadSource = 0;
    337 		}
    338 		else
    339 #endif
    340 		{
    341 			bLoadSource = 1;
    342 		}
    343 	}
    344 
    345 	// If it fails, load from source
    346 	if (bLoadSource)
    347 	{
    348 		if(pszFragmentShader)
    349 		{
    350 			if (PVRTShaderLoadSourceFromMemory(pszFragmentShader, GL_FRAGMENT_SHADER, &uiFragShader, &error) != PVR_SUCCESS)
    351 			{
    352 				*pReturnError = CPVRTString("ERROR: Fragment Shader compile error in file '") + pszFileName + "':\n" + error;
    353 				if(bFreeVertexShader)	FREE(pszVertexShader);
    354 				if(bFreeFragmentShader)	FREE(pszFragmentShader);
    355 				return PVR_FAIL;
    356 			}
    357 		}
    358 		else // Shader not found or failed binary block
    359 		{
    360 			if (src.GetFragmentShader(uiFragIdx).pbGLSLBinary==NULL)
    361 			{
    362 				*pReturnError = CPVRTString("ERROR: Fragment shader ") + ParserEffect.FragmentShaderName.String() + "  not found in " + pszFileName + ".\n";
    363 			}
    364 			else
    365 			{
    366 				*pReturnError = CPVRTString("ERROR: Binary Fragment shader ") + ParserEffect.FragmentShaderName.String() + " not supported.\n";
    367 			}
    368 
    369 			if(bFreeVertexShader)
    370 				FREE(pszVertexShader);
    371 			if(bFreeFragmentShader)
    372 				FREE(pszFragmentShader);
    373 
    374 			return PVR_FAIL;
    375 		}
    376 	}
    377 
    378 	if(bFreeVertexShader)
    379 		FREE(pszVertexShader);
    380 
    381 	if(bFreeFragmentShader)
    382 		FREE(pszFragmentShader);
    383 
    384 	// Create the shader program
    385 	m_uiProgram = glCreateProgram();
    386 
    387 
    388 	// Attach the fragment and vertex shaders to it
    389 	glAttachShader(m_uiProgram, uiFragShader);
    390 	glAttachShader(m_uiProgram, uiVertexShader);
    391 
    392 	glDeleteShader(uiVertexShader);
    393 	glDeleteShader(uiFragShader);
    394 
    395 	// Bind vertex attributes
    396 	for(unsigned int i = 0; i < ParserEffect.Attributes.GetSize(); ++i)
    397 	{
    398 		glBindAttribLocation(m_uiProgram, i, ParserEffect.Attributes[i].pszName);
    399 	}
    400 
    401 	//	Link the program.
    402 	glLinkProgram(m_uiProgram);
    403 	GLint Linked;
    404 	glGetProgramiv(m_uiProgram, GL_LINK_STATUS, &Linked);
    405 	if (!Linked)
    406 	{
    407 		int i32InfoLogLength, i32CharsWritten;
    408 		glGetProgramiv(m_uiProgram, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
    409 		char* pszInfoLog = new char[i32InfoLogLength];
    410 		glGetProgramInfoLog(m_uiProgram, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
    411 		*pReturnError = CPVRTString("ERROR: Linking shaders in file '") + pszFileName + "':\n\n"
    412 			+ CPVRTString("Failed to link: ") + pszInfoLog + "\n";
    413 		delete [] pszInfoLog;
    414 		return PVR_FAIL;
    415 	}
    416 
    417 	return PVR_SUCCESS;
    418 }
    419 
    420 /*!***************************************************************************
    421  @Function			Destroy
    422  @Description		Deletes the gl program object and texture data.
    423 *****************************************************************************/
    424 void CPVRTPFXEffect::Destroy()
    425 {
    426 	{
    427 		if(m_uiProgram != 0)
    428 		{
    429             GLint val;
    430             glGetProgramiv(m_uiProgram, GL_DELETE_STATUS, &val);
    431             if(val == GL_FALSE)
    432             {
    433                 glDeleteProgram(m_uiProgram);
    434             }
    435 			m_uiProgram = 0;
    436 		}
    437 	}
    438 
    439 	m_bLoaded = false;
    440 }
    441 
    442 /*!***************************************************************************
    443  @Function			Activate
    444  @Returns			PVR_SUCCESS if activate succeeded
    445  @Description		Selects the gl program object and binds the textures.
    446 *****************************************************************************/
    447 EPVRTError CPVRTPFXEffect::Activate(const int i32RenderTextureId, const unsigned int ui32ReplacementTexture)
    448 {
    449 	GLuint uiTextureId;
    450 	GLenum eTarget;
    451 
    452 	// Set the program
    453 	glUseProgram(m_uiProgram);
    454 
    455 	// Set the textures
    456 	for(unsigned int uiTex = 0; uiTex < m_Textures.GetSize(); ++uiTex)
    457 	{
    458 		uiTextureId = m_Textures[uiTex].ui;
    459 		if(i32RenderTextureId != -1 && (uiTextureId == (unsigned int)i32RenderTextureId))
    460 			uiTextureId = ui32ReplacementTexture;
    461 
    462 		// Set active texture unit.
    463 		glActiveTexture(GL_TEXTURE0 + m_Textures[uiTex].unit);
    464 
    465 		// Bind texture
    466 		eTarget = (m_Textures[uiTex].flags & PVRTEX_CUBEMAP ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
    467 		glBindTexture(eTarget, uiTextureId);
    468 	}
    469 
    470 	return PVR_SUCCESS;
    471 }
    472 
    473 /*!***************************************************************************
    474  @Function			GetSemantics
    475  @Output			aUniforms				an array of uniform data
    476  @Output			pnUnknownUniformCount	unknown uniform count
    477  @Input				psParams				pointer to semantic data array
    478  @Input				nParamCount				number of samantic items
    479  @Input				psUniformSemantics		pointer to uniform semantics array
    480  @Input				nUniformSemantics		number of uniform semantic items
    481  @Input				pglesExt				opengl extensions object
    482  @Input				uiProgram				program object index
    483  @Input				bIsAttribue				true if getting attribute semantics
    484  @Output			errorMsg				error string
    485  @Returns			unsigned int			number of successful semantics
    486  @Description		Get the data array for the semantics.
    487 *****************************************************************************/
    488 static unsigned int GetSemantics(
    489 	CPVRTArray<SPVRTPFXUniform>&				aUniforms,
    490 	const CPVRTArray<SPVRTPFXParserSemantic>&	aParams,
    491 	const CPVRTArray<SPVRTPFXUniformSemantic>&	aUniformSemantics,
    492 	unsigned int*								const pnUnknownUniformCount,
    493 	const GLuint								uiProgram,
    494 	bool										bIsAttribue,
    495 	CPVRTString*								const errorMsg)
    496 {
    497 	unsigned int	i, j, nCount, nCountUnused;
    498 	int				nLocation;
    499 
    500 	/*
    501 		Loop over the parameters searching for their semantics. If
    502 		found/recognised, it should be placed in the output array.
    503 	*/
    504 	nCount = 0;
    505 	nCountUnused = 0;
    506 	char szTmpUniformName[2048];		// Temporary buffer to use for building uniform names.
    507 
    508 	for(j = 0; j < aParams.GetSize(); ++j)
    509 	{
    510 		for(i = 0; i < aUniformSemantics.GetSize(); ++i)
    511 		{
    512 			if(strcmp(aParams[j].pszValue, aUniformSemantics[i].p) != 0)
    513 			{
    514 				continue;
    515 			}
    516 
    517 			// Semantic found for this parameter
    518 			if(bIsAttribue)
    519 			{
    520 				nLocation = glGetAttribLocation(uiProgram, aParams[j].pszName);
    521 			}
    522 			else
    523 			{
    524 				nLocation = glGetUniformLocation(uiProgram, aParams[j].pszName);
    525 
    526 				// Check for array. Workaround for some OpenGL:ES implementations which require array element appended to uniform name
    527 				// in order to return the correct location.
    528 				if(nLocation == -1)
    529 				{
    530 					strcpy(szTmpUniformName, aParams[j].pszName);
    531 					strcat(szTmpUniformName, "[0]");
    532 					nLocation = glGetUniformLocation(uiProgram, szTmpUniformName);
    533 				}
    534 			}
    535 
    536 			if(nLocation != -1)
    537 			{
    538 				unsigned int uiIdx = aUniforms.Append();
    539 				aUniforms[uiIdx].nSemantic	= aUniformSemantics[i].n;
    540 				aUniforms[uiIdx].nLocation	= nLocation;
    541 				aUniforms[uiIdx].nIdx		= aParams[j].nIdx;
    542 				aUniforms[uiIdx].sValueName	= aParams[j].pszName;
    543 				++nCount;
    544 			}
    545 			else
    546 			{
    547 				*errorMsg += "WARNING: Variable not used by GLSL code: ";
    548 				*errorMsg += CPVRTString(aParams[j].pszName) + " ";
    549 				*errorMsg += CPVRTString(aParams[j].pszValue) + "\n";
    550 				++nCountUnused;
    551 			}
    552 
    553 			// Skip to the next parameter
    554 			break;
    555 		}
    556 		if(i == aUniformSemantics.GetSize())
    557 		{
    558 			*errorMsg += "WARNING: Semantic unknown to application: ";
    559 			*errorMsg += CPVRTString(aParams[j].pszValue) + "\n";
    560 		}
    561 	}
    562 
    563 	*pnUnknownUniformCount	= aParams.GetSize() - nCount - nCountUnused;
    564 	return nCount;
    565 }
    566 
    567 /*!***************************************************************************
    568 @Function		GetUniformArray
    569 @Return			const CPVRTArray<SPVRTPFXUniform>&
    570 @Description	Returns a list of known semantics.
    571 *****************************************************************************/
    572 const CPVRTArray<SPVRTPFXUniform>& CPVRTPFXEffect::GetUniformArray() const
    573 {
    574 	return m_Uniforms;
    575 }
    576 
    577 /*!***************************************************************************
    578 @Function		BuildUniformTable
    579 @Output			uiUnknownSemantics
    580 @Output			pReturnError
    581 @Return			EPVRTError
    582 @Description	Builds the uniform table from a list of known semantics.
    583 *****************************************************************************/
    584 EPVRTError CPVRTPFXEffect::RebuildUniformTable(unsigned int& uiUnknownSemantics, CPVRTString* pReturnError)
    585 {
    586 	unsigned int			nUnknownCount;
    587 	const SPVRTPFXParserEffect&	ParserEffect = m_pParser->GetEffect(m_nEffect);
    588 
    589 	GetSemantics(m_Uniforms, ParserEffect.Uniforms, m_Semantics, &nUnknownCount, m_uiProgram, false, pReturnError);
    590 	uiUnknownSemantics	= nUnknownCount;
    591 
    592 	GetSemantics(m_Uniforms, ParserEffect.Attributes, m_Semantics, &nUnknownCount, m_uiProgram, true, pReturnError);
    593 	uiUnknownSemantics	+= nUnknownCount;
    594 
    595 	return PVR_SUCCESS;
    596 }
    597 
    598 /*!***************************************************************************
    599 @Function		RegisterUniformSemantic
    600 @Input			psUniforms
    601 @Input			uiNumUniforms
    602 @Return			EPVRTError
    603 @Description	Registers a user-provided uniform semantic.
    604 *****************************************************************************/
    605 EPVRTError CPVRTPFXEffect::RegisterUniformSemantic(const SPVRTPFXUniformSemantic* const psUniforms, unsigned int uiNumUniforms, CPVRTString* pReturnError)
    606 {
    607 	for(unsigned int uiIndex = 0; uiIndex < uiNumUniforms; ++uiIndex)
    608 	{
    609 		// Check that this doesn't already exist.
    610 		if(m_Semantics.Contains(psUniforms[uiIndex]))
    611 		{
    612 			*pReturnError += PVRTStringFromFormattedStr("ERROR: Uniform semantic with ID '%u' already exists.\n", psUniforms[uiIndex].n);
    613 			return PVR_FAIL;
    614 		}
    615 
    616 		// Make copy as we need to manage the memory.
    617 		char* pSemName = new char[strlen(psUniforms[uiIndex].p)+1];
    618 		strcpy(pSemName, psUniforms[uiIndex].p);
    619 
    620 		unsigned int uiIdx = m_Semantics.Append();
    621 		m_Semantics[uiIdx].n = psUniforms[uiIndex].n;
    622 		m_Semantics[uiIdx].p = pSemName;
    623 	}
    624 
    625 	// Check if the effect has already been loaded. If it hasn't, great. If it has, we need to rebuild the uniform table.
    626 	if(m_bLoaded)
    627 	{
    628 		// Clear the current list.
    629 		m_Uniforms.Clear();
    630 
    631 		unsigned int uiUnknownSemantics;
    632 		return RebuildUniformTable(uiUnknownSemantics, pReturnError);
    633 	}
    634 
    635 	return PVR_SUCCESS;
    636 }
    637 
    638 /*!***************************************************************************
    639 @Function		RemoveUniformSemantic
    640 @Input			uiSemanticID
    641 @Output			pReturnError
    642 @Return			PVR_SUCCESS on success
    643 @Description	Removes a given semantic ID from the 'known' semantic list and
    644 				re-parses the effect to update the uniform table.
    645 *****************************************************************************/
    646 EPVRTError CPVRTPFXEffect::RemoveUniformSemantic(unsigned int uiSemanticID, CPVRTString* pReturnError)
    647 {
    648 	// Make sure that the given ID isn't a PFX semantic
    649 	if(uiSemanticID < ePVRTPFX_NumSemantics)
    650 	{
    651 		*pReturnError += "ERROR: Cannot remove a default PFX semantic.";
    652 		return PVR_FAIL;
    653 	}
    654 
    655 	// Find the index in the array
    656 	unsigned int uiSemanticIndex = 0;
    657 	while(uiSemanticIndex < m_Semantics.GetSize() && m_Semantics[uiSemanticIndex].n != uiSemanticID) ++uiSemanticIndex;
    658 
    659 	if(uiSemanticIndex == m_Semantics.GetSize())
    660 	{
    661 		*pReturnError += PVRTStringFromFormattedStr("ERROR: Semantic with ID %d does not exist.", uiSemanticID);
    662 		return PVR_FAIL;
    663 	}
    664 
    665 	m_Semantics.Remove(uiSemanticIndex);
    666 
    667 	// Check if the effect has already been loaded. If it hasn't, great. If it has, we need to rebuild the uniform table.
    668 	if(m_bLoaded)
    669 	{
    670 		// Clear the current list.
    671 		m_Uniforms.Clear();
    672 
    673 		unsigned int uiUnknownSemantics;
    674 		return RebuildUniformTable(uiUnknownSemantics, pReturnError);
    675 	}
    676 
    677 	return PVR_SUCCESS;
    678 }
    679 
    680 /*!***************************************************************************
    681  @Function			GetTextureArray
    682  @Output			nCount					number of textures
    683  @Returns			SPVRTPFXTexture*		pointer to the texture data array
    684  @Description		Gets the texture data array.
    685 *****************************************************************************/
    686 const CPVRTArray<SPVRTPFXTexture>& CPVRTPFXEffect::GetTextureArray() const
    687 {
    688 	return m_Textures;
    689 }
    690 
    691 /*!***************************************************************************
    692  @Function			SetTexture
    693  @Input				nIdx				texture number
    694  @Input				ui					opengl texture handle
    695  @Input				u32flags			texture flags
    696  @Description		Sets the textrue and applys the filtering.
    697 *****************************************************************************/
    698 void CPVRTPFXEffect::SetTexture(const unsigned int nIdx, const GLuint ui, const unsigned int u32flags)
    699 {
    700 	if(nIdx < (unsigned int) m_Textures.GetSize())
    701 	{
    702 		GLenum u32Target = GL_TEXTURE_2D;
    703 
    704 		// Check if texture is a cubemap
    705 		if((u32flags & PVRTEX_CUBEMAP) != 0)
    706 			u32Target = GL_TEXTURE_CUBE_MAP;
    707 
    708 		// Get the texture details from the PFX Parser. This contains details such as mipmapping and filter modes.
    709 		const CPVRTStringHash& TexName = m_pParser->GetEffect(m_nEffect).Textures[nIdx].Name;
    710 		int iTexIdx = m_pParser->FindTextureByName(TexName);
    711 		if(iTexIdx == -1)
    712 			return;
    713 
    714 		const SPVRTPFXParserTexture* pPFXTex = m_pParser->GetTexture(iTexIdx);
    715 
    716 		// Only change parameters if ui (handle is > 0)
    717 		if(ui > 0)
    718 		{
    719 			glBindTexture(u32Target, ui);
    720 
    721 			// Set default filter from PFX file
    722 
    723 			// --- Mipmapping/Minification
    724 			switch(pPFXTex->nMIP)
    725 			{
    726 			case eFilter_None:			// No mipmapping
    727 				switch(pPFXTex->nMin)
    728 				{
    729 				case eFilter_Nearest:
    730 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);					// Off
    731 					break;
    732 				case eFilter_Linear:
    733 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);					// Bilinear - no Mipmap
    734 					break;
    735 				}
    736 				break;
    737 			case eFilter_Nearest:		// Standard mipmapping
    738 				switch(pPFXTex->nMin)
    739 				{
    740 				case eFilter_Nearest:
    741 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);		// Nearest	- std. Mipmap
    742 					break;
    743 				case eFilter_Linear:
    744 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);		// Bilinear - std. Mipmap
    745 					break;
    746 				}
    747 				break;
    748 			case eFilter_Linear:		// Trilinear mipmapping
    749 				switch(pPFXTex->nMin)
    750 				{
    751 				case eFilter_Nearest:
    752 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);		// Nearest - Trilinear
    753 					break;
    754 				case eFilter_Linear:
    755 					glTexParameteri(u32Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);			// Bilinear - Trilinear
    756 					break;
    757 				}
    758 				break;
    759 			}
    760 
    761 			// --- Magnification
    762 			switch(pPFXTex->nMag)
    763 			{
    764 			case eFilter_Nearest:
    765 				glTexParameteri(u32Target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    766 				break;
    767 			case eFilter_Linear:
    768 				glTexParameteri(u32Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    769 				break;
    770 			}
    771 
    772 			// --- Wrapping S
    773 			switch(pPFXTex->nWrapS)
    774 			{
    775 			case eWrap_Clamp:
    776 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    777 				break;
    778 			case eWrap_Repeat:
    779 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_S, GL_REPEAT);
    780 				break;
    781 			}
    782 
    783 			// --- Wrapping T
    784 			switch(pPFXTex->nWrapT)
    785 			{
    786 			case eWrap_Clamp:
    787 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    788 				break;
    789 			case eWrap_Repeat:
    790 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_T, GL_REPEAT);
    791 				break;
    792 			}
    793 
    794 			// --- Wrapping R
    795 	#ifdef GL_TEXTURE_WRAP_R
    796 			switch(pPFXTex->nWrapR)
    797 			{
    798 			case eWrap_Clamp:
    799 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    800 				break;
    801 			case eWrap_Repeat:
    802 				glTexParameteri(u32Target, GL_TEXTURE_WRAP_R, GL_REPEAT);
    803 				break;
    804 			}
    805 	#endif
    806 		}
    807 
    808 		// Store the texture details
    809 		m_Textures[nIdx].ui	   = ui;
    810 		m_Textures[nIdx].flags = u32flags;
    811 
    812 		// Find the texture unit from the parser
    813 		unsigned int uiIndex = m_pParser->FindTextureIndex(pPFXTex->Name, m_nEffect);
    814 		if(uiIndex != 0xFFFFFFFF)
    815 		{
    816 			m_Textures[nIdx].unit = m_pParser->GetEffect(m_nEffect).Textures[uiIndex].nNumber;
    817 		}
    818 	}
    819 }
    820 
    821 
    822 /*!***************************************************************************
    823  @Function			SetDefaultSemanticValue
    824  @Input				pszName				name of uniform
    825  @Input				psDefaultValue      pointer to default value
    826  @Description		Sets the default value for the uniform semantic.
    827 *****************************************************************************/
    828 void CPVRTPFXEffect::SetDefaultUniformValue(const char *const pszName, const SPVRTSemanticDefaultData *psDefaultValue)
    829 {
    830 
    831 	GLint nLocation = glGetUniformLocation(m_uiProgram, pszName);
    832 	// Check for array. Workaround for some OpenGL:ES implementations which require array element appended to uniform name
    833 	// in order to return the correct location.
    834 	if(nLocation == -1)
    835 	{
    836 		char szTmpUniformName[2048];
    837 		strcpy(szTmpUniformName, pszName);
    838 		strcat(szTmpUniformName, "[0]");
    839 		nLocation = glGetUniformLocation(m_uiProgram, szTmpUniformName);
    840 	}
    841 
    842 	switch(psDefaultValue->eType)
    843 	{
    844 		case eDataTypeMat2:
    845 			glUniformMatrix2fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData);
    846 			break;
    847 		case eDataTypeMat3:
    848 			glUniformMatrix3fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData);
    849 			break;
    850 		case eDataTypeMat4:
    851 			glUniformMatrix4fv(nLocation, 1, GL_FALSE, psDefaultValue->pfData);
    852 			break;
    853 		case eDataTypeVec2:
    854 			glUniform2fv(nLocation, 1, psDefaultValue->pfData);
    855 			break;
    856 		case eDataTypeRGB:
    857 		case eDataTypeVec3:
    858 			glUniform3fv(nLocation, 1, psDefaultValue->pfData);
    859 			break;
    860 		case eDataTypeRGBA:
    861 		case eDataTypeVec4:
    862 			glUniform4fv(nLocation, 1, psDefaultValue->pfData);
    863 			break;
    864 		case eDataTypeIvec2:
    865 			glUniform2iv(nLocation, 1, psDefaultValue->pnData);
    866 			break;
    867 		case eDataTypeIvec3:
    868 			glUniform3iv(nLocation, 1, psDefaultValue->pnData);
    869 			break;
    870 		case eDataTypeIvec4:
    871 			glUniform4iv(nLocation, 1, psDefaultValue->pnData);
    872 			break;
    873 		case eDataTypeBvec2:
    874 			glUniform2i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0);
    875 			break;
    876 		case eDataTypeBvec3:
    877 			glUniform3i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0, psDefaultValue->pbData[2] ? 1 : 0);
    878 			break;
    879 		case eDataTypeBvec4:
    880 			glUniform4i(nLocation, psDefaultValue->pbData[0] ? 1 : 0, psDefaultValue->pbData[1] ? 1 : 0, psDefaultValue->pbData[2] ? 1 : 0, psDefaultValue->pbData[3] ? 1 : 0);
    881 			break;
    882 		case eDataTypeFloat:
    883 			glUniform1f(nLocation, psDefaultValue->pfData[0]);
    884 			break;
    885 		case eDataTypeInt:
    886 			glUniform1i(nLocation, psDefaultValue->pnData[0]);
    887 			break;
    888 		case eDataTypeBool:
    889 			glUniform1i(nLocation, psDefaultValue->pbData[0] ? 1 : 0);
    890 			break;
    891 
    892 		case eNumDefaultDataTypes:
    893 		case eDataTypeNone:
    894 		default:
    895 			break;
    896 	}
    897 }
    898 
    899 /*!***************************************************************************
    900 @Function		SetContext
    901 @Input			pContext
    902 @Description
    903 *****************************************************************************/
    904 void CPVRTPFXEffect::SetContext(SPVRTContext *const pContext)
    905 {
    906 	m_psContext = pContext;
    907 }
    908 
    909 /*!***************************************************************************
    910 @Function		GetProgramHandle
    911 @Return			unsigned int
    912 @Description	Returns the OGL program handle.
    913 *****************************************************************************/
    914 unsigned int CPVRTPFXEffect::GetProgramHandle() const
    915 {
    916 	return m_uiProgram;
    917 }
    918 
    919 /*!***************************************************************************
    920 @Function		GetEffectIndex
    921 @Return			unsigned int
    922 @Description	Gets the active effect index within the PFX file.
    923 *****************************************************************************/
    924 unsigned int CPVRTPFXEffect::GetEffectIndex() const
    925 {
    926 	return m_nEffect;
    927 }
    928 
    929 /*!***************************************************************************
    930 @Function		GetSemanticArray
    931 @Return			const CPVRTArray<SPVRTPFXUniformSemantic>&
    932 @Description	Gets the array of registered semantics which will be used to
    933 				match PFX code.
    934 *****************************************************************************/
    935 const CPVRTArray<SPVRTPFXUniformSemantic>& CPVRTPFXEffect::GetSemanticArray() const
    936 {
    937 	return m_Semantics;
    938 }
    939 
    940 /*****************************************************************************
    941  End of file (PVRTPFXParserAPI.cpp)
    942 *****************************************************************************/
    943 
    944