# 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