# 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  

driver_opengl_vertex_program.cpp

Go to the documentation of this file.
00001 
00009 /* Copyright, 2000 Nevrax Ltd.
00010  *
00011  * This file is part of NEVRAX NEL.
00012  * NEVRAX NEL is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2, or (at your option)
00015  * any later version.
00016 
00017  * NEVRAX NEL is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00020  * General Public License for more details.
00021 
00022  * You should have received a copy of the GNU General Public License
00023  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00024  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00025  * MA 02111-1307, USA.
00026  */
00027 
00028 #include "stdopengl.h"
00029 
00030 #include "3d/primitive_block.h"
00031 #include "3d/vertex_program.h"
00032 #include "3d/vertex_program_parse.h"
00033 #include <algorithm>
00034 
00035 
00036 using namespace std;
00037 using namespace NLMISC;
00038 
00039  
00040 namespace NL3D
00041 {
00042 
00043 // ***************************************************************************
00044 CVertexProgamDrvInfosGL::CVertexProgamDrvInfosGL (CDriverGL *drv, ItVtxPrgDrvInfoPtrList it) : IVertexProgramDrvInfos (drv, it) 
00045 {
00046         // Extension must exist
00047         nlassert (drv->_Extensions.NVVertexProgram
00048                       || drv->_Extensions.EXTVertexShader
00049                      );
00050 
00051         if (drv->_Extensions.NVVertexProgram) // nvidia implemntation
00052         {       
00053                 // Generate a program
00054                 nglGenProgramsNV (1, &ID);
00055         }
00056         else
00057         {
00058                 ID = nglGenVertexShadersEXT(1);
00059         }
00060 }
00061 
00062 
00063 // ***************************************************************************
00064 bool CDriverGL::isVertexProgramSupported () const
00065 {       
00066         return _Extensions.NVVertexProgram || _Extensions.EXTVertexShader;
00067 }
00068 
00069 // ***************************************************************************
00070 bool CDriverGL::isVertexProgramEmulated () const
00071 {
00072         return _Extensions.NVVertexProgramEmulated;
00073 }
00074 
00075 
00076 
00077 // ***************************************************************************
00078 bool CDriverGL::activeNVVertexProgram (CVertexProgram *program)
00079 {
00080         // Setup or unsetup ?
00081         if (program)
00082         {
00083                 // Enable vertex program
00084                 glEnable (GL_VERTEX_PROGRAM_NV);
00085                 _VertexProgramEnabled= true;
00086 
00087 
00088                 // Driver info
00089                 CVertexProgamDrvInfosGL *drvInfo;
00090 
00091                 // Program setuped ?
00092                 if (program->_DrvInfo==NULL)
00093                 {
00097                         CVPParser parser;
00098                         CVPParser::TProgram parsedProgram;
00099                         std::string errorOutput;
00100                         bool result = parser.parse(program->getProgram().c_str(), parsedProgram, errorOutput);
00101                         if (!result)
00102                         {
00103                                 nlwarning("Unable to parse a vertex program :");
00104                                 nlwarning(errorOutput.c_str());
00105                                 #ifdef NL_DEBUG
00106                                         nlassert(0);
00107                                 #endif
00108                                 return false;
00109                         }
00110 
00111                         // Insert into driver list. (so it is deleted when driver is deleted).
00112                         ItVtxPrgDrvInfoPtrList  it= _VtxPrgDrvInfos.insert(_VtxPrgDrvInfos.end());
00113 
00114                         // Create a driver info
00115                         *it = drvInfo = new CVertexProgamDrvInfosGL (this, it);
00116 
00117                         // Set the pointer
00118                         program->_DrvInfo=drvInfo;                                              
00119 
00120                         // Compile the program
00121                         nglLoadProgramNV (GL_VERTEX_PROGRAM_NV, drvInfo->ID, program->getProgram().length(), (const GLubyte*)program->getProgram().c_str());
00122 
00123                         // Get loading error code
00124                         GLint errorOff;
00125                         glGetIntegerv (GL_PROGRAM_ERROR_POSITION_NV, &errorOff);
00126 
00127                         // Compilation error ?
00128                         if (errorOff>=0)
00129                         {
00130                                 // String length
00131                                 uint length = program->getProgram ().length();
00132                                 const char* sString= program->getProgram ().c_str();
00133 
00134                                 // Line count and char count
00135                                 uint line=1;
00136                                 uint charC=1;
00137 
00138                                 // Find the line
00139                                 uint offset=0;
00140                                 while ((offset<length)&&(offset<(uint)errorOff))
00141                                 {
00142                                         if (sString[offset]=='\n')
00143                                         {
00144                                                 line++;
00145                                                 charC=1;
00146                                         }
00147                                         else
00148                                                 charC++;
00149 
00150                                         // Next character
00151                                         offset++;
00152                                 }
00153 
00154                                 // Show the error
00155                                 nlinfo ("Vertex program syntax error line %d character %d\n", line, charC);
00156 
00157                                 // Disable vertex program
00158                                 glDisable (GL_VERTEX_PROGRAM_NV);
00159                                 _VertexProgramEnabled= false;
00160 
00161                                 // Setup not ok
00162                                 return false;
00163                         }
00164 
00165                         // Setup ok
00166                         return true;
00167                 }
00168                 else
00169                 {
00170                         // Cast the driver info pointer
00171                         drvInfo=safe_cast<CVertexProgamDrvInfosGL*>((IVertexProgramDrvInfos*)program->_DrvInfo);
00172                 }
00173 
00174                 // Setup this program
00175                 nglBindProgramNV (GL_VERTEX_PROGRAM_NV, drvInfo->ID);
00176                 _LastSetuppedVP = program;
00177 
00178                 // Ok
00179                 return true;
00180         }
00181         else // Unsetup
00182         {
00183                 // Disable vertex program
00184                 glDisable (GL_VERTEX_PROGRAM_NV);
00185                 _VertexProgramEnabled= false;
00186                 // Ok
00187                 return true;
00188         }
00189 }
00190 
00191 
00192 // ***************************************************************************
00193 static 
00194 inline GLenum convSwizzleToGLFormat(CVPSwizzle::EComp comp, bool negate)
00195 {
00196         if (!negate)
00197         {
00198                 switch(comp)
00199                 {
00200                         case CVPSwizzle::X: return GL_X_EXT;
00201                         case CVPSwizzle::Y: return GL_Y_EXT;
00202                         case CVPSwizzle::Z: return GL_Z_EXT;
00203                         case CVPSwizzle::W: return GL_W_EXT;
00204                         default:
00205                                 nlstop;
00206                                 return 0;
00207                         break;
00208                 }
00209         }
00210         else
00211         {
00212                 switch(comp)
00213                 {
00214                         case CVPSwizzle::X: return GL_NEGATIVE_X_EXT;
00215                         case CVPSwizzle::Y: return GL_NEGATIVE_Y_EXT;
00216                         case CVPSwizzle::Z: return GL_NEGATIVE_Z_EXT;
00217                         case CVPSwizzle::W: return GL_NEGATIVE_W_EXT;
00218                         default:
00219                                 nlstop;
00220                                 return 0;
00221                         break;
00222                 }
00223         }
00224 }
00225 
00226 // ***************************************************************************
00229 static GLuint convOutputRegisterToEXTVertexShader(CVPOperand::EOutputRegister r)
00230 {
00231         switch (r)
00232         {
00233                 case    CVPOperand::OHPosition:                 return GL_OUTPUT_VERTEX_EXT;
00234                 case    CVPOperand::OPrimaryColor:              return GL_OUTPUT_COLOR0_EXT;
00235                 case    CVPOperand::OSecondaryColor:    return GL_OUTPUT_COLOR1_EXT;
00236                 case    CVPOperand::OBackFacePrimaryColor:
00237                         nlwarning("Backface color used in a vertex program is not supported by device, defaulting to front color");
00238                         return GL_OUTPUT_COLOR0_EXT;
00239                 break;
00240                 case    CVPOperand::OBackFaceSecondaryColor:
00241                         nlwarning("Backface color used in a vertex program is not supported by device, defaulting to front color");
00242                         return GL_OUTPUT_COLOR1_EXT;
00243                 break;
00244                 case    CVPOperand::OFogCoord:                  return GL_OUTPUT_FOG_EXT;
00245                 case    CVPOperand::OPointSize:                 nlstop; return 0; // sorry, not supported
00246                 case    CVPOperand::OTex0:                              return GL_OUTPUT_TEXTURE_COORD0_EXT;
00247                 case    CVPOperand::OTex1:                              return GL_OUTPUT_TEXTURE_COORD1_EXT;
00248                 case    CVPOperand::OTex2:                              return GL_OUTPUT_TEXTURE_COORD2_EXT;
00249                 case    CVPOperand::OTex3:                              return GL_OUTPUT_TEXTURE_COORD3_EXT;
00250                 case    CVPOperand::OTex4:                              return GL_OUTPUT_TEXTURE_COORD4_EXT;
00251                 case    CVPOperand::OTex5:                              return GL_OUTPUT_TEXTURE_COORD5_EXT;
00252                 case    CVPOperand::OTex6:                              return GL_OUTPUT_TEXTURE_COORD6_EXT;
00253                 case    CVPOperand::OTex7:                              return GL_OUTPUT_TEXTURE_COORD7_EXT;
00254                 default:
00255                         nlstop;
00256                 break;
00257         }
00258         return 0;
00259 }
00260 
00261 // ***************************************************************************
00264 static uint convInputRegisterToVBFlag(uint index)
00265 {
00266         switch (index)
00267         {       
00268                 case CVPOperand::IPosition:                             return CVertexBuffer::PositionFlag;
00269                 case CVPOperand::IWeight:                               return CVertexBuffer::WeightFlag;
00270                 case CVPOperand::INormal:                               return CVertexBuffer::NormalFlag;
00271                 case CVPOperand::IPrimaryColor:                 return CVertexBuffer::PrimaryColorFlag;
00272                 case CVPOperand::ISecondaryColor:               return CVertexBuffer::SecondaryColorFlag;
00273                 case CVPOperand::IFogCoord:                             return CVertexBuffer::FogFlag;
00274                 case CVPOperand::IPaletteSkin:                  return CVertexBuffer::PaletteSkinFlag;
00275                 case CVPOperand::IEmpty: nlassert(0); break;
00276                 case CVPOperand::ITex0:
00277                 case CVPOperand::ITex1: 
00278                 case CVPOperand::ITex2:
00279                 case CVPOperand::ITex3:
00280                 case CVPOperand::ITex4:
00281                 case CVPOperand::ITex5:
00282                 case CVPOperand::ITex6:
00283                 case CVPOperand::ITex7:
00284                 case CVPOperand::ITex8:
00285                         return CVertexBuffer::TexCoord0Flag << (index - CVPOperand::ITex0);
00286                 default:
00287                         nlassert(0);
00288                 break;
00289         }
00290         return 0;
00291 }
00292 
00293 
00294 
00295 // A macro to debug the generated instruction
00296 #define DEBUG_SETUP_EXT_VERTEX_SHADER
00297 
00298 #ifdef DEBUG_SETUP_EXT_VERTEX_SHADER
00299         #define EVS_INFO(what) nlinfo(what)
00300 #else
00301         #define EVS_INFO(what)
00302 #endif
00303 
00304 
00305 // For debugging with swizzling
00306 static void doSwizzle(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW)
00307 {
00308         nglSwizzleEXT(res, in, outX, outY, outZ, outW);
00309 #ifdef DEBUG_SETUP_EXT_VERTEX_SHADER
00310         std::string swzStr = "Swizzle : ";
00311         GLenum swz[] = { outX, outY, outZ, outW };              
00312         for(uint k = 0; k < 4; ++k)
00313         {
00314                 switch(swz[k])
00315                 {
00316                         case GL_X_EXT:
00317                                 swzStr +=" X";
00318                         break;
00319                         case GL_NEGATIVE_X_EXT:
00320                                 swzStr +=" -X";
00321                         break;
00322                         case GL_Y_EXT:
00323                                 swzStr +=" Y";
00324                         break;
00325                         case GL_NEGATIVE_Y_EXT:
00326                                 swzStr +=" -Y";
00327                         break;
00328                         break;
00329                         case GL_Z_EXT:
00330                                 swzStr +=" Z";
00331                         break;
00332                         case GL_NEGATIVE_Z_EXT:
00333                                 swzStr +=" -Z";
00334                         break;
00335                         case GL_W_EXT:
00336                                 swzStr +=" W";
00337                         break;
00338                         case GL_NEGATIVE_W_EXT:
00339                                 swzStr +=" -W";
00340                         break;
00341                         case GL_ZERO_EXT:
00342                                 swzStr +="0";
00343                         break;
00344                         case GL_ONE_EXT:
00345                                 swzStr +="1";
00346                         break;
00347                 }
00348         }
00349         EVS_INFO(swzStr.c_str());
00350 #endif
00351 
00352 }
00353 
00354 // Perform write mask and output de bug informations
00355 static void doWriteMask(GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW)
00356 {
00357         nglWriteMaskEXT(res, in, outX, outY, outZ, outW);
00358         #ifdef DEBUG_SETUP_EXT_VERTEX_SHADER
00359         nlinfo("Write Mask : %c%c%c%c",
00360                    outX ? 'x' : '-',
00361                    outY ? 'y' : '-',
00362                    outZ ? 'z' : '-',
00363                    outW ? 'w' : '-'                
00364                   );
00365         #endif
00366 }
00367 
00368 // ***************************************************************************
00371 bool CDriverGL::setupEXTVertexShader(const CVPParser::TProgram &program, GLuint id, uint variants[EVSNumVariants], uint16 &usedInputRegisters)
00372 {
00373         // counter to see what is generated
00374         uint numOp = 0;
00375         uint numOpIndex = 0;
00376         uint numSwizzle = 0;
00377         uint numEC = 0; // extract component
00378         uint numIC = 0; // insert component
00379         uint numWM = 0; // write maks
00380 
00381         
00382         #ifdef DEBUG_SETUP_EXT_VERTEX_SHADER
00383                 nlinfo("**********************************************************");
00384         #endif
00385 
00386         // clear last error
00387         GLenum glError = glGetError();
00388 
00389         // allocate the symbols
00390         nglBindVertexShaderEXT(id);
00391         nglBeginVertexShaderEXT();
00392         {                               
00393                 // Allocate register and variant
00394                 GLuint firstRegister = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 12); // 12 register
00395                 GLuint firstTempRegister = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 4); // 4  temp register used for swizzle & indexing
00396                 GLuint firstTempScalar = nglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 3); // 3  temp scalars used for EXPP & LOGG emulation
00397                 GLuint firstAddressRegister = nglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
00398 
00399                 // allocate variants
00400                 variants[EVSSecondaryColorVariant] = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_VARIANT_EXT, GL_NORMALIZED_RANGE_EXT, 1);
00401                 variants[EVSFogCoordsVariant] = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_VARIANT_EXT, GL_FULL_RANGE_EXT, 1);
00402                 variants[EVSSkinWeightVariant] = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_VARIANT_EXT, GL_NORMALIZED_RANGE_EXT, 1);
00403                 variants[EVSPaletteSkinVariant] = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_VARIANT_EXT, GL_FULL_RANGE_EXT, 1);
00404 
00405                 // allocate one temporary register for fog before conversion
00406                 GLuint fogTemp = nglGenSymbolsEXT(GL_VECTOR_EXT, GL_LOCAL_EXT, GL_FULL_RANGE_EXT, 1);
00407 
00408 
00409                 // local constant : 0 and 1
00410                 GLuint cteOne = nglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_CONSTANT_EXT, GL_FULL_RANGE_EXT, 1);
00411                 GLuint cteZero = nglGenSymbolsEXT(GL_SCALAR_EXT, GL_LOCAL_CONSTANT_EXT, GL_FULL_RANGE_EXT, 1);
00412 
00413 
00414                 float oneValue = 1.f;
00415                 float zeroValue = 0.f;
00416 
00417                 nglSetLocalConstantEXT( cteOne, GL_FLOAT, &oneValue);
00418                 nglSetLocalConstantEXT( cteZero, GL_FLOAT, &zeroValue);
00419 
00420 
00421                 
00422                 if (firstRegister == 0)
00423                 {
00424                         nlwarning("Unable to allocate local registers for EXT_vertex_shader");
00425                         return false;
00426                 }
00427                 if (firstTempRegister == 0)
00428                 {
00429                         nlwarning("Unable to allocate local temp registers for EXT_vertex_shader");
00430                         return false;
00431                 }
00432                 if (firstTempScalar == 0)
00433                 {
00434                         nlwarning("Unable to allocate temp scalar registers for EXT_vertex_shader");
00435                         return false;
00436                 }
00437                 if (firstAddressRegister == 0)
00438                 {
00439                         nlwarning("Unable to allocate address register for EXT_vertex_shader");
00440                         return false;
00441                 }
00442 
00443                 uint k;
00444                 for(k = 0; k < EVSNumVariants; ++k)
00445                 {
00446                         if (variants[k] == 0)
00447                         {
00448                                 nlwarning("Unable to allocate variants for EXT_vertex_shader");
00449                                 return false;
00450                         }
00451                 }
00452 
00453                 // Mask of output component that are being written
00454                 uint componentWritten[16];
00455                 std::fill(componentWritten, componentWritten + 16, 0);
00456                 
00457                 //
00458                 GLuint srcValue[3];
00459                 //
00460                 GLuint destValue;
00461                 GLuint maskedDestValue;
00462                 
00463 
00464                 uint l;
00465                 // convert each instruction of the vertex program
00466                 for(k = 0; k < program.size(); ++k)
00467                 {
00468                         // get src values, eventually applying swizzle, negate, and index on them
00469                         uint numSrc = program[k].getNumUsedSrc();
00470                         for(l = 0; l < numSrc; ++l)
00471                         {
00472                                 EVS_INFO(("Build source " + toString(l)).c_str());
00473                                 const CVPOperand &operand = program[k].getSrc(l);
00474                                 switch (operand.Type)
00475                                 {
00476                                         case CVPOperand::InputRegister: 
00477                                         {
00478                                                 switch(operand.Value.InputRegisterValue)
00479                                                 {
00480                                                         case  0: srcValue[l] = _EVSPositionHandle; EVS_INFO("Src = position"); break;
00481                                                         case  1: srcValue[l] = variants[EVSSkinWeightVariant]; EVS_INFO("Src = skin weight"); break;
00482                                                         case  2: srcValue[l] = _EVSNormalHandle; EVS_INFO("Src = normal"); break;
00483                                                         case  3: srcValue[l] = _EVSColorHandle; EVS_INFO("Src = color 0"); break;
00484                                                         case  4: srcValue[l] = variants[EVSSecondaryColorVariant]; EVS_INFO("Src = color 1"); break;
00485                                                         case  5: srcValue[l] = variants[EVSFogCoordsVariant]; EVS_INFO("Src = fog coord"); break;
00486                                                         case  6: srcValue[l] = variants[EVSPaletteSkinVariant]; EVS_INFO("Src = palette skin"); break;
00487                                                         case  7: nlstop; // not supported
00488                                                         case  8:
00489                                                         case  9:
00490                                                         case  10:
00491                                                         case  11:
00492                                                         case  12:
00493                                                         case  13:
00494                                                         case  14:
00495                                                         case  15:
00496                                                         {                                                               
00497                                                                 EVS_INFO(("Src = Tex" + toString(operand.Value.InputRegisterValue - 8)).c_str());
00498                                                                 srcValue[l] = _EVSTexHandle[operand.Value.InputRegisterValue - 8];
00499                                                                 if (srcValue[l] == 0)
00500                                                                 {                                                               
00501                                                                         nlwarning("Trying to read an unaccessible texture coords for the device when using EXT_vertex_shader, shader loading failed");
00502                                                                         return false;
00503                                                                 }
00504                                                         }
00505                                                         break;
00506                                                         default:
00507                                                                 nlstop; // invalid value
00508                                                         break;
00509                                                 }
00510                                         }
00511                                         break;
00512                                         case CVPOperand::Constant: 
00513                                                 srcValue[l] = _EVSConstantHandle + operand.Value.ConstantValue; 
00514                                                 EVS_INFO(("Src = constant" + toString(operand.Value.ConstantValue)).c_str());
00515                                         break;
00516                                         case CVPOperand::Variable: 
00517                                                 srcValue[l] = firstRegister + operand.Value.VariableValue;
00518                                                 EVS_INFO(("Src = variable register" + toString(operand.Value.VariableValue)).c_str());
00519                                         break;
00520                                         default:
00521                                                 nlassert(0);
00522                                         break;
00523                                 }
00524                                 // test if indexed access is used (can be used on one register only)
00525                                 if (operand.Type == CVPOperand::Constant && operand.Indexed)
00526                                 {
00527                                         nglShaderOp2EXT(GL_OP_INDEX_EXT, firstTempRegister + 3, firstAddressRegister, srcValue[l]);
00528                                         EVS_INFO("GL_OP_INDEX_EXT");
00529                                         ++ numOpIndex;
00530                                         srcValue[l] = firstTempRegister + 3;
00531                                         glError = glGetError();
00532                                         nlassert(glError == GL_NO_ERROR)
00533                                 }
00534 
00535                                 // test if swizzle or negate is used
00536                                 if (!operand.Swizzle.isIdentity() || operand.Negate)
00537                                 {
00538                                         // if the instruction reads a scalar, no need for swizzle (except if negate is used)
00539                                         if (!                                           
00540                                                 (
00541                                                  (program[k].Opcode == CVPInstruction::RSQ
00542                                                   || program[k].Opcode == CVPInstruction::RCP
00543                                                   || program[k].Opcode == CVPInstruction::LOG
00544                                                   || program[k].Opcode == CVPInstruction::EXPP
00545                                              ) 
00546                                                  && 
00547                                                  !operand.Negate
00548                                                 )
00549                                         )
00550                                         {                                       
00551                                                 // need a temp register for swizzle and/or negate
00552                                                 doSwizzle(firstTempRegister + l, srcValue[l],
00553                                                                           convSwizzleToGLFormat(operand.Swizzle.Comp[0], operand.Negate),
00554                                                                           convSwizzleToGLFormat(operand.Swizzle.Comp[1], operand.Negate),
00555                                                                           convSwizzleToGLFormat(operand.Swizzle.Comp[2], operand.Negate),
00556                                                                           convSwizzleToGLFormat(operand.Swizzle.Comp[3], operand.Negate));                                              
00557                                                 ++numSwizzle;
00558                                                 srcValue[l] = firstTempRegister + l;
00559                                                 glError = glGetError();
00560                                                 nlassert(glError == GL_NO_ERROR)
00561                                         }
00562                                 }
00563                         }
00564 
00565                         // get dest value
00566                         const CVPOperand &destOperand = program[k].Dest;
00567                         switch(destOperand.Type)
00568                         {
00569                                 case CVPOperand::Variable: 
00570                                         destValue = firstRegister + destOperand.Value.VariableValue; 
00571                                 break;
00572                                 case CVPOperand::OutputRegister:
00573                                         if (destOperand.Value.OutputRegisterValue != CVPOperand::OFogCoord)
00574                                         {                                       
00575                                                 destValue = convOutputRegisterToEXTVertexShader(destOperand.Value.OutputRegisterValue);
00576                                         }
00577                                         else
00578                                         {
00579                                                 destValue = fogTemp;
00580                                         }
00581                                 break;
00582                                 case CVPOperand::AddressRegister:
00583                                         destValue = firstAddressRegister;
00584                                 break;
00585                                 default:
00586                                         nlassert(0);
00587                                 break;
00588                         }
00589 
00590                         uint writeMask = program[k].Dest.WriteMask;
00591                         CVPInstruction::EOpcode opcode = program[k].Opcode;
00592                         uint outputRegisterIndex = destOperand.Value.OutputRegisterValue;
00593                         nlassert(outputRegisterIndex < 16);
00594 
00595                         // Tells wether the output has already been written before the final write mask. This happens with instructions LOG, EXPP, LIT, RSQ and RCP,
00596                         // because they write their output component by components
00597                         bool outputWritten = false;
00598 
00599                         // test for write mask                                          
00600                         if (writeMask != 0x0f) 
00601                         {                                       
00605                                 if (!(destOperand.Type == CVPOperand::OutputRegister && destValue == fogTemp))
00606                                 {
00607                                         // For instructions that write their output components by components, we don't need an intermediary register
00608                                         if (opcode == CVPInstruction::LOG
00609                                                 || opcode == CVPInstruction::EXPP
00610                                                 || opcode == CVPInstruction::LIT
00611                                                 || opcode == CVPInstruction::RSQ
00612                                                 || opcode == CVPInstruction::RCP
00613                                            )
00614                                         {
00615                                                 outputWritten = true;   
00616                                         }
00617                                         else
00618                                         {                                       
00619                                                 maskedDestValue = destValue;
00620                                                 // use a temp register before masking
00621                                                 destValue = firstTempRegister;
00622                                         }
00623                                 }
00624                                 else
00625                                 {
00626                                         componentWritten[outputRegisterIndex] = 0xf;
00627                                 }
00628                         }
00629                         else
00630                         {
00631                                 if (destOperand.Type == CVPOperand::OutputRegister)
00632                                 {
00633                                         componentWritten[outputRegisterIndex] = 0xf; // say all components have been written for that output                            
00634                                 }
00635                         }                       
00636                         
00637                         // generate opcode
00638                         switch (opcode)
00639                         {
00640                                 case  CVPInstruction::ARL:
00641                                 {                                       
00642                                         nlassert(program[k].Src1.Swizzle.isScalar());
00643                                         GLuint index = program[k].Src1.Swizzle.Comp[0];
00644                                         nglExtractComponentEXT(firstAddressRegister, srcValue[0],  index);
00645                                         EVS_INFO("Extract component");
00646                                         ++numEC;
00647                                 }
00648                                 break;
00649                                 case  CVPInstruction::MOV:
00650                                 {                                                                                       
00651                                         nglShaderOp1EXT(GL_OP_MOV_EXT, destValue, srcValue[0]);
00652                                         EVS_INFO("GL_OP_MOV_EXT");
00653                                         ++numOp;                                        
00654                                 }
00655                                 break;
00656                                 case  CVPInstruction::MUL: 
00657                                         nglShaderOp2EXT(GL_OP_MUL_EXT, destValue, srcValue[0], srcValue[1]); 
00658                                         EVS_INFO("GL_OP_MUL_EXT");
00659                                         ++numOp;
00660                                 break;
00661                                 case  CVPInstruction::ADD: 
00662                                         nglShaderOp2EXT(GL_OP_ADD_EXT, destValue, srcValue[0], srcValue[1]); 
00663                                         EVS_INFO("GL_OP_ADD_EXT");
00664                                         ++numOp;
00665                                 break;
00666                                 case  CVPInstruction::MAD: 
00667                                         nglShaderOp3EXT(GL_OP_MADD_EXT, destValue, srcValue[0], srcValue[1], srcValue[2]); 
00668                                         EVS_INFO("GL_OP_MADD_EXT");
00669                                         ++numOp;
00670                                 break;
00671                                 case  CVPInstruction::RSQ:
00672                                 {
00673                                         nlassert(program[k].Src1.Swizzle.isScalar());
00674                                         // extract the component we need
00675                                         GLuint index = program[k].Src1.Swizzle.Comp[0];
00676                                         nglExtractComponentEXT(firstTempScalar, srcValue[0],  index);
00677                                         EVS_INFO("Extract component");
00678                                         ++numEC;
00679                                         nglShaderOp1EXT(GL_OP_RECIP_SQRT_EXT, firstTempScalar + 1, firstTempScalar);
00680                                         EVS_INFO("GL_OP_RECIP_SQRT_EXT");
00681                                         ++numOp;
00682                                         // duplicate result in destination
00683                                         for(uint l = 0; l < 4; ++l)
00684                                         {
00685                                                 if (writeMask & (1 << l))
00686                                                 {                                               
00687                                                         nglInsertComponentEXT(destValue, firstTempScalar + 1, l);
00688                                                         EVS_INFO("Insert component");
00689                                                         nlassert(glGetError() == GL_NO_ERROR);
00690                                                 }
00691                                         }
00692                                 }
00693                                 break;
00694                                 case  CVPInstruction::DP3: 
00695                                         nglShaderOp2EXT(GL_OP_DOT3_EXT, destValue, srcValue[0], srcValue[1]);
00696                                         EVS_INFO("GL_OP_DOT3_EXT");
00697                                         ++numOp;
00698                                 break;
00699                                 case  CVPInstruction::DP4: 
00700                                         nglShaderOp2EXT(GL_OP_DOT4_EXT, destValue, srcValue[0], srcValue[1]); 
00701                                         EVS_INFO("GL_OP_DOT4_EXT");
00702                                         ++numOp;
00703                                 break;
00704                                 case  CVPInstruction::DST: 
00705                                         doSwizzle(firstTempRegister, srcValue[0], GL_ONE_EXT, GL_Y_EXT, GL_Z_EXT, GL_ONE_EXT);
00706                                         EVS_INFO("GL_OP_DOT4_EXT");
00707                                         ++numOp;
00708                                         doSwizzle(firstTempRegister + 1, srcValue[1], GL_ONE_EXT, GL_Y_EXT, GL_ONE_EXT, GL_W_EXT);                                      
00709                                         ++numSwizzle;
00710                                         nglShaderOp2EXT(GL_OP_MUL_EXT, destValue, firstTempRegister, firstTempRegister + 1);
00711                                         EVS_INFO("GL_OP_MUL_EXT");
00712                                         ++numOp;
00713                                 break;                                  
00714                                 case  CVPInstruction::LIT:
00715                                 {
00716                                         uint writeMask = program[k].Dest.WriteMask;                                     
00717                                         nglExtractComponentEXT(firstTempScalar, srcValue[0], 0); // extract X from the source
00718                                         if (writeMask & 4)
00719                                         {                                       
00720                                                 nglExtractComponentEXT(firstTempScalar + 1, srcValue[0], 1); // extract Y from the source
00721                                                 EVS_INFO("Extract component");
00722                                                 ++numEC;
00723                                                 nglExtractComponentEXT(firstTempScalar + 2, srcValue[0], 3); // extract W from the source
00724                                                 EVS_INFO("Extract component");
00725                                                 ++numEC;
00726                                                 // result = X > 0 ? Y^W : 0                                     
00727                                                 nglShaderOp2EXT(GL_OP_POWER_EXT, firstTempScalar + 2, firstTempScalar + 1, firstTempScalar + 2);
00728                                                 EVS_INFO("GL_OP_POWER_EXT");
00729                                                 ++numOp;
00730                                                 nglShaderOp2EXT(GL_OP_SET_GE_EXT, firstTempScalar + 1, firstTempScalar, cteZero);
00731                                                 EVS_INFO("GL_OP_SET_GE_EXT");
00732                                                 ++numOp;
00733                                                 nglShaderOp2EXT(GL_OP_MUL_EXT, firstTempScalar + 2, firstTempScalar + 2, firstTempScalar + 1);
00734                                                 EVS_INFO("GL_OP_MUL_EXT");
00735                                                 ++numOp;
00736                                                 // store result
00737                                                 nglInsertComponentEXT(destValue, firstTempScalar + 2, 2);
00738                                                 EVS_INFO("Insert component");
00739                                                 ++numIC;
00740                                         }
00741                                         if (writeMask & 2) 
00742                                         {
00743                                                 // clamp N.L to [0, 1]
00744                                                 nglShaderOp3EXT(GL_OP_CLAMP_EXT, firstTempScalar, firstTempScalar, cteZero, cteOne);
00745                                                 EVS_INFO("GL_OP_CLAMP_EXT");
00746                                                 ++numOp;
00747                                                 nglInsertComponentEXT(destValue, firstTempScalar, 1);
00748                                                 EVS_INFO("Insert component");
00749                                                 ++numIC;
00750                                         }
00751                                         // set x and w to 1 if they are not masked
00752                                         if (writeMask & (1 + 8)) 
00753                                         {                                       
00754                                                 doSwizzle(destValue, destValue, 
00755                                                                           (writeMask & 1) ? GL_ONE_EXT : GL_X_EXT,
00756                                                                           GL_Y_EXT,
00757                                                                           GL_Z_EXT,
00758                                                                           (writeMask & 8) ? GL_ONE_EXT : GL_W_EXT);                                             
00759                                                 ++numSwizzle;
00760                                         }                                       
00761                                                  
00762                                 }
00763                                 break;
00764                                 case  CVPInstruction::MIN: 
00765                                         nglShaderOp2EXT(GL_OP_MIN_EXT, destValue, srcValue[0], srcValue[1]);
00766                                         EVS_INFO("GL_OP_MIN_EXT");
00767                                         ++numOp;
00768                                 break;
00769                                 case  CVPInstruction::MAX: 
00770                                         nglShaderOp2EXT(GL_OP_MAX_EXT, destValue, srcValue[0], srcValue[1]);
00771                                         EVS_INFO("GL_OP_MAX_EXT");
00772                                         ++numOp;
00773                                 break;
00774                                 case  CVPInstruction::SLT: 
00775                                         nglShaderOp2EXT(GL_OP_SET_LT_EXT, destValue, srcValue[0], srcValue[1]);
00776                                         EVS_INFO("GL_OP_SET_LT_EXT");
00777                                         ++numOp;
00778                                 break;
00779                                 case  CVPInstruction::SGE: 
00780                                         nglShaderOp2EXT(GL_OP_SET_GE_EXT, destValue, srcValue[0], srcValue[1]);
00781                                         EVS_INFO("GL_OP_SET_GE_EXT");
00782                                         ++numOp;
00783                                 break;
00784                                 case  CVPInstruction::EXPP:
00785                                 {                       
00786                                         uint writeMask = program[k].Dest.WriteMask;
00787                                         nlassert(program[k].Src1.Swizzle.isScalar());
00788                                         GLuint compIndex = program[k].Src1.Swizzle.Comp[0];
00789                                         nglExtractComponentEXT(firstTempScalar + 2, srcValue[0], compIndex); // extract W from the source
00790                                         EVS_INFO("Extract component");
00791                                         ++numEC;
00792                                         if (writeMask & 1)
00793                                         {                                       
00794                                                 nglShaderOp1EXT(GL_OP_FLOOR_EXT, firstTempScalar, firstTempScalar + 2); // (int) W
00795                                                 EVS_INFO("GL_OP_FLOOR_EXT");
00796                                                 ++numOp;
00797                                                 nglShaderOp1EXT(GL_OP_EXP_BASE_2_EXT, firstTempScalar, firstTempScalar); // 2 ^ (int) W         
00798                                                 EVS_INFO("GL_OP_EXP_BASE_2_EXT");
00799                                                 ++numOp;
00800                                         }
00801                                         if (writeMask & 2) 
00802                                         {                                       
00803                                                 nglShaderOp1EXT(GL_OP_FRAC_EXT, firstTempScalar + 1, firstTempScalar + 2); // frac(W)
00804                                                 EVS_INFO("GL_OP_FRAC_EXT");
00805                                                 ++numOp;
00806                                         }
00807                                         if (writeMask & 4) nglShaderOp1EXT(GL_OP_EXP_BASE_2_EXT, firstTempScalar + 2, firstTempScalar + 2); // 2 ^W
00808                                         // store the results
00809                                         if (writeMask & 1) { nglInsertComponentEXT(destValue, firstTempScalar, 0); EVS_INFO("Insert component"); ++numIC;  }
00810                                         if (writeMask & 2) { nglInsertComponentEXT(destValue, firstTempScalar + 1, 1); EVS_INFO("Insert component"); ++numIC; }
00811                                         if (writeMask & 4) { nglInsertComponentEXT(destValue, firstTempScalar + 2, 2); EVS_INFO("Insert component"); ++numIC; }
00812                                         // set W to 1 and leave other values unchanged
00813                                         if (writeMask & 8) { doSwizzle(destValue, destValue, GL_X_EXT, GL_Y_EXT, GL_Z_EXT, GL_ONE_EXT); ++numSwizzle; }
00814                                 }
00815                                 break;
00816                                 case  CVPInstruction::LOG:
00817                                 {                                       
00818                                         uint writeMask = program[k].Dest.WriteMask;
00819                                         nlassert(program[k].Src1.Swizzle.isScalar());
00820                                         // extract the component we need
00821                                         nglExtractComponentEXT(firstTempScalar, srcValue[0], (GLuint) program[k].Src1.Swizzle.Comp[0]);
00822                                         EVS_INFO("Extract component");
00823                                         ++numEC;
00824                                         // get abs(src) : abs(src) = max(src, -src)
00825                                         nglShaderOp1EXT(GL_OP_NEGATE_EXT, firstTempScalar + 1, firstTempScalar);
00826                                         EVS_INFO("GL_OP_NEGATE_EXT");
00827                                         ++numOp;
00828                                         nglShaderOp2EXT(GL_OP_MAX_EXT, firstTempScalar, firstTempScalar, firstTempScalar + 1);
00829                                         EVS_INFO("GL_OP_MAX_EXT");
00830                                         ++numOp;
00831                                         nglShaderOp1EXT(GL_OP_LOG_BASE_2_EXT, firstTempScalar, firstTempScalar); // (int) W
00832                                         EVS_INFO("GL_OP_LOG_BASE_2_EXT");
00833                                         ++numOp;
00834                                         // store the results
00835                                         for(uint l = 0; l < 4; ++l)
00836                                         {
00837                                                 if (writeMask & (1 << l))
00838                                                 {                                               
00839                                                         nglInsertComponentEXT(destValue, firstTempScalar, l);
00840                                                         EVS_INFO("Insert component");
00841                                                         nlassert(glGetError() == GL_NO_ERROR);
00842                                                 }
00843                                         }                                       
00844                                 }
00845                                 break;
00846                                 case  CVPInstruction::RCP:
00847                                 {
00848                                         uint writeMask = program[k].Dest.WriteMask;
00849                                         nlassert(program[k].Src1.Swizzle.isScalar());
00850                                         // extract the component we need
00851                                         nglExtractComponentEXT(firstTempScalar, srcValue[0], (GLuint) program[k].Src1.Swizzle.Comp[0]);
00852                                         EVS_INFO("Extract component");
00853                                         ++numEC;
00854                                         nglShaderOp1EXT(GL_OP_RECIP_EXT, firstTempScalar + 1, firstTempScalar);
00855                                         EVS_INFO("GL_OP_RECIP_EXT");
00856                                         ++numOp;
00857                                         // duplicate result in destination
00858                                         for(uint l = 0; l < 4; ++l)
00859                                         {
00860                                                 if (writeMask & (1 << l))
00861                                                 {                                               
00862                                                         nglInsertComponentEXT(destValue, firstTempScalar + 1, l);
00863                                                         EVS_INFO("insert component");
00864                                                         ++numIC;
00865                                                 }
00866                                         }
00867                                 }                                       
00868                                 break;
00869                         }
00870 
00871                         glError = glGetError();
00872                         nlassert(glError == GL_NO_ERROR)
00873 
00874                                 
00875                         // apply write mask if any
00876                         if (writeMask != 0x0f)
00877                         {                                                                       
00878                                 if (destOperand.Type == CVPOperand::OutputRegister && destValue != fogTemp)
00879                                 {
00880                                         uint &outputMask = componentWritten[outputRegisterIndex];
00881                                         // is a texture coordinate or a color being written ?
00882                                         if ((maskedDestValue >= GL_OUTPUT_TEXTURE_COORD0_EXT && maskedDestValue <= GL_OUTPUT_TEXTURE_COORD7_EXT)
00883                                                 || maskedDestValue == GL_OUTPUT_COLOR0_EXT
00884                                                 || maskedDestValue == GL_OUTPUT_COLOR1_EXT
00885                                            )
00886                                         {                                       
00887                                                 // test if this is the last time this output will be written
00888                                                 bool found = false;
00889                                                 // if this was the last write for this output, must set unfilled component
00890                                                 // NB : this loop could be optimized, but vertex program are rather short for now ..
00891                                                 for(uint m = k + 1; m < program.size(); ++m)
00892                                                 {
00893                                                         if (program[m].Dest.Type == CVPOperand::OutputRegister) // another output to this texture ?
00894                                                         {
00895                                                                 if (program[m].Dest.Value.OutputRegisterValue == program[k].Dest.Value.OutputRegisterValue)
00896                                                                 {
00897                                                                         found = true;
00898                                                                         break;
00899                                                                 }
00900                                                         }
00901                                                 }
00902 
00903                                                 if (found)
00904                                                 {
00905                                                         if (!outputWritten)
00906                                                         {                                                       
00907                                                                 // write values
00908                                                                 doWriteMask(maskedDestValue, destValue,
00909                                                                                                 writeMask & 1 ? GL_TRUE : GL_FALSE,
00910                                                                                                 writeMask & 2 ? GL_TRUE : GL_FALSE,
00911                                                                                                 writeMask & 4 ? GL_TRUE : GL_FALSE,
00912                                                                                                 writeMask & 8 ? GL_TRUE : GL_FALSE);
00913                                                                 ++numWM;
00914                                                         }
00915                                                 }
00916                                                 else // this is the last write, check if the mask is complete
00917                                                 {
00918                                                         if ((outputMask | writeMask) == 0xf)
00919                                                         {
00920                                                                 if (!outputWritten)
00921                                                                 {
00922                                                                         // ok, after this call everything has been written
00923                                                                         // write values
00924                                                                             doWriteMask(maskedDestValue, destValue,
00925                                                                                                         writeMask & 1 ? GL_TRUE : GL_FALSE,
00926                                                                                                         writeMask & 2 ? GL_TRUE : GL_FALSE,
00927                                                                                                         writeMask & 4 ? GL_TRUE : GL_FALSE,
00928                                                                                                         writeMask & 8 ? GL_TRUE : GL_FALSE);
00929                                                                         ++numWM;
00930                                                                 }
00931                                                         }
00932                                                         else
00933                                                         {
00934                                                                 uint prevMask = outputMask;
00935                                                                 uint newMask  = writeMask | outputMask;
00936                                                                 
00937                                                                 // complete unused entries
00938 
00939                                                                 // if primary color is output, then the default color is white
00940                                                                 if (maskedDestValue == GL_OUTPUT_COLOR0_EXT)
00941                                                                 {
00942                                                                         doSwizzle(firstTempRegister, destValue,
00943                                                                                                   newMask & 1 ? GL_X_EXT : GL_ONE_EXT,
00944                                                                                                   newMask & 2 ? GL_Y_EXT : GL_ONE_EXT,
00945                                                                                                   newMask & 4 ? GL_Z_EXT : GL_ONE_EXT,
00946                                                                                                   newMask & 8 ? GL_W_EXT : GL_ONE_EXT);
00947                                                                 }
00948                                                                 else
00949                                                                 {                                                               
00950                                                                         doSwizzle(firstTempRegister, destValue,
00951                                                                                                   newMask & 1 ? GL_X_EXT : GL_ZERO_EXT,
00952                                                                                                   newMask & 2 ? GL_Y_EXT : GL_ZERO_EXT,
00953                                                                                                   newMask & 4 ? GL_Z_EXT : GL_ZERO_EXT,
00954                                                                                                   newMask & 8 ? GL_W_EXT : GL_ONE_EXT);
00955                                                                 }
00956                                                                 if (!outputWritten)
00957                                                                 {                                                       
00958                                                                         ++numWM;
00959                                                                             doWriteMask(maskedDestValue, firstTempRegister,
00960                                                                                                         prevMask & 1 ? GL_FALSE : GL_TRUE,
00961                                                                                                         prevMask & 2 ? GL_FALSE : GL_TRUE,
00962                                                                                                         prevMask & 4 ? GL_FALSE : GL_TRUE,
00963                                                                                                         prevMask & 8 ? GL_FALSE : GL_TRUE
00964                                                                                                   );                                                                    
00965                                                                         ++numWM;
00966                                                                 }
00967                                                                 outputMask = 0xf;
00968                                                         }
00969                                                 }                                                                               
00970                                         }
00971                                         else
00972                                         {
00973                                                 if (!outputWritten)
00974                                                 {
00975                                                             doWriteMask(maskedDestValue, destValue,
00976                                                                                         writeMask & 1 ? GL_TRUE : GL_FALSE,
00977                                                                                         writeMask & 2 ? GL_TRUE : GL_FALSE,
00978                                                                                         writeMask & 4 ? GL_TRUE : GL_FALSE,
00979                                                                                         writeMask & 8 ? GL_TRUE : GL_FALSE);
00980                                                         ++numWM;
00981                                                 }
00982                                         }
00983                                         // complete the mask 
00984                                         outputMask |= writeMask;
00985                                 }
00986                                 else if (destOperand.Type != CVPOperand::OutputRegister)
00987                                 {
00988                                         if (!outputWritten)
00989                                         {
00990                                                     doWriteMask(maskedDestValue, destValue,
00991                                                                                 writeMask & 1 ? GL_TRUE : GL_FALSE,
00992                                                                                 writeMask & 2 ? GL_TRUE : GL_FALSE,
00993                                                                                 writeMask & 4 ? GL_TRUE : GL_FALSE,
00994                                                                                 writeMask & 8 ? GL_TRUE : GL_FALSE);
00995                                                 ++numWM;
00996                                         }
00997                                 }                               
00998                         }
00999 
01000                         glError = glGetError();
01001                         nlassert(glError == GL_NO_ERROR)
01002                 }
01003 
01004                 
01005 
01006                 // if color have not been written, write with default values
01007                 if (componentWritten[CVPOperand::OPrimaryColor] == 0)
01008                 {
01009                         // we specify vertex coord has input for swizzle, but we don't read any component.. 
01010                         doSwizzle(GL_OUTPUT_COLOR0_EXT, _EVSPositionHandle, GL_ONE_EXT, GL_ONE_EXT, GL_ONE_EXT, GL_ONE_EXT);
01011                         EVS_INFO("Swizzle (Complete primary color)");
01012                         ++numSwizzle;
01013                 }
01014                 else
01015                 {
01016                         nlassert(componentWritten[CVPOperand::OPrimaryColor] == 0xf)
01017                 }
01018                 if (componentWritten[CVPOperand::OSecondaryColor] == 0)
01019                 {
01020                         // we specify vertex coord has input for swizzle, but we don't read any component..
01021                         doSwizzle(GL_OUTPUT_COLOR1_EXT, _EVSPositionHandle, GL_ZERO_EXT, GL_ZERO_EXT, GL_ZERO_EXT, GL_ONE_EXT);
01022                         EVS_INFO("Swizzle (Complete secondary color)");
01023                         ++numSwizzle;
01024                 }
01025                 else
01026                 {
01027                         nlassert(componentWritten[CVPOperand::OSecondaryColor] == 0xf)
01028                 }
01029                 nlassert(componentWritten[CVPOperand::OHPosition] == 0xf); // should have written all component of position     
01030 
01031                 glError = glGetError();
01032                 nlassert(glError == GL_NO_ERROR);
01033 
01034                 // if fog has been written, perform conversion
01035                 if (componentWritten[CVPOperand::OFogCoord] == 0xf)
01036                 {
01037                         // Well this could be avoided, but we should make 2 cases for each vertex program.. :(
01038                         doSwizzle(firstTempRegister, _EVSConstantHandle + 96, GL_X_EXT, GL_X_EXT, GL_X_EXT, GL_X_EXT);
01039                         doSwizzle(firstTempRegister + 1, _EVSConstantHandle + 96, GL_Y_EXT, GL_Y_EXT, GL_Y_EXT, GL_Y_EXT);                      
01040                         nglShaderOp3EXT(GL_OP_MADD_EXT, firstTempRegister + 2, fogTemp, firstTempRegister, firstTempRegister + 1);
01041                         EVS_INFO("Use MAD for fog conversion");
01042                         nglExtractComponentEXT(GL_OUTPUT_FOG_EXT, firstTempRegister + 2, 0);
01043                         EVS_INFO("Extract component to fog");
01044                 }
01045 
01046                 glError = glGetError();
01047                 nlassert(glError == GL_NO_ERROR);
01048         }
01049         nglEndVertexShaderEXT();
01050 
01051         glError = glGetError();
01052         nlassert(glError == GL_NO_ERROR);
01053 
01054         GLboolean optimizedShader;
01055         glGetBooleanv(GL_VERTEX_SHADER_OPTIMIZED_EXT, &optimizedShader);
01056         if (!optimizedShader)
01057         {
01058                 nlwarning("Failed to optimize a vertex program with the EXT_vertex_shader extension, this shader will be disabled");
01059                 return false;
01060         }       
01061 
01062         // see which input registers are used
01063         usedInputRegisters = 0;
01064         
01065         uint k, l;
01066         // convert each instruction of the vertex program
01067         for(k = 0; k < program.size(); ++k)
01068         {
01069                 uint numSrc = program[k].getNumUsedSrc();
01070                 for(l = 0; l < numSrc; ++l)
01071                 {
01072                         const CVPOperand &op = program[k].getSrc(l);
01073                         if (op.Type == CVPOperand::InputRegister)
01074                         {
01075                                 usedInputRegisters |= convInputRegisterToVBFlag(op.Value.InputRegisterValue);
01076                         }
01077                 }               
01078         }
01079 
01080 #ifdef DEBUG_SETUP_EXT_VERTEX_SHADER
01081         nlinfo("========================");
01082         nlinfo("num Opcode  = %d", numOp);
01083         nlinfo("num Indexing = %d", numOpIndex);
01084         nlinfo("num Swizzle = %d", numSwizzle);
01085         nlinfo("num extract component = %d", numEC);
01086         nlinfo("num insert component = %d", numIC);     
01087         nlinfo("num write mask = %d", numWM);
01088 #endif
01089 
01090         return true;
01091                         
01092 }
01093 
01094 // ***************************************************************************
01095 bool CDriverGL::activeEXTVertexShader (CVertexProgram *program)
01096 {
01097         // Setup or unsetup ?
01098         if (program)
01099         {               
01100                 // Driver info
01101                 CVertexProgamDrvInfosGL *drvInfo;
01102 
01103                 // Program setuped ?
01104                 if (program->_DrvInfo==NULL)
01105                 {
01106                         // try to parse the program
01107                         CVPParser parser;
01108                         CVPParser::TProgram parsedProgram;
01109                         std::string errorOutput;
01110                         bool result = parser.parse(program->getProgram().c_str(), parsedProgram, errorOutput);
01111                         if (!result)
01112                         {
01113                                 nlwarning("Unable to parse a vertex program.");
01114                                 #ifdef NL_DEBUG
01115                                         nlerror(errorOutput.c_str());
01116                                 #endif
01117                                 return false;
01118                         }
01119 
01120                         /* 
01121                         FILE *f = fopen("c:\\test.txt", "wb");
01122                         if (f)
01123                         {
01124                                 std::string vpText;
01125                                 CVPParser::dump(parsedProgram, vpText);
01126                                 fwrite(vpText.c_str(), vpText.size(), 1, f);
01127                                 fclose(f);
01128                         }
01129                         */
01130 
01131                         // Insert into driver list. (so it is deleted when driver is deleted).
01132                         ItVtxPrgDrvInfoPtrList  it= _VtxPrgDrvInfos.insert(_VtxPrgDrvInfos.end());
01133 
01134                         // Create a driver info
01135                         *it = drvInfo = new CVertexProgamDrvInfosGL (this, it);
01136                         // Set the pointer
01137                         program->_DrvInfo=drvInfo;
01138 
01139                         if (!setupEXTVertexShader(parsedProgram, drvInfo->ID, drvInfo->Variants, drvInfo->UsedVertexComponents))
01140                         {
01141                                 delete drvInfo;
01142                                 program->_DrvInfo = NULL;
01143                                 _VtxPrgDrvInfos.erase(it);
01144                                 return false;
01145                         }
01146                 }
01147                 else
01148                 {
01149                         // Cast the driver info pointer
01150                         drvInfo=safe_cast<CVertexProgamDrvInfosGL*>((IVertexProgramDrvInfos*)program->_DrvInfo);
01151                 }
01152 
01153                 glEnable( GL_VERTEX_SHADER_EXT);
01154                 _VertexProgramEnabled = true;
01155                 nglBindVertexShaderEXT( drvInfo->ID );
01156                 _LastSetuppedVP = program;
01157         }
01158         else
01159         {
01160                 glDisable( GL_VERTEX_SHADER_EXT );
01161                 _VertexProgramEnabled = false;
01162         }
01163         return true;    
01164 }
01165 
01166 // ***************************************************************************
01167 bool CDriverGL::activeVertexProgram (CVertexProgram *program)
01168 {
01169         // Extension here ?
01170         if (_Extensions.NVVertexProgram)
01171         {
01172                 return activeNVVertexProgram(program);
01173         }
01174         else if (_Extensions.EXTVertexShader)
01175         {
01176                 return activeEXTVertexShader(program);          
01177         }
01178 
01179         // Can't do anything
01180         return false;
01181 }
01182 
01183 
01184 // ***************************************************************************
01185 
01186 void CDriverGL::setConstant (uint index, float f0, float f1, float f2, float f3)
01187 {
01188         // Vertex program exist ?
01189         if (_Extensions.NVVertexProgram)
01190         {
01191                 // Setup constant
01192                 nglProgramParameter4fNV (GL_VERTEX_PROGRAM_NV, index, f0, f1, f2, f3);
01193         }
01194         else if (_Extensions.EXTVertexShader)
01195         {
01196                 float datas[] = { f0, f1, f2, f3 };
01197                 nglSetInvariantEXT(_EVSConstantHandle + index, GL_FLOAT, datas);
01198         }                
01199 }
01200 
01201 
01202 // ***************************************************************************
01203 
01204 void CDriverGL::setConstant (uint index, double d0, double d1, double d2, double d3)
01205 {
01206         // Vertex program exist ?
01207         if (_Extensions.NVVertexProgram)
01208         {
01209                 // Setup constant
01210                 nglProgramParameter4dNV (GL_VERTEX_PROGRAM_NV, index, d0, d1, d2, d3);
01211         }
01212         else if (_Extensions.EXTVertexShader)
01213         {
01214                 double datas[] = { d0, d1, d2, d3 };
01215                 nglSetInvariantEXT(_EVSConstantHandle + index, GL_DOUBLE, datas);
01216         }
01217 }
01218 
01219 
01220 // ***************************************************************************
01221 
01222 void CDriverGL::setConstant (uint index, const NLMISC::CVector& value)
01223 {
01224         // Vertex program exist ?
01225         if (_Extensions.NVVertexProgram)
01226         {
01227                 // Setup constant
01228                 nglProgramParameter4fNV (GL_VERTEX_PROGRAM_NV, index, value.x, value.y, value.z, 0);    
01229         }
01230         else if (_Extensions.EXTVertexShader)
01231         {
01232                 float datas[] = { value.x, value.y, value.z, 0 };
01233                 nglSetInvariantEXT(_EVSConstantHandle + index, GL_FLOAT, datas);
01234         }
01235 }
01236 
01237 
01238 // ***************************************************************************
01239 
01240 void CDriverGL::setConstant (uint index, const NLMISC::CVectorD& value)
01241 {
01242         // Vertex program exist ?
01243         if (_Extensions.NVVertexProgram)
01244         {
01245                 // Setup constant
01246                 nglProgramParameter4dNV (GL_VERTEX_PROGRAM_NV, index, value.x, value.y, value.z, 0);
01247         }
01248         else if (_Extensions.EXTVertexShader)
01249         {
01250                 double datas[] = { value.x, value.y, value.z, 0 };
01251                 nglSetInvariantEXT(_EVSConstantHandle + index, GL_DOUBLE, datas);
01252         }
01253 }
01254 
01255 
01256 // ***************************************************************************
01257 void    CDriverGL::setConstant (uint index, uint num, const float *src)
01258 {
01259         // Vertex program exist ?
01260         if (_Extensions.NVVertexProgram)
01261         {
01262                 nglProgramParameters4fvNV(GL_VERTEX_PROGRAM_NV, index, num, src);
01263         }       
01264         else if (_Extensions.EXTVertexShader)
01265         {
01266                 for(uint k = 0; k < num; ++k)
01267                 {                                       
01268                         nglSetInvariantEXT(_EVSConstantHandle + index + k, GL_FLOAT, (void *) (src + 4 * k));
01269                 }
01270         }       
01271 }
01272 
01273 // ***************************************************************************
01274 void    CDriverGL::setConstant (uint index, uint num, const double *src)
01275 {
01276         // Vertex program exist ?
01277         if (_Extensions.NVVertexProgram)
01278         {
01279                 nglProgramParameters4dvNV(GL_VERTEX_PROGRAM_NV, index, num, src);
01280         }
01281         else if (_Extensions.EXTVertexShader)
01282         {
01283                 for(uint k = 0; k < num; ++k)
01284                 {                                       
01285                         nglSetInvariantEXT(_EVSConstantHandle + index + k, GL_DOUBLE, (void *) (src + 4 * k));
01286                 }
01287         }
01288 }
01289 
01290 // ***************************************************************************
01291 
01292 const uint CDriverGL::GLMatrix[IDriver::NumMatrix]=
01293 {
01294         GL_MODELVIEW,
01295         GL_PROJECTION,
01296         GL_MODELVIEW_PROJECTION_NV
01297 };
01298 
01299 
01300 // ***************************************************************************
01301 
01302 const uint CDriverGL::GLTransform[IDriver::NumTransform]=
01303 {
01304         GL_IDENTITY_NV,
01305         GL_INVERSE_NV,
01306         GL_TRANSPOSE_NV,
01307         GL_INVERSE_TRANSPOSE_NV
01308 };
01309 
01310 
01311 // ***************************************************************************
01312 
01313 void CDriverGL::setConstantMatrix (uint index, IDriver::TMatrix matrix, IDriver::TTransform transform)
01314 {
01315         // Vertex program exist ?
01316         if (_Extensions.NVVertexProgram)
01317         {
01318                 // First, ensure that the render setup is correclty setuped.
01319                 refreshRenderSetup();
01320 
01321                 // Track the matrix
01322                 nglTrackMatrixNV (GL_VERTEX_PROGRAM_NV, index, GLMatrix[matrix], GLTransform[transform]);
01323                 // Release Track => matrix data is copied.
01324                 nglTrackMatrixNV (GL_VERTEX_PROGRAM_NV, index, GL_NONE, GL_IDENTITY_NV);
01325         }
01326         else if (_Extensions.EXTVertexShader)
01327         {
01328                 // First, ensure that the render setup is correctly setuped.
01329                 refreshRenderSetup();           
01330                 CMatrix mat;            
01331                 switch (matrix)
01332                 {
01333                         case IDriver::ModelView:
01334                                 mat = _ModelViewMatrix;
01335                         break;
01336                         case IDriver::Projection:
01337                         {
01338                                 refreshProjMatrixFromGL();
01339                                 mat = _GLProjMat;
01340                         }
01341                         break;
01342                         case IDriver::ModelViewProjection:
01343                                 refreshProjMatrixFromGL();                              
01344                                 mat = _GLProjMat * _ModelViewMatrix;
01345                         break;
01346                 }
01347 
01348                 switch(transform)
01349                 {
01350                         case IDriver::Identity: break;
01351                         case IDriver::Inverse:
01352                                 mat.invert();
01353                         break;          
01354                         case IDriver::Transpose:
01355                                 mat.transpose();                                                                
01356                         break;
01357                         case IDriver::InverseTranspose:
01358                                 mat.invert();
01359                                 mat.transpose();                                
01360                         break;
01361                 }
01362                 mat.transpose();
01363                 float matDatas[16];
01364                 mat.get(matDatas);
01365                 nglSetInvariantEXT(_EVSConstantHandle + index, GL_FLOAT, matDatas);
01366                 nglSetInvariantEXT(_EVSConstantHandle + index + 1, GL_FLOAT, matDatas + 4);
01367                 nglSetInvariantEXT(_EVSConstantHandle + index + 2, GL_FLOAT, matDatas + 8);
01368                 nglSetInvariantEXT(_EVSConstantHandle + index + 3, GL_FLOAT, matDatas + 12);
01369         }                
01370 }
01371 
01372 // ***************************************************************************
01373 
01374 void CDriverGL::enableVertexProgramDoubleSidedColor(bool doubleSided)
01375 {
01376         // Vertex program exist ?
01377         if (_Extensions.NVVertexProgram)
01378         {
01379                 // change mode (not cached because supposed to be rare)
01380                 if(doubleSided)
01381                         glEnable (GL_VERTEX_PROGRAM_TWO_SIDE_NV);
01382                 else
01383                         glDisable (GL_VERTEX_PROGRAM_TWO_SIDE_NV);
01384         }       
01385 }
01386 
01387 
01388 // ***************************************************************************
01389 bool CDriverGL::supportVertexProgramDoubleSidedColor() const
01390 {
01391         // currenlty only supported by NV_VERTEX_PROGRAM
01392         return _Extensions.NVVertexProgram;
01393 }
01394 
01395 
01396 } // NL3D