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*****************************************************************************/
39CPVRTPFXEffect::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*****************************************************************************/
48CPVRTPFXEffect::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*****************************************************************************/
57CPVRTPFXEffect::~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*****************************************************************************/
79EPVRTError 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*****************************************************************************/
153EPVRTError 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*****************************************************************************/
199EPVRTError 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*****************************************************************************/
424void 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*****************************************************************************/
447EPVRTError 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*****************************************************************************/
488static 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*****************************************************************************/
572const 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*****************************************************************************/
584EPVRTError 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*****************************************************************************/
605EPVRTError 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*****************************************************************************/
646EPVRTError 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*****************************************************************************/
686const 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*****************************************************************************/
698void 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*****************************************************************************/
828void 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*****************************************************************************/
904void 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*****************************************************************************/
914unsigned 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*****************************************************************************/
924unsigned 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*****************************************************************************/
935const CPVRTArray<SPVRTPFXUniformSemantic>& CPVRTPFXEffect::GetSemanticArray() const
936{
937	return m_Semantics;
938}
939
940/*****************************************************************************
941 End of file (PVRTPFXParserAPI.cpp)
942*****************************************************************************/
943
944