# 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.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 "driver_opengl_vertex_buffer_hard.h"
00032 
00033 
00034 using namespace std;
00035 using namespace NLMISC;
00036 
00037 
00038 
00039 // ***************************************************************************
00040 // Flags for software vertex skinning.
00041 #define NL3D_DRV_SOFTSKIN_VNEEDCOMPUTE  3
00042 #define NL3D_DRV_SOFTSKIN_VMUSTCOMPUTE  1
00043 #define NL3D_DRV_SOFTSKIN_VCOMPUTED             0
00044 // 3 means "vertex may need compute".
00045 // 1 means "Primitive say vertex must be computed".
00046 // 0 means "vertex is computed".
00047 
00048 
00049 // 500K min.
00050 #define NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE               (512*1024)
00051 
00052 
00053 
00054 namespace NL3D
00055 {
00056 
00057 
00058 
00059 // ***************************************************************************
00060 bool CDriverGL::setupVertexBuffer(CVertexBuffer& VB)
00061 {
00062         // 1. Retrieve/Create driver shader.
00063         //==================================
00064         if (!VB.DrvInfos)
00065         {
00066                 // insert into driver list. (so it is deleted when driver is deleted).
00067                 ItVBDrvInfoPtrList      it= _VBDrvInfos.insert(_VBDrvInfos.end());
00068                 // create and set iterator, for future deletion.
00069                 *it= VB.DrvInfos= new CVBDrvInfosGL(this, it);
00070         }
00071 
00072         // 2. If necessary, do modifications.
00073         //==================================
00074         if( VB.getTouchFlags()!=0 )
00075         {
00076                 // nop
00077                 // OK!
00078                 VB.resetTouchFlags();
00079         }
00080 
00081 
00082         return true;
00083 }
00084 
00085 
00086 // ***************************************************************************
00087 bool CDriverGL::activeVertexBuffer(CVertexBuffer& VB, uint first, uint end)
00088 {
00089         // NB: must duplicate changes in activeVertexBufferHard()
00090 
00091         uint32  flags;
00092 
00093         if (!setupVertexBuffer(VB))
00094                 return false;
00095 
00096         if (VB.getNumVertices()==0)
00097                 return true;
00098 
00099         nlassert(end<=VB.getNumVertices());
00100         nlassert(first<=end);
00101 
00102         // Get VB flags, to setup matrixes and arrays.
00103         flags=VB.getVertexFormat();
00104 
00105 
00106         // 2. Setup Arrays.
00107         //===================
00108 
00109         // Fence mgt.
00110         fenceOnCurVBHardIfNeeded(NULL);
00111 
00112         // For MultiPass Material.
00113         _LastVB.setupVertexBuffer(VB);
00114 
00115         // Disable the current vertexBufferHard if setuped.
00116         if(_CurrentVertexBufferHard)
00117                 _CurrentVertexBufferHard->disable();
00118 
00119         // Setup the OpenGL arrays.
00120         setupGlArrays(_LastVB);
00121 
00122 
00123         return true;
00124 }
00125 
00126 
00127 // ***************************************************************************
00128 bool            CDriverGL::activeVertexBuffer(CVertexBuffer& VB)
00129 {
00130         return activeVertexBuffer(VB, 0, VB.getNumVertices());
00131 }
00132 
00133 
00134 // ***************************************************************************
00135 bool CDriverGL::render(CPrimitiveBlock& PB, CMaterial& Mat)
00136 {       
00137         // update matrix and Light in OpenGL if needed
00138         refreshRenderSetup();
00139 
00140         // setup material
00141         if ( !setupMaterial(Mat) )
00142                 return false;
00143 
00144 
00145         // render primitives.
00146         //==============================
00147         // start multipass.
00148         uint    nPass;
00149         nPass= beginMultiPass();
00150         // draw all passes.
00151         for(uint pass=0;pass<nPass; pass++)
00152         {
00153                 // setup the pass.
00154                 setupPass(pass);                
00155                 // draw the primitives.
00156                 if(PB.getNumTri()!=0)
00157                         glDrawElements(GL_TRIANGLES,3*PB.getNumTri(),GL_UNSIGNED_INT,PB.getTriPointer());
00158                 if(PB.getNumQuad()!=0)
00159                         glDrawElements(GL_QUADS,4*PB.getNumQuad(),GL_UNSIGNED_INT,PB.getQuadPointer());
00160                 if(PB.getNumLine()!=0)
00161                         glDrawElements(GL_LINES,2*PB.getNumLine(),GL_UNSIGNED_INT,PB.getLinePointer());
00162         }
00163         // end multipass.
00164         endMultiPass();
00165 
00166 
00167         // Profiling.
00168         _PrimitiveProfileIn.NLines+= PB.getNumLine();
00169         _PrimitiveProfileIn.NTriangles+= PB.getNumTri();
00170         _PrimitiveProfileIn.NQuads+= PB.getNumQuad();
00171         _PrimitiveProfileOut.NLines+= PB.getNumLine() * nPass;
00172         _PrimitiveProfileOut.NTriangles+= PB.getNumTri() * nPass;
00173         _PrimitiveProfileOut.NQuads+= PB.getNumQuad() * nPass;
00174 
00175         // We have render some prims. inform the VBHard.
00176         if(_CurrentVertexBufferHard)
00177                 _CurrentVertexBufferHard->GPURenderingAfterFence= true;
00178 
00179         return true;
00180 
00181 
00182 }
00183 
00184 
00185 // ***************************************************************************
00186 void    CDriverGL::renderTriangles(CMaterial& Mat, uint32 *tri, uint32 ntris)
00187 {
00188         // update matrix and Light in OpenGL if needed
00189         refreshRenderSetup();
00190 
00191         // setup material
00192         if ( !setupMaterial(Mat) )
00193                 return;
00194 
00195         
00196         // render primitives.
00197         //==============================
00198         // start multipass.
00199         uint    nPass;
00200         nPass= beginMultiPass();
00201         // draw all passes.
00202         for(uint pass=0;pass<nPass; pass++)
00203         {
00204                 // setup the pass.
00205                 setupPass(pass);
00206                 // draw the primitives.
00207                 if(ntris!=0)
00208                         glDrawElements(GL_TRIANGLES,3*ntris,GL_UNSIGNED_INT, tri);
00209         }
00210         // end multipass.
00211         endMultiPass();
00212 
00213 
00214         // Profiling.
00215         _PrimitiveProfileIn.NTriangles+= ntris;
00216         _PrimitiveProfileOut.NTriangles+= ntris * nPass;
00217 
00218         // We have render some prims. inform the VBHard.
00219         if(_CurrentVertexBufferHard)
00220                 _CurrentVertexBufferHard->GPURenderingAfterFence= true;
00221 }
00222 
00223 
00224 // ***************************************************************************
00225 void    CDriverGL::renderSimpleTriangles(uint32 *tri, uint32 ntris)
00226 {
00227         nlassert(ntris>0);
00228 
00229         // update matrix and Light in OpenGL if needed
00230         refreshRenderSetup();
00231 
00232 
00233         // Don't setup any material here.
00234         
00235         // render primitives.
00236         //==============================
00237         // NO MULTIPASS HERE!!
00238         // draw the primitives. (nb: ntrsi>0).
00239         glDrawElements(GL_TRIANGLES,3*ntris,GL_UNSIGNED_INT, tri);
00240 
00241         // Profiling.
00242         _PrimitiveProfileIn.NTriangles+= ntris;
00243         _PrimitiveProfileOut.NTriangles+= ntris;
00244 
00245         // We have render some prims. inform the VBHard.
00246         if(_CurrentVertexBufferHard)
00247                 _CurrentVertexBufferHard->GPURenderingAfterFence= true;
00248 }
00249 
00250 
00251 // ***************************************************************************
00252 void    CDriverGL::renderPoints(CMaterial& Mat, uint32 numPoints)
00253 {
00254         // update matrix and Light in OpenGL if needed
00255         refreshRenderSetup();
00256 
00257         // setup material
00258         if ( !setupMaterial(Mat) )
00259                 return; 
00260 
00261 
00262         // render primitives.
00263         //==============================
00264         // start multipass.
00265         uint    nPass;
00266         nPass= beginMultiPass();
00267         // draw all passes.
00268         for(uint pass=0;pass<nPass; pass++)
00269         {
00270                 // setup the pass.
00271                 setupPass(pass);
00272                 // draw the primitives.
00273                 if(numPoints)
00274                         glDrawArrays(GL_POINTS,0, numPoints);
00275         }
00276         // end multipass.
00277         endMultiPass();
00278 
00279 
00280         // Profiling.
00281         _PrimitiveProfileIn.NPoints+= numPoints;
00282         _PrimitiveProfileOut.NPoints+= numPoints * nPass;
00283 
00284         // We have render some prims. inform the VBHard.
00285         if(_CurrentVertexBufferHard)
00286                 _CurrentVertexBufferHard->GPURenderingAfterFence= true;
00287 }
00288 
00289 
00290 
00291 
00292 // ***************************************************************************
00293 void    CDriverGL::renderQuads(CMaterial& Mat, uint32 startIndex, uint32 numQuads)
00294 {
00295         // update matrix and Light in OpenGL if needed
00296         refreshRenderSetup();
00297 
00298         // setup material
00299         if ( !setupMaterial(Mat) )
00300                 return; 
00301 
00302 
00303         // render primitives.
00304         //==============================
00305         // start multipass.
00306         uint    nPass;
00307         nPass= beginMultiPass();
00308         // draw all passes.
00309         for(uint pass=0;pass<nPass; pass++)
00310         {
00311                 // setup the pass.
00312                 setupPass(pass);
00313                 // draw the primitives.
00314                 if(numQuads)
00315                         glDrawArrays(GL_QUADS, startIndex << 2, numQuads << 2) ;
00316         }
00317         // end multipass.
00318         endMultiPass();
00319 
00320 
00321         // Profiling.
00322         _PrimitiveProfileIn.NQuads  += numQuads ;
00323         _PrimitiveProfileOut.NQuads += numQuads  * nPass;
00324 
00325         // We have render some prims. inform the VBHard.
00326         if(_CurrentVertexBufferHard)
00327                 _CurrentVertexBufferHard->GPURenderingAfterFence= true;
00328 }
00329 
00330 
00331 // ***************************************************************************
00332 void            CDriverGL::setupUVPtr(uint stage, CVertexBufferInfo &VB, uint uvId)
00333 {
00334         // sould not be called with vertex program Array setuped.
00335         nlassert(!_LastSetupGLArrayVertexProgram);
00336 
00337         _DriverGLStates.clientActiveTextureARB(stage);
00338         if (VB.VertexFormat & (CVertexBuffer::TexCoord0Flag<<uvId))
00339         {
00340                 // Check type, if not supported, just ignore
00341                 if (VB.Type[CVertexBuffer::TexCoord0+uvId]==CVertexBuffer::Float2)
00342                 {
00343                         _DriverGLStates.enableTexCoordArray(true);
00344                         // Setup ATI VBHard or std ptr.
00345                         if(VB.ATIVBHardMode)
00346                                 nglArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, VB.VertexSize, 
00347                                         VB.ATIVertexObjectId, VB.ATIValueOffset[CVertexBuffer::TexCoord0+uvId]);
00348                         else
00349                                 glTexCoordPointer(2,GL_FLOAT,VB.VertexSize,VB.ValuePtr[CVertexBuffer::TexCoord0+uvId]);
00350                 }
00351                 else
00352                 {
00353                         _DriverGLStates.enableTexCoordArray(false);
00354                 }
00355         }
00356         else
00357                 _DriverGLStates.enableTexCoordArray(false);
00358 }
00359 
00360 
00361 // ***************************************************************************
00362 void            CDriverGL::mapTextureStageToUV(uint stage, uint uv)
00363 {
00364         // Just call it for last VertexBuffer setuped.
00365         setupUVPtr(stage, _LastVB, uv);
00366 }
00367 
00368 
00369 
00370 // ***************************************************************************
00371 // ***************************************************************************
00372 // VertexBufferHard
00373 // ***************************************************************************
00374 // ***************************************************************************
00375 
00376 
00377 // ***************************************************************************
00378 bool                    CDriverGL::supportVertexBufferHard() const
00379 {
00380         return _SupportVBHard;
00381 }
00382 
00383 
00384 // ***************************************************************************
00385 bool                    CDriverGL::slowUnlockVertexBufferHard() const
00386 {
00387         return _SlowUnlockVBHard;
00388 }
00389 
00390 
00391 // ***************************************************************************
00392 uint                    CDriverGL::getMaxVerticesByVertexBufferHard() const
00393 {
00394         return _MaxVerticesByVBHard;
00395 }
00396 
00397 
00398 // ***************************************************************************
00399 IVertexBufferHard       *CDriverGL::createVertexBufferHard(uint16 vertexFormat, const uint8 *typeArray, uint32 numVertices, IDriver::TVBHardType vbType)
00400 {
00401         // choose the VertexArrayRange of good type
00402         IVertexArrayRange       *vertexArrayRange= NULL;
00403         switch(vbType)
00404         {
00405         case IDriver::VBHardAGP: 
00406                 vertexArrayRange= _AGPVertexArrayRange;
00407                 break;
00408         case IDriver::VBHardVRAM:
00409                 vertexArrayRange= _VRAMVertexArrayRange;
00410                 break;
00411         };
00412 
00413         // If this one at least created (an extension support it).
00414         if( !vertexArrayRange )
00415                 return NULL;
00416         else
00417         {
00418                 // check max vertex
00419                 if(numVertices > _MaxVerticesByVBHard)
00420                         return NULL;
00421 
00422                 // Create a CVertexBufferHardGL
00423                 IVertexBufferHardGL             *vb;
00424                 // let the VAR create the vbhard.
00425                 vb= vertexArrayRange->createVBHardGL(vertexFormat, typeArray, numVertices);
00426                 // if fails
00427                 if(!vb)
00428                 {
00429                         return NULL;
00430                 }
00431                 else
00432                 {
00433                         // insert in list.
00434                         return _VertexBufferHardSet.insert(vb);
00435                 }
00436         }
00437 }
00438 
00439 
00440 // ***************************************************************************
00441 void                    CDriverGL::deleteVertexBufferHard(IVertexBufferHard *VB)
00442 {
00443         // If one _CurrentVertexBufferHard enabled, first End its drawning, and disable it.
00444         // This is very important, because after deletion, the space is free. 
00445         // If the GPU has not finisehd his drawing, and if any allocation occurs on this free space, and if 
00446         // the user locks to fill this space (feww!) Then some data crash may results....
00447         if(_CurrentVertexBufferHard)
00448         {
00449                 // Must ensure it has ended any drawing
00450                 _CurrentVertexBufferHard->lock();
00451                 _CurrentVertexBufferHard->unlock();
00452                 // disable the VBHard.
00453                 _CurrentVertexBufferHard->disable();
00454         }
00455 
00456         // Then just delete the VBuffer hard from list.
00457         _VertexBufferHardSet.erase(safe_cast<IVertexBufferHardGL*>(VB));
00458 }
00459 
00460 
00461 
00462 // ***************************************************************************
00463 void                    CDriverGL::activeVertexBufferHard(IVertexBufferHard *iVB)
00464 {
00465         // NB: must duplicate changes in activeVertexBuffer()
00466 
00467         nlassert(iVB);
00468         IVertexBufferHardGL             *VB= safe_cast<IVertexBufferHardGL*>(iVB);
00469 
00470         uint32  flags;
00471 
00472         if (VB->getNumVertices()==0)
00473                 return;
00474 
00475         // Get VB flags, to setup matrixes and arrays.
00476         flags=VB->getVertexFormat();
00477 
00478 
00479         // 2. Setup Arrays.
00480         //===================
00481 
00482         // Fence mgt.
00483         fenceOnCurVBHardIfNeeded(VB);
00484 
00485         // For MultiPass Material.
00486         _LastVB.setupVertexBufferHard(*VB);
00487 
00488         // Enable the vertexArrayRange of this array.
00489         VB->enable();
00490 
00491         // Setup the OpenGL arrays.
00492         setupGlArrays(_LastVB);
00493 
00494 }
00495 
00496 
00497 // ***************************************************************************
00498 const uint              CDriverGL::NumCoordinatesType[CVertexBuffer::NumType]=
00499 {
00500         1,      // Double1
00501         1,      // Float1
00502         1,      // Short1
00503         2,      // Double2
00504         2,      // Float2
00505         2,      // Short2
00506         3,      // Double3
00507         3,      // Float3
00508         3,      // Short3
00509         4,      // Double4
00510         4,      // Float4
00511         4,      // Short4
00512         4       // UChar4
00513 };
00514 
00515 
00516 // ***************************************************************************
00517 const uint              CDriverGL::GLType[CVertexBuffer::NumType]=
00518 {
00519         GL_DOUBLE,      // Double1
00520         GL_FLOAT,       // Float1
00521         GL_SHORT,       // Short1
00522         GL_DOUBLE,      // Double2
00523         GL_FLOAT,       // Float2
00524         GL_SHORT,       // Short2
00525         GL_DOUBLE,      // Double3
00526         GL_FLOAT,       // Float3
00527         GL_SHORT,       // Short3
00528         GL_DOUBLE,      // Double4
00529         GL_FLOAT,       // Float4
00530         GL_SHORT,       // Short4
00531         GL_UNSIGNED_BYTE        // UChar4
00532 };
00533 
00534 
00535 // ***************************************************************************
00536 const uint              CDriverGL::GLVertexAttribIndex[CVertexBuffer::NumValue]=
00537 {
00538         0,      // Position
00539         2,      // Normal
00540         8,      // TexCoord0
00541         9,      // TexCoord1
00542         10,     // TexCoord2
00543         11,     // TexCoord3
00544         12,     // TexCoord4
00545         13,     // TexCoord5
00546         14,     // TexCoord6
00547         15,     // TexCoord7
00548         3,      // PrimaryColor
00549         4,      // SecondaryColor
00550         1,      // Weight
00551         6,      // Empty (PaletteSkin)
00552         5,      // Fog
00553         7,      // Empty
00554 };
00555 
00556 
00557 
00558 // ***************************************************************************
00559 void            CDriverGL::setupGlArraysStd(CVertexBufferInfo &vb)
00560 {
00561         uint32  flags= vb.VertexFormat;
00562         // setup vertex ptr.
00563         //-----------
00564         uint numVertexCoord = CVertexBuffer::NumComponentsType[vb.Type[CVertexBuffer::Position]];
00565         nlassert (numVertexCoord >= 2);
00566 
00567         _DriverGLStates.enableVertexArray(true);
00568         // Setup ATI VBHard or std ptr.
00569         if(vb.ATIVBHardMode)
00570                 nglArrayObjectATI(GL_VERTEX_ARRAY, numVertexCoord, GL_FLOAT, vb.VertexSize, 
00571                         vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::Position]);
00572         else
00573                 glVertexPointer(numVertexCoord, GL_FLOAT, vb.VertexSize, vb.ValuePtr[CVertexBuffer::Position]);
00574 
00575 
00576         // setup normal ptr.
00577         //-----------
00578         // Check for normal param in vertex buffer
00579         if (flags & CVertexBuffer::NormalFlag)
00580         {
00581                 // Check type
00582                 nlassert (vb.Type[CVertexBuffer::Normal]==CVertexBuffer::Float3);
00583 
00584                 _DriverGLStates.enableNormalArray(true);
00585                 // Setup ATI VBHard or std ptr.
00586                 if(vb.ATIVBHardMode)
00587                         nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, vb.VertexSize, 
00588                                 vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::Normal]);
00589                 else
00590                         glNormalPointer(GL_FLOAT, vb.VertexSize, vb.ValuePtr[CVertexBuffer::Normal]);
00591         }
00592         else
00593         {
00594                 _DriverGLStates.enableNormalArray(false);
00595         }
00596 
00597 
00598         // Setup Color
00599         //-----------
00600         // Check for color param in vertex buffer
00601         if (flags & CVertexBuffer::PrimaryColorFlag)
00602         {
00603                 // Check type
00604                 nlassert (vb.Type[CVertexBuffer::PrimaryColor]==CVertexBuffer::UChar4);
00605 
00606                 _DriverGLStates.enableColorArray(true);
00607                 // Setup ATI VBHard or std ptr.
00608                 if(vb.ATIVBHardMode)
00609                         nglArrayObjectATI(GL_COLOR_ARRAY, 4, GL_UNSIGNED_BYTE, vb.VertexSize, 
00610                                 vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::PrimaryColor]);
00611                 else
00612                         glColorPointer(4,GL_UNSIGNED_BYTE, vb.VertexSize, vb.ValuePtr[CVertexBuffer::PrimaryColor]);
00613         }
00614         else
00615                 _DriverGLStates.enableColorArray(false);
00616 
00617 
00618         // Setup Uvs
00619         //-----------
00620         for(sint i=0; i<inlGetNumTextStages(); i++)
00621         {
00622                 // normal behavior: each texture has its own UV.
00623                 setupUVPtr(i, vb, i);
00624         }
00625 }
00626 
00627 
00628 
00629 // ***************************************************************************
00630 void            CDriverGL::toggleGlArraysForNVVertexProgram()
00631 {
00632         // If change of setup type, must disable olds.
00633         //=======================
00634 
00635         // If last was a VertexProgram setup, and now it is a standard GL array setup.
00636         if( _LastSetupGLArrayVertexProgram && !isVertexProgramEnabled () )
00637         {
00638                                 
00639                 // Disable all VertexAttribs.
00640                 for (uint value=0; value<CVertexBuffer::NumValue; value++)
00641                 {
00642                         // Index
00643                         uint glIndex=GLVertexAttribIndex[value];
00644                         _DriverGLStates.enableVertexAttribArray(glIndex, false);
00645                 }
00646                 _DriverGLStates.enableColorArray(false);
00647                 _DriverGLStates.enableSecondaryColorArray(false);               
00648 
00649                 // no more a vertex program setup.
00650                 _LastSetupGLArrayVertexProgram= false;
00651         }
00652 
00653         // If last was a standard GL array setup, and now it is a VertexProgram setup.
00654         if( !_LastSetupGLArrayVertexProgram && isVertexProgramEnabled () )
00655         {
00656                 // Disable all standards ptrs.
00657                 _DriverGLStates.enableVertexArray(false);
00658                 _DriverGLStates.enableNormalArray(false);
00659                 _DriverGLStates.enableColorArray(false);
00660                 for(sint i=0; i<inlGetNumTextStages(); i++)
00661                 {
00662                         _DriverGLStates.clientActiveTextureARB(i);
00663                         _DriverGLStates.enableTexCoordArray(false);
00664                 }
00665 
00666 
00667                 // now, vertex program setup.
00668                 _LastSetupGLArrayVertexProgram= true;
00669         }
00670 }
00671 
00672 
00673 // ***************************************************************************
00674 void            CDriverGL::toggleGlArraysForEXTVertexShader()
00675 {
00676         // If change of setup type, must disable olds.
00677         //=======================
00678 
00679 
00680         // If last was a VertexProgram setup, and now it is a standard GL array setup.
00681         if( _LastSetupGLArrayVertexProgram && !isVertexProgramEnabled () )
00682         {
00683                 CVertexProgram *vp = _LastSetuppedVP;
00684                 if (vp)
00685                 {               
00686                         CVertexProgamDrvInfosGL *drvInfo = NLMISC::safe_cast<CVertexProgamDrvInfosGL *>((IVertexProgramDrvInfos *) vp->_DrvInfo);
00687                         if (drvInfo)
00688                         {
00689                                 // Disable all VertexAttribs.
00690                                 for (uint value=0; value<CVertexBuffer::NumValue; value++)
00691                                 {
00692                                         _DriverGLStates.enableVertexAttribArrayForEXTVertexShader(value, false, drvInfo->Variants);
00693                                 }
00694                         }                                                                               
00695                 }
00696                 // no more a vertex program setup.
00697                 _LastSetupGLArrayVertexProgram= false;
00698         }
00699 
00700         // If last was a standard GL array setup, and now it is a VertexProgram setup.
00701         if( !_LastSetupGLArrayVertexProgram && isVertexProgramEnabled () )
00702         {
00703                 // Disable all standards ptrs.
00704                 _DriverGLStates.enableVertexArray(false);
00705                 _DriverGLStates.enableNormalArray(false);
00706                 _DriverGLStates.enableColorArray(false);
00707                 for(sint i=0; i<inlGetNumTextStages(); i++)
00708                 {
00709                         _DriverGLStates.clientActiveTextureARB(i);
00710                         _DriverGLStates.enableTexCoordArray(false);
00711                 }
00712 
00713 
00714                 // now, vertex program setup.
00715                 _LastSetupGLArrayVertexProgram= true;
00716         }
00717 }
00718 
00719 // ***************************************************************************
00720 void            CDriverGL::setupGlArraysForNVVertexProgram(CVertexBufferInfo &vb)
00721 {                       
00722         uint32  flags= vb.VertexFormat;
00723         
00724         // For each value
00725         for (uint value=0; value<CVertexBuffer::NumValue; value++)
00726         {
00727                 // Flag
00728                 uint16 flag=1<<value;
00729 
00730                 // Type
00731                 CVertexBuffer::TType type=vb.Type[value];
00732 
00733                 // Index
00734                 uint glIndex=GLVertexAttribIndex[value];
00735 
00736                 // Not setuped value and used
00737                 if (flags & flag)
00738                 {
00739                         /* OpenGL Driver Bug with VertexProgram, UChar4 type, and VertexArrayRange.
00740                                 Don't work and lead to very poor performance (1/10) (VAR is "disabled").
00741                         */
00742                         // Test if can use glColorPointer() / glSecondaryColorPointerEXT() instead.
00743                         if( (glIndex==3 || glIndex==4) )
00744                         {
00745                                 if( type == CVertexBuffer::UChar4 )
00746                                 {
00747                                         // Must disable VertexAttrib array.
00748                                         _DriverGLStates.enableVertexAttribArray(glIndex, false);
00749 
00750                                         // Active this value, with standard gl calls
00751                                         if(glIndex==3)
00752                                         {
00753                                                 // Primary color
00754                                                 _DriverGLStates.enableColorArray(true);
00755                                                 glColorPointer(4,GL_UNSIGNED_BYTE, vb.VertexSize, vb.ValuePtr[value]);
00756                                         }
00757                                         else
00758                                         {
00759                                                 // Secondary color
00760                                                 _DriverGLStates.enableSecondaryColorArray(true);
00761                                                 nglSecondaryColorPointerEXT(4,GL_UNSIGNED_BYTE, vb.VertexSize, vb.ValuePtr[value]);
00762                                         }
00763                                 }
00764                                 else
00765                                 {
00766                                         // Can use normal VertexAttribArray.
00767                                         // Disable first standard Color Array.
00768                                         if(glIndex==3)
00769                                                 _DriverGLStates.enableColorArray(false);
00770                                         else
00771                                                 _DriverGLStates.enableSecondaryColorArray(false);
00772 
00773                                         // Active this value
00774                                         _DriverGLStates.enableVertexAttribArray(glIndex, true);
00775                                         nglVertexAttribPointerNV (glIndex, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00776                                 }
00777                         }
00778                         // Else normal case, can't do anything for other values with UChar4....
00779                         else
00780                         {
00781                                 // Active this value
00782                                 _DriverGLStates.enableVertexAttribArray(glIndex, true);
00783                                 nglVertexAttribPointerNV (glIndex, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00784                         }
00785                 }
00786                 else
00787                 {
00788                         _DriverGLStates.enableVertexAttribArray(glIndex, false);
00789                         /* OpenGL Driver Bug with VertexProgram, UChar4 type, and VertexArrayRange.
00790                                 Must also disable colorArray in standard gl calls.
00791                         */
00792                         if(glIndex==3)
00793                                 _DriverGLStates.enableColorArray(false);
00794                         else if(glIndex==4)
00795                                 _DriverGLStates.enableSecondaryColorArray(false);
00796                 }
00797         }
00798 }
00799 
00800 
00801 // ***************************************************************************
00802 void            CDriverGL::setupGlArraysForEXTVertexShader(CVertexBufferInfo &vb)
00803 {
00804 
00805         CVertexProgram *vp = _LastSetuppedVP;
00806         if (!vp) return;                
00807         CVertexProgamDrvInfosGL *drvInfo = NLMISC::safe_cast<CVertexProgamDrvInfosGL *>((IVertexProgramDrvInfos *) vp->_DrvInfo);
00808         if (!drvInfo) return;
00809         
00810         uint32  flags= vb.VertexFormat;
00811 
00812         // For each value
00813         for (uint value=0; value<CVertexBuffer::NumValue; value++)
00814         {
00815                 // Flag
00816                 uint16 flag=1<<value;
00817 
00818                 // Type
00819                 CVertexBuffer::TType type=vb.Type[value];
00820 
00821                 // Index
00822                 uint glIndex=GLVertexAttribIndex[value];
00823 
00824                 // Not setuped value and used
00825                 if (flags & flag & drvInfo->UsedVertexComponents)
00826                 {                                               
00827                         _DriverGLStates.enableVertexAttribArrayForEXTVertexShader(glIndex, true, drvInfo->Variants);
00828                         // use variant or open gl standard array
00829                         switch(value)
00830                         {
00831                                         case CVertexBuffer::Position: // position 
00832                                         {                                       
00833                                                 nlassert(NumCoordinatesType[type] >= 2);
00834                                                 if(vb.ATIVBHardMode) nglArrayObjectATI(GL_VERTEX_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::Position]);
00835                                             else                 glVertexPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00836                                         }
00837                                         break;
00838                                         case CVertexBuffer::Weight: // skin weight
00839                                         {
00840                                                 nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported
00841                                                 if(vb.ATIVBHardMode) nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSSkinWeightVariant], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::Weight]);
00842                                             else                 nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSSkinWeightVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00843                                         }
00844                                         break;
00845                                         case CVertexBuffer::Normal: // normal
00846                                         {
00847                                                 nlassert(NumCoordinatesType[type] == 3); // must have 3 components for normals
00848                                                 if(vb.ATIVBHardMode) nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[value]);
00849                                             else                 glNormalPointer(GLType[type], vb.VertexSize, vb.ValuePtr[CVertexBuffer::Normal]);                                              
00850                                         }
00851                                         break;
00852                                         case CVertexBuffer::PrimaryColor: // color
00853                                         {
00854                                                 nlassert(NumCoordinatesType[type] >= 3); // must have 3 or 4 components for primary color
00855                                                 if(vb.ATIVBHardMode) nglArrayObjectATI(GL_COLOR_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::PrimaryColor]);
00856                                             else                 glColorPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00857                                         }                                               
00858                                         break;
00859                                         case CVertexBuffer::SecondaryColor: // secondary color
00860                                         {                                                               
00861                                                 // implemented using a variant, as not available with EXTVertexShader
00862                                                 nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported
00863                                                 if(vb.ATIVBHardMode) nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSSecondaryColorVariant], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::SecondaryColor]);
00864                                             else                 nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSSecondaryColorVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]);                                                                                                 
00865                                         }                                               
00866                                         break;
00867                                         case CVertexBuffer::Fog: // fog coordinate
00868                                         {
00869                                                 // implemented using a variant
00870                                                 nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported
00871                                                 if(vb.ATIVBHardMode) nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSFogCoordsVariant], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::Fog]);
00872                                                 else                 nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSFogCoordsVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00873                                         }                                               
00874                                         break;
00875                                         case CVertexBuffer::PaletteSkin: // palette skin
00876                                         {                                       
00877                                                 // implemented using a variant
00878                                                 nlassert(NumCoordinatesType[type] == 4); // variant, only 4 component supported
00879                                                 if(vb.ATIVBHardMode) nglVariantArrayObjectATI(drvInfo->Variants[CDriverGL::EVSPaletteSkinVariant], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[CVertexBuffer::PaletteSkin]);
00880                                                 else                 nglVariantPointerEXT(drvInfo->Variants[CDriverGL::EVSPaletteSkinVariant], GLType[type], vb.VertexSize, vb.ValuePtr[value]);
00881                                         }
00882                                         break;
00883                                         case CVertexBuffer::Empty: // empty
00884                                                 nlstop
00885                                         break;
00886                                         case CVertexBuffer::TexCoord0:
00887                                         case CVertexBuffer::TexCoord1:
00888                                         case CVertexBuffer::TexCoord2:
00889                                         case CVertexBuffer::TexCoord3:
00890                                         case CVertexBuffer::TexCoord4:
00891                                         case CVertexBuffer::TexCoord5:
00892                                         case CVertexBuffer::TexCoord6:
00893                                         case CVertexBuffer::TexCoord7:
00894                                         {                       
00895                                                 _DriverGLStates.clientActiveTextureARB(value - CVertexBuffer::TexCoord0);
00896                                                 if(vb.ATIVBHardMode) nglArrayObjectATI(GL_TEXTURE_COORD_ARRAY, NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ATIVertexObjectId, vb.ATIValueOffset[value]);
00897                                                 else glTexCoordPointer(NumCoordinatesType[type], GLType[type], vb.VertexSize, vb.ValuePtr[value ]);
00898                                         }
00899                                         break;
00900                                         default:
00901                                                 nlstop; // invalid value
00902                                         break;                                  
00903                         }                       
00904                 }
00905                 else
00906                 {
00907                         _DriverGLStates.enableVertexAttribArrayForEXTVertexShader(glIndex, false, drvInfo->Variants);
00908                 }
00909         }       
00910 }
00911 
00912 
00913 
00914 // ***************************************************************************
00915 void            CDriverGL::setupGlArrays(CVertexBufferInfo &vb)
00916 {
00917         uint32  flags= vb.VertexFormat;
00918 
00923         // Standard case (NVVertexProgram or no vertex program case)
00924         if (_Extensions.NVVertexProgram || !_Extensions.EXTVertexShader)
00925         {       
00926                 toggleGlArraysForNVVertexProgram();
00927                 // Use a vertex program ?
00928                 if (!isVertexProgramEnabled ())
00929                 {
00930                         setupGlArraysStd(vb);
00931                 }
00932                 else
00933                 {               
00934                         setupGlArraysForNVVertexProgram(vb);
00935                 }
00936         }       
00937         else // EXTVertexShader case
00938         {
00939                 toggleGlArraysForEXTVertexShader();
00940                 // Use a vertex program ?
00941                 if (!isVertexProgramEnabled ())
00942                 {
00943                         setupGlArraysStd(vb);
00944                 }
00945                 else
00946                 {               
00947                         setupGlArraysForEXTVertexShader(vb);
00948                 }               
00949         }
00950         
00951         // Reset specials flags.
00952         _LastVertexSetupIsLightMap= false;
00953 }
00954 
00955 
00956 // ***************************************************************************
00957 void            CVertexBufferInfo::setupVertexBuffer(CVertexBuffer &vb)
00958 {
00959         sint    i;
00960         uint    flags= vb.getVertexFormat();
00961         VertexFormat= flags;
00962         VertexSize= vb.getVertexSize();
00963         NumVertices= vb.getNumVertices();
00964         NumWeight= vb.getNumWeight();
00965 
00966         // No VBhard.
00967         ATIVBHardMode= false;
00968 
00969         // Get value pointer
00970         for (i=0; i<CVertexBuffer::NumValue; i++)
00971         {
00972                 // Value used ?
00973                 if (VertexFormat&(1<<i))
00974                 {
00975                         // Get the pointer
00976                         ValuePtr[i]=vb.getValueEx ((CVertexBuffer::TValue)i);
00977 
00978                         // Type of the value
00979                         Type[i]=vb.getValueType (i);
00980                 }
00981         }
00982 }
00983 
00984 
00985 // ***************************************************************************
00986 void            CVertexBufferInfo::setupVertexBufferHard(IVertexBufferHardGL &vb)
00987 {
00988         sint    i;
00989         uint    flags= vb.getVertexFormat();
00990         VertexFormat= flags;
00991         VertexSize= vb.getVertexSize();
00992         NumVertices= vb.getNumVertices();
00993         NumWeight= vb.getNumWeight();
00994 
00995         // Not ATI VBHard by default
00996         ATIVBHardMode= false;
00997 
00998         // Setup differs from ATI or NVidia VBHard.
00999         if(vb.NVidiaVertexBufferHard)
01000         {
01001                 CVertexBufferHardGLNVidia       &vbHardNV= static_cast<CVertexBufferHardGLNVidia&>(vb);
01002 
01003                 // Get value pointer
01004                 for (i=0; i<CVertexBuffer::NumValue; i++)
01005                 {
01006                         // Value used ?
01007                         if (VertexFormat&(1<<i))
01008                         {
01009                                 // Get the pointer
01010                                 ValuePtr[i]= vbHardNV.getNVidiaValueEx(i);
01011 
01012                                 // Type of the value
01013                                 Type[i]= vbHardNV.getValueType (i);
01014                         }
01015                 }
01016         }
01017         else
01018         {
01019                 nlassert(vb.ATIVertexBufferHard);
01020                 CVertexBufferHardGLATI  &vbHardATI= static_cast<CVertexBufferHardGLATI&>(vb);
01021 
01022                 // special setup in setupGlArrays()...
01023                 ATIVBHardMode= true;
01024 
01025                 // store the VertexObject Id.
01026                 ATIVertexObjectId= vbHardATI.getATIVertexObjectId();
01027 
01028                 // Get value offset
01029                 for (i=0; i<CVertexBuffer::NumValue; i++)
01030                 {
01031                         // Value used ?
01032                         if (VertexFormat&(1<<i))
01033                         {
01034                                 // Get the pointer
01035                                 ATIValueOffset[i]= vbHardATI.getATIValueOffset(i);
01036 
01037                                 // Type of the value
01038                                 Type[i]= vbHardATI.getValueType (i);
01039                         }
01040                 }
01041         }
01042 }
01043 
01044 
01045 
01046 // ***************************************************************************
01047 void                    CDriverGL::resetVertexArrayRange()
01048 {
01049         if(_CurrentVertexBufferHard)
01050         {
01051                 // Must ensure it has ended any drawing
01052                 _CurrentVertexBufferHard->lock();
01053                 _CurrentVertexBufferHard->unlock();
01054                 // disable it
01055                 _CurrentVertexBufferHard->disable();
01056         }
01057         // Clear any VertexBufferHard created.
01058         _VertexBufferHardSet.clear();
01059 
01060         // After, Clear the 2 vertexArrayRange, if any.
01061         if(_AGPVertexArrayRange)
01062                 _AGPVertexArrayRange->free();
01063         if(_VRAMVertexArrayRange)
01064                 _VRAMVertexArrayRange->free();
01065 }
01066 
01067 
01068 // ***************************************************************************
01069 bool                    CDriverGL::initVertexArrayRange(uint agpMem, uint vramMem)
01070 {
01071         if(!supportVertexBufferHard())
01072                 return false;
01073 
01074         // must be supported
01075         if(!_AGPVertexArrayRange || !_VRAMVertexArrayRange)
01076                 return false;
01077 
01078         // First, reset any VBHard created.
01079         resetVertexArrayRange();
01080         bool    ok= true;
01081 
01082         // Try to allocate AGPMemory.
01083         if(agpMem>0)
01084         {
01085                 agpMem&= ~15;   // ensure 16-bytes aligned mem count (maybe usefull :) ).
01086                 agpMem= max(agpMem, (uint)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE);
01087                 while(agpMem>= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
01088                 {
01089                         if(_AGPVertexArrayRange->allocate(agpMem, IDriver::VBHardAGP))
01090                         {
01091                                 nlinfo("VAR: %.d vertices supported", _MaxVerticesByVBHard);
01092                                 nlinfo("VAR: Success to allocate %.1f Mo of AGP VAR Ram", agpMem / 1000000.f);
01093                                 break;
01094                         }
01095                         else
01096                         {
01097                                 agpMem/=2;
01098                                 agpMem &=~15;
01099                         }
01100                 }
01101 
01102                 if(agpMem< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
01103                 {
01104                         nlinfo("VAR: %.d vertices supported", _MaxVerticesByVBHard);
01105                         nlinfo("VAR: Failed to allocate %.1f Mo of AGP VAR Ram", NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE / 1000000.f);
01106                         ok= false;
01107                 }
01108         }
01109 
01110 
01111         // Try to allocate VRAMMemory.
01112         if(vramMem>0)
01113         {
01114                 vramMem&= ~15;  // ensure 16-bytes aligned mem count (maybe usefull :) ).
01115                 vramMem= max(vramMem, (uint)NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE);
01116                 while(vramMem>= NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
01117                 {
01118                         if(_VRAMVertexArrayRange->allocate(vramMem, IDriver::VBHardVRAM))
01119                                 break;
01120                         else
01121                         {
01122                                 vramMem/=2;
01123                                 vramMem &=~15;
01124                         }
01125                 }
01126 
01127                 if(vramMem< NL3D_DRV_VERTEXARRAY_MINIMUM_SIZE)
01128                 {
01129                         ok= false;
01130                 }
01131         }
01132 
01133 
01134         return ok;
01135 }
01136 
01137 
01138 // ***************************************************************************
01139 void                            CDriverGL::fenceOnCurVBHardIfNeeded(IVertexBufferHardGL *newVBHard)
01140 {
01141         // If old is not a VBHard, or if not a NVidia VBHard, no-op.
01142         if( _CurrentVertexBufferHard==NULL || !_CurrentVertexBufferHard->NVidiaVertexBufferHard )
01143                 return;
01144 
01145         // if we do not activate the same (NB: newVBHard==NULL if not a VBHard).
01146         if(_CurrentVertexBufferHard!=newVBHard)
01147         {
01148                 // get NVidia interface
01149                 CVertexBufferHardGLNVidia       *vbHardNV= static_cast<CVertexBufferHardGLNVidia*>(_CurrentVertexBufferHard);
01150 
01151                 // If some render() have been done with this VB.
01152                 if( vbHardNV->GPURenderingAfterFence )
01153                 {
01154                         // If an old fence is activated, we wait for him.
01155                         /* NB: performance issue: maybe a wait for nothing in some cases like this one:
01156                                 render with VBHard_A    ---- end with a fence
01157                                 render with VBHard_B    ....
01158                                 render with VBHard_A    ---- end: must finish prec fence before setting a new one.
01159 
01160                                 This is not a hard issue, if we suppose first A is finished to be rendered during render of VBHard_B.
01161                         */
01162                         vbHardNV->finishFence();
01163                         // Since we won't work with this VB for a long time, we set a fence.
01164                         vbHardNV->setFence();
01165                         vbHardNV->GPURenderingAfterFence= false;
01166                 }
01167         }
01168 }
01169 
01170 
01171 } // NL3D