1 /******************************************************************************
2
3 @File PVRTPFXParser.cpp
4
5 @Title PVRTPFXParser
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 <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #include "PVRTGlobal.h"
25 #include "PVRTContext.h"
26 #include "PVRTMatrix.h"
27 #include "PVRTFixedPoint.h"
28 #include "PVRTMisc.h"
29 #include "PVRTPFXParser.h"
30 #include "PVRTResourceFile.h"
31 #include "PVRTString.h"
32 #include "PVRTMisc.h" // Used for POT functions
33
34 /****************************************************************************
35 ** Constants
36 ****************************************************************************/
37 const char* c_pszLinear = "LINEAR";
38 const char* c_pszNearest = "NEAREST";
39 const char* c_pszNone = "NONE";
40 const char* c_pszClamp = "CLAMP";
41 const char* c_pszRepeat = "REPEAT";
42 const char* c_pszCurrentView = "PFX_CURRENTVIEW";
43
44 const unsigned int CPVRTPFXParser::VIEWPORT_SIZE = 0xAAAA;
45
46 const char* c_ppszFilters[eFilter_Size] =
47 {
48 c_pszNearest, // eFilter_Nearest
49 c_pszLinear, // eFilter_Linear
50 c_pszNone, // eFilter_None
51 };
52 const char* c_ppszWraps[eWrap_Size] =
53 {
54 c_pszClamp, // eWrap_Clamp
55 c_pszRepeat // eWrap_Repeat
56 };
57
58 #define NEWLINE_TOKENS "\r\n"
59 #define DELIM_TOKENS " \t"
60
61 #define DEFAULT_EFFECT_NUM_TEX 100
62 #define DEFAULT_EFFECT_NUM_UNIFORM 100
63 #define DEFAULT_EFFECT_NUM_ATTRIB 100
64
65 /****************************************************************************
66 ** Data tables
67 ****************************************************************************/
68
69 /****************************************************************************
70 ** CPVRTPFXParserReadContext Class
71 ****************************************************************************/
72 class CPVRTPFXParserReadContext
73 {
74 public:
75 char **ppszEffectFile;
76 int *pnFileLineNumber;
77 unsigned int nNumLines, nMaxLines;
78
79 public:
80 CPVRTPFXParserReadContext();
81 ~CPVRTPFXParserReadContext();
82 };
83
84 /*!***************************************************************************
85 @Function CPVRTPFXParserReadContext
86 @Description Initialises values.
87 *****************************************************************************/
CPVRTPFXParserReadContext()88 CPVRTPFXParserReadContext::CPVRTPFXParserReadContext()
89 {
90 nMaxLines = 5000;
91 nNumLines = 0;
92 ppszEffectFile = new char*[nMaxLines];
93 pnFileLineNumber = new int[nMaxLines];
94 }
95
96 /*!***************************************************************************
97 @Function ~CPVRTPFXParserReadContext
98 @Description Frees allocated memory
99 *****************************************************************************/
~CPVRTPFXParserReadContext()100 CPVRTPFXParserReadContext::~CPVRTPFXParserReadContext()
101 {
102 // free effect file
103 for(unsigned int i = 0; i < nNumLines; i++)
104 {
105 FREE(ppszEffectFile[i]);
106 }
107 delete [] ppszEffectFile;
108 delete [] pnFileLineNumber;
109 }
110
111 /*!***************************************************************************
112 @Function IgnoreWhitespace
113 @Input pszString
114 @Output pszString
115 @Description Skips space, tab, new-line and return characters.
116 *****************************************************************************/
IgnoreWhitespace(char ** pszString)117 static void IgnoreWhitespace(char **pszString)
118 {
119 while( *pszString[0] == '\t' ||
120 *pszString[0] == '\n' ||
121 *pszString[0] == '\r' ||
122 *pszString[0] == ' ' )
123 {
124 (*pszString)++;
125 }
126 }
127
128 /*!***************************************************************************
129 @Function ReadEOLToken
130 @Input pToken
131 @Output char*
132 @Description Reads next strings to the end of the line and interperts as
133 a token.
134 *****************************************************************************/
ReadEOLToken(char * pToken)135 static char* ReadEOLToken(char* pToken)
136 {
137 char* pReturn = NULL;
138
139 char szDelim[2] = {'\n', 0}; // try newline
140 pReturn = strtok(pToken, szDelim);
141 if(pReturn == NULL)
142 {
143 szDelim[0] = '\r';
144 pReturn = strtok (pToken, szDelim); // try linefeed
145 }
146 return pReturn;
147 }
148
149 /*!***************************************************************************
150 @Function GetSemanticDataFromString
151 @Output pDataItem
152 @Modified pszArgumentString
153 @Input eType
154 @Output pError error message
155 @Return true if successful
156 @Description Extracts the semantic data from the string and stores it
157 in the output SPVRTSemanticDefaultData parameter.
158 *****************************************************************************/
GetSemanticDataFromString(SPVRTSemanticDefaultData * pDataItem,const char * const pszArgumentString,ESemanticDefaultDataType eType,CPVRTString * pError)159 static bool GetSemanticDataFromString(SPVRTSemanticDefaultData *pDataItem, const char * const pszArgumentString, ESemanticDefaultDataType eType, CPVRTString *pError)
160 {
161 char *pszString = (char *)pszArgumentString;
162 char *pszTmp;
163
164 IgnoreWhitespace(&pszString);
165
166 if(pszString[0] != '(')
167 {
168 *pError = CPVRTString("Missing '(' after ") + c_psSemanticDefaultDataTypeInfo[eType].pszName;
169 return false;
170 }
171 pszString++;
172
173 IgnoreWhitespace(&pszString);
174
175 if(!strlen(pszString))
176 {
177 *pError = c_psSemanticDefaultDataTypeInfo[eType].pszName + CPVRTString(" missing arguments");
178 return false;
179 }
180
181 pszTmp = pszString;
182 switch(c_psSemanticDefaultDataTypeInfo[eType].eInternalType)
183 {
184 case eFloating:
185 pDataItem->pfData[0] = (float)strtod(pszString, &pszTmp);
186 break;
187 case eInteger:
188 pDataItem->pnData[0] = (int)strtol(pszString, &pszTmp, 10);
189 break;
190 case eBoolean:
191 if(strncmp(pszString, "true", 4) == 0)
192 {
193 pDataItem->pbData[0] = true;
194 pszTmp = &pszString[4];
195 }
196 else if(strncmp(pszString, "false", 5) == 0)
197 {
198 pDataItem->pbData[0] = false;
199 pszTmp = &pszString[5];
200 }
201 break;
202 }
203
204 if(pszString == pszTmp)
205 {
206 size_t n = strcspn(pszString, ",\t ");
207 char *pszError = (char *)malloc(n + 1);
208 strcpy(pszError, "");
209 strncat(pszError, pszString, n);
210 *pError = CPVRTString("'") + pszError + "' unexpected for " + c_psSemanticDefaultDataTypeInfo[eType].pszName;
211 FREE(pszError);
212 return false;
213 }
214 pszString = pszTmp;
215
216 IgnoreWhitespace(&pszString);
217
218 for(unsigned int i = 1; i < c_psSemanticDefaultDataTypeInfo[eType].nNumberDataItems; i++)
219 {
220 if(!strlen(pszString))
221 {
222 *pError = c_psSemanticDefaultDataTypeInfo[eType].pszName + CPVRTString(" missing arguments");
223 return false;
224 }
225
226 if(pszString[0] != ',')
227 {
228 size_t n = strcspn(pszString, ",\t ");
229 char *pszError = (char *)malloc(n + 1);
230 strcpy(pszError, "");
231 strncat(pszError, pszString, n);
232 *pError = CPVRTString("'") + pszError + "' unexpected for " + c_psSemanticDefaultDataTypeInfo[eType].pszName;
233 FREE(pszError);
234 return false;
235 }
236 pszString++;
237
238 IgnoreWhitespace(&pszString);
239
240 if(!strlen(pszString))
241 {
242 *pError = c_psSemanticDefaultDataTypeInfo[eType].pszName + CPVRTString(" missing arguments");
243 return false;
244 }
245
246 pszTmp = pszString;
247 switch(c_psSemanticDefaultDataTypeInfo[eType].eInternalType)
248 {
249 case eFloating:
250 pDataItem->pfData[i] = (float)strtod(pszString, &pszTmp);
251 break;
252 case eInteger:
253 pDataItem->pnData[i] = (int)strtol(pszString, &pszTmp, 10);
254 break;
255 case eBoolean:
256 if(strncmp(pszString, "true", 4) == 0)
257 {
258 pDataItem->pbData[i] = true;
259 pszTmp = &pszString[4];
260 }
261 else if(strncmp(pszString, "false", 5) == 0)
262 {
263 pDataItem->pbData[i] = false;
264 pszTmp = &pszString[5];
265 }
266 break;
267 }
268
269 if(pszString == pszTmp)
270 {
271 size_t n = strcspn(pszString, ",\t ");
272 char *pszError = (char *)malloc(n + 1);
273 strcpy(pszError, "");
274 strncat(pszError, pszString, n);
275 *pError = CPVRTString("'") + pszError + "' unexpected for " + c_psSemanticDefaultDataTypeInfo[eType].pszName;
276 FREE(pszError);
277 return false;
278 }
279 pszString = pszTmp;
280
281 IgnoreWhitespace(&pszString);
282 }
283
284 if(pszString[0] != ')')
285 {
286 size_t n = strcspn(pszString, "\t )");
287 char *pszError = (char *)malloc(n + 1);
288 strcpy(pszError, "");
289 strncat(pszError, pszString, n);
290 *pError = CPVRTString("'") + pszError + "' found when expecting ')' for " + c_psSemanticDefaultDataTypeInfo[eType].pszName;
291 FREE(pszError);
292 return false;
293 }
294 pszString++;
295
296 IgnoreWhitespace(&pszString);
297
298 if(strlen(pszString))
299 {
300 *pError = CPVRTString("'") + pszString + "' unexpected after ')'";
301 return false;
302 }
303
304 return true;
305 }
306
307 /*!***************************************************************************
308 @Function ConcatenateLinesUntil
309 @Output pszOut output text
310 @Output nLine end line number
311 @Input nLine start line number
312 @Input ppszLines input text - one array element per line
313 @Input nLimit number of lines input
314 @Input pszEnd end string
315 @Return true if successful
316 @Description Outputs a block of text starting from nLine and ending
317 when the string pszEnd is found.
318 *****************************************************************************/
ConcatenateLinesUntil(CPVRTString & Out,int & nLine,const char * const * const ppszLines,const unsigned int nLimit,const char * const pszEnd)319 static bool ConcatenateLinesUntil(CPVRTString& Out, int &nLine, const char * const * const ppszLines, const unsigned int nLimit, const char * const pszEnd)
320 {
321 unsigned int i, j;
322 size_t nLen;
323
324 nLen = 0;
325 for(i = nLine; i < nLimit; ++i)
326 {
327 if(strcmp(ppszLines[i], pszEnd) == 0)
328 break;
329 nLen += strlen(ppszLines[i]) + 1;
330 }
331 if(i == nLimit)
332 {
333 return false;
334 }
335
336 if(nLen)
337 {
338 ++nLen;
339
340 Out.reserve(nLen);
341
342 for(j = nLine; j < i; ++j)
343 {
344 Out.append(ppszLines[j]);
345 Out.append("\n");
346 }
347 }
348
349 nLine = i;
350 return true;
351 }
352
353 /****************************************************************************
354 ** SPVRTPFXParserEffect Struct
355 ****************************************************************************/
SPVRTPFXParserEffect()356 SPVRTPFXParserEffect::SPVRTPFXParserEffect() :
357 Uniforms(DEFAULT_EFFECT_NUM_UNIFORM),
358 Attributes(DEFAULT_EFFECT_NUM_ATTRIB),
359 Textures(DEFAULT_EFFECT_NUM_TEX)
360 {
361 }
362
363 /****************************************************************************
364 ** SPVRTPFXRenderPass Class
365 ****************************************************************************/
SPVRTPFXRenderPass()366 SPVRTPFXRenderPass::SPVRTPFXRenderPass() :
367 eRenderPassType(eNULL_PASS),
368 eViewType(eVIEW_NONE),
369 uiFormatFlags(0),
370 pEffect(NULL),
371 pTexture(NULL)
372 {
373 }
374
375 /****************************************************************************
376 ** SPVRTPFXParserShader Class
377 ****************************************************************************/
SPVRTPFXParserShader()378 SPVRTPFXParserShader::SPVRTPFXParserShader()
379 :
380 pszGLSLfile(NULL),
381 pszGLSLBinaryFile(NULL),
382 pszGLSLcode(NULL),
383 pbGLSLBinary(NULL)
384 {
385 }
386
~SPVRTPFXParserShader()387 SPVRTPFXParserShader::~SPVRTPFXParserShader()
388 {
389 FREE(pszGLSLfile);
390 FREE(pszGLSLcode);
391 FREE(pszGLSLBinaryFile);
392 FREE(pbGLSLBinary);
393 }
394
SPVRTPFXParserShader(const SPVRTPFXParserShader & rhs)395 SPVRTPFXParserShader::SPVRTPFXParserShader(const SPVRTPFXParserShader& rhs)
396 {
397 Copy(rhs);
398 }
399
operator =(const SPVRTPFXParserShader & rhs)400 SPVRTPFXParserShader& SPVRTPFXParserShader::operator=(const SPVRTPFXParserShader& rhs)
401 {
402 if(&rhs != this)
403 Copy(rhs);
404
405 return *this;
406 }
407
Copy(const SPVRTPFXParserShader & rhs)408 void SPVRTPFXParserShader::Copy(const SPVRTPFXParserShader& rhs)
409 {
410 Name = rhs.Name;
411
412 PVRTPFXCreateStringCopy(&pszGLSLfile, rhs.pszGLSLfile);
413 PVRTPFXCreateStringCopy(&pszGLSLBinaryFile, rhs.pszGLSLBinaryFile);
414 PVRTPFXCreateStringCopy(&pszGLSLcode, rhs.pszGLSLcode);
415 PVRTPFXCreateStringCopy(&pbGLSLBinary, rhs.pbGLSLBinary);
416
417 bUseFileName = rhs.bUseFileName;
418 nGLSLBinarySize = rhs.nGLSLBinarySize;
419 nFirstLineNumber= rhs.nFirstLineNumber;
420 nLastLineNumber = rhs.nLastLineNumber;
421 }
422
423 /****************************************************************************
424 ** SPVRTSemanticDefaultData Struct
425 ****************************************************************************/
SPVRTSemanticDefaultData()426 SPVRTSemanticDefaultData::SPVRTSemanticDefaultData()
427 :
428 eType(eDataTypeNone)
429 {
430 }
431
SPVRTSemanticDefaultData(const SPVRTSemanticDefaultData & rhs)432 SPVRTSemanticDefaultData::SPVRTSemanticDefaultData(const SPVRTSemanticDefaultData& rhs)
433 {
434 Copy(rhs);
435 }
436
operator =(const SPVRTSemanticDefaultData & rhs)437 SPVRTSemanticDefaultData& SPVRTSemanticDefaultData::operator=(const SPVRTSemanticDefaultData& rhs)
438 {
439 if(&rhs != this)
440 Copy(rhs);
441 return *this;
442 }
443
Copy(const SPVRTSemanticDefaultData & rhs)444 void SPVRTSemanticDefaultData::Copy(const SPVRTSemanticDefaultData& rhs)
445 {
446 memcpy(pfData, rhs.pfData, sizeof(pfData));
447 memcpy(pnData, rhs.pnData, sizeof(pnData));
448 memcpy(pbData, rhs.pbData, sizeof(pbData));
449 eType = rhs.eType;
450 }
451
452 /****************************************************************************
453 ** SPVRTPFXParserSemantic Struct
454 ****************************************************************************/
SPVRTPFXParserSemantic()455 SPVRTPFXParserSemantic::SPVRTPFXParserSemantic()
456 :
457 pszName(NULL),
458 pszValue(NULL)
459 {
460 }
461
~SPVRTPFXParserSemantic()462 SPVRTPFXParserSemantic::~SPVRTPFXParserSemantic()
463 {
464 FREE(pszName);
465 FREE(pszValue);
466 }
467
SPVRTPFXParserSemantic(const SPVRTPFXParserSemantic & rhs)468 SPVRTPFXParserSemantic::SPVRTPFXParserSemantic(const SPVRTPFXParserSemantic& rhs)
469 {
470 Copy(rhs);
471 }
472
operator =(const SPVRTPFXParserSemantic & rhs)473 SPVRTPFXParserSemantic& SPVRTPFXParserSemantic::operator=(const SPVRTPFXParserSemantic& rhs)
474 {
475 if(&rhs != this)
476 Copy(rhs);
477
478 return *this;
479 }
480
Copy(const SPVRTPFXParserSemantic & rhs)481 void SPVRTPFXParserSemantic::Copy(const SPVRTPFXParserSemantic& rhs)
482 {
483 PVRTPFXCreateStringCopy(&pszName, rhs.pszName);
484 PVRTPFXCreateStringCopy(&pszValue, rhs.pszValue);
485 nIdx = rhs.nIdx;
486 sDefaultValue = rhs.sDefaultValue;
487 }
488
489 /****************************************************************************
490 ** CPVRTPFXParser Class
491 ****************************************************************************/
492 /*!***************************************************************************
493 @Function CPVRTPFXParser
494 @Description Sets initial values.
495 *****************************************************************************/
CPVRTPFXParser()496 CPVRTPFXParser::CPVRTPFXParser()
497 {
498 m_szFileName.assign("");
499
500 // NOTE: Temp hardcode viewport size
501 m_uiViewportWidth = 640;
502 m_uiViewportHeight = 480;
503 }
504
505 /*!***************************************************************************
506 @Function ~CPVRTPFXParser
507 @Description Frees memory used.
508 *****************************************************************************/
~CPVRTPFXParser()509 CPVRTPFXParser::~CPVRTPFXParser()
510 {
511 }
512
513 /*!***************************************************************************
514 @Function Parse
515 @Output pReturnError error string
516 @Return bool true for success parsing file
517 @Description Parses a loaded PFX file.
518 *****************************************************************************/
Parse(CPVRTString * const pReturnError)519 bool CPVRTPFXParser::Parse(CPVRTString * const pReturnError)
520 {
521 enum eCmd
522 {
523 eCmds_Header,
524 eCmds_Texture,
525 eCmds_Target,
526 eCmds_Textures,
527 eCmds_VertexShader,
528 eCmds_FragmentShader,
529 eCmds_Effect,
530
531 eCmds_Size
532 };
533
534 const CPVRTHash ParserCommands[] =
535 {
536 "[HEADER]", // eCmds_Header
537 "[TEXTURE]", // eCmds_Texture
538 "[TARGET]", // eCmds_Target
539 "[TEXTURES]", // eCmds_Textures
540 "[VERTEXSHADER]", // eCmds_VertexShader
541 "[FRAGMENTSHADER]", // eCmds_FragmentShader
542 "[EFFECT]", // eCmds_Effect
543 };
544 PVRTCOMPILEASSERT(ParserCommands, sizeof(ParserCommands) / sizeof(ParserCommands[0]) == eCmds_Size);
545
546 int nEndLine = 0;
547 int nHeaderCounter = 0, nTexturesCounter = 0;
548 unsigned int i,j,k;
549
550 // Loop through the file
551 for(unsigned int nLine=0; nLine < m_psContext->nNumLines; nLine++)
552 {
553 // Skip blank lines
554 if(!*m_psContext->ppszEffectFile[nLine])
555 continue;
556
557 CPVRTHash Cmd(m_psContext->ppszEffectFile[nLine]);
558 if(Cmd == ParserCommands[eCmds_Header])
559 {
560 if(nHeaderCounter>0)
561 {
562 *pReturnError = PVRTStringFromFormattedStr("[HEADER] redefined on line %d\n", m_psContext->pnFileLineNumber[nLine]);
563 return false;
564 }
565 if(GetEndTag("HEADER", nLine, &nEndLine))
566 {
567 if(ParseHeader(nLine, nEndLine, pReturnError))
568 nHeaderCounter++;
569 else
570 return false;
571 }
572 else
573 {
574 *pReturnError = PVRTStringFromFormattedStr("Missing [/HEADER] tag after [HEADER] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
575 return false;
576 }
577 nLine = nEndLine;
578 }
579 else if(Cmd == ParserCommands[eCmds_Texture])
580 {
581 if(GetEndTag("TEXTURE", nLine, &nEndLine))
582 {
583 if(!ParseTexture(nLine, nEndLine, pReturnError))
584 return false;
585 }
586 else
587 {
588 *pReturnError = PVRTStringFromFormattedStr("Missing [/TEXTURE] tag after [TEXTURE] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
589 return false;
590 }
591 nLine = nEndLine;
592 }
593 else if(Cmd == ParserCommands[eCmds_Target])
594 {
595 if(GetEndTag("TARGET", nLine, &nEndLine))
596 {
597 if(!ParseTarget(nLine, nEndLine, pReturnError))
598 return false;
599 }
600 else
601 {
602 *pReturnError = PVRTStringFromFormattedStr("Missing [/TARGET] tag after [TARGET] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
603 return false;
604 }
605 nLine = nEndLine;
606 }
607 else if(Cmd == ParserCommands[eCmds_Textures])
608 {
609 if(nTexturesCounter>0)
610 {
611 *pReturnError = PVRTStringFromFormattedStr("[TEXTURES] redefined on line %d\n", m_psContext->pnFileLineNumber[nLine]);
612 return false;
613 }
614 if(GetEndTag("TEXTURES", nLine, &nEndLine))
615 {
616 if(ParseTextures(nLine, nEndLine, pReturnError))
617 nTexturesCounter++;
618 else
619 return false;
620 }
621 else
622 {
623 *pReturnError = PVRTStringFromFormattedStr("Missing [/TEXTURES] tag after [TEXTURES] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
624 return false;
625 }
626 nLine = nEndLine;
627 }
628 else if(Cmd == ParserCommands[eCmds_VertexShader])
629 {
630 if(GetEndTag("VERTEXSHADER", nLine, &nEndLine))
631 {
632 SPVRTPFXParserShader VertexShader;
633 if(ParseShader(nLine, nEndLine, pReturnError, VertexShader, "VERTEXSHADER"))
634 m_psVertexShader.Append(VertexShader);
635 else
636 return false;
637 }
638 else
639 {
640 *pReturnError = PVRTStringFromFormattedStr("Missing [/VERTEXSHADER] tag after [VERTEXSHADER] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
641 return false;
642 }
643 nLine = nEndLine;
644 }
645 else if(Cmd == ParserCommands[eCmds_FragmentShader])
646 {
647 if(GetEndTag("FRAGMENTSHADER", nLine, &nEndLine))
648 {
649 SPVRTPFXParserShader FragShader;
650 if(ParseShader(nLine, nEndLine, pReturnError, FragShader, "FRAGMENTSHADER"))
651 m_psFragmentShader.Append(FragShader);
652 else
653 return false;
654 }
655 else
656 {
657 *pReturnError = PVRTStringFromFormattedStr("Missing [/FRAGMENTSHADER] tag after [FRAGMENTSHADER] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
658 return false;
659 }
660 nLine = nEndLine;
661 }
662 else if(Cmd == ParserCommands[eCmds_Effect])
663 {
664 if(GetEndTag("EFFECT", nLine, &nEndLine))
665 {
666 SPVRTPFXParserEffect Effect;
667 if(ParseEffect(Effect, nLine, nEndLine, pReturnError))
668 m_psEffect.Append(Effect);
669 else
670 return false;
671 }
672 else
673 {
674 *pReturnError = PVRTStringFromFormattedStr("Missing [/EFFECT] tag after [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nLine]);
675 return false;
676 }
677 nLine = nEndLine;
678 }
679 else
680 {
681 *pReturnError = PVRTStringFromFormattedStr("'%s' unexpected on line %d\n", m_psContext->ppszEffectFile[nLine], m_psContext->pnFileLineNumber[nLine]);
682 return false;
683 }
684 }
685
686 if(m_psEffect.GetSize() < 1)
687 {
688 *pReturnError = CPVRTString("No [EFFECT] found. PFX file must have at least one defined.\n");
689 return false;
690 }
691
692 if(m_psFragmentShader.GetSize() < 1)
693 {
694 *pReturnError = CPVRTString("No [FRAGMENTSHADER] found. PFX file must have at least one defined.\n");;
695 return false;
696 }
697
698 if(m_psVertexShader.GetSize() < 1)
699 {
700 *pReturnError = CPVRTString("No [VERTEXSHADER] found. PFX file must have at least one defined.\n");
701 return false;
702 }
703
704 // Loop Effects
705 for(i = 0; i < m_psEffect.GetSize(); ++i)
706 {
707 // Loop Textures in Effects
708 for(j = 0; j < m_psEffect[i].Textures.GetSize(); ++j)
709 {
710 // Loop Textures in whole PFX
711 unsigned int uiTexSize = m_psTexture.GetSize();
712 for(k = 0; k < uiTexSize; ++k)
713 {
714 if(m_psTexture[k]->Name == m_psEffect[i].Textures[j].Name)
715 break;
716 }
717
718 // Texture mismatch. Report error.
719 if(!uiTexSize || k == uiTexSize)
720 {
721 *pReturnError = "Error: TEXTURE '" + m_psEffect[i].Textures[j].Name.String() + "' is not defined in [TEXTURES].\n";
722 return false;
723 }
724 }
725 }
726
727 DetermineRenderPassDependencies(pReturnError);
728 if(pReturnError->compare(""))
729 {
730 return false;
731 }
732
733 return true;
734 }
735
736 /*!***************************************************************************
737 @Function ParseFromMemory
738 @Input pszScript PFX script
739 @Output pReturnError error string
740 @Return EPVRTError PVR_SUCCESS for success parsing file
741 PVR_FAIL if file doesn't exist or is invalid
742 @Description Parses a PFX script from memory.
743 *****************************************************************************/
ParseFromMemory(const char * const pszScript,CPVRTString * const pReturnError)744 EPVRTError CPVRTPFXParser::ParseFromMemory(const char * const pszScript, CPVRTString * const pReturnError)
745 {
746 CPVRTPFXParserReadContext context;
747 char pszLine[512];
748 const char *pszEnd, *pszCurr;
749 int nLineCounter;
750 unsigned int nLen;
751 unsigned int nReduce;
752 bool bDone;
753
754 if(!pszScript)
755 return PVR_FAIL;
756
757 m_psContext = &context;
758
759 // Find & process each line
760 nLineCounter = 0;
761 bDone = false;
762 pszCurr = pszScript;
763 while(!bDone)
764 {
765 nLineCounter++;
766
767 while(*pszCurr == '\r')
768 ++pszCurr;
769
770 // Find length of line
771 pszEnd = strchr(pszCurr, '\n');
772 if(pszEnd)
773 {
774 nLen = (unsigned int)(pszEnd - pszCurr);
775 }
776 else
777 {
778 nLen = (unsigned int)strlen(pszCurr);
779 bDone = true;
780 }
781
782 nReduce = 0; // Tells how far to go back because of '\r'.
783 while(nLen - nReduce > 0 && pszCurr[nLen - 1 - nReduce] == '\r')
784 nReduce++;
785
786 // Ensure pszLine will not be not overrun
787 if(nLen+1-nReduce > sizeof(pszLine) / sizeof(*pszLine))
788 nLen = sizeof(pszLine) / sizeof(*pszLine) - 1 + nReduce;
789
790 // Copy line into pszLine
791 strncpy(pszLine, pszCurr, nLen - nReduce);
792 pszLine[nLen - nReduce] = 0;
793 pszCurr += nLen + 1;
794
795 _ASSERT(strchr(pszLine, '\r') == 0);
796 _ASSERT(strchr(pszLine, '\n') == 0);
797
798 // Ignore comments
799 char *tmp = strstr(pszLine, "//");
800 if(tmp != NULL) *tmp = '\0';
801
802 // Reduce whitespace to one character.
803 ReduceWhitespace(pszLine);
804
805 // Store the line, even if blank lines (to get correct errors from GLSL compiler).
806 if(m_psContext->nNumLines < m_psContext->nMaxLines)
807 {
808 m_psContext->pnFileLineNumber[m_psContext->nNumLines] = nLineCounter;
809 m_psContext->ppszEffectFile[m_psContext->nNumLines] = (char *)malloc((strlen(pszLine) + 1) * sizeof(char));
810 strcpy(m_psContext->ppszEffectFile[m_psContext->nNumLines], pszLine);
811 m_psContext->nNumLines++;
812 }
813 else
814 {
815 *pReturnError = PVRTStringFromFormattedStr("Too many lines of text in file (maximum is %d)\n", m_psContext->nMaxLines);
816 return PVR_FAIL;
817 }
818 }
819
820 return Parse(pReturnError) ? PVR_SUCCESS : PVR_FAIL;
821 }
822
823 /*!***************************************************************************
824 @Function ParseFromFile
825 @Input pszFileName PFX file name
826 @Output pReturnError error string
827 @Return EPVRTError PVR_SUCCESS for success parsing file
828 PVR_FAIL if file doesn't exist or is invalid
829 @Description Reads the PFX file and calls the parser.
830 *****************************************************************************/
ParseFromFile(const char * const pszFileName,CPVRTString * const pReturnError)831 EPVRTError CPVRTPFXParser::ParseFromFile(const char * const pszFileName, CPVRTString * const pReturnError)
832 {
833 CPVRTResourceFile PfxFile(pszFileName);
834 if (!PfxFile.IsOpen())
835 {
836 *pReturnError = CPVRTString("Unable to open file ") + pszFileName;
837 return PVR_FAIL;
838 }
839
840 CPVRTString PfxFileString;
841 const char* pPfxData = (const char*) PfxFile.DataPtr();
842
843 // Is our shader resource file data null terminated?
844 if(pPfxData[PfxFile.Size()-1] != '\0')
845 {
846 // If not create a temporary null-terminated string
847 PfxFileString.assign(pPfxData, PfxFile.Size());
848 pPfxData = PfxFileString.c_str();
849 }
850
851 m_szFileName.assign(pszFileName);
852
853 return ParseFromMemory(pPfxData, pReturnError);
854 }
855
856 /*!***************************************************************************
857 @Function SetViewportSize
858 @Input uiWidth New viewport width
859 @Input uiHeight New viewport height
860 @Return bool True on success
861 @Description Allows the current viewport size to be set. This value
862 is used for calculating relative texture resolutions
863 *****************************************************************************/
SetViewportSize(unsigned int uiWidth,unsigned int uiHeight)864 bool CPVRTPFXParser::SetViewportSize(unsigned int uiWidth, unsigned int uiHeight)
865 {
866 if(uiWidth > 0 && uiHeight > 0)
867 {
868 m_uiViewportWidth = uiWidth;
869 m_uiViewportHeight = uiHeight;
870 return true;
871 }
872 else
873 {
874 return false;
875 }
876 }
877 /*!***************************************************************************
878 @Function RetrieveRenderPassDependencies
879 @Output aRequiredRenderPasses
880 @Output aszActiveEffectStrings
881 @Return bool
882 @Description Returns a list of dependencies associated with the pass.
883 *****************************************************************************/
RetrieveRenderPassDependencies(CPVRTArray<SPVRTPFXRenderPass * > & aRequiredRenderPasses,CPVRTArray<CPVRTStringHash> & aszActiveEffectStrings)884 bool CPVRTPFXParser::RetrieveRenderPassDependencies(CPVRTArray<SPVRTPFXRenderPass*> &aRequiredRenderPasses, CPVRTArray<CPVRTStringHash> &aszActiveEffectStrings)
885 {
886 unsigned int ui(0), uj(0), uk(0), ul(0);
887 const SPVRTPFXParserEffect* pTempEffect(NULL);
888
889 if(aRequiredRenderPasses.GetSize() > 0)
890 {
891 /* aRequiredRenderPasses should be empty when it is passed in */
892 return false;
893 }
894
895 for(ui = 0; ui < (unsigned int)aszActiveEffectStrings.GetSize(); ++ui)
896 {
897 if(aszActiveEffectStrings[ui].String().empty())
898 {
899 // Empty strings are not valid
900 return false;
901 }
902
903 // Find the specified effect
904 for(uj = 0, pTempEffect = NULL; uj < (unsigned int)m_psEffect.GetSize(); ++uj)
905 {
906 if(aszActiveEffectStrings[ui] == m_psEffect[uj].Name)
907 {
908 // Effect found
909 pTempEffect = &m_psEffect[uj];
910 break;
911 }
912 }
913
914 if(pTempEffect == NULL)
915 {
916 // Effect not found
917 return false;
918 }
919
920 for(uj = 0; uj < m_renderPassSkipGraph.GetNumNodes(); ++uj)
921 {
922 if(m_renderPassSkipGraph[uj]->pEffect == pTempEffect)
923 {
924 m_renderPassSkipGraph.RetreiveSortedDependencyList(aRequiredRenderPasses, uj);
925 return true;
926 }
927 }
928
929 /*
930 The effect wasn't a post-process. Check to see if it has any non-post-process dependencies,
931 e.g. RENDER CAMERA textures.
932 */
933 // Loop Effects
934 for(uj = 0; uj < (unsigned int)m_psEffect.GetSize(); ++uj)
935 {
936 if(aszActiveEffectStrings[ui] != m_psEffect[uj].Name)
937 continue;
938
939 // Loop Textures in Effect
940 for(uk = 0; uk < m_psEffect[uj].Textures.GetSize();++uk)
941 {
942 // Loop Render Passes for whole PFX
943 for(ul = 0; ul < m_RenderPasses.GetSize(); ++ul)
944 {
945 // Check that the name of this render pass output texture matches a provided texture in an Effect
946 if(m_RenderPasses[ul].pTexture->Name == m_psEffect[uj].Textures[uk].Name)
947 aRequiredRenderPasses.Append(&m_RenderPasses[ul]);
948 }
949 }
950
951 return true;
952 }
953 }
954
955 return false;
956 }
957 /*!***************************************************************************
958 @Function GetEndTag
959 @Input pszTagName tag name
960 @Input nStartLine start line
961 @Output pnEndLine line end tag found
962 @Return true if tag found
963 @Description Searches for end tag pszTagName from line nStartLine.
964 Returns true and outputs the line number of the end tag if
965 found, otherwise returning false.
966 *****************************************************************************/
GetEndTag(const char * pszTagName,int nStartLine,int * pnEndLine)967 bool CPVRTPFXParser::GetEndTag(const char* pszTagName, int nStartLine, int *pnEndLine)
968 {
969 char pszEndTag[100];
970 strcpy(pszEndTag, "[/");
971 strcat(pszEndTag, pszTagName);
972 strcat(pszEndTag, "]");
973
974 for(unsigned int i = nStartLine; i < m_psContext->nNumLines; i++)
975 {
976 if(strcmp(pszEndTag, m_psContext->ppszEffectFile[i]) == 0)
977 {
978 *pnEndLine = i;
979 return true;
980 }
981 }
982
983 return false;
984 }
985
986 /*!***************************************************************************
987 @Function ReduceWhitespace
988 @Output line output text
989 @Input line input text
990 @Description Reduces all white space characters in the string to one
991 blank space.
992 *****************************************************************************/
ReduceWhitespace(char * line)993 void CPVRTPFXParser::ReduceWhitespace(char *line)
994 {
995 // convert tabs and newlines to ' '
996 char *tmp = strpbrk (line, "\t\n");
997 while(tmp != NULL)
998 {
999 *tmp = ' ';
1000 tmp = strpbrk (line, "\t\n");
1001 }
1002
1003 // remove all whitespace at start
1004 while(line[0] == ' ')
1005 {
1006 // move chars along to omit whitespace
1007 int counter = 0;
1008 do{
1009 line[counter] = line[counter+1];
1010 counter++;
1011 }while(line[counter] != '\0');
1012 }
1013
1014 // step through chars of line remove multiple whitespace
1015 for(int i=0; i < (int)strlen(line); i++)
1016 {
1017 // whitespace found
1018 if(line[i] == ' ')
1019 {
1020 // count number of whitespace chars
1021 int numWhiteChars = 0;
1022 while(line[i+1+numWhiteChars] == ' ')
1023 {
1024 numWhiteChars++;
1025 }
1026
1027 // multiple whitespace chars found
1028 if(numWhiteChars>0)
1029 {
1030 // move chars along to omit whitespace
1031 int counter=1;
1032 while(line[i+counter] != '\0')
1033 {
1034 line[i+counter] = line[i+numWhiteChars+counter];
1035 counter++;
1036 }
1037 }
1038 }
1039 }
1040
1041 // If there is no string then do not remove terminating white symbols
1042 if(!strlen(line))
1043 return;
1044
1045 // remove all whitespace from end
1046 while(line[strlen(line)-1] == ' ')
1047 {
1048 // move chars along to omit whitespace
1049 line[strlen(line)-1] = '\0';
1050 }
1051 }
1052
1053 /*!***************************************************************************
1054 @Function FindParameter
1055 @Output
1056 @Input
1057 @Description Finds the parameter after the specified delimiting character and
1058 returns the parameter as a string. An empty string is returned
1059 if a parameter cannot be found
1060
1061 *****************************************************************************/
FindParameter(char * aszSourceString,const CPVRTString & parameterTag,const CPVRTString & delimiter)1062 CPVRTString CPVRTPFXParser::FindParameter(char *aszSourceString, const CPVRTString ¶meterTag, const CPVRTString &delimiter)
1063 {
1064 CPVRTString returnString("");
1065 char* aszTagStart = strstr(aszSourceString, parameterTag.c_str());
1066
1067 // Tag was found, so search for parameter
1068 if(aszTagStart)
1069 {
1070 char* aszDelimiterStart = strstr(aszTagStart, delimiter.c_str());
1071 char* aszSpaceStart = strstr(aszTagStart, " ");
1072
1073 // Delimiter found
1074 if(aszDelimiterStart && (!aszSpaceStart ||(aszDelimiterStart < aszSpaceStart)))
1075 {
1076 // Create a string from the delimiter to the next space
1077 size_t strCount(strcspn(aszDelimiterStart, " "));
1078 aszDelimiterStart++; // Skip =
1079 returnString.assign(aszDelimiterStart, strCount-1);
1080 }
1081 }
1082
1083 return returnString;
1084 }
1085
1086 /*!***************************************************************************
1087 @Function ReadStringToken
1088 @Input pszSource Parameter string to process
1089 @Output output Processed string
1090 @Output ErrorStr String containing errors
1091 @Return Returns true on success
1092 @Description Processes the null terminated char array as if it's a
1093 formatted string array. Quote marks are determined to be
1094 start and end of strings. If no quote marks are found the
1095 string is delimited by whitespace.
1096 *****************************************************************************/
ReadStringToken(char * pszSource,CPVRTString & output,CPVRTString & ErrorStr,int i,const char * pCaller)1097 bool CPVRTPFXParser::ReadStringToken(char* pszSource, CPVRTString& output, CPVRTString &ErrorStr, int i, const char* pCaller)
1098 {
1099 if(*pszSource == '\"') // Quote marks. Continue parsing until end mark or NULL
1100 {
1101 pszSource++; // Skip past first quote
1102 while(*pszSource != '\"')
1103 {
1104 if(*pszSource == '\0')
1105 {
1106 ErrorStr = PVRTStringFromFormattedStr("Incomplete argument in [%s] on line %d: %s\n", pCaller,m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1107 return false;
1108 }
1109
1110 output.push_back(*pszSource);
1111 pszSource++;
1112 }
1113
1114 pszSource++; // Skip past final quote.
1115 }
1116 else // No quotes. Read until space
1117 {
1118 pszSource = strtok(pszSource, DELIM_TOKENS NEWLINE_TOKENS);
1119 output = pszSource;
1120
1121 pszSource += strlen(pszSource);
1122 }
1123
1124 // Check that there's nothing left on this line
1125 pszSource = strtok(pszSource, NEWLINE_TOKENS);
1126 if(pszSource)
1127 {
1128 ErrorStr = PVRTStringFromFormattedStr("Unknown keyword '%s' in [%s] on line %d: %s\n", pszSource, pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1129 return false;
1130 }
1131
1132 return true;
1133 }
1134
1135 /*!***************************************************************************
1136 @Function ParseHeader
1137 @Input nStartLine start line number
1138 @Input nEndLine end line number
1139 @Output pReturnError error string
1140 @Return bool true if parse is successful
1141 @Description Parses the HEADER section of the PFX file.
1142 *****************************************************************************/
ParseHeader(int nStartLine,int nEndLine,CPVRTString * const pReturnError)1143 bool CPVRTPFXParser::ParseHeader(int nStartLine, int nEndLine, CPVRTString * const pReturnError)
1144 {
1145 enum eCmd
1146 {
1147 eCmds_Version,
1148 eCmds_Description,
1149 eCmds_Copyright,
1150
1151 eCmds_Size
1152 };
1153
1154 const CPVRTHash HeaderCommands[] =
1155 {
1156 "VERSION", // eCmds_Version
1157 "DESCRIPTION", // eCmds_Description
1158 "COPYRIGHT", // eCmds_Copyright
1159 };
1160 PVRTCOMPILEASSERT(HeaderCommands, sizeof(HeaderCommands) / sizeof(HeaderCommands[0]) == eCmds_Size);
1161
1162 for(int i = nStartLine+1; i < nEndLine; i++)
1163 {
1164 // Skip blank lines
1165 if(!*m_psContext->ppszEffectFile[i])
1166 continue;
1167
1168 char *str = strtok (m_psContext->ppszEffectFile[i]," ");
1169 if(str != NULL)
1170 {
1171 CPVRTHash Cmd(str);
1172 if(Cmd == HeaderCommands[eCmds_Version])
1173 {
1174 str += (strlen(str)+1);
1175 m_sHeader.Version = str;
1176 }
1177 else if(Cmd == HeaderCommands[eCmds_Description])
1178 {
1179 str += (strlen(str)+1);
1180 m_sHeader.Description = str;
1181 }
1182 else if(Cmd == HeaderCommands[eCmds_Copyright])
1183 {
1184 str += (strlen(str)+1);
1185 m_sHeader.Copyright = str;
1186 }
1187 else
1188 {
1189 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [HEADER] on line %d\n", str, m_psContext->pnFileLineNumber[i]);
1190 return false;
1191 }
1192 }
1193 else
1194 {
1195 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [HEADER] on line %d : %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1196 return false;
1197 }
1198 }
1199
1200 return true;
1201 }
1202
1203 /*!***************************************************************************
1204 @Function ParseGenericSurface
1205 @Input nStartLine start line number
1206 @Input nEndLine end line number
1207 @Output uiWrapS
1208 @Output uiWrapT
1209 @Output uiWrapR
1210 @Output uiMin
1211 @Output uiMag
1212 @Output uiMip
1213 @Output pReturnError error string
1214 @Return bool true if parse is successful
1215 @Description Parses generic data from TARGET and TEXTURE blocks. Namely
1216 wrapping and filter commands.
1217 *****************************************************************************/
ParseGenericSurface(int nStartLine,int nEndLine,SPVRTPFXParserTexture & Params,CPVRTArray<CPVRTHash> & KnownCmds,const char * pCaller,CPVRTString * const pReturnError)1218 bool CPVRTPFXParser::ParseGenericSurface(int nStartLine, int nEndLine, SPVRTPFXParserTexture& Params, CPVRTArray<CPVRTHash>& KnownCmds,
1219 const char* pCaller, CPVRTString * const pReturnError)
1220 {
1221 const unsigned int INVALID_TYPE = 0xAC1DBEEF;
1222
1223 enum eCmd
1224 {
1225 eCmds_Min,
1226 eCmds_Mag,
1227 eCmds_Mip,
1228 eCmds_WrapS,
1229 eCmds_WrapT,
1230 eCmds_WrapR,
1231 eCmds_Filter,
1232 eCmds_Wrap,
1233 eCmds_Resolution,
1234 eCmds_Surface,
1235
1236 eCmds_Size
1237 };
1238
1239 const CPVRTHash GenericSurfCommands[] =
1240 {
1241 "MINIFICATION", // eCmds_Min
1242 "MAGNIFICATION", // eCmds_Mag
1243 "MIPMAP", // eCmds_Mip
1244 "WRAP_S", // eCmds_WrapS
1245 "WRAP_T", // eCmds_WrapT
1246 "WRAP_R", // eCmds_WrapR
1247 "FILTER", // eCmds_Filter
1248 "WRAP", // eCmds_Wrap
1249 "RESOLUTION", // eCmds_Resolution
1250 "SURFACETYPE", // eCmds_Surface
1251 };
1252 PVRTCOMPILEASSERT(GenericSurfCommands, sizeof(GenericSurfCommands) / sizeof(GenericSurfCommands[0]) == eCmds_Size);
1253
1254 struct SSurfacePair
1255 {
1256 CPVRTHash Name;
1257 PVRTPixelType eType;
1258 unsigned int BufferType;
1259 };
1260
1261 const SSurfacePair SurfacePairs[] =
1262 {
1263 { "RGBA8888", OGL_RGBA_8888, PVRPFXTEX_COLOUR },
1264 { "RGBA4444", OGL_RGBA_4444, PVRPFXTEX_COLOUR },
1265 { "RGB888", OGL_RGB_888, PVRPFXTEX_COLOUR },
1266 { "RGB565", OGL_RGB_565, PVRPFXTEX_COLOUR },
1267 { "INTENSITY8", OGL_I_8, PVRPFXTEX_COLOUR },
1268 { "DEPTH24", OGL_RGB_888, PVRPFXTEX_DEPTH },
1269 { "DEPTH16", OGL_RGB_565, PVRPFXTEX_DEPTH },
1270 { "DEPTH8", OGL_I_8, PVRPFXTEX_DEPTH },
1271 };
1272 const unsigned int uiNumSurfTypes = sizeof(SurfacePairs) / sizeof(SurfacePairs[0]);
1273
1274 for(int i = nStartLine+1; i < nEndLine; i++)
1275 {
1276 // Skip blank lines
1277 if(!*m_psContext->ppszEffectFile[i])
1278 continue;
1279
1280 // Need to make a copy so we can use strtok and not affect subsequent parsing
1281 size_t lineLen = strlen(m_psContext->ppszEffectFile[i]);
1282 char* pBlockCopy = new char[lineLen+1];
1283 strcpy(pBlockCopy, m_psContext->ppszEffectFile[i]);
1284
1285 char *str = strtok (pBlockCopy, NEWLINE_TOKENS DELIM_TOKENS);
1286 if(!str)
1287 {
1288 delete[] pBlockCopy;
1289 return false;
1290 }
1291
1292 CPVRTHash Cmd(str);
1293 const char** ppFilters = NULL;
1294 bool bKnown = false;
1295
1296 // --- Verbose filtering flags
1297 if(Cmd == GenericSurfCommands[eCmds_Min] || Cmd == GenericSurfCommands[eCmds_Mag] || Cmd == GenericSurfCommands[eCmds_Mip])
1298 {
1299 ppFilters = c_ppszFilters;
1300 bKnown = true;
1301 }
1302 // --- Verbose wrapping flags
1303 else if(Cmd == GenericSurfCommands[eCmds_WrapS] || Cmd == GenericSurfCommands[eCmds_WrapT] || Cmd == GenericSurfCommands[eCmds_WrapR])
1304 {
1305 ppFilters = c_ppszWraps;
1306 bKnown = true;
1307 }
1308 // --- Inline filtering flags
1309 else if(Cmd == GenericSurfCommands[eCmds_Filter])
1310 {
1311 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1312 if(!pszRemaining)
1313 {
1314 *pReturnError = PVRTStringFromFormattedStr("Missing FILTER arguments in [%s] on line %d: %s\n", pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1315 delete[] pBlockCopy;
1316 return false;
1317 }
1318
1319 unsigned int* pFlags[3] =
1320 {
1321 &Params.nMin,
1322 &Params.nMag,
1323 &Params.nMIP,
1324 };
1325
1326 if(!ParseTextureFlags(pszRemaining, pFlags, 3, c_ppszFilters, eFilter_Size, pReturnError, i))
1327 {
1328 delete[] pBlockCopy;
1329 return false;
1330 }
1331
1332 bKnown = true;
1333 }
1334 // --- Inline wrapping flags
1335 else if(Cmd == GenericSurfCommands[eCmds_Wrap])
1336 {
1337 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1338 if(!pszRemaining)
1339 {
1340 *pReturnError = PVRTStringFromFormattedStr("Missing WRAP arguments in [%s] on line %d: %s\n", pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1341 delete[] pBlockCopy;
1342 return false;
1343 }
1344
1345 unsigned int* pFlags[3] =
1346 {
1347 &Params.nWrapS,
1348 &Params.nWrapT,
1349 &Params.nWrapR,
1350 };
1351
1352 if(!ParseTextureFlags(pszRemaining, pFlags, 3, c_ppszWraps, eWrap_Size, pReturnError, i))
1353 {
1354 delete[] pBlockCopy;
1355 return false;
1356 }
1357
1358 bKnown = true;
1359 }
1360 // --- Resolution
1361 else if(Cmd == GenericSurfCommands[eCmds_Resolution])
1362 {
1363 char* pszRemaining;
1364
1365 unsigned int* uiVals[2] = { &Params.uiWidth, &Params.uiHeight };
1366
1367 // There should be precisely TWO arguments for resolution (width and height)
1368 for(unsigned int uiIndex = 0; uiIndex < 2; ++uiIndex)
1369 {
1370 pszRemaining = strtok(NULL, DELIM_TOKENS NEWLINE_TOKENS);
1371 if(!pszRemaining)
1372 {
1373 *pReturnError = PVRTStringFromFormattedStr("Missing RESOLUTION argument(s) (requires width AND height) in [TARGET] on line %d\n", m_psContext->pnFileLineNumber[i]);
1374 delete[] pBlockCopy;
1375 return false;
1376 }
1377
1378 int val = atoi(pszRemaining);
1379
1380 if( (val == 0 && *pszRemaining != '0') // Make sure they haven't explicitly set the value to be 0 as this might be a valid use-case.
1381 || (val < 0))
1382 {
1383 *pReturnError = PVRTStringFromFormattedStr("Invalid RESOLUTION argument \"%s\" in [TEXTURE] on line %d\n", pszRemaining, m_psContext->pnFileLineNumber[i]);
1384 delete[] pBlockCopy;
1385 return false;
1386 }
1387
1388 *(uiVals[uiIndex]) = (unsigned int)val;
1389 }
1390
1391 bKnown = true;
1392 }
1393 // --- Surface type
1394 else if(Cmd == GenericSurfCommands[eCmds_Surface])
1395 {
1396 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1397 if(!pszRemaining)
1398 {
1399 *pReturnError = PVRTStringFromFormattedStr("Missing SURFACETYPE arguments in [TARGET] on line %d\n", m_psContext->pnFileLineNumber[i]);
1400 delete[] pBlockCopy;
1401 return false;
1402 }
1403
1404 CPVRTHash hashType(pszRemaining);
1405 for(unsigned int uiIndex = 0; uiIndex < uiNumSurfTypes; ++uiIndex)
1406 {
1407 if(hashType == SurfacePairs[uiIndex].Name)
1408 {
1409 Params.uiFlags = SurfacePairs[uiIndex].eType | SurfacePairs[uiIndex].BufferType;
1410 break;
1411 }
1412 }
1413
1414 bKnown = true;
1415 }
1416
1417 // Valid Verbose command
1418 if(ppFilters)
1419 {
1420 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1421 if(!pszRemaining)
1422 {
1423 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [%s] on line %d: %s\n", pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1424 delete[] pBlockCopy;
1425 return false;
1426 }
1427
1428 unsigned int Type = INVALID_TYPE;
1429 for(unsigned int uiIndex = 0; uiIndex < 3; ++uiIndex)
1430 {
1431 if(strcmp(pszRemaining, ppFilters[uiIndex]) == 0)
1432 {
1433 Type = uiIndex; // Yup, it's valid.
1434 break;
1435 }
1436 }
1437
1438 // Tell the user it's invalid.
1439 if(Type == INVALID_TYPE)
1440 {
1441 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [%s] on line %d: %s\n", pszRemaining, pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1442 delete[] pBlockCopy;
1443 return false;
1444 }
1445
1446 if(Cmd == GenericSurfCommands[eCmds_Min]) Params.nMin = Type;
1447 else if(Cmd == GenericSurfCommands[eCmds_Mag]) Params.nMag = Type;
1448 else if(Cmd == GenericSurfCommands[eCmds_Mip]) Params.nMIP = Type;
1449 else if(Cmd == GenericSurfCommands[eCmds_WrapR]) Params.nWrapR = Type;
1450 else if(Cmd == GenericSurfCommands[eCmds_WrapS]) Params.nWrapS = Type;
1451 else if(Cmd == GenericSurfCommands[eCmds_WrapT]) Params.nWrapT = Type;
1452 }
1453
1454 if(bKnown)
1455 {
1456 KnownCmds.Append(Cmd);
1457
1458 // Make sure nothing else exists on the line that hasn't been parsed.
1459 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS);
1460 if(pszRemaining)
1461 {
1462 *pReturnError = PVRTStringFromFormattedStr("Unexpected keyword '%s' in [%s] on line %d: %s\n", pszRemaining, pCaller, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1463 delete[] pBlockCopy;
1464 return false;
1465 }
1466 }
1467
1468 delete [] pBlockCopy;
1469 }
1470
1471 return true;
1472 }
1473
1474 /*!***************************************************************************
1475 @Function ParseTexture
1476 @Input nStartLine start line number
1477 @Input nEndLine end line number
1478 @Output pReturnError error string
1479 @Return bool true if parse is successful
1480 @Description Parses the TEXTURE section of the PFX file.
1481 *****************************************************************************/
ParseTexture(int nStartLine,int nEndLine,CPVRTString * const pReturnError)1482 bool CPVRTPFXParser::ParseTexture(int nStartLine, int nEndLine, CPVRTString * const pReturnError)
1483 {
1484 enum eCmd
1485 {
1486 eCmds_Name,
1487 eCmds_Path,
1488 eCmds_View,
1489 eCmds_Camera,
1490
1491 eCmds_Size
1492 };
1493
1494 const CPVRTHash TextureCmds[] =
1495 {
1496 "NAME", // eTextureCmds_Name
1497 "PATH", // eTextureCmds_Path
1498 "VIEW", // eTextureCmds_View
1499 "CAMERA", // eTextureCmds_Camera
1500 };
1501 PVRTCOMPILEASSERT(TextureCmds, sizeof(TextureCmds) / sizeof(TextureCmds[0]) == eCmds_Size);
1502
1503 SPVRTPFXParserTexture TexDesc;
1504 TexDesc.nMin = eFilter_Default;
1505 TexDesc.nMag = eFilter_Default;
1506 TexDesc.nMIP = eFilter_MipDefault;
1507 TexDesc.nWrapS = eWrap_Default;
1508 TexDesc.nWrapT = eWrap_Default;
1509 TexDesc.nWrapR = eWrap_Default;
1510 TexDesc.uiWidth = VIEWPORT_SIZE;
1511 TexDesc.uiHeight = VIEWPORT_SIZE;
1512 TexDesc.uiFlags = OGL_RGBA_8888 | PVRPFXTEX_COLOUR;
1513
1514 CPVRTArray<CPVRTHash> KnownCmds;
1515 if(!ParseGenericSurface(nStartLine, nEndLine, TexDesc, KnownCmds, "TEXTURE", pReturnError))
1516 return false;
1517
1518 CPVRTString texName, filePath, viewName;
1519 for(int i = nStartLine+1; i < nEndLine; i++)
1520 {
1521 // Skip blank lines
1522 if(!*m_psContext->ppszEffectFile[i])
1523 continue;
1524
1525 char *str = strtok (m_psContext->ppszEffectFile[i], NEWLINE_TOKENS DELIM_TOKENS);
1526 if(!str)
1527 {
1528 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [TEXTURE] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1529 return false;
1530 }
1531
1532 CPVRTHash texCmd(str);
1533 // --- Texture Name
1534 if(texCmd == TextureCmds[eCmds_Name])
1535 {
1536 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1537 if(!pszRemaining)
1538 {
1539 *pReturnError = PVRTStringFromFormattedStr("Missing NAME arguments in [TEXTURE] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1540 return false;
1541 }
1542
1543 texName = pszRemaining;
1544 }
1545 // --- Texture Path
1546 else if(texCmd == TextureCmds[eCmds_Path])
1547 {
1548 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS);
1549 if(!pszRemaining)
1550 {
1551 *pReturnError = PVRTStringFromFormattedStr("Missing PATH arguments in [TEXTURE] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1552 return false;
1553 }
1554
1555 if(!ReadStringToken(pszRemaining, filePath, *pReturnError, i, "TEXTURE"))
1556 {
1557 return false;
1558 }
1559 }
1560 // --- View/Camera Name
1561 else if(texCmd == TextureCmds[eCmds_View] || texCmd == TextureCmds[eCmds_Camera])
1562 {
1563 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS); // String component. Get the rest of the line.
1564 if(!pszRemaining || strlen(pszRemaining) == 0)
1565 {
1566 *pReturnError = PVRTStringFromFormattedStr("Missing VIEW argument in [TEXTURE] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1567 return false;
1568 }
1569
1570 if(!ReadStringToken(pszRemaining, viewName, *pReturnError, i, "TEXTURE"))
1571 {
1572 return false;
1573 }
1574 }
1575 else if(KnownCmds.Contains(texCmd))
1576 {
1577 // Remove from 'unknown' list.
1578 for(unsigned int uiIndex = 0; uiIndex < KnownCmds.GetSize(); ++uiIndex)
1579 {
1580 if(KnownCmds[uiIndex] == texCmd)
1581 {
1582 KnownCmds.Remove(uiIndex);
1583 break;
1584 }
1585 }
1586
1587 continue; // This line has already been processed.
1588 }
1589 else
1590 {
1591 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TEXTURE] on line %d: %s\n", str, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1592 return false;
1593 }
1594
1595 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS);
1596 if(pszRemaining)
1597 {
1598 *pReturnError = PVRTStringFromFormattedStr("Unexpected keyword '%s' in [TEXTURE] on line %d: %s\n", pszRemaining, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1599 return false;
1600 }
1601 }
1602
1603 if(texName.empty())
1604 {
1605 *pReturnError = PVRTStringFromFormattedStr("No NAME tag specified in [TEXTURE] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
1606 return false;
1607 }
1608 if(!filePath.empty() && !viewName.empty())
1609 {
1610 *pReturnError = PVRTStringFromFormattedStr("Both PATH and VIEW tags specified in [TEXTURE] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
1611 return false;
1612 }
1613 if(filePath.empty() && viewName.empty())
1614 {
1615 *pReturnError = PVRTStringFromFormattedStr("No PATH or VIEW tag specified in [TEXTURE] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
1616 return false;
1617 }
1618
1619 bool bRTT = (viewName.empty() ? false : true);
1620 if(bRTT)
1621 {
1622 filePath = texName; // RTT doesn't have a physical file.
1623 }
1624
1625 // Create a new texture and copy over the vals.
1626 SPVRTPFXParserTexture* pTex = new SPVRTPFXParserTexture();
1627 pTex->Name = CPVRTStringHash(texName);
1628 pTex->FileName = CPVRTStringHash(filePath);
1629 pTex->bRenderToTexture = bRTT;
1630 pTex->nMin = TexDesc.nMin;
1631 pTex->nMag = TexDesc.nMag;
1632 pTex->nMIP = TexDesc.nMIP;
1633 pTex->nWrapS = TexDesc.nWrapS;
1634 pTex->nWrapT = TexDesc.nWrapT;
1635 pTex->nWrapR = TexDesc.nWrapR;
1636 pTex->uiWidth = TexDesc.uiWidth;
1637 pTex->uiHeight = TexDesc.uiHeight;
1638 pTex->uiFlags = TexDesc.uiFlags;
1639 m_psTexture.Append(pTex);
1640
1641 if(bRTT)
1642 {
1643 unsigned int uiPassIdx = m_RenderPasses.Append();
1644 m_RenderPasses[uiPassIdx].SemanticName = texName;
1645
1646 if(viewName == c_pszCurrentView)
1647 {
1648 m_RenderPasses[uiPassIdx].eViewType = eVIEW_CURRENT;
1649 }
1650 else
1651 {
1652 m_RenderPasses[uiPassIdx].eViewType = eVIEW_POD_CAMERA;
1653 m_RenderPasses[uiPassIdx].NodeName = viewName;
1654 }
1655
1656 m_RenderPasses[uiPassIdx].eRenderPassType = eCAMERA_PASS; // Textures are always 'camera' passes
1657
1658 // Set render pass texture to the newly created texture.
1659 m_RenderPasses[uiPassIdx].pTexture = pTex;
1660 m_RenderPasses[uiPassIdx].uiFormatFlags = TexDesc.uiFlags;
1661 }
1662
1663 return true;
1664 }
1665
1666 /*!***************************************************************************
1667 @Function ParseTarget
1668 @Input nStartLine start line number
1669 @Input nEndLine end line number
1670 @Output pReturnError error string
1671 @Return bool true if parse is successful
1672 @Description Parses the TARGET section of the PFX file.
1673 *****************************************************************************/
ParseTarget(int nStartLine,int nEndLine,CPVRTString * const pReturnError)1674 bool CPVRTPFXParser::ParseTarget(int nStartLine, int nEndLine, CPVRTString * const pReturnError)
1675 {
1676 enum eCmd
1677 {
1678 eCmds_Name,
1679
1680 eCmds_Size
1681 };
1682
1683 const CPVRTHash TargetCommands[] =
1684 {
1685 "NAME", // eCmds_Name
1686 };
1687 PVRTCOMPILEASSERT(TargetCommands, sizeof(TargetCommands) / sizeof(TargetCommands[0]) == eCmds_Size);
1688
1689 CPVRTString targetName;
1690 SPVRTPFXParserTexture TexDesc;
1691 TexDesc.nMin = eFilter_Default;
1692 TexDesc.nMag = eFilter_Default;
1693 TexDesc.nMIP = eFilter_MipDefault;
1694 TexDesc.nWrapS = eWrap_Default;
1695 TexDesc.nWrapT = eWrap_Default;
1696 TexDesc.nWrapR = eWrap_Default;
1697 TexDesc.uiWidth = VIEWPORT_SIZE;
1698 TexDesc.uiHeight = VIEWPORT_SIZE;
1699 TexDesc.uiFlags = OGL_RGBA_8888 | PVRPFXTEX_COLOUR;
1700
1701 CPVRTArray<CPVRTHash> KnownCmds;
1702 if(!ParseGenericSurface(nStartLine, nEndLine, TexDesc, KnownCmds, "TARGET", pReturnError))
1703 return false;
1704
1705 for(int i = nStartLine+1; i < nEndLine; i++)
1706 {
1707 // Skip blank lines
1708 if(!*m_psContext->ppszEffectFile[i])
1709 continue;
1710
1711 char *str = strtok (m_psContext->ppszEffectFile[i], NEWLINE_TOKENS DELIM_TOKENS);
1712 if(!str)
1713 {
1714 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [TARGET] on line %d\n", m_psContext->pnFileLineNumber[i]);
1715 return false;
1716 }
1717
1718 CPVRTHash texCmd(str);
1719 // --- Target Name
1720 if(texCmd == TargetCommands[eCmds_Name])
1721 {
1722 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS DELIM_TOKENS);
1723 if(!pszRemaining)
1724 {
1725 *pReturnError = PVRTStringFromFormattedStr("Missing NAME arguments in [TARGET] on line %d\n", m_psContext->pnFileLineNumber[i]);
1726 return false;
1727 }
1728
1729 targetName = pszRemaining;
1730 }
1731 else if(KnownCmds.Contains(texCmd))
1732 {
1733 // Remove from 'unknown' list.
1734 for(unsigned int uiIndex = 0; uiIndex < KnownCmds.GetSize(); ++uiIndex)
1735 {
1736 if(KnownCmds[uiIndex] == texCmd)
1737 {
1738 KnownCmds.Remove(uiIndex);
1739 break;
1740 }
1741 }
1742
1743 continue; // This line has already been processed.
1744 }
1745 else
1746 {
1747 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TARGET] on line %d\n", str, m_psContext->pnFileLineNumber[i]);
1748 return false;
1749 }
1750
1751 char* pszRemaining = strtok(NULL, NEWLINE_TOKENS);
1752 if(pszRemaining)
1753 {
1754 *pReturnError = PVRTStringFromFormattedStr("Unexpected keyword '%s' in [TARGET] on line %d\n", pszRemaining, m_psContext->pnFileLineNumber[i]);
1755 return false;
1756 }
1757 }
1758
1759 // Create a new texture and copy over the vals.
1760 SPVRTPFXParserTexture* pTex = new SPVRTPFXParserTexture();
1761 pTex->Name = CPVRTStringHash(targetName);
1762 pTex->FileName = CPVRTStringHash(targetName);
1763 pTex->bRenderToTexture = true;
1764 pTex->nMin = TexDesc.nMin;
1765 pTex->nMag = TexDesc.nMag;
1766 pTex->nMIP = TexDesc.nMIP;
1767 pTex->nWrapS = TexDesc.nWrapS;
1768 pTex->nWrapT = TexDesc.nWrapT;
1769 pTex->nWrapR = TexDesc.nWrapR;
1770 pTex->uiWidth = TexDesc.uiWidth;
1771 pTex->uiHeight = TexDesc.uiHeight;
1772 pTex->uiFlags = TexDesc.uiFlags;
1773 m_psTexture.Append(pTex);
1774
1775 // Copy to render pass struct
1776 unsigned int uiPassIdx = m_RenderPasses.Append();
1777 m_RenderPasses[uiPassIdx].SemanticName = targetName;
1778 m_RenderPasses[uiPassIdx].eViewType = eVIEW_NONE;
1779 m_RenderPasses[uiPassIdx].eRenderPassType = ePOSTPROCESS_PASS; // Targets are always post-process passes.
1780 m_RenderPasses[uiPassIdx].pTexture = pTex;
1781 m_RenderPasses[uiPassIdx].uiFormatFlags = TexDesc.uiFlags;
1782
1783 return true;
1784 }
1785
1786 /*!***************************************************************************
1787 @Function ParseTextures ** DEPRECATED **
1788 @Input nStartLine start line number
1789 @Input nEndLine end line number
1790 @Output pReturnError error string
1791 @Return bool true if parse is successful
1792 @Description Parses the TEXTURE section of the PFX file.
1793 *****************************************************************************/
ParseTextures(int nStartLine,int nEndLine,CPVRTString * const pReturnError)1794 bool CPVRTPFXParser::ParseTextures(int nStartLine, int nEndLine, CPVRTString * const pReturnError)
1795 {
1796 char *pszName(NULL), *pszFile(NULL), *pszKeyword(NULL);
1797 char *pszRemaining(NULL), *pszTemp(NULL);
1798 bool bReturnVal(false);
1799
1800 for(int i = nStartLine+1; i < nEndLine; i++)
1801 {
1802 // Skip blank lines
1803 if(!*m_psContext->ppszEffectFile[i])
1804 continue;
1805
1806 char *str = strtok (m_psContext->ppszEffectFile[i]," ");
1807 if(str != NULL)
1808 {
1809 // Set defaults
1810 unsigned int uiMin(eFilter_Default), uiMag(eFilter_Default), uiMip(eFilter_MipDefault);
1811 unsigned int uiWrapS(eWrap_Default), uiWrapT(eWrap_Default), uiWrapR(eWrap_Default);
1812 unsigned int uiFlags = 0;
1813
1814 unsigned int uiWidth = CPVRTPFXParser::VIEWPORT_SIZE;
1815 unsigned int uiHeight = CPVRTPFXParser::VIEWPORT_SIZE;
1816
1817 // Reset variables
1818 FREE(pszName) pszName = NULL;
1819 FREE(pszFile) pszFile = NULL;
1820 FREE(pszKeyword) pszKeyword = NULL;
1821 FREE(pszTemp) pszTemp = NULL;
1822 pszRemaining = NULL;
1823
1824 // Compare against all valid keywords
1825 if((strcmp(str, "FILE") != 0) && (strcmp(str, "RENDER") != 0))
1826 {
1827 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TEXTURES] on line %d\n", str, m_psContext->pnFileLineNumber[i]);
1828 goto fail_release_return;
1829 }
1830
1831 #if 1
1832 if((strcmp(str, "RENDER") == 0))
1833 {
1834 *pReturnError = PVRTStringFromFormattedStr("RENDER tag no longer supported in [TEXTURES] block. Use new [TARGET] block instead\n");
1835 goto fail_release_return;
1836 }
1837 #endif
1838
1839 pszKeyword = (char *)malloc( ((int)strlen(str)+1) * sizeof(char));
1840 strcpy(pszKeyword, str);
1841
1842 str = strtok (NULL, " ");
1843 if(str != NULL)
1844 {
1845 pszName = (char *)malloc( ((int)strlen(str)+1) * sizeof(char));
1846 strcpy(pszName, str);
1847 }
1848 else
1849 {
1850 *pReturnError = PVRTStringFromFormattedStr("Texture name missing in [TEXTURES] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1851 goto fail_release_return;
1852 }
1853
1854 /*
1855 The pszRemaining string is used to look for remaining flags.
1856 This has the advantage of allowing flags to be order independent
1857 and makes it easier to ommit some flags, but still pick up others
1858 (the previous method made it diffifult to retrieve filtering info
1859 if flags before it were missing)
1860 */
1861 pszRemaining = strtok(NULL, "\n");
1862
1863 if(pszRemaining == NULL)
1864 {
1865 *pReturnError = PVRTStringFromFormattedStr("Incomplete definition in [TEXTURES] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1866 goto fail_release_return;
1867 }
1868 else if(strcmp(pszKeyword, "FILE") == 0)
1869 {
1870 pszTemp = (char *)malloc( ((int)strlen(pszRemaining)+1) * sizeof(char));
1871 strcpy(pszTemp, pszRemaining);
1872 str = strtok (pszTemp, " ");
1873
1874 if(str != NULL)
1875 {
1876 pszFile = (char *)malloc( ((int)strlen(str)+1) * sizeof(char));
1877 strcpy(pszFile, str);
1878 }
1879 else
1880 {
1881 *pReturnError = PVRTStringFromFormattedStr("Texture name missing in [TEXTURES] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1882 goto fail_release_return;
1883 }
1884 }
1885
1886 if(strcmp(pszKeyword, "FILE") == 0)
1887 {
1888 // --- Filter flags
1889 {
1890 unsigned int* pFlags[3] =
1891 {
1892 &uiMin,
1893 &uiMag,
1894 &uiMip,
1895 };
1896
1897 if(!ParseTextureFlags(pszRemaining, pFlags, 3, c_ppszFilters, eFilter_Size, pReturnError, i))
1898 goto fail_release_return;
1899 }
1900
1901 // --- Wrap flags
1902 {
1903 unsigned int* pFlags[3] =
1904 {
1905 &uiWrapS,
1906 &uiWrapT,
1907 &uiWrapR,
1908 };
1909
1910 if(!ParseTextureFlags(pszRemaining, pFlags, 3, c_ppszWraps, eWrap_Size, pReturnError, i))
1911 goto fail_release_return;
1912 }
1913
1914 SPVRTPFXParserTexture* pTex = new SPVRTPFXParserTexture();
1915 pTex->Name = CPVRTStringHash(pszName);
1916 pTex->FileName = CPVRTStringHash(pszFile);
1917 pTex->bRenderToTexture = false;
1918 pTex->nMin = uiMin;
1919 pTex->nMag = uiMag;
1920 pTex->nMIP = uiMip;
1921 pTex->nWrapS = uiWrapS;
1922 pTex->nWrapT = uiWrapT;
1923 pTex->nWrapR = uiWrapR;
1924 pTex->uiWidth = uiWidth;
1925 pTex->uiHeight = uiHeight;
1926 pTex->uiFlags = uiFlags;
1927 m_psTexture.Append(pTex);
1928 }
1929 else
1930 {
1931 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TEXTURES] on line %d\n", str, m_psContext->pnFileLineNumber[i]);;
1932 goto fail_release_return;
1933 }
1934 }
1935 else
1936 {
1937 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [TEXTURES] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
1938 goto fail_release_return;
1939 }
1940 }
1941
1942 /*
1943 Should only reach here if there have been no issues
1944 */
1945 bReturnVal = true;
1946 goto release_return;
1947
1948 fail_release_return:
1949 bReturnVal = false;
1950 release_return:
1951 FREE(pszKeyword);
1952 FREE(pszName);
1953 FREE(pszFile);
1954 FREE(pszTemp);
1955 return bReturnVal;
1956 }
1957
1958 /*!***************************************************************************
1959 @Function ParseTextureFlags
1960 @Input c_pszCursor
1961 @Output pFlagsOut
1962 @Input uiNumFlags
1963 @Input ppszFlagNames
1964 @Input uiNumFlagNames
1965 @Input pReturnError
1966 @Input iLineNum
1967 @Return bool
1968 @Description Parses the texture flag sections.
1969 *****************************************************************************/
ParseTextureFlags(const char * c_pszRemainingLine,unsigned int ** ppFlagsOut,unsigned int uiNumFlags,const char ** c_ppszFlagNames,unsigned int uiNumFlagNames,CPVRTString * const pReturnError,int iLineNum)1970 bool CPVRTPFXParser::ParseTextureFlags( const char* c_pszRemainingLine, unsigned int** ppFlagsOut, unsigned int uiNumFlags, const char** c_ppszFlagNames, unsigned int uiNumFlagNames,
1971 CPVRTString * const pReturnError, int iLineNum)
1972 {
1973 const unsigned int INVALID_TYPE = 0xAC1DBEEF;
1974 unsigned int uiIndex;
1975 const char* c_pszCursor;
1976 const char* c_pszResult;
1977
1978 // --- Find the first flag
1979 uiIndex = 0;
1980 c_pszCursor = strstr(c_pszRemainingLine, c_ppszFlagNames[uiIndex++]);
1981 while(uiIndex < uiNumFlagNames)
1982 {
1983 c_pszResult = strstr(c_pszRemainingLine, c_ppszFlagNames[uiIndex++]);
1984 if(((c_pszResult < c_pszCursor) || !c_pszCursor) && c_pszResult)
1985 c_pszCursor = c_pszResult;
1986 }
1987
1988 if(!c_pszCursor)
1989 return true; // No error, but just return as no flags specified.
1990
1991 // Quick error check - make sure that the first flag found is valid.
1992 if(c_pszCursor != c_pszRemainingLine)
1993 {
1994 if(*(c_pszCursor-1) == '-') // Yeah this shouldn't be there. Must be invalid first tag.
1995 {
1996 char szBuffer[128]; // Find out the tag.
1997 memset(szBuffer, 0, sizeof(szBuffer));
1998 const char* pszStart = c_pszCursor-1;
1999 while(pszStart != c_pszRemainingLine && *pszStart != ' ') pszStart--;
2000 pszStart++; // Escape the space.
2001 unsigned int uiNumChars = (unsigned int) ((c_pszCursor-1) - pszStart);
2002 strncpy(szBuffer, pszStart, uiNumChars);
2003
2004 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TEXTURES] on line %d: %s\n", szBuffer, m_psContext->pnFileLineNumber[iLineNum], m_psContext->ppszEffectFile[iLineNum]);
2005 return false;
2006 }
2007 }
2008
2009 unsigned int uiFlagsFound = 0;
2010 unsigned int uiBufferIdx;
2011 char szBuffer[128]; // Buffer to hold the token
2012
2013 while(*c_pszCursor != ' ' && *c_pszCursor != 0 && uiFlagsFound < uiNumFlags)
2014 {
2015 memset(szBuffer, 0, sizeof(szBuffer)); // Clear the buffer
2016 uiBufferIdx = 0;
2017
2018 while(*c_pszCursor != '-' && *c_pszCursor != 0 && *c_pszCursor != ' ' && uiBufferIdx < 128) // - = delim. token
2019 szBuffer[uiBufferIdx++] = *c_pszCursor++;
2020
2021 // Check if the buffer content is a valid flag name.
2022 unsigned int Type = INVALID_TYPE;
2023 for(unsigned int uiIndex = 0; uiIndex < uiNumFlagNames; ++uiIndex)
2024 {
2025 if(strcmp(szBuffer, c_ppszFlagNames[uiIndex]) == 0)
2026 {
2027 Type = uiIndex; // Yup, it's valid. uiIndex here would translate to one of the enums that matches the string array of flag names passed in.
2028 break;
2029 }
2030 }
2031
2032 // Tell the user it's invalid.
2033 if(Type == INVALID_TYPE)
2034 {
2035 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [TEXTURES] on line %d: %s\n", szBuffer, m_psContext->pnFileLineNumber[iLineNum], m_psContext->ppszEffectFile[iLineNum]);
2036 return false;
2037 }
2038
2039 // Set the flag to the enum type.
2040 *ppFlagsOut[uiFlagsFound++] = Type;
2041
2042 if(*c_pszCursor == '-') c_pszCursor++;
2043 }
2044
2045 return true;
2046 }
2047
2048 /*!***************************************************************************
2049 @Function ParseShader
2050 @Input nStartLine start line number
2051 @Input nEndLine end line number
2052 @Output pReturnError error string
2053 @Output shader shader data object
2054 @Input pszBlockName name of block in PFX file
2055 @Return bool true if parse is successful
2056 @Description Parses the VERTEXSHADER or FRAGMENTSHADER section of the
2057 PFX file.
2058 *****************************************************************************/
ParseShader(int nStartLine,int nEndLine,CPVRTString * const pReturnError,SPVRTPFXParserShader & shader,const char * const pszBlockName)2059 bool CPVRTPFXParser::ParseShader(int nStartLine, int nEndLine, CPVRTString * const pReturnError, SPVRTPFXParserShader &shader, const char * const pszBlockName)
2060 {
2061 enum eCmd
2062 {
2063 eCmds_GLSLCode,
2064 eCmds_Name,
2065 eCmds_File,
2066 eCmds_BinaryFile,
2067
2068 eCmds_Size
2069 };
2070
2071 const CPVRTHash ShaderCommands[] =
2072 {
2073 "[GLSL_CODE]",
2074 "NAME",
2075 "FILE",
2076 "BINARYFILE",
2077 };
2078 PVRTCOMPILEASSERT(ShaderCommands, sizeof(ShaderCommands) / sizeof(ShaderCommands[0]) == eCmds_Size);
2079
2080 bool glslcode=0, glslfile=0, bName=0;
2081
2082 shader.bUseFileName = false;
2083 shader.pszGLSLfile = NULL;
2084 shader.pszGLSLcode = NULL;
2085 shader.pszGLSLBinaryFile= NULL;
2086 shader.pbGLSLBinary = NULL;
2087 shader.nFirstLineNumber = 0;
2088 shader.nLastLineNumber = 0;
2089
2090 for(int i = nStartLine+1; i < nEndLine; i++)
2091 {
2092 // Skip blank lines
2093 if(!*m_psContext->ppszEffectFile[i])
2094 continue;
2095
2096 char *str = strtok (m_psContext->ppszEffectFile[i]," ");
2097 if(str != NULL)
2098 {
2099 CPVRTHash Cmd(str);
2100
2101 // Check for [GLSL_CODE] tags first and remove those lines from loop.
2102 if(Cmd == ShaderCommands[eCmds_GLSLCode])
2103 {
2104 if(glslcode)
2105 {
2106 *pReturnError = PVRTStringFromFormattedStr("[GLSL_CODE] redefined in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2107 return false;
2108 }
2109 if(glslfile && shader.pbGLSLBinary==NULL )
2110 {
2111 *pReturnError = PVRTStringFromFormattedStr("[GLSL_CODE] not allowed with FILE in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2112 return false;
2113 }
2114
2115 shader.nFirstLineNumber = m_psContext->pnFileLineNumber[i];
2116
2117 // Skip the block-start
2118 i++;
2119
2120 CPVRTString GLSLCode;
2121 if(!ConcatenateLinesUntil(
2122 GLSLCode,
2123 i,
2124 m_psContext->ppszEffectFile,
2125 m_psContext->nNumLines,
2126 "[/GLSL_CODE]"))
2127 {
2128 return false;
2129 }
2130
2131 shader.nLastLineNumber = m_psContext->pnFileLineNumber[i];
2132
2133 shader.pszGLSLcode = (char*)malloc((GLSLCode.size()+1) * sizeof(char));
2134 strcpy(shader.pszGLSLcode, GLSLCode.c_str());
2135
2136 shader.bUseFileName = false;
2137 glslcode = 1;
2138 }
2139 else if(Cmd == ShaderCommands[eCmds_Name])
2140 {
2141 if(bName)
2142 {
2143 *pReturnError = PVRTStringFromFormattedStr("NAME redefined in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2144 return false;
2145 }
2146
2147 str = ReadEOLToken(NULL);
2148
2149 if(str == NULL)
2150 {
2151 *pReturnError = PVRTStringFromFormattedStr("NAME missing value in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2152 return false;
2153 }
2154
2155 shader.Name.assign(str);
2156 bName = true;
2157 }
2158 else if(Cmd == ShaderCommands[eCmds_File])
2159 {
2160 if(glslfile)
2161 {
2162 *pReturnError = PVRTStringFromFormattedStr("FILE redefined in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2163 return false;
2164 }
2165 if(glslcode)
2166 {
2167 *pReturnError = PVRTStringFromFormattedStr("FILE not allowed with [GLSL_CODE] in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2168 return false;
2169 }
2170
2171 str = ReadEOLToken(NULL);
2172
2173 if(str == NULL)
2174 {
2175 *pReturnError = PVRTStringFromFormattedStr("FILE missing value in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2176 return false;
2177 }
2178
2179 shader.pszGLSLfile = (char*)malloc((strlen(str)+1) * sizeof(char));
2180 strcpy(shader.pszGLSLfile, str);
2181
2182 CPVRTResourceFile GLSLFile(str);
2183
2184 if(!GLSLFile.IsOpen())
2185 {
2186 *pReturnError = PVRTStringFromFormattedStr("Error loading file '%s' in [%s] on line %d\n", str, pszBlockName, m_psContext->pnFileLineNumber[i]);
2187 return false;
2188 }
2189 shader.pszGLSLcode = (char*)malloc((GLSLFile.Size()+1) * sizeof(char));
2190 memcpy(shader.pszGLSLcode, (const char*) GLSLFile.DataPtr(), GLSLFile.Size());
2191 shader.pszGLSLcode[GLSLFile.Size()] = '\0';
2192
2193 shader.nFirstLineNumber = m_psContext->pnFileLineNumber[i]; // Mark position where GLSL file is defined.
2194
2195 shader.bUseFileName = true;
2196 glslfile = 1;
2197 }
2198 else if(Cmd == ShaderCommands[eCmds_BinaryFile])
2199 {
2200 str = ReadEOLToken(NULL);
2201
2202 if(str == NULL)
2203 {
2204 *pReturnError = PVRTStringFromFormattedStr("BINARYFILE missing value in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[i]);
2205 return false;
2206 }
2207
2208 shader.pszGLSLBinaryFile = (char*)malloc((strlen(str)+1) * sizeof(char));
2209 strcpy(shader.pszGLSLBinaryFile, str);
2210
2211 CPVRTResourceFile GLSLFile(str);
2212
2213 if(!GLSLFile.IsOpen())
2214 {
2215 *pReturnError = PVRTStringFromFormattedStr("Error loading file '%s' in [%s] on line %d\n", str, pszBlockName, m_psContext->pnFileLineNumber[i]);
2216 return false;
2217 }
2218 shader.pbGLSLBinary = new char[GLSLFile.Size()];
2219 shader.nGLSLBinarySize = (unsigned int)GLSLFile.Size();
2220 memcpy(shader.pbGLSLBinary, GLSLFile.DataPtr(), GLSLFile.Size());
2221
2222 shader.bUseFileName = true;
2223 glslfile = 1;
2224 }
2225 else
2226 {
2227 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [%s] on line %d\n", str, pszBlockName, m_psContext->pnFileLineNumber[i]);
2228 return false;
2229 }
2230
2231 str = strtok (NULL, " ");
2232 if(str != NULL)
2233 {
2234 *pReturnError = PVRTStringFromFormattedStr("Unexpected data in [%s] on line %d: '%s'\n", pszBlockName, m_psContext->pnFileLineNumber[i], str);
2235 return false;
2236 }
2237 }
2238 else
2239 {
2240 *pReturnError = PVRTStringFromFormattedStr("Missing arguments in [%s] on line %d: %s\n", pszBlockName, m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
2241 return false;
2242 }
2243 }
2244
2245 if(!bName)
2246 {
2247 *pReturnError = PVRTStringFromFormattedStr("NAME not found in [%s] on line %d.\n", pszBlockName, m_psContext->pnFileLineNumber[nStartLine]);
2248 return false;
2249 }
2250
2251 if(!glslfile && !glslcode)
2252 {
2253 *pReturnError = PVRTStringFromFormattedStr("No Shader File or Shader Code specified in [%s] on line %d\n", pszBlockName, m_psContext->pnFileLineNumber[nStartLine]);
2254 return false;
2255 }
2256
2257 return true;
2258 }
2259
2260 /*!***************************************************************************
2261 @Function ParseSemantic
2262 @Output semantic semantic data object
2263 @Input nStartLine start line number
2264 @Output pReturnError error string
2265 @Return bool true if parse is successful
2266 @Description Parses a semantic.
2267 *****************************************************************************/
ParseSemantic(SPVRTPFXParserSemantic & semantic,const int nStartLine,CPVRTString * const pReturnError)2268 bool CPVRTPFXParser::ParseSemantic(SPVRTPFXParserSemantic &semantic, const int nStartLine, CPVRTString * const pReturnError)
2269 {
2270 char *str;
2271
2272 semantic.pszName = 0;
2273 semantic.pszValue = 0;
2274 semantic.sDefaultValue.eType = eDataTypeNone;
2275 semantic.nIdx = 0;
2276
2277 str = strtok (NULL, " ");
2278 if(str == NULL)
2279 {
2280 *pReturnError = PVRTStringFromFormattedStr("UNIFORM missing name in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2281 return false;
2282 }
2283 semantic.pszName = (char*)malloc((strlen(str)+1) * sizeof(char));
2284 strcpy(semantic.pszName, str);
2285
2286 str = strtok (NULL, " ");
2287 if(str == NULL)
2288 {
2289 *pReturnError = PVRTStringFromFormattedStr("UNIFORM missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2290
2291 FREE(semantic.pszName);
2292 return false;
2293 }
2294
2295 /*
2296 If the final digits of the semantic are a number they are
2297 stripped off and used as the index, with the remainder
2298 used as the semantic.
2299 */
2300 {
2301 size_t idx, len;
2302 len = strlen(str);
2303
2304 idx = len;
2305 while(idx)
2306 {
2307 --idx;
2308 if(strcspn(&str[idx], "0123456789") != 0)
2309 {
2310 break;
2311 }
2312 }
2313 if(idx == 0)
2314 {
2315 *pReturnError = PVRTStringFromFormattedStr("Semantic contains only numbers in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2316
2317 FREE(semantic.pszName);
2318 return false;
2319 }
2320
2321 ++idx;
2322 // Store the semantic index
2323 if(len == idx)
2324 {
2325 semantic.nIdx = 0;
2326 }
2327 else
2328 {
2329 semantic.nIdx = atoi(&str[idx]);
2330 }
2331
2332 // Chop off the index from the string containing the semantic
2333 str[idx] = 0;
2334 }
2335
2336 // Store a copy of the semantic name
2337 semantic.pszValue = (char*)malloc((strlen(str)+1) * sizeof(char));
2338 strcpy(semantic.pszValue, str);
2339
2340 /*
2341 Optional default semantic value
2342 */
2343 char pszString[2048];
2344 strcpy(pszString,"");
2345 str = strtok (NULL, " ");
2346 if(str != NULL)
2347 {
2348 // Get all ramainning arguments
2349 while(str != NULL)
2350 {
2351 strcat(pszString, str);
2352 strcat(pszString, " ");
2353 str = strtok (NULL, " ");
2354 }
2355
2356 // default value
2357 int i;
2358 for(i = 0; i < eNumDefaultDataTypes; i++)
2359 {
2360 if(strncmp(pszString, c_psSemanticDefaultDataTypeInfo[i].pszName, strlen(c_psSemanticDefaultDataTypeInfo[i].pszName)) == 0)
2361 {
2362 if(!GetSemanticDataFromString( &semantic.sDefaultValue,
2363 &pszString[strlen(c_psSemanticDefaultDataTypeInfo[i].pszName)],
2364 c_psSemanticDefaultDataTypeInfo[i].eType,
2365 pReturnError
2366 ))
2367 {
2368 *pReturnError = PVRTStringFromFormattedStr(" on line %d.\n", m_psContext->pnFileLineNumber[nStartLine]);
2369
2370 FREE(semantic.pszValue);
2371 FREE(semantic.pszName);
2372 return false;
2373 }
2374
2375 semantic.sDefaultValue.eType = c_psSemanticDefaultDataTypeInfo[i].eType;
2376 break;
2377 }
2378 }
2379
2380 // invalid data type
2381 if(i == eNumDefaultDataTypes)
2382 {
2383 *pReturnError = PVRTStringFromFormattedStr("'%s' unknown on line %d.\n", pszString, m_psContext->pnFileLineNumber[nStartLine]);
2384
2385 FREE(semantic.pszValue);
2386 FREE(semantic.pszName);
2387 return false;
2388 }
2389
2390 }
2391
2392 return true;
2393 }
2394
2395 /*!***************************************************************************
2396 @Function ParseEffect
2397 @Output effect effect data object
2398 @Input nStartLine start line number
2399 @Input nEndLine end line number
2400 @Output pReturnError error string
2401 @Return bool true if parse is successful
2402 @Description Parses the EFFECT section of the PFX file.
2403 *****************************************************************************/
ParseEffect(SPVRTPFXParserEffect & effect,const int nStartLine,const int nEndLine,CPVRTString * const pReturnError)2404 bool CPVRTPFXParser::ParseEffect(SPVRTPFXParserEffect &effect, const int nStartLine, const int nEndLine, CPVRTString * const pReturnError)
2405 {
2406 enum eCmds
2407 {
2408 eCmds_Annotation,
2409 eCmds_VertexShader,
2410 eCmds_FragmentShader,
2411 eCmds_Texture,
2412 eCmds_Uniform,
2413 eCmds_Attribute,
2414 eCmds_Name,
2415 eCmds_Target,
2416
2417 eCmds_Size
2418 };
2419
2420 const CPVRTHash EffectCommands[] =
2421 {
2422 "[ANNOTATION]",
2423 "VERTEXSHADER",
2424 "FRAGMENTSHADER",
2425 "TEXTURE",
2426 "UNIFORM",
2427 "ATTRIBUTE",
2428 "NAME",
2429 "TARGET",
2430 };
2431 PVRTCOMPILEASSERT(EffectCommands, sizeof(EffectCommands) / sizeof(EffectCommands[0]) == eCmds_Size);
2432
2433 bool bName = false;
2434 bool bVertShader = false;
2435 bool bFragShader = false;
2436
2437 for(int i = nStartLine+1; i < nEndLine; i++)
2438 {
2439 // Skip blank lines
2440 if(!*m_psContext->ppszEffectFile[i])
2441 continue;
2442
2443 char *str = strtok (m_psContext->ppszEffectFile[i]," ");
2444 if(str != NULL)
2445 {
2446 CPVRTHash Cmd(str);
2447
2448 if(Cmd == EffectCommands[eCmds_Annotation])
2449 {
2450 if(!effect.Annotation.empty())
2451 {
2452 *pReturnError = PVRTStringFromFormattedStr("ANNOTATION redefined in [EFFECT] on line %d: \n", m_psContext->pnFileLineNumber[i]);
2453 return false;
2454 }
2455
2456 i++; // Skip the block-start
2457 if(!ConcatenateLinesUntil(
2458 effect.Annotation,
2459 i,
2460 m_psContext->ppszEffectFile,
2461 m_psContext->nNumLines,
2462 "[/ANNOTATION]"))
2463 {
2464 return false;
2465 }
2466 }
2467 else if(Cmd == EffectCommands[eCmds_VertexShader])
2468 {
2469 if(bVertShader)
2470 {
2471 *pReturnError = PVRTStringFromFormattedStr("VERTEXSHADER redefined in [EFFECT] on line %d: \n", m_psContext->pnFileLineNumber[i]);
2472 return false;
2473 }
2474
2475 str = ReadEOLToken(NULL);
2476
2477 if(str == NULL)
2478 {
2479 *pReturnError = PVRTStringFromFormattedStr("VERTEXSHADER missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[i]);
2480 return false;
2481 }
2482 effect.VertexShaderName.assign(str);
2483
2484 bVertShader = true;
2485 }
2486 else if(Cmd == EffectCommands[eCmds_FragmentShader])
2487 {
2488 if(bFragShader)
2489 {
2490 *pReturnError = PVRTStringFromFormattedStr("FRAGMENTSHADER redefined in [EFFECT] on line %d: \n", m_psContext->pnFileLineNumber[i]);
2491 return false;
2492 }
2493
2494 str = ReadEOLToken(NULL);
2495
2496 if(str == NULL)
2497 {
2498 *pReturnError = PVRTStringFromFormattedStr("FRAGMENTSHADER missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[i]);
2499 return false;
2500 }
2501 effect.FragmentShaderName.assign(str);
2502
2503 bFragShader = true;
2504 }
2505 else if(Cmd == EffectCommands[eCmds_Texture])
2506 {
2507 unsigned int uiTexIdx = effect.Textures.Append();
2508 // texture number
2509 str = strtok(NULL, " ");
2510 if(str != NULL)
2511 effect.Textures[uiTexIdx].nNumber = atoi(str);
2512 else
2513 {
2514 *pReturnError = PVRTStringFromFormattedStr("TEXTURE missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[i]);
2515 return false;
2516 }
2517
2518 // texture name
2519 str = strtok(NULL, " ");
2520 if(str != NULL)
2521 {
2522 effect.Textures[uiTexIdx].Name = CPVRTStringHash(str);
2523 }
2524 else
2525 {
2526 *pReturnError = PVRTStringFromFormattedStr("TEXTURE missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[i]);
2527 return false;
2528 }
2529 }
2530 else if(Cmd == EffectCommands[eCmds_Uniform])
2531 {
2532 unsigned int uiUniformIdx = effect.Uniforms.Append();
2533 if(!ParseSemantic(effect.Uniforms[uiUniformIdx], i, pReturnError))
2534 return false;
2535
2536 }
2537 else if(Cmd == EffectCommands[eCmds_Attribute])
2538 {
2539 unsigned int uiAttribIdx = effect.Attributes.Append();
2540 if(!ParseSemantic(effect.Attributes[uiAttribIdx], i, pReturnError))
2541 return false;
2542 }
2543 else if(Cmd == EffectCommands[eCmds_Name])
2544 {
2545 if(bName)
2546 {
2547 *pReturnError = PVRTStringFromFormattedStr("NAME redefined in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2548 return false;
2549 }
2550
2551 str = strtok (NULL, " ");
2552 if(str == NULL)
2553 {
2554 *pReturnError = PVRTStringFromFormattedStr("NAME missing value in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2555 return false;
2556 }
2557
2558 effect.Name.assign(str);
2559 bName = true;
2560 }
2561 else if(Cmd == EffectCommands[eCmds_Target])
2562 {
2563 unsigned int uiIndex = effect.Targets.Append();
2564
2565 // Target requires 2 components
2566 CPVRTString* pVals[] = { &effect.Targets[uiIndex].BufferType, &effect.Targets[uiIndex].TargetName };
2567
2568 for(unsigned int uiVal = 0; uiVal < 2; ++uiVal)
2569 {
2570 str = strtok (NULL, " ");
2571 if(str == NULL)
2572 {
2573 *pReturnError = PVRTStringFromFormattedStr("TARGET missing value(s) in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2574 return false;
2575 }
2576
2577 *(pVals[uiVal]) = str;
2578 }
2579 }
2580 else
2581 {
2582 *pReturnError = PVRTStringFromFormattedStr("Unknown keyword '%s' in [EFFECT] on line %d\n", str, m_psContext->pnFileLineNumber[i]);
2583 return false;
2584 }
2585 }
2586 else
2587 {
2588 *pReturnError = PVRTStringFromFormattedStr( "Missing arguments in [EFFECT] on line %d: %s\n", m_psContext->pnFileLineNumber[i], m_psContext->ppszEffectFile[i]);
2589 return false;
2590 }
2591 }
2592
2593 // Check that every TEXTURE has a matching UNIFORM
2594 for(unsigned int uiTex = 0; uiTex < effect.Textures.GetSize(); ++uiTex)
2595 {
2596 unsigned int uiTexUnit = effect.Textures[uiTex].nNumber;
2597 const CPVRTStringHash& texName = effect.Textures[uiTex].Name;
2598 // Find UNIFORM associated with the TexUnit (e.g TEXTURE0).
2599 bool bFound = false;
2600 for(unsigned int uiUniform = 0; uiUniform < effect.Uniforms.GetSize(); ++uiUniform)
2601 {
2602 const SPVRTPFXParserSemantic& Sem = effect.Uniforms[uiUniform];
2603 if(strcmp(Sem.pszValue, "TEXTURE") == 0 && Sem.nIdx == uiTexUnit)
2604 {
2605 bFound = true;
2606 break;
2607 }
2608 }
2609
2610 if(!bFound)
2611 {
2612 *pReturnError = PVRTStringFromFormattedStr("TEXTURE %s missing matching UNIFORM in [EFFECT] on line %d\n", texName.c_str(), m_psContext->pnFileLineNumber[nStartLine]);
2613 return false;
2614 }
2615 }
2616
2617
2618 if(!bName)
2619 {
2620 *pReturnError = PVRTStringFromFormattedStr("No 'NAME' found in [EFFECT] on line %d\n", m_psContext->pnFileLineNumber[nStartLine]);
2621 return false;
2622 }
2623 if(!bVertShader)
2624 {
2625 *pReturnError = PVRTStringFromFormattedStr("No 'VERTEXSHADER' defined in [EFFECT] starting on line %d: \n", m_psContext->pnFileLineNumber[nStartLine-1]);
2626 return false;
2627 }
2628 if(!bFragShader)
2629 {
2630 *pReturnError = PVRTStringFromFormattedStr("No 'FRAGMENTSHADER' defined in [EFFECT] starting on line %d: \n", m_psContext->pnFileLineNumber[nStartLine-1]);
2631 return false;
2632 }
2633
2634 return true;
2635 }
2636
2637 /*!***************************************************************************
2638 @Function DetermineRenderPassDependencies
2639 @Return True if dependency tree is valid. False if there are errors
2640 in the dependency tree (e.g. recursion)
2641 @Description Looks through all of the effects in the .pfx and determines
2642 the order of render passes that have been declared with
2643 the RENDER tag (found in [TEXTURES]
2644 *****************************************************************************/
DetermineRenderPassDependencies(CPVRTString * const pReturnError)2645 bool CPVRTPFXParser::DetermineRenderPassDependencies(CPVRTString * const pReturnError)
2646 {
2647 unsigned int ui(0), uj(0), uk(0);
2648
2649 if(m_RenderPasses.GetSize() == 0)
2650 return true;
2651
2652 // --- Add all render pass nodes to the skip graph.
2653 for(ui = 0; ui < m_RenderPasses.GetSize(); ++ui)
2654 {
2655 SPVRTPFXRenderPass& Pass = m_RenderPasses[ui];
2656 bool bFound = false;
2657
2658 // Search all EFFECT blocks for matching TARGET. This is for post-processes behavior.
2659 for(unsigned int uiEffect = 0; uiEffect < m_psEffect.GetSize(); ++uiEffect)
2660 {
2661 SPVRTPFXParserEffect& Effect = m_psEffect[uiEffect];
2662
2663 // Search all TARGETs in this effect
2664 for(unsigned int uiTargets = 0; uiTargets < Effect.Targets.GetSize(); ++uiTargets)
2665 {
2666 const SPVRTTargetPair& Target = Effect.Targets[uiTargets];
2667 if(Target.TargetName == Pass.SemanticName)
2668 {
2669 // Match. This EFFECT block matches the pass name.
2670 Pass.pEffect = &Effect;
2671 bFound = true;
2672
2673 // This is now a post-process pass. Set relevant values.
2674 Pass.eRenderPassType = ePOSTPROCESS_PASS;
2675 m_aszPostProcessNames.Append(Pass.SemanticName);
2676
2677 // Check that the surface type and output match are relevant (i.e DEPTH != RGBA8888).
2678 if( (Target.BufferType.find_first_of("DEPTH") != CPVRTString::npos && !(Pass.uiFormatFlags & PVRPFXTEX_DEPTH))
2679 || (Target.BufferType.find_first_of("COLOR") != CPVRTString::npos && !(Pass.uiFormatFlags & PVRPFXTEX_COLOUR)) )
2680 {
2681 *pReturnError = PVRTStringFromFormattedStr("Surface type mismatch in [EFFECT]. \"%s\" has different type than \"%s\"\n", Target.TargetName.c_str(), Pass.SemanticName.c_str());
2682 return false;
2683 }
2684
2685 break;
2686 }
2687 }
2688
2689 if(bFound)
2690 break;
2691 }
2692
2693 // Add a pointer to the post process
2694 m_renderPassSkipGraph.AddNode(&Pass);
2695 }
2696
2697
2698 // --- Loop through all created render passes in the skip graph and determine their dependencies
2699 for(ui = 0; ui < m_renderPassSkipGraph.GetNumNodes(); ++ui)
2700 {
2701 // Loop through all other nodes in the skip graph
2702 SPVRTPFXRenderPass* pPass = m_renderPassSkipGraph[ui];
2703 SPVRTPFXRenderPass* pTestPass = NULL;
2704
2705 for(uj = 0; uj < m_RenderPasses.GetSize(); ++uj)
2706 {
2707 pTestPass = m_renderPassSkipGraph[uj];
2708
2709 // No self compare
2710 if(pPass == pTestPass)
2711 continue;
2712
2713 // No effect associated.
2714 if(!pPass->pEffect)
2715 continue;
2716
2717 // Is the node a render pass I rely on?
2718 for(uk = 0; uk < pPass->pEffect->Textures.GetSize(); ++uk)
2719 {
2720 /*
2721 If the texture names match, add a new node
2722 */
2723 if(pTestPass->pTexture->Name == pPass->pEffect->Textures[uk].Name)
2724 {
2725 m_renderPassSkipGraph.AddNodeDependency(pPass, pTestPass);
2726 break;
2727 }
2728 }
2729 }
2730 }
2731
2732 return true;
2733 }
2734
2735 /*!***************************************************************************
2736 @Function FindTextureIndex
2737 @Input TextureName
2738 @Return unsigned int Index in to the effect.Texture array.
2739 @Description Returns the index in to the texture array within the effect
2740 block where the given texture resides.
2741 *****************************************************************************/
FindTextureIndex(const CPVRTStringHash & TextureName,unsigned int uiEffect) const2742 unsigned int CPVRTPFXParser::FindTextureIndex( const CPVRTStringHash& TextureName, unsigned int uiEffect ) const
2743 {
2744 for(unsigned int uiIndex = 0; uiIndex < m_psEffect[uiEffect].Textures.GetSize(); ++uiIndex)
2745 {
2746 const SPVRTPFXParserEffectTexture& Tex = m_psEffect[uiEffect].Textures[uiIndex];
2747 if(Tex.Name == TextureName)
2748 {
2749 return uiIndex;
2750 }
2751 }
2752
2753 return 0xFFFFFFFF;
2754 }
2755
2756 /*!***************************************************************************
2757 @Function GetNumberRenderPasses
2758 @Return unsigned int
2759 @Description Returns the number of render passes within this PFX.
2760 *****************************************************************************/
GetNumberRenderPasses() const2761 unsigned int CPVRTPFXParser::GetNumberRenderPasses() const
2762 {
2763 return m_RenderPasses.GetSize();
2764 }
2765
2766 /*!***************************************************************************
2767 @Function GetNumberRenderPasses
2768 @Input unsigned int The render pass index.
2769 @Return SPVRTPFXRenderPass*
2770 @Description Returns the given render pass.
2771 *****************************************************************************/
GetRenderPass(unsigned int uiIndex) const2772 const SPVRTPFXRenderPass& CPVRTPFXParser::GetRenderPass( unsigned int uiIndex ) const
2773 {
2774 _ASSERT(uiIndex >= 0 && uiIndex < GetNumberRenderPasses());
2775 return m_RenderPasses[uiIndex];
2776 }
2777
2778 /*!***************************************************************************
2779 @Function GetPFXFileName
2780 @Return const CPVRTString &
2781 @Description Returns the PFX file name associated with this object.
2782 *****************************************************************************/
GetPFXFileName() const2783 const CPVRTString& CPVRTPFXParser::GetPFXFileName() const
2784 {
2785 return m_szFileName;
2786 }
2787
2788 /*!***************************************************************************
2789 @Function GetPostProcessNames
2790 @Return const CPVRTArray<CPVRTString>&
2791 @Description Returns a list of prost process effect names.
2792 *****************************************************************************/
GetPostProcessNames() const2793 const CPVRTArray<CPVRTString>& CPVRTPFXParser::GetPostProcessNames() const
2794 {
2795 return m_aszPostProcessNames;
2796 }
2797
2798 /*!***************************************************************************
2799 @Function GetNumberFragmentShaders
2800 @Return unsigned int Number of fragment shaders.
2801 @Description Returns the number of fragment shaders referenced in the PFX.
2802 *****************************************************************************/
GetNumberFragmentShaders() const2803 unsigned int CPVRTPFXParser::GetNumberFragmentShaders() const
2804 {
2805 return m_psFragmentShader.GetSize();
2806 }
2807
2808
2809 /*!***************************************************************************
2810 @Function GetFragmentShader
2811 @Input unsigned int The index of this shader.
2812 @Return const SPVRTPFXParserShader& The PFX fragment shader.
2813 @Description Returns a given fragment shader.
2814 *****************************************************************************/
GetFragmentShader(unsigned int uiIndex)2815 SPVRTPFXParserShader& CPVRTPFXParser::GetFragmentShader( unsigned int uiIndex )
2816 {
2817 _ASSERT(uiIndex < GetNumberFragmentShaders());
2818 return m_psFragmentShader[uiIndex];
2819 }
2820
2821 /*!***************************************************************************
2822 @Function GetNumberVertexShaders
2823 @Return unsigned int Number of vertex shaders.
2824 @Description Returns the number of vertex shaders referenced in the PFX.
2825 *****************************************************************************/
GetNumberVertexShaders() const2826 unsigned int CPVRTPFXParser::GetNumberVertexShaders() const
2827 {
2828 return m_psVertexShader.GetSize();
2829 }
2830
2831 /*!***************************************************************************
2832 @Function GetVertexShader
2833 @Input unsigned int The index of this shader.
2834 @Return const SPVRTPFXParserShader& The PFX vertex shader.
2835 @Description Returns a given vertex shader.
2836 *****************************************************************************/
GetVertexShader(unsigned int uiIndex)2837 SPVRTPFXParserShader& CPVRTPFXParser::GetVertexShader( unsigned int uiIndex )
2838 {
2839 _ASSERT(uiIndex < GetNumberVertexShaders());
2840 return m_psVertexShader[uiIndex];
2841 }
2842
2843 /*!***************************************************************************
2844 @Function GetNumberEffects
2845 @Return unsigned int Number of effects.
2846 @Description Returns the number of effects referenced in the PFX.
2847 *****************************************************************************/
GetNumberEffects() const2848 unsigned int CPVRTPFXParser::GetNumberEffects() const
2849 {
2850 return m_psEffect.GetSize();
2851 }
2852
2853 /*!***************************************************************************
2854 @Function GetEffect
2855 @Input uiIndex The index of this effect.
2856 @Return The PFX effect.
2857 @Description Returns a given effect.
2858 *****************************************************************************/
GetEffect(unsigned int uiIndex) const2859 const SPVRTPFXParserEffect& CPVRTPFXParser::GetEffect(unsigned int uiIndex) const
2860 {
2861 _ASSERT(uiIndex < GetNumberEffects());
2862 return m_psEffect[uiIndex];
2863 }
2864
2865 /*!***************************************************************************
2866 @Function GetNumberTextures
2867 @Return unsigned int Number of effects.
2868 @Description Returns the number of textures referenced in the PFX.
2869 *****************************************************************************/
GetNumberTextures() const2870 unsigned int CPVRTPFXParser::GetNumberTextures() const
2871 {
2872 return m_psTexture.GetSize();
2873 }
2874
2875 /*!***************************************************************************
2876 @Function GetTexture
2877 @Input unsigned int The index of this texture
2878 @Return const SPVRTPFXParserEffect& The PFX texture.
2879 @Description Returns a given texture.
2880 *****************************************************************************/
GetTexture(unsigned int uiIndex) const2881 const SPVRTPFXParserTexture* CPVRTPFXParser::GetTexture( unsigned int uiIndex ) const
2882 {
2883 _ASSERT(uiIndex < GetNumberTextures());
2884 return m_psTexture[uiIndex];
2885 }
2886
2887 /*!***************************************************************************
2888 @Function FindEffectByName
2889 @Input Name
2890 @Return int
2891 @Description Returns the index of the given string. Returns -1 on failure.
2892 *****************************************************************************/
FindEffectByName(const CPVRTStringHash & Name) const2893 int CPVRTPFXParser::FindEffectByName(const CPVRTStringHash& Name) const
2894 {
2895 if(Name.Hash() == 0)
2896 return -1;
2897
2898 for(unsigned int uiIndex = 0; uiIndex < GetNumberEffects(); ++uiIndex)
2899 {
2900 if(GetEffect(uiIndex).Name == Name)
2901 {
2902 return (int)uiIndex;
2903 }
2904 }
2905
2906 return -1;
2907 }
2908
2909 /*!***************************************************************************
2910 @Function FindTextureByName
2911 @Input Name Name of the texture.
2912 @Return int
2913 @Description Returns the index of the given texture. Returns -1 on failure.
2914 *****************************************************************************/
FindTextureByName(const CPVRTStringHash & Name) const2915 int CPVRTPFXParser::FindTextureByName(const CPVRTStringHash& Name) const
2916 {
2917 if(Name.Hash() == 0)
2918 return -1;
2919
2920 for(unsigned int uiIndex = 0; uiIndex < GetNumberTextures(); ++uiIndex)
2921 {
2922 if(GetTexture(uiIndex)->Name == Name)
2923 {
2924 return (int)uiIndex;
2925 }
2926 }
2927
2928 return -1;
2929 }
2930
2931 /*!***************************************************************************
2932 @Function PVRTPFXCreateStringCopy
2933 @Return void
2934 @Description Safely copies a C string.
2935 *****************************************************************************/
PVRTPFXCreateStringCopy(char ** ppDst,const char * pSrc)2936 void PVRTPFXCreateStringCopy(char** ppDst, const char* pSrc)
2937 {
2938 if(pSrc)
2939 {
2940 FREE(*ppDst);
2941 *ppDst = (char*)malloc((strlen(pSrc)+1) * sizeof(char));
2942 strcpy(*ppDst, pSrc);
2943 }
2944 }
2945
2946 /*****************************************************************************
2947 End of file (PVRTPFXParser.cpp)
2948 *****************************************************************************/
2949
2950