From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- .../nel/vertex__program__parse_8cpp-source.html | 1166 ++++++++++++++++++++ 1 file changed, 1166 insertions(+) create mode 100644 docs/doxygen/nel/vertex__program__parse_8cpp-source.html (limited to 'docs/doxygen/nel/vertex__program__parse_8cpp-source.html') diff --git a/docs/doxygen/nel/vertex__program__parse_8cpp-source.html b/docs/doxygen/nel/vertex__program__parse_8cpp-source.html new file mode 100644 index 00000000..56f9bf70 --- /dev/null +++ b/docs/doxygen/nel/vertex__program__parse_8cpp-source.html @@ -0,0 +1,1166 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

vertex_program_parse.cpp

Go to the documentation of this file.
00001 
+00006 /* Copyright, 2000, 2001, 2002 Nevrax Ltd.
+00007  *
+00008  * This file is part of NEVRAX NEL.
+00009  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00010  * it under the terms of the GNU General Public License as published by
+00011  * the Free Software Foundation; either version 2, or (at your option)
+00012  * any later version.
+00013 
+00014  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00017  * General Public License for more details.
+00018 
+00019  * You should have received a copy of the GNU General Public License
+00020  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00021  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00022  * MA 02111-1307, USA.
+00023  */
+00024 
+00025 #include "std3d.h"
+00026 #include "vertex_program_parse.h"
+00027 
+00028 
+00029 
+00030 //=====================================
+00031 bool CVPParser::parseWriteMask(uint &mask, std::string &errorOutput)
+00032 {       
+00033         // parse output mask
+00034         if (*_CurrChar != '.')
+00035         {
+00036                 // no output masks
+00037                 mask = 0xf; //output 4 coordinates
+00038                 return true;
+00039         }
+00040         else
+00041         {
+00042                 ++ _CurrChar;
+00043                 mask = 0;
+00044                 for(uint k = 0; k < 4; ++k)
+00045                 {
+00046                         uint maskIndex;
+00047                         switch(*_CurrChar)
+00048                         {
+00049                                 case 'x': maskIndex = 0; break;
+00050                                 case 'y': maskIndex = 1; break;
+00051                                 case 'z': maskIndex = 2; break;
+00052                                 case 'w': maskIndex = 3; break;
+00053                                 default:
+00054                                         if (k >= 1) return true;
+00055                                         else
+00056                                         {                                       
+00057                                                 errorOutput = "Can't parse output mask.";
+00058                                                 return false;
+00059                                         }
+00060                                 break;
+00061                         }
+00062                         ++_CurrChar;
+00063                         if (mask & (1 << maskIndex))
+00064                         {
+00065                                 errorOutput = "Duplicated output mask component.";
+00066                                 return false;
+00067                         }
+00068                         mask |= 1 << maskIndex;
+00069                 }
+00070                 return true;
+00071         }
+00072 }
+00073 
+00074 //=====================================
+00077 void CVPParser::skipSpacesAndComments()
+00078 {
+00079         bool stop = false;
+00080         do
+00081         {       
+00082                 switch(*_CurrChar)
+00083                 {
+00084                         case '\t':
+00085                         case '\r':
+00086                         case ' ' : 
+00087                                 ++_CurrChar; 
+00088                         break;
+00089                         //
+00090                         case '\n': 
+00091                                 ++_CurrChar; 
+00092                                 ++_LineIndex; 
+00093                                 _LineStart = _CurrChar;
+00094                         break;
+00095                         case '#': // comment go till end of line
+00096                                 while (*_CurrChar != '\n' && *_CurrChar != '\0') ++_CurrChar;
+00097                                 skipSpacesAndComments();
+00098                         break;
+00099                         default:
+00100                                 stop = true;
+00101                         break;                  
+00102                 }
+00103         }
+00104         while (!stop);
+00105 }
+00106 
+00107 //=================================================================================================
+00108 uint CVPInstruction::getNumUsedSrc() const
+00109 {
+00110         switch(Opcode)
+00111         {
+00112                 case CVPInstruction::ARL:               
+00113                 case CVPInstruction::RSQ:                       
+00114                 case CVPInstruction::EXPP:                      
+00115                 case CVPInstruction::LOG:                       
+00116                 case CVPInstruction::RCP:                       
+00117                 case CVPInstruction::MOV:                       
+00118                 case CVPInstruction::LIT:
+00119                         return 1;
+00120                 //
+00121                 case CVPInstruction::MAD:
+00122                         return 3;
+00123                 //
+00124                 case CVPInstruction::MUL:
+00125                 case CVPInstruction::ADD:
+00126                 case CVPInstruction::DP3:
+00127                 case CVPInstruction::DP4:                       
+00128                 case CVPInstruction::DST:       
+00129                 case CVPInstruction::MIN:
+00130                 case CVPInstruction::MAX:       
+00131                 case CVPInstruction::SLT:       
+00132                 case CVPInstruction::SGE:
+00133                         return 2;
+00134                 //
+00135                 default:
+00136                         nlstop;         
+00137         }
+00138         return 0;
+00139 }
+00140 
+00141 //=================================================================================================
+00142 bool CVPParser::parseOperand(CVPOperand &operand, bool outputOperand, std::string &errorOutput)
+00143 {
+00144         skipSpacesAndComments();
+00145         bool result;
+00146         if (outputOperand)
+00147         {
+00148                 operand.Negate = false;
+00149                 switch(*_CurrChar)
+00150                 {                       
+00151                         case 'o': result = parseOutputRegister(operand, errorOutput); break;
+00152                         case 'R': 
+00153                                 result = parseVariableRegister(operand, errorOutput);                                                   
+00154                         break;
+00155                         case 'A': result = parseAddressRegister(operand, errorOutput); break;
+00156                         case '-':
+00157                                 errorOutput = "Negation not allowed on ouput register.";
+00158                                 return false;
+00159                         default:
+00160                                 errorOutput = "Output, Address, or Temporary register expected as an output operand.";
+00161                                 return false;                   
+00162                 }
+00163                 if (!result) return false;
+00164 
+00165                 // parse the write mask
+00166                 return parseWriteMask(operand.WriteMask, errorOutput);                          
+00167         }
+00168         else
+00169         {
+00170                 operand.Negate = false;
+00171                 switch(*_CurrChar)
+00172                 {
+00173                         case 'v': result = parseInputRegister(operand, errorOutput); break;
+00174                         case 'R': result = parseVariableRegister(operand, errorOutput); break;
+00175                         case 'c': result = parseConstantRegister(operand, errorOutput); break;
+00176                         case 'a': result = parseAddressRegister(operand, errorOutput); break;
+00177                         case '-':
+00178                         {
+00179                                 operand.Negate = true;
+00180                                 // negation
+00181                                 ++ _CurrChar;
+00182                                 skipSpacesAndComments();
+00183                                 switch(*_CurrChar)
+00184                                 {
+00185                                         case 'v': result = parseInputRegister(operand, errorOutput); break;
+00186                                         case 'R': result = parseVariableRegister(operand, errorOutput); break;
+00187                                         case 'c': result = parseConstantRegister(operand, errorOutput); break;
+00188                                         default:
+00189                                                 errorOutput = "Negation must be followed by an input register, a variable register, or a constant.";
+00190                                                 return false;
+00191                                         break;
+00192                                 }
+00193                         }
+00194                         break;
+00195                         default:
+00196                                 errorOutput = "Syntax error.";
+00197                                 return false;
+00198                         break;
+00199                 }
+00200                 if (!result) return false;              
+00201                 if (operand.Type != CVPOperand::AddressRegister)
+00202                 {
+00203                         if (!parseSwizzle(operand.Swizzle, errorOutput)) return false;          
+00204                         if (operand.Type == CVPOperand::Variable)
+00205                         {
+00206                                 for(uint k = 0; k < 4; ++k)
+00207                                 {
+00208                                         if (!(_RegisterMask[operand.Value.VariableValue] & (1 << operand.Swizzle.Comp[k])))
+00209                                         {
+00210                                                 errorOutput = "Can't read a register component before writing to it.";
+00211                                                 return false;
+00212                                         }
+00213                                 }
+00214                         }
+00215                 }
+00216                 return true;
+00217         }
+00218 
+00219         
+00220 }
+00221 
+00222 
+00223 //=================================================================================================
+00224 bool CVPParser::parseInputRegister(CVPOperand &operand, std::string &errorOutput)
+00225 {
+00226         ++_CurrChar;
+00227         operand.Type = CVPOperand::InputRegister;       
+00228         if (*_CurrChar != '[')
+00229         {
+00230                 errorOutput = "'[' expected when parsing an input register.";
+00231                 return false;
+00232         }
+00233         ++_CurrChar;
+00234         skipSpacesAndComments();
+00235         if (isdigit(*_CurrChar))
+00236         {
+00237                 // The input register is expressed as an index
+00238                 uint index = *_CurrChar - '0';
+00239                 ++_CurrChar;
+00240                 if (isdigit(*_CurrChar))
+00241                 {
+00242                         index =  10 * index + (*_CurrChar - '0');
+00243                         ++_CurrChar;
+00244                 }
+00245                 if (index > 15)
+00246                 {               
+00247                         errorOutput = "Invalid index for input register, must be in [0, 15].";
+00248                         return false;
+00249                 }
+00250                 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) index;
+00251         }
+00252         else
+00253         {
+00254                 // The input register is expressed as a string
+00255                 uint32 strValue = 0;
+00256                 // read the 4 letters
+00257                 for(uint k = 0; k < 4; ++k)
+00258                 {
+00259                         if (!isalnum(*_CurrChar))
+00260                         {
+00261                                 errorOutput = "Can't parse index for input register.";
+00262                                 return false;
+00263                         }
+00264                         strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
+00265                         ++_CurrChar;
+00266                 }
+00267                 switch (strValue)
+00268                 {
+00269                         case 'OPOS': operand.Value.InputRegisterValue = CVPOperand::IPosition; break;
+00270                         case 'WGHT': operand.Value.InputRegisterValue = CVPOperand::IWeight; break;
+00271                         case 'NRML': operand.Value.InputRegisterValue = CVPOperand::INormal; break;
+00272                         case 'COL0': operand.Value.InputRegisterValue = CVPOperand::IPrimaryColor; break;
+00273                         case 'COL1': operand.Value.InputRegisterValue = CVPOperand::ISecondaryColor; break;                     
+00274                         case 'FOGC': operand.Value.InputRegisterValue = CVPOperand::IFogCoord; break;
+00275                         // texture argument
+00276                         case 'TEX0':
+00277                         case 'TEX1':
+00278                         case 'TEX2':
+00279                         case 'TEX3':
+00280                         case 'TEX4':
+00281                         case 'TEX5':
+00282                         case 'TEX6':
+00283                         case 'TEX7':
+00284                                 operand.Value.InputRegisterValue = (CVPOperand::EInputRegister) (CVPOperand::ITex0 + strValue & 0xff - '0'); 
+00285                         break;
+00286                         default:
+00287                                 errorOutput = "Can't parse index for input register.";
+00288                                 return false;
+00289                 }               
+00290         }
+00291         skipSpacesAndComments();
+00292         if (*_CurrChar != ']')
+00293         {
+00294                 errorOutput = "']' expected when parsing an input register.";
+00295                 return false;
+00296         }
+00297         ++ _CurrChar;
+00298         return true;
+00299 }
+00300 
+00301 //=================================================================================================
+00302 static inline bool letterToSwizzleComp(char letter, CVPSwizzle::EComp &comp)
+00303 {
+00304         switch (letter)
+00305         {
+00306                 case 'x': comp = CVPSwizzle::X; return true;
+00307                 case 'y': comp = CVPSwizzle::Y; return true;
+00308                 case 'z': comp = CVPSwizzle::Z; return true;
+00309                 case 'w': comp = CVPSwizzle::W; return true;
+00310         }
+00311         return false;
+00312 }
+00313 
+00314 //=================================================================================================
+00315 bool CVPParser::parseSwizzle(CVPSwizzle &swizzle,std::string &errorOutput)
+00316 {
+00317         if (*_CurrChar != '.')
+00318         {
+00319                 // no swizzle
+00320                 swizzle.Comp[0] = CVPSwizzle::X;        
+00321                 swizzle.Comp[1] = CVPSwizzle::Y;
+00322                 swizzle.Comp[2] = CVPSwizzle::Z;
+00323                 swizzle.Comp[3] = CVPSwizzle::W;
+00324                 return true;
+00325         }       
+00326         ++_CurrChar;
+00327         // 4 letters case
+00328         for(uint k = 0; k < 4; ++k)
+00329         {
+00330                 if (!isalpha(*_CurrChar))
+00331                 {
+00332                         if (k == 1) // 1 letter case
+00333                         {
+00334                                 switch(*_CurrChar)
+00335                                 {
+00336                                         case ',':
+00337                                         case ';':
+00338                                         case ' ':
+00339                                         case '\t':
+00340                                         case '\r':
+00341                                         case '\n':
+00342                                         case '#':
+00343                                                 swizzle.Comp[1] = swizzle.Comp[2] = swizzle.Comp[3] = swizzle.Comp[0];
+00344                                                 return true;
+00345                                         break;
+00346                                         default:
+00347                                                 errorOutput = "Can't parse swizzle.";
+00348 
+00349                                 }
+00350                         }
+00351                         else
+00352                         {
+00353                                 errorOutput = "Invalid swizzle value.";
+00354                                 return false;
+00355                         }                       
+00356                 }
+00357                 
+00358                 if (!letterToSwizzleComp(*_CurrChar, swizzle.Comp[k]))
+00359                 {       
+00360                         errorOutput = "Invalid swizzle value.";
+00361                         return false;
+00362                 }
+00363                 ++ _CurrChar;
+00364         }
+00365         
+00366         return true;
+00367 }
+00368 
+00369 //=================================================================================================
+00370 bool CVPParser::parseOutputRegister(CVPOperand &operand, std::string &errorOutput)
+00371 {       
+00372         ++_CurrChar;
+00373         operand.Type = CVPOperand::OutputRegister;      
+00374         if (*_CurrChar != '[')
+00375         {
+00376                 errorOutput = "'[' expected when parsing an ouput register.";
+00377                 return false;
+00378         }
+00379         ++_CurrChar;
+00380         skipSpacesAndComments();
+00381         // The input register is expressed as a string
+00382         uint32 strValue = 0;
+00383         // read the 4 letters
+00384         for(uint k = 0; k < 4; ++k)
+00385         {
+00386                 if (!isalnum(*_CurrChar))
+00387                 {
+00388                         errorOutput = "Can't parse index for output register.";
+00389                         return false;
+00390                 }
+00391                 strValue |= ((uint32) *_CurrChar) << (8 * (3 - k));
+00392                 ++_CurrChar;
+00393         }
+00394         // convert to enum
+00395         switch(strValue)
+00396         {
+00397                 case 'HPOS': operand.Value.OutputRegisterValue = CVPOperand::OHPosition; break;
+00398                 case 'COL0': operand.Value.OutputRegisterValue = CVPOperand::OPrimaryColor; break;
+00399                 case 'COL1': operand.Value.OutputRegisterValue = CVPOperand::OSecondaryColor; break;
+00400                 case 'BFC0': operand.Value.OutputRegisterValue = CVPOperand::OBackFacePrimaryColor; break;
+00401                 case 'BFC1': operand.Value.OutputRegisterValue = CVPOperand::OBackFaceSecondaryColor; break;
+00402                 case 'FOGC': operand.Value.OutputRegisterValue = CVPOperand::OFogCoord; break;
+00403                 case 'PSIZ': operand.Value.OutputRegisterValue = CVPOperand::OPointSize; break;
+00404                 case 'TEX0': operand.Value.OutputRegisterValue = CVPOperand::OTex0; break;
+00405                 case 'TEX1': operand.Value.OutputRegisterValue = CVPOperand::OTex1; break;
+00406                 case 'TEX2': operand.Value.OutputRegisterValue = CVPOperand::OTex2; break;
+00407                 case 'TEX3': operand.Value.OutputRegisterValue = CVPOperand::OTex3; break;
+00408                 case 'TEX4': operand.Value.OutputRegisterValue = CVPOperand::OTex4; break;
+00409                 case 'TEX5': operand.Value.OutputRegisterValue = CVPOperand::OTex5; break;
+00410                 case 'TEX6': operand.Value.OutputRegisterValue = CVPOperand::OTex6; break;
+00411                 case 'TEX7': operand.Value.OutputRegisterValue = CVPOperand::OTex7; break;
+00412                 default:
+00413                         errorOutput = "Can't read index for output register.";
+00414                         return false;
+00415                 break;
+00416         }
+00417         skipSpacesAndComments();
+00418         if (*_CurrChar != ']')
+00419         {
+00420                 errorOutput = "']' expected when parsing an output register.";
+00421                 return false;
+00422         }
+00423         ++_CurrChar;
+00424         return true;
+00425 }
+00426 
+00427 //=================================================================================================
+00428 static inline const char *parseUInt(const char *src, uint &dest)
+00429 {
+00430         uint index = 0;
+00431         while (isdigit(*src))
+00432         {
+00433                 index = 10 * index + *src - '0';
+00434                 ++ src;
+00435         }
+00436         dest = index;
+00437         return src;
+00438 }
+00439 
+00440 
+00441 //=================================================================================================
+00442 bool CVPParser::parseConstantRegister(CVPOperand &operand, std::string &errorOutput)
+00443 {
+00444         ++_CurrChar;
+00445         operand.Type = CVPOperand::Constant;    
+00446         if (*_CurrChar != '[')
+00447         {
+00448                 errorOutput = "'[' expected when parsing a constant register.";
+00449                 return false;
+00450         }
+00451         ++_CurrChar;
+00452         skipSpacesAndComments();
+00453         uint &index = operand.Value.ConstantValue;
+00454         if (isdigit(*_CurrChar))
+00455         {               
+00456                 // immediat case : c[0] to c[95]
+00457                 _CurrChar = parseUInt(_CurrChar, index);
+00458                 if (index > 95)
+00459                 {
+00460                         errorOutput = "Constant register index must range from 0 to 95.";
+00461                         return false;
+00462                 }
+00463                 operand.Indexed = false;
+00464         }
+00465         else if (*_CurrChar == 'A')
+00466         {
+00467                 // indexed case : c[A0.x + 0] to c[A0.x + 95]
+00468                 operand.Indexed = true;
+00469                 index = 0;
+00470                 if (_CurrChar[1] == '0'
+00471                         && _CurrChar[2] == '.'
+00472                         && _CurrChar[3] == 'x')
+00473                 {
+00474                         _CurrChar += 4;
+00475                         skipSpacesAndComments();
+00476                         if (*_CurrChar == '+')
+00477                         {
+00478                                 ++ _CurrChar;
+00479                                 skipSpacesAndComments();
+00480                                 if (isdigit(*_CurrChar))
+00481                                 {
+00482                                         _CurrChar = parseUInt(_CurrChar, index);
+00483                                         if (index > 95)
+00484                                         {
+00485                                                 errorOutput = "Constant register index must range from 0 to 95.";
+00486                                                 return false;
+00487                                         }
+00488                                 }
+00489                                 else
+00490                                 {
+00491                                         errorOutput = "Can't parse offset for constant register.";
+00492                                         return false;
+00493                                 }
+00494                         }
+00495                 }
+00496                 else
+00497                 {
+00498                         errorOutput = "Can't parse constant register index.";
+00499                         return false;
+00500                 }
+00501         }
+00502         skipSpacesAndComments();
+00503         if (*_CurrChar != ']')
+00504         {
+00505                 errorOutput = "']' expected when parsing an input register.";
+00506                 return false;
+00507         }
+00508         ++_CurrChar;
+00509         return true;
+00510 }
+00511 
+00512 //=================================================================================================
+00513 bool CVPParser::parseVariableRegister(CVPOperand &operand, std::string &errorOutput)
+00514 {
+00515         ++_CurrChar;
+00516         operand.Type = CVPOperand::Variable;    
+00517         if (!isdigit(*_CurrChar))
+00518         {
+00519                 errorOutput = "Can't parse variable register.";
+00520                 return false;
+00521         }
+00522         uint &index = operand.Value.VariableValue;
+00523         _CurrChar = parseUInt(_CurrChar, index);
+00524         if (index > 11)
+00525         {
+00526                 errorOutput = "Variable register index must range from 0 to 11.";
+00527                 return false;
+00528         }
+00529         return true;
+00530 }
+00531 
+00532 //=================================================================================================
+00533 bool CVPParser::parseAddressRegister(CVPOperand &operand, std::string &errorOutput)
+00534 {
+00535         ++_CurrChar;
+00536         operand.Type = CVPOperand::AddressRegister;
+00537         if (_CurrChar[0] != '0' || _CurrChar[1] != '.' || _CurrChar[2] != 'x')
+00538         {
+00539                 errorOutput = "Can't parse address register.";
+00540                 return false;
+00541         }
+00542         _CurrChar += 3;
+00543         return true;    
+00544 }
+00545 
+00546 //=================================================================================================
+00547 bool CVPParser::parseOp2(CVPInstruction &instr,std::string &errorOutput)
+00548 {
+00549         skipSpacesAndComments();
+00550         // parse ouput
+00551         if (!parseOperand(instr.Dest, true, errorOutput)) return false;
+00552         // Can't write in input or consant register
+00553         if (instr.Dest.Type == CVPOperand::Constant || instr.Dest.Type == CVPOperand::InputRegister)
+00554         {
+00555                 errorOutput = "Can't write to a constant or input register";
+00556                 return false;
+00557         }
+00558         //
+00559         skipSpacesAndComments();
+00560         if (*_CurrChar != ',')
+00561         {
+00562                 errorOutput = "',' expected.";
+00563                 return false;
+00564         }
+00565         ++_CurrChar;
+00566         skipSpacesAndComments();
+00567         // parse src1
+00568         if (!parseOperand(instr.Src1, false, errorOutput)) return false;
+00569         if (instr.Src1.Type == CVPOperand::AddressRegister 
+00570                 || instr.Src1.Type == CVPOperand::OutputRegister)
+00571         {
+00572                 errorOutput = "Src1 must be constant, variable, or input register.";
+00573                 return false;
+00574         }
+00575         return true;
+00576 }
+00577 
+00578 //=================================================================================================
+00579 bool CVPParser::parseOp3(CVPInstruction &instr, std::string &errorOutput)
+00580 {       
+00581         if (!parseOp2(instr, errorOutput)) return false;
+00582         skipSpacesAndComments();
+00583         if (*_CurrChar != ',')
+00584         {
+00585                 errorOutput = "',' expected.";
+00586                 return false;
+00587         }
+00588         ++_CurrChar;
+00589         skipSpacesAndComments();
+00590         // parse src2
+00591         if (!parseOperand(instr.Src2, false, errorOutput)) return false;
+00592         if (instr.Src2.Type == CVPOperand::AddressRegister 
+00593                 || instr.Src2.Type == CVPOperand::OutputRegister)
+00594         {
+00595                 errorOutput = "Src2 must be constant, variable, or input register.";
+00596                 return false;
+00597         }
+00598         // make sure we do not have 2 =/= contant register as src (or in put register)
+00599 
+00600         // 2 constant registers ?
+00601         if (instr.Src1.Type == CVPOperand::Constant
+00602                 && instr.Src2.Type == CVPOperand::Constant)
+00603         {
+00604                 // the index must be the same
+00605                 if (!
+00606                         (
+00607                                 instr.Src1.Indexed == instr.Src2.Indexed
+00608                          && instr.Src1.Value.ConstantValue == instr.Src2.Value.ConstantValue
+00609                         )
+00610                    )
+00611                 {
+00612                         errorOutput = "Can't read 2 different constant registers in a single instruction.";
+00613                         return false;
+00614                 }                       
+00615         }
+00616 
+00617         // 2 input registers ?
+00618         if (instr.Src1.Type == CVPOperand::InputRegister
+00619                 && instr.Src2.Type == CVPOperand::InputRegister)
+00620         {
+00621                 // the index must be the same
+00622                 if (instr.Src1.Value.InputRegisterValue != instr.Src2.Value.InputRegisterValue)
+00623                 {
+00624                         errorOutput = "Can't read 2 different input registers in a single instruction.";
+00625                         return false;
+00626                 }                       
+00627         }
+00628         return true;
+00629 }
+00630 
+00631 //=================================================================================================
+00632 bool CVPParser::parseOp4(CVPInstruction &instr, std::string &errorOutput)
+00633 {
+00634         if (!parseOp3(instr, errorOutput)) return false;
+00635         // parse src 3
+00636         skipSpacesAndComments();
+00637         if (*_CurrChar != ',')
+00638         {
+00639                 errorOutput = "',' expected.";
+00640                 return false;
+00641         }
+00642         ++_CurrChar;
+00643         skipSpacesAndComments();
+00644         // parse src4
+00645         if (!parseOperand(instr.Src3, false, errorOutput)) return false;
+00646         if (instr.Src3.Type == CVPOperand::AddressRegister 
+00647                 || instr.Src3.Type == CVPOperand::OutputRegister)
+00648         {
+00649                 errorOutput = "Src3 must be constant, variable, or input register.";
+00650                 return false;
+00651         }
+00652         
+00654         // check for different contant / input registers //
+00656 
+00657         // Duplicated constant register
+00658         if (instr.Src3.Type == CVPOperand::Constant)
+00659         {
+00660                 if (instr.Src1.Type == CVPOperand::Constant)
+00661                 {
+00662                         if (!
+00663                             (
+00664                                     instr.Src1.Indexed == instr.Src3.Indexed
+00665                              && instr.Src1.Value.ConstantValue == instr.Src3.Value.ConstantValue
+00666                             )
+00667                        )
+00668                         {
+00669                                 errorOutput = "Can't read 2 different constant registers in a single instruction.";
+00670                                 return false;
+00671                         }
+00672                 }
+00673                 if (instr.Src2.Type == CVPOperand::Constant)
+00674                 {
+00675                         if (!
+00676                             (
+00677                                     instr.Src2.Indexed == instr.Src3.Indexed
+00678                              && instr.Src2.Value.ConstantValue == instr.Src3.Value.ConstantValue
+00679                             )
+00680                        )
+00681                         {
+00682                                 errorOutput = "Can't read 2 different constant registers in a single instruction.";
+00683                                 return false;
+00684                         }
+00685                 }
+00686         }
+00687 
+00688         // Duplicated input register
+00689         if (instr.Src3.Type == CVPOperand::InputRegister)
+00690         {
+00691                 if (instr.Src1.Type == CVPOperand::InputRegister)
+00692                 {                       
+00693                         if (instr.Src1.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
+00694                         {
+00695                                 errorOutput = "Can't read 2 different input registers in a single instruction.";
+00696                                 return false;
+00697                         }
+00698                 }
+00699                 if (instr.Src2.Type == CVPOperand::InputRegister)
+00700                 {
+00701                         if (instr.Src2.Value.InputRegisterValue != instr.Src3.Value.InputRegisterValue)
+00702                         {
+00703                                 errorOutput = "Can't read 2 different input registers in a single instruction.";
+00704                                 return false;
+00705                         }
+00706                 }
+00707         }
+00708 
+00709 
+00710         return true;
+00711 }
+00712 
+00713 //=================================================================================================
+00714 bool CVPParser::parseInstruction(CVPInstruction &instr, std::string &errorOutput, bool &endEncountered)
+00715 {
+00716         skipSpacesAndComments();
+00717         endEncountered = false;
+00718         uint32 instrStr = 0;
+00719         uint k;
+00720         for(k = 0; k < 4; ++k)
+00721         {
+00722                 if (!isalnum(*_CurrChar))
+00723                 {
+00724                         if (k < 3) // at least 3 letter in an instruction
+00725                         {
+00726                                 errorOutput = "Syntax error : can't read opcode.";
+00727                                 return false;
+00728                         }
+00729                         else break;                     
+00730                 }
+00731                 instrStr |= ((uint) *_CurrChar) << (8 * (3 - k));
+00732                 ++ _CurrChar;
+00733         }
+00734         if (k != 4)
+00735         {
+00736                 instrStr |= (uint32) ' ';
+00737         }
+00738         switch (instrStr)
+00739         {
+00740                 case 'ARL ':
+00741                         instr.Opcode = CVPInstruction::ARL;
+00742                         if (!parseOp2(instr, errorOutput)) return false;
+00743                         if (!instr.Src1.Swizzle.isScalar())
+00744                         {
+00745                                 errorOutput = "ARL need a scalar src value.";
+00746                                 return false;
+00747                         }
+00748                 break;          
+00749                 case 'RSQ ':
+00750                         instr.Opcode = CVPInstruction::RSQ;
+00751                         if (!parseOp2(instr, errorOutput)) return false;
+00752                         if (!instr.Src1.Swizzle.isScalar())
+00753                         {
+00754                                 errorOutput = "RSQ need a scalar src value.";
+00755                                 return false;
+00756                         }
+00757                 break;
+00758                 case 'EXP ':
+00759                 case 'EXPP':
+00760                         instr.Opcode = CVPInstruction::EXPP;
+00761                         if (!parseOp2(instr, errorOutput)) return false;
+00762                         if (!instr.Src1.Swizzle.isScalar())
+00763                         {
+00764                                 errorOutput = "EXP need a scalar src value.";
+00765                                 return false;
+00766                         }
+00767                         /*
+00768                         if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
+00769                         {
+00770                                 errorOutput = "EXPP input scalar must be w";
+00771                                 return false;
+00772                         }*/
+00773                 break;
+00774                 case 'LOG ':
+00775                         instr.Opcode = CVPInstruction::LOG;
+00776                         if (!parseOp2(instr, errorOutput)) return false;
+00777                         if (!instr.Src1.Swizzle.isScalar())
+00778                         {
+00779                                 errorOutput = "LOG need a scalar src value.";
+00780                                 return false;
+00781                         }
+00782                         /*
+00783                         if (instr.Src1.Swizzle.Comp[0] != CVPSwizzle.W)
+00784                         {
+00785                                 errorOutput = "LOG input scalar must be w";
+00786                                 return false;
+00787                         }
+00788                         */
+00789                 break;
+00790                 case 'RCP ':
+00791                         instr.Opcode = CVPInstruction::RCP;
+00792                         if (!parseOp2(instr, errorOutput)) return false;
+00793                         if (!instr.Src1.Swizzle.isScalar())
+00794                         {
+00795                                 errorOutput = "RCP need a scalar src value.";
+00796                                 return false;
+00797                         }
+00798                 break;
+00800                 case 'MOV ':
+00801                         instr.Opcode = CVPInstruction::MOV;
+00802                         if (!parseOp2(instr, errorOutput)) return false;
+00803                         
+00804                 break;
+00805                 case 'LIT ':
+00806                         instr.Opcode = CVPInstruction::LIT;
+00807                         if (!parseOp2(instr, errorOutput)) return false;
+00808                 break;          
+00810                 case 'MAD ':
+00811                         instr.Opcode = CVPInstruction::MAD;
+00812                         if (!parseOp4(instr, errorOutput)) return false;
+00813                 break;
+00815                 case 'ADD ':
+00816                         instr.Opcode = CVPInstruction::ADD;
+00817                         if (!parseOp3(instr, errorOutput)) return false;
+00818                 break;
+00820                 case 'MUL ':
+00821                         instr.Opcode = CVPInstruction::MUL;
+00822                         if (!parseOp3(instr, errorOutput)) return false;
+00823                 break;                          
+00824                 case 'DP3 ':
+00825                         instr.Opcode = CVPInstruction::DP3;
+00826                         if (!parseOp3(instr, errorOutput)) return false;
+00827                 break;
+00828                 case 'DP4 ':
+00829                         instr.Opcode = CVPInstruction::DP4;
+00830                         if (!parseOp3(instr, errorOutput)) return false;
+00831                 break;
+00832                 case 'DST ':
+00833                         instr.Opcode = CVPInstruction::DST;
+00834                         if (!parseOp3(instr, errorOutput)) return false;
+00835                 break;          
+00836                 case 'MIN ':
+00837                         instr.Opcode = CVPInstruction::MIN;
+00838                         if (!parseOp3(instr, errorOutput)) return false;
+00839                 break;
+00840                 case 'MAX ':
+00841                         instr.Opcode = CVPInstruction::MAX;
+00842                         if (!parseOp3(instr, errorOutput)) return false;
+00843                 break;
+00844                 case 'SLT ':
+00845                         instr.Opcode = CVPInstruction::SLT;
+00846                         if (!parseOp3(instr, errorOutput)) return false;
+00847                 break;
+00848                 case 'SGE ':
+00849                         instr.Opcode = CVPInstruction::SGE;
+00850                         if (!parseOp3(instr, errorOutput)) return false;
+00851                 break;
+00853                 case 'END ':
+00854                         endEncountered = true;
+00855                         return true;
+00856                 break;
+00857                 default:
+00858                         errorOutput = "Syntax error : unknow opcode.";
+00859                         return false;
+00860                 break;
+00861         }
+00862 
+00863 
+00864         if (instr.Dest.Type == CVPOperand::Variable)
+00865         {
+00866                 _RegisterMask[instr.Dest.Value.VariableValue] |= instr.Dest.WriteMask;
+00867         }
+00868 
+00869         // it is not allowed to write to an adress register except for ARL
+00870         if (instrStr != 'ARL ')
+00871         {
+00872                 if (instr.Dest.Type == CVPOperand::AddressRegister)
+00873                 {
+00874                         errorOutput = "Can't write to address register.";
+00875                         return false;
+00876                 }
+00877         }
+00878 
+00879         // parse semi-colon
+00880         skipSpacesAndComments();
+00881         //
+00882         if (*_CurrChar != ';')
+00883         {
+00884                 errorOutput = "';' expected.";
+00885                 return false;
+00886         }
+00887         ++_CurrChar;
+00888         return true;
+00889 }
+00890 
+00891 
+00892 //=================================================================================================
+00893 static std::string getStringUntilCR(const char *src)
+00894 {
+00895         nlassert(src);
+00896         std::string result;
+00897         while (*src != '\n' && *src != '\r' && *src != '\0') 
+00898         {
+00899                 result += *src;
+00900                 ++src;
+00901         }
+00902         return result;
+00903 }
+00904 
+00905 //=================================================================================================
+00906 bool CVPParser::parse(const char *src, CVPParser::TProgram &result, std::string &errorOutput)
+00907 {
+00908         if (!src) return false; 
+00909         //
+00910         std::fill(_RegisterMask, _RegisterMask + 96, 0);
+00911 
+00912         //
+00913         _CurrChar = src;
+00914         _LineStart = src;
+00915         _LineIndex = 1;
+00916         //
+00917         skipSpacesAndComments();
+00918 
+00919         // parse version
+00920         if (   _CurrChar[0] != '!' 
+00921                 || _CurrChar[1] != '!'
+00922                 || _CurrChar[2] != 'V'
+00923                 || _CurrChar[3] != 'P'
+00924                 || _CurrChar[4] != '1'
+00925                 || _CurrChar[5] != '.'
+00926                 || (_CurrChar[6] != '0' && _CurrChar[6] != '1'))
+00927         {
+00928                 errorOutput = "Can't parse version.";
+00929                 return false;
+00930         }
+00931         _CurrChar += 7;
+00932 
+00933         errorOutput.clear();
+00934         // parse instructions
+00935         bool endEncoutered = false;
+00936         
+00937         std::string errorMess;
+00938         for(;;)
+00939         {
+00940                 CVPInstruction instr;           
+00941                 if (!parseInstruction(instr, errorMess, endEncoutered))
+00942                 {
+00943                         errorOutput = std::string("CVPParser::parse : Error encountered at line ") + NLMISC::toString(_LineIndex) + std::string(" : ") + errorMess + std::string(" Text : ") + getStringUntilCR(_LineStart);
+00944                         return false;
+00945                 }
+00946                 if (endEncoutered) break;               
+00947                 result.push_back(instr);
+00948         }       
+00949         return true;    
+00950 }
+00951 
+00952 
+00953 //=================================================================================================
+00954 static const char *instrToName[] =
+00955 {
+00956         "MOV  ",
+00957         "ARL  ",
+00958         "MUL  ",
+00959         "ADD  ",
+00960         "MAD  ",
+00961         "RSQ  ",
+00962         "DP3  ",
+00963         "DP4  ",
+00964         "DST  ",
+00965         "LIT  ",
+00966         "MIN  ",
+00967         "MAX  ",
+00968         "SLT  ",
+00969         "SGE  ",
+00970         "EXPP ",
+00971         "LOG  ",
+00972         "RCP  "
+00973 };
+00974 
+00975 //=================================================================================================
+00976 static const char *outputRegisterToName[] =
+00977 {
+00978         "HPOS",
+00979         "COL0",
+00980         "COL1",
+00981         "BFC0",
+00982         "BFC1",
+00983         "FOGC",
+00984         "PSIZ",
+00985         "TEX0",
+00986         "TEX1",
+00987         "TEX2",
+00988         "TEX3",
+00989         "TEX4",
+00990         "TEX5",
+00991         "TEX6",
+00992         "TEX7"
+00993 };
+00994 
+00995 
+00996 //=================================================================================================
+00997 static void dumpWriteMask(uint mask, std::string &out)
+00998 {
+00999         if (mask == 0xf)
+01000         {
+01001                 out = "";
+01002                 return;
+01003         }
+01004         out = ".";
+01005         if (mask & 1) out +="x";
+01006         if (mask & 2) out +="y";
+01007         if (mask & 4) out +="z";
+01008         if (mask & 8) out +="w";
+01009 }
+01010 
+01011 //=================================================================================================
+01012 static void dumpSwizzle(const CVPSwizzle &swz, std::string &out)
+01013 {
+01014         if (swz.isIdentity())
+01015         {
+01016                 out = "";
+01017                 return;
+01018         }
+01019         out = ".";
+01020         for(uint k = 0; k < 4; ++k)
+01021         {
+01022                 switch(swz.Comp[k])
+01023                 {
+01024                         case CVPSwizzle::X: out += "x"; break;
+01025                         case CVPSwizzle::Y: out += "y"; break;
+01026                         case CVPSwizzle::Z: out += "z"; break;
+01027                         case CVPSwizzle::W: out += "w"; break;
+01028                         default:
+01029                                 nlassert(0);
+01030                         break;
+01031                 }
+01032                 if (swz.isScalar() && k == 0) break;
+01033         }
+01034 
+01035 }
+01036 
+01037 //=================================================================================================
+01038 static void dumpOperand(const CVPOperand &op, bool destOperand, std::string &out)
+01039 {
+01040         out = op.Negate ? " -" : " ";
+01041         switch(op.Type)
+01042         {
+01043                 case CVPOperand::Variable: out += "R" + NLMISC::toString(op.Value.VariableValue); break;
+01044                 case CVPOperand::Constant: 
+01045                         out += "c[";
+01046                         if (op.Indexed)
+01047                         {
+01048                                 out += "A0.x + ";
+01049                         }
+01050                         out += NLMISC::toString(op.Value.ConstantValue) + "]"; 
+01051                 break;
+01052                 case CVPOperand::InputRegister: out += "v[" + NLMISC::toString((uint) op.Value.InputRegisterValue) + "]"; break;
+01053                 case CVPOperand::OutputRegister:
+01054                         nlassert(op.Value.OutputRegisterValue < CVPOperand::OutputRegisterCount);
+01055                         out += "o[" + std::string(outputRegisterToName[op.Value.OutputRegisterValue]) + "]";
+01056                 break;
+01057                 case CVPOperand::AddressRegister:
+01058                         out += "A0.x";
+01059                 break;
+01060         }
+01061         std::string suffix;
+01062         if (destOperand)
+01063         {
+01064                 dumpWriteMask(op.WriteMask, suffix);
+01065         }
+01066         else
+01067         {
+01068                 dumpSwizzle(op.Swizzle, suffix);
+01069         }
+01070         out += suffix;
+01071 }
+01072 
+01073 //=================================================================================================
+01076 static void dumpInstr(const CVPInstruction &instr, std::string &out)
+01077 {
+01078         nlassert(instr.Opcode < CVPInstruction::OpcodeCount)
+01079         out = instrToName[instr.Opcode];
+01080         uint nbOp = instr.getNumUsedSrc();
+01081         std::string destOperand;
+01082         dumpOperand(instr.Dest, true, destOperand);
+01083         out += destOperand;
+01084         for(uint k = 0; k < nbOp; ++k)
+01085         {
+01086                 out += ", ";
+01087                 std::string srcOperand;
+01088                 dumpOperand(instr.getSrc(k), false, srcOperand);
+01089                 out += srcOperand;
+01090         }
+01091         out +="; \n";
+01092 }
+01093 
+01094 //=================================================================================================
+01095 void CVPParser::dump(const TProgram &prg, std::string &dest)
+01096 {       
+01097         dest = "!!VP1.0 \n";
+01098         for(uint k = 0; k < prg.size(); ++k)
+01099         {
+01100                 std::string instr;
+01101                 dumpInstr(prg[k], instr);
+01102                 dest += instr;
+01103         }
+01104         dest +="END";
+01105 }
+01106 
+01107 
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1