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 *****************************************************************************/
CPVRTPFXEffect()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 *****************************************************************************/
CPVRTPFXEffect(SPVRTContext & sContext)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 *****************************************************************************/
~CPVRTPFXEffect()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 *****************************************************************************/
Load(CPVRTPFXParser & src,const char * const pszEffect,const char * const pszFileName,PVRTPFXEffectDelegate * pDelegate,unsigned int & uiUnknownUniforms,CPVRTString * pReturnError)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 *****************************************************************************/
LoadTexturesForEffect(PVRTPFXEffectDelegate * pDelegate,CPVRTString * pReturnError)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 *****************************************************************************/
LoadShadersForEffect(CPVRTPFXParser & src,const char * const pszFileName,CPVRTString * pReturnError)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 *****************************************************************************/
Destroy()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 *****************************************************************************/
Activate(const int i32RenderTextureId,const unsigned int ui32ReplacementTexture)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 *****************************************************************************/
GetSemantics(CPVRTArray<SPVRTPFXUniform> & aUniforms,const CPVRTArray<SPVRTPFXParserSemantic> & aParams,const CPVRTArray<SPVRTPFXUniformSemantic> & aUniformSemantics,unsigned int * const pnUnknownUniformCount,const GLuint uiProgram,bool bIsAttribue,CPVRTString * const errorMsg)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 *****************************************************************************/
GetUniformArray() const572 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 *****************************************************************************/
RebuildUniformTable(unsigned int & uiUnknownSemantics,CPVRTString * pReturnError)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 *****************************************************************************/
RegisterUniformSemantic(const SPVRTPFXUniformSemantic * const psUniforms,unsigned int uiNumUniforms,CPVRTString * pReturnError)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 *****************************************************************************/
RemoveUniformSemantic(unsigned int uiSemanticID,CPVRTString * pReturnError)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 *****************************************************************************/
GetTextureArray() const686 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 *****************************************************************************/
SetTexture(const unsigned int nIdx,const GLuint ui,const unsigned int u32flags)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 *****************************************************************************/
SetDefaultUniformValue(const char * const pszName,const SPVRTSemanticDefaultData * psDefaultValue)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 *****************************************************************************/
SetContext(SPVRTContext * const pContext)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 *****************************************************************************/
GetProgramHandle() const914 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 *****************************************************************************/
GetEffectIndex() const924 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 *****************************************************************************/
GetSemanticArray() const935 const CPVRTArray<SPVRTPFXUniformSemantic>& CPVRTPFXEffect::GetSemanticArray() const
936 {
937 return m_Semantics;
938 }
939
940 /*****************************************************************************
941 End of file (PVRTPFXParserAPI.cpp)
942 *****************************************************************************/
943
944