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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 ****************************************************************************/ 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 ****************************************************************************/ 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 ****************************************************************************/ 378 SPVRTPFXParserShader::SPVRTPFXParserShader() 379 : 380 pszGLSLfile(NULL), 381 pszGLSLBinaryFile(NULL), 382 pszGLSLcode(NULL), 383 pbGLSLBinary(NULL) 384 { 385 } 386 387 SPVRTPFXParserShader::~SPVRTPFXParserShader() 388 { 389 FREE(pszGLSLfile); 390 FREE(pszGLSLcode); 391 FREE(pszGLSLBinaryFile); 392 FREE(pbGLSLBinary); 393 } 394 395 SPVRTPFXParserShader::SPVRTPFXParserShader(const SPVRTPFXParserShader& rhs) 396 { 397 Copy(rhs); 398 } 399 400 SPVRTPFXParserShader& SPVRTPFXParserShader::operator=(const SPVRTPFXParserShader& rhs) 401 { 402 if(&rhs != this) 403 Copy(rhs); 404 405 return *this; 406 } 407 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 ****************************************************************************/ 426 SPVRTSemanticDefaultData::SPVRTSemanticDefaultData() 427 : 428 eType(eDataTypeNone) 429 { 430 } 431 432 SPVRTSemanticDefaultData::SPVRTSemanticDefaultData(const SPVRTSemanticDefaultData& rhs) 433 { 434 Copy(rhs); 435 } 436 437 SPVRTSemanticDefaultData& SPVRTSemanticDefaultData::operator=(const SPVRTSemanticDefaultData& rhs) 438 { 439 if(&rhs != this) 440 Copy(rhs); 441 return *this; 442 } 443 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 ****************************************************************************/ 455 SPVRTPFXParserSemantic::SPVRTPFXParserSemantic() 456 : 457 pszName(NULL), 458 pszValue(NULL) 459 { 460 } 461 462 SPVRTPFXParserSemantic::~SPVRTPFXParserSemantic() 463 { 464 FREE(pszName); 465 FREE(pszValue); 466 } 467 468 SPVRTPFXParserSemantic::SPVRTPFXParserSemantic(const SPVRTPFXParserSemantic& rhs) 469 { 470 Copy(rhs); 471 } 472 473 SPVRTPFXParserSemantic& SPVRTPFXParserSemantic::operator=(const SPVRTPFXParserSemantic& rhs) 474 { 475 if(&rhs != this) 476 Copy(rhs); 477 478 return *this; 479 } 480 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 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 *****************************************************************************/ 2742 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 *****************************************************************************/ 2761 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 *****************************************************************************/ 2772 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 *****************************************************************************/ 2783 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 *****************************************************************************/ 2793 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 *****************************************************************************/ 2803 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 *****************************************************************************/ 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 *****************************************************************************/ 2826 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 *****************************************************************************/ 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 *****************************************************************************/ 2848 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 *****************************************************************************/ 2859 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 *****************************************************************************/ 2870 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 *****************************************************************************/ 2881 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 *****************************************************************************/ 2893 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 *****************************************************************************/ 2915 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 *****************************************************************************/ 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