render_trav.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/3d/render_trav.h"
00027 #include "nel/3d/hrc_trav.h"
00028 #include "nel/3d/clip_trav.h"
00029 #include "nel/3d/light_trav.h"
00030 #include "nel/3d/driver.h"
00031 #include "nel/3d/light.h"
00032 #include "nel/3d/skeleton_model.h"
00033 #include "nel/3d/scene.h"
00034 #include "nel/3d/coarse_mesh_manager.h"
00035 #include "nel/3d/lod_character_manager.h"
00036 #include "nel/3d/water_model.h"
00037 #include "nel/3d/water_shape.h"
00038 #include "nel/misc/hierarchical_timer.h"
00039 
00040 #include "nel/3d/transform.h"
00041 #include "nel/misc/fast_floor.h"
00042 #include "nel/3d/vertex_stream_manager.h"
00043 #include "nel/3d/landscape_model.h"
00044 #include "nel/3d/shape_bank.h"
00045 
00046 using namespace std;
00047 using namespace NLMISC;
00048 
00049 namespace   NL3D
00050 {
00051 
00052 // default is undefined, allows to see which CTransformShape are displayed in a scene, useful for debugging
00053 //#define NL_DEBUG_RENDER_TRAV
00054 
00055 
00056 
00057 
00058 
00059 
00060 // ***************************************************************************
00061 // ***************************************************************************
00062 // CRenderTrav
00063 // ***************************************************************************
00064 // ***************************************************************************
00065 
00066 
00067 // ***************************************************************************
00068 CRenderTrav::CRenderTrav()
00069 {
00070     RenderList.resize(1024);
00071     _CurrentNumVisibleModels= 0;
00072     _MaxTransparencyPriority = 0;
00073     OrderOpaqueList.init(1024);
00074     setupTransparencySorting();
00075     Driver = NULL;
00076     _CurrentPassOpaque = true;
00077 
00078     _CacheLightContribution= NULL;
00079 
00080     // Default light Setup.
00081     LightingSystemEnabled= false;
00082     AmbientGlobal= CRGBA(50, 50, 50);
00083     SunAmbient= CRGBA::Black;
00084     SunDiffuse= SunSpecular= CRGBA::White;
00085     _SunDirection.set(0, 0.5, -0.5);
00086     _SunDirection.normalize();
00087 
00088     _StrongestLightTouched = true;
00089 
00090     _MeshSkinManager= NULL;
00091     _ShadowMeshSkinManager= NULL;
00092 
00093     _LayersRenderingOrder= true;
00094     _FirstWaterModel = NULL;
00095 }
00096 
00097 
00098 
00099 
00100 
00101 // ***************************************************************************
00102 void        CRenderTrav::traverse(UScene::TRenderPart renderPart, bool newRender)
00103 {
00104     #ifdef NL_DEBUG_RENDER_TRAV
00105         nlwarning("Render trave begin");
00106     #endif
00107     H_AUTO( NL3D_TravRender );
00108     if (getDriver()->isLost()) return; // device is lost so no need to render anything
00109     CTravCameraScene::update();
00110     // Bind to Driver.
00111     setupDriverCamera();
00112     getDriver()->setupViewport(_Viewport);
00113 
00114     // reset the light setup, and set global ambient.
00115     resetLightSetup();
00116     if (newRender)
00117     {
00118 
00119         // reset the Skin manager, if needed
00120         if(_MeshSkinManager)
00121         {
00122             if(Driver!=_MeshSkinManager->getDriver())
00123             {
00124                 _MeshSkinManager->release();
00125                 _MeshSkinManager->init(Driver,
00126                     NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT,
00127                     NL3D_MESH_SKIN_MANAGER_MAXVERTICES,
00128                     NL3D_MESH_SKIN_MANAGER_NUMVB,
00129                     "MRMSkinVB", true);
00130             }
00131         }
00132 
00133         // Same For Shadow ones. NB: use AuxDriver here!!!
00134         if(_ShadowMeshSkinManager)
00135         {
00136             if(getAuxDriver()!=_ShadowMeshSkinManager->getDriver())
00137             {
00138                 _ShadowMeshSkinManager->release();
00139                 _ShadowMeshSkinManager->init(getAuxDriver(),
00140                     NL3D_SHADOW_MESH_SKIN_MANAGER_VERTEXFORMAT,
00141                     NL3D_SHADOW_MESH_SKIN_MANAGER_MAXVERTICES,
00142                     NL3D_SHADOW_MESH_SKIN_MANAGER_NUMVB,
00143                     "ShadowSkinVB", true);
00144             }
00145         }
00146 
00147 
00148         // Fill OT with models, for both Opaque and transparent pass
00149         // =============================
00150 
00151         // Sort the models by distance from camera
00152         // This is done here and not in the addRenderModel because of the LoadBalancing traversal which can modify
00153         // the transparency flag (multi lod for instance)
00154 
00155         // clear the OTs, and prepare to allocate max element space
00156         OrderOpaqueList.reset(_CurrentNumVisibleModels);
00157         for(uint k = 0; k <= (uint) _MaxTransparencyPriority; ++k)
00158         {
00159             _OrderTransparentListByPriority[k].reset(_CurrentNumVisibleModels); // all table share the same allocator (CLayeredOrderingTable::shareAllocator has been called)
00160                                                                             // and an object can be only inserted in one table, so we only need to init the main allocator
00161         }
00162 
00163         // fill the OTs.
00164         CTransform          **itRdrModel= NULL;
00165         uint32              nNbModels = _CurrentNumVisibleModels;
00166         if(nNbModels)
00167             itRdrModel= &RenderList[0];
00168         float   rPseudoZ, rPseudoZ2;
00169 
00170         // Some precalc
00171         float   OOFar= 1.0f / this->Far;
00172         uint32  opaqueOtSize= OrderOpaqueList.getSize();
00173         uint32  opaqueOtMax= OrderOpaqueList.getSize()-1;
00174         uint32  transparentOtSize= _OrderTransparentListByPriority[0].getSize(); // there is at least one list, and all list have the same number of entries
00175         uint32  transparentOtMax= _OrderTransparentListByPriority[0].getSize()-1;
00176         uint32  otId;
00177         // fast floor
00178         NLMISC::OptFastFloorBegin();
00179         // For all rdr models
00180         for( ; nNbModels>0; itRdrModel++, nNbModels-- )
00181         {
00182             CTransform          *pTransform = *itRdrModel;
00183 
00184             // if this entry was killed by removeRenderModel(), skip!
00185             if(!pTransform)
00186                 continue;
00187 
00188             // Yoyo: skins are rendered through skeletons, so models WorldMatrix are all good here (even sticked objects)
00189             rPseudoZ = (pTransform->getWorldMatrix().getPos() - CamPos).norm();
00190 
00191             // rPseudoZ from 0.0 -> 1.0
00192             rPseudoZ =  sqrtf( rPseudoZ * OOFar );
00193 
00194             if( pTransform->isOpaque() )
00195             {
00196                 // since norm, we are sure that rPseudoZ>=0
00197                 rPseudoZ2 = rPseudoZ * opaqueOtSize;
00198                 otId= NLMISC::OptFastFloor(rPseudoZ2);
00199                 otId= min(otId, opaqueOtMax);
00200                 OrderOpaqueList.insert( otId, pTransform );
00201             }
00202             if( pTransform->isTransparent() )
00203             {
00204                 // since norm, we are sure that rPseudoZ>=0
00205                 rPseudoZ2 = rPseudoZ * transparentOtSize;
00206                 otId= NLMISC::OptFastFloor(rPseudoZ2);
00207                 otId= min(otId, transparentOtMax);
00208                 // must invert id, because transparent, sort from back to front
00209                 _OrderTransparentListByPriority[std::min(pTransform->getTransparencyPriority(), _MaxTransparencyPriority)].insert( pTransform->getOrderingLayer(), pTransform, transparentOtMax-otId );
00210             }
00211 
00212         }
00213         // fast floor
00214         NLMISC::OptFastFloorEnd();
00215     }
00216 
00217     if (renderPart & UScene::RenderOpaque)
00218     {
00219         // Render Opaque stuff.
00220         // =============================
00221 
00222         // TestYoyo
00223         //OrderOpaqueList.reset(0);
00224         //OrderTransparentList.reset(0);
00225 
00226         // Clear any landscape
00227         clearRenderLandscapeList();
00228 
00229         // Start LodCharacter Manager render.
00230         CLodCharacterManager    *clodMngr= Scene->getLodCharacterManager();
00231         if(clodMngr)
00232             clodMngr->beginRender(getDriver(), CamPos);
00233 
00234         // Render the opaque materials
00235         _CurrentPassOpaque = true;
00236         OrderOpaqueList.begin();
00237         while( OrderOpaqueList.get() != NULL )
00238         {
00239             CTransform  *tr= OrderOpaqueList.get();
00240             #ifdef NL_DEBUG_RENDER_TRAV
00241                 CTransformShape *trShape = dynamic_cast<CTransformShape *>(tr);
00242                 if (trShape)
00243                 {
00244                     const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape);
00245                     if (shapeName)
00246                     {
00247                         nlwarning("Displaying %s", shapeName->c_str());
00248                     }
00249                 }
00250             #endif
00251             tr->traverseRender();
00252             OrderOpaqueList.next();
00253         }
00254 
00255         /* Render MeshBlock Manager.
00256             Some Meshs may be render per block. Interesting to remove VertexBuffer and Material setup overhead.
00257             Faster if rendered before lods, for ZBuffer optimisation: render first near objects then far.
00258             Lods are usually far objects.
00259         */
00260         MeshBlockManager.flush(Driver, Scene, this);
00261 
00262 
00263         // End LodCharacter Manager render.
00264         if(clodMngr)
00265             clodMngr->endRender();
00266 
00267 
00268         /* Render Scene CoarseMeshManager.
00269             Important to render them at end of Opaque rendering, because coarses instances are created/removed during
00270             this model opaque rendering pass.
00271         */
00272         if( Scene->getCoarseMeshManager() )
00273             Scene->getCoarseMeshManager()->flushRender(Driver);
00274 
00275         /* Render ShadowMaps.
00276             Important to render them at end of Opaque rendering, because alphaBlended objects must blend with opaque
00277             objects shadowed.
00278             Therefore, transparent objects neither can't cast or receive shadows...
00279 
00280             NB: Split in 2 calls and interleave Landscape Rendering between the 2. WHY???
00281             Because it is far more efficient for VBLock (but not for ZBuffer optim...) because in renderGenerate()
00282             the ShadowMeshSkinManager do lot of VBLocks that really stall (because only 2 VBHard with swap scheme).
00283 
00284             Therefore the first Lock that stall will wait not only for the first MeshSkin to finish but also for the
00285             preceding landscape render to finish too! => big STALL.
00286         */
00287 
00288         // Generate ShadowMaps
00289         _ShadowMapManager.renderGenerate(Scene);
00290 
00291         // Render the Landscape
00292         renderLandscapes();
00293 
00294         // Project ShadowMaps.
00295         if(Scene->getLandscapePolyDrawingCallback() != NULL)
00296         {
00297             Scene->getLandscapePolyDrawingCallback()->beginPolyDrawing();
00298         }
00299         _ShadowMapManager.renderProject(Scene);
00300         if(Scene->getLandscapePolyDrawingCallback())
00301         {
00302             Scene->getLandscapePolyDrawingCallback()->endPolyDrawing();
00303         }
00304 
00305         // Profile this frame?
00306         if(Scene->isNextRenderProfile())
00307         {
00308             OrderOpaqueList.begin();
00309             while( OrderOpaqueList.get() != NULL )
00310             {
00311                 OrderOpaqueList.get()->profileRender();
00312                 OrderOpaqueList.next();
00313             }
00314         }
00315     }
00316 
00317 
00318     if (renderPart & UScene::RenderTransparent)
00319     {
00320         if (_FirstWaterModel) // avoid a lock if no water is to be rendered
00321         {
00322             // setup water models
00323             CWaterModel *curr = _FirstWaterModel;
00324             uint numWantedVertices = 0;
00325             while (curr)
00326             {
00327                 numWantedVertices += curr->getNumWantedVertices();
00328                 curr = curr->_Next;
00329             }
00330             if (numWantedVertices != 0)
00331             {
00332                 CWaterModel::setupVertexBuffer(Scene->getWaterVB(), numWantedVertices, getDriver());
00333                 //
00334                 {
00335                     CVertexBufferReadWrite vbrw;
00336                     Scene->getWaterVB().lock(vbrw);
00337                     CWaterModel *curr = _FirstWaterModel;
00338                     void *datas = vbrw.getVertexCoordPointer(0);
00339                     //
00340                     uint tri = 0;
00341                     while (curr)
00342                     {
00343                         tri = curr->fillVB(datas, tri, *getDriver());
00344                         nlassert(tri <= numWantedVertices);
00345                         curr = curr->_Next;
00346                     }
00347                     nlassert(tri * 3 == numWantedVertices);
00348                 }
00349             }
00350             // Unlink all water model
00351             clearWaterModelList();
00352         }
00353     }
00354 
00355     if ((renderPart & UScene::RenderTransparent) &&
00356         (renderPart & UScene::RenderFlare)
00357        )
00358     {
00359         // Render all transparent stuffs including flares.
00360         // =============================
00361          // Render transparent materials (draw higher priority last, because their appear in front)
00362         _CurrentPassOpaque = false;
00363         for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00364         {
00365             it->begin(_LayersRenderingOrder);
00366             while( it->get() != NULL )
00367             {
00368                 #ifdef NL_DEBUG_RENDER_TRAV
00369                     CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get());
00370                     if (trShape)
00371                     {
00372                         const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape);
00373                         if (shapeName)
00374                         {
00375                             nlwarning("Displaying %s", shapeName->c_str());
00376                         }
00377                     }
00378                 #endif
00379                 it->get()->traverseRender();
00380                 it->next();
00381             }
00382         }
00383 
00384         // Profile this frame?
00385         if(Scene->isNextRenderProfile())
00386         {
00387             for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00388             {
00389                 it->begin();
00390                 while( it->get() != NULL )
00391                 {
00392                     it->get()->profileRender();
00393                     it->next();
00394                 }
00395             }
00396         }
00397     }
00398     else if (renderPart & UScene::RenderTransparent)
00399     {
00400         // Render all transparent stuffs, don't render flares
00401         // =============================
00402         _CurrentPassOpaque = false;
00403         for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00404         {
00405             it->begin(_LayersRenderingOrder);
00406             while( it->get() != NULL )
00407             {
00408                 if (!it->get()->isFlare())
00409                 {
00410                     #ifdef NL_DEBUG_RENDER_TRAV
00411                         CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get());
00412                         if (trShape)
00413                         {
00414                             const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape);
00415                             if (shapeName)
00416                             {
00417                                 nlwarning("Displaying %s", shapeName->c_str());
00418                             }
00419                         }
00420                     #endif
00421                     it->get()->traverseRender();
00422                 }
00423                 it->next();
00424             }
00425         }
00426 
00427         // Profile this frame?
00428         if(Scene->isNextRenderProfile())
00429         {
00430             for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00431             {
00432                 it->begin();
00433                 while( it->get() != NULL )
00434                 {
00435                     if (!it->get()->isFlare())
00436                     {
00437                         it->get()->profileRender();
00438                     }
00439                     it->next();
00440                 }
00441             }
00442         }
00443     }
00444     else if (renderPart & UScene::RenderFlare)
00445     {
00446         // Render flares only
00447         // =============================
00448         _CurrentPassOpaque = false;
00449         for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00450         {
00451             it->begin(_LayersRenderingOrder);
00452             while( it->get() != NULL )
00453             {
00454                 if (it->get()->isFlare())
00455                 {
00456                     #ifdef NL_DEBUG_RENDER_TRAV
00457                         CTransformShape *trShape = dynamic_cast<CTransformShape *>(it->get());
00458                         if (trShape)
00459                         {
00460                             const std::string *shapeName = Scene->getShapeBank()->getShapeNameFromShapePtr(trShape->Shape);
00461                             if (shapeName)
00462                             {
00463                                 nlwarning("Displaying %s", shapeName->c_str());
00464                             }
00465                         }
00466                     #endif
00467                     it->get()->traverseRender();
00468                 }
00469                 it->next();
00470             }
00471         }
00472 
00473         // Profile this frame?
00474         if(Scene->isNextRenderProfile())
00475         {
00476             for(std::vector<CLayeredOrderingTable<CTransform> >::iterator it = _OrderTransparentListByPriority.begin(); it != _OrderTransparentListByPriority.end(); ++it)
00477             {
00478                 it->begin();
00479                 while( it->get() != NULL )
00480                 {
00481                     if (it->get()->isFlare())
00482                     {
00483                         it->get()->profileRender();
00484                     }
00485                     it->next();
00486                 }
00487             }
00488         }
00489     }
00490 
00491     // END!
00492     // =============================
00493 
00494     // clean: reset the light setup
00495     resetLightSetup();
00496 
00497 }
00498 
00499 // ***************************************************************************
00500 void        CRenderTrav::setupDriverCamera()
00501 {
00502     getDriver()->setFrustum(Left, Right, Bottom, Top, Near, Far, Perspective);
00503     // Use setupViewMatrixEx() for ZBuffer precision.
00504     getDriver()->setupViewMatrixEx(ViewMatrix, CamPos);
00505 }
00506 
00507 // ***************************************************************************
00508 void        CRenderTrav::clearRenderList()
00509 {
00510     _CurrentNumVisibleModels= 0;
00511 }
00512 
00513 
00514 // ***************************************************************************
00515 void        CRenderTrav::setSunDirection(const CVector &dir)
00516 {
00517     _SunDirection= dir;
00518     _SunDirection.normalize();
00519 }
00520 
00521 
00522 // ***************************************************************************
00523 void        CRenderTrav::setMeshSkinManager(CVertexStreamManager *msm)
00524 {
00525     _MeshSkinManager= msm;
00526 }
00527 
00528 // ***************************************************************************
00529 void        CRenderTrav::setShadowMeshSkinManager(CVertexStreamManager *msm)
00530 {
00531     _ShadowMeshSkinManager= msm;
00532 }
00533 
00534 // ***************************************************************************
00535 void        CRenderTrav::reserveRenderList(uint numModels)
00536 {
00537     // enlarge only.
00538     if(numModels>RenderList.size())
00539         RenderList.resize(numModels);
00540 }
00541 
00542 // ***************************************************************************
00543 void        CRenderTrav::removeRenderModel(CTransform *m)
00544 {
00545     // NB: storing a 8 bit in CTransform, instead of a 32 bits, is just to save space.
00546     uint    lsb= m->_IndexLSBInRenderList;
00547 
00548     // this method is rarely called, so don't bother the slow down
00549     // btw, we parse the entire list / 256!!! which is surely fast!!
00550     for(uint i=lsb;i<_CurrentNumVisibleModels;i+=256)
00551     {
00552         // if i am really this entry, then set NULL
00553         if(RenderList[i]==m)
00554         {
00555             RenderList[i]= NULL;
00556             break;
00557         }
00558     }
00559 }
00560 
00561 
00562 // ***************************************************************************
00563 // ***************************************************************************
00564 // LightSetup
00565 // ***************************************************************************
00566 // ***************************************************************************
00567 
00568 
00569 // ***************************************************************************
00570 void        CRenderTrav::resetLightSetup()
00571 {
00572     // If lighting System disabled, skip
00573     if(!LightingSystemEnabled)
00574     {
00575         // Dont modify Driver lights, but setup default lighting For VertexProgram Lighting.
00576         _NumLightEnabled= 1;
00577         // Setup A default directionnal.
00578         CVector     defDir(-0.5f, 0.0, -0.85f);
00579         defDir.normalize();
00580         CRGBA       aday= CRGBA(130,  105,  119);
00581         CRGBA       dday= CRGBA(238, 225, 204);
00582         _DriverLight[0].setupDirectional(aday, dday, dday, defDir);
00583 
00584         return;
00585     }
00586     else
00587     {
00588         uint i;
00589 
00590         // Disable all lights.
00591         for(i=0; i<Driver->getMaxLight(); ++i)
00592         {
00593             Driver->enableLight(uint8(i), false);
00594         }
00595 
00596 
00597         // setup the precise cache, and setup lights according to this cache?
00598         // setup blackSun (factor==0).
00599         _LastSunFactor= 0;
00600         _LastFinalAmbient.set(0,0,0,255);
00601         _DriverLight[0].setupDirectional(CRGBA::Black, CRGBA::Black, CRGBA::Black, _SunDirection);
00602         Driver->setLight(0, _DriverLight[0]);
00603         // setup NULL point lights (=> cache will fail), so no need to setup other lights in Driver.
00604         for(i=0; i<NL3D_MAX_LIGHT_CONTRIBUTION; i++)
00605         {
00606             _LastPointLight[i]= NULL;
00607         }
00608 
00609 
00610         // Set the global ambientColor
00611         Driver->setAmbientColor(AmbientGlobal);
00612 
00613 
00614         // clear the cache.
00615         _CacheLightContribution= NULL;
00616         _NumLightEnabled= 0;
00617 
00618         _StrongestLightTouched = true;
00619     }
00620 }
00621 
00622 
00623 // ***************************************************************************
00624 void        CRenderTrav::changeLightSetup(CLightContribution    *lightContribution, bool useLocalAttenuation)
00625 {
00626     // If lighting System disabled, skip
00627     if(!LightingSystemEnabled)
00628         return;
00629 
00630     uint        i;
00631 
00632     // if same lightContribution, no-op.
00633     if(_CacheLightContribution == lightContribution &&  _LastLocalAttenuation == useLocalAttenuation)
00634         return;
00635     // else, must setup the lights into driver.
00636     else
00637     {
00638         _StrongestLightTouched = true;
00639         // if the setup is !NULL
00640         if(lightContribution)
00641         {
00642             // Compute SunAmbient / LocalAmbient
00643             //-----------
00644             // Take the current model ambient
00645             CRGBA   finalAmbient= lightContribution->computeCurrentAmbient(SunAmbient);
00646             // If use the mergedPointLight, add it to final Ambient
00647             if(lightContribution->UseMergedPointLight)
00648                 finalAmbient.addRGBOnly(finalAmbient, lightContribution->MergedPointLight);
00649             // Force Alpha to 255 for good cache test.
00650             finalAmbient.A= 255;
00651 
00652 
00653             // Setup the directionnal Sunlight.
00654             //-----------
00655             // expand 0..255 to 0..256, to avoid loss of precision.
00656             uint    ufactor= lightContribution->SunContribution;
00657             //  different SunLight as in cache ??
00658             //  NB: sunSetup can't change during renderPass, so need only to test factor.
00659             if(ufactor != _LastSunFactor || finalAmbient != _LastFinalAmbient)
00660             {
00661                 // cache (before expanding!!)
00662                 _LastSunFactor= ufactor;
00663                 // Cache final ambient light
00664                 _LastFinalAmbient= finalAmbient;
00665 
00666                 // expand to 0..256.
00667                 ufactor+= ufactor>>7;   // add 0 or 1.
00668                 // modulate color with factor of the lightContribution.
00669                 CRGBA   sunDiffuse, sunSpecular;
00670                 sunDiffuse.modulateFromuiRGBOnly(SunDiffuse, ufactor);
00671                 sunSpecular.modulateFromuiRGBOnly(SunSpecular, ufactor);
00672                 // setup driver light
00673                 _DriverLight[0].setupDirectional(finalAmbient, sunDiffuse, sunSpecular, _SunDirection);
00674                 Driver->setLight(0, _DriverLight[0]);
00675             }
00676 
00677 
00678             // Setup other point lights
00679             //-----------
00680             uint    plId=0;
00681             // for the list of light.
00682             while(lightContribution->PointLight[plId]!=NULL)
00683             {
00684                 CPointLight     *pl= lightContribution->PointLight[plId];
00685                 uint            inf;
00686                 if(useLocalAttenuation)
00687                     inf= lightContribution->Factor[plId];
00688                 else
00689                     inf= lightContribution->AttFactor[plId];
00690 
00691                 // different PointLight setup than in cache??
00692                 // NB: pointLight setup can't change during renderPass, so need only to test pointer,
00693                 // attenuation mode and factor.
00694                 if( pl!=_LastPointLight[plId] ||
00695                     inf!=_LastPointLightFactor[plId] ||
00696                     useLocalAttenuation!=_LastPointLightLocalAttenuation[plId] )
00697                 {
00698                     // need to resetup the light. Cache it.
00699                     _LastPointLight[plId]= pl;
00700                     _LastPointLightFactor[plId]= uint8(inf);
00701                     _LastPointLightLocalAttenuation[plId]= useLocalAttenuation;
00702 
00703                     // compute the driver light
00704                     if(useLocalAttenuation)
00705                         pl->setupDriverLight(_DriverLight[plId+1], uint8(inf));
00706                     else
00707                         // Compute it with user Attenuation
00708                         pl->setupDriverLightUserAttenuation(_DriverLight[plId+1], uint8(inf));
00709 
00710                     // setup driver. decal+1 because of sun.
00711                     Driver->setLight(uint8(plId+1), _DriverLight[plId+1]);
00712                 }
00713 
00714                 // next light?
00715                 plId++;
00716                 if(plId>=NL3D_MAX_LIGHT_CONTRIBUTION)
00717                     break;
00718             }
00719 
00720 
00721             // Disable olds, enable news, and cache.
00722             //-----------
00723             // count new number of light enabled.
00724             uint    newNumLightEnabled;
00725             // number of pointLight + the sun
00726             newNumLightEnabled= plId + 1;
00727 
00728             // enable lights which are used now and were not before.
00729             for(i=_NumLightEnabled; i<newNumLightEnabled; i++)
00730             {
00731                 Driver->enableLight(uint8(i), true);
00732             }
00733 
00734             // disable lights which are no more used.
00735             for(i=newNumLightEnabled; i<_NumLightEnabled; i++)
00736             {
00737                 Driver->enableLight(uint8(i), false);
00738             }
00739 
00740             // cache the setup.
00741             _CacheLightContribution = lightContribution;
00742             _NumLightEnabled= newNumLightEnabled;
00743             _LastLocalAttenuation= useLocalAttenuation;
00744         }
00745         else
00746         {
00747             // Disable old lights, and cache.
00748             //-----------
00749             // disable lights which are no more used.
00750             for(i=0; i<_NumLightEnabled; i++)
00751             {
00752                 Driver->enableLight(uint8(i), false);
00753             }
00754 
00755             // cache the setup.
00756             _CacheLightContribution = NULL;
00757             _NumLightEnabled= 0;
00758         }
00759 
00760 
00761     }
00762 }
00763 
00764 // ***************************************************************************
00765 // ***************************************************************************
00766 // VertexProgram LightSetup
00767 // ***************************************************************************
00768 // ***************************************************************************
00769 
00770 
00771 // ***************************************************************************
00772 void        CRenderTrav::beginVPLightSetup(uint ctStart, bool supportSpecular, const CMatrix &invObjectWM)
00773 {
00774     uint    i;
00775     nlassert(MaxVPLight==4);
00776     _VPNumLights= min(_NumLightEnabled, (uint)MaxVPLight);
00777     _VPCurrentCtStart= ctStart;
00778     _VPSupportSpecular= supportSpecular;
00779 
00780     // Prepare Colors (to be multiplied by material)
00781     //================
00782     // Ambient. _VPCurrentCtStart+0
00783     _VPFinalAmbient= AmbientGlobal;
00784     for(i=0; i<_VPNumLights; i++)
00785     {
00786         _VPFinalAmbient+= _DriverLight[i].getAmbiant();
00787     }
00788     // Diffuse. _VPCurrentCtStart+1 to 4
00789     for(i=0; i<_VPNumLights; i++)
00790     {
00791         _VPLightDiffuse[i]= _DriverLight[i].getDiffuse();
00792     }
00793     // reset other to 0.
00794     for(; i<MaxVPLight; i++)
00795     {
00796         _VPLightDiffuse[i]= CRGBA::Black;
00797         Driver->setConstant(_VPCurrentCtStart+1+i, 0.f, 0.f, 0.f, 0.f);
00798     }
00799     // Specular. _VPCurrentCtStart+5 to 8 (only if supportSpecular)
00800     if(supportSpecular)
00801     {
00802         for(i=0; i<_VPNumLights; i++)
00803         {
00804             _VPLightSpecular[i]= _DriverLight[i].getSpecular();
00805         }
00806         // reset other to 0.
00807         for(; i<MaxVPLight; i++)
00808         {
00809             _VPLightSpecular[i]= CRGBA::Black;
00810             Driver->setConstant(_VPCurrentCtStart+5+i, 0.f, 0.f, 0.f, 0.f);
00811         }
00812     }
00813 
00814 
00815     // Compute Eye position in Object space.
00816     CVector     eye= invObjectWM * CamPos;
00817 
00818 
00819     // Setup Sun Directionnal light.
00820     //================
00821     CVector     lightDir;
00822     // in objectSpace.
00823     lightDir= invObjectWM.mulVector(_DriverLight[0].getDirection());
00824     lightDir.normalize();
00825     lightDir= -lightDir;
00826     if(supportSpecular)
00827     {
00828         // Setup lightDir.
00829         Driver->setConstant(_VPCurrentCtStart+9, lightDir);
00830     }
00831     else
00832     {
00833         // Setup lightDir. NB: no specular color!
00834         Driver->setConstant(_VPCurrentCtStart+5, lightDir);
00835     }
00836 
00837 
00838     // Setup PointLights
00839     //================
00840     uint        startPLPos;
00841     if(supportSpecular)
00842     {
00843         // Setup eye in objectSpace for localViewer
00844         Driver->setConstant(_VPCurrentCtStart+11, eye);
00845         // Start at 12.
00846         startPLPos= 12;
00847     }
00848     else
00849     {
00850         // Start at 6.
00851         startPLPos= 6;
00852     }
00853     // For all pointLight enabled (other are black: don't matter)
00854     for(i=1; i<_VPNumLights; i++)
00855     {
00856         // Setup position of light.
00857         CVector     lightPos;
00858         lightPos= invObjectWM * _DriverLight[i].getPosition();
00859         Driver->setConstant(_VPCurrentCtStart+startPLPos+(i-1), lightPos);
00860     }
00861 
00862 
00863     // Must force real light setup at least the first time, in changeVPLightSetupMaterial()
00864     _VPMaterialCacheDirty= true;
00865 }
00866 
00867 // ***************************************************************************
00868 void        CRenderTrav::changeVPLightSetupMaterial(const CMaterial &mat, bool excludeStrongest)
00869 {
00870     // Must test if at least done one time.
00871     if(!_VPMaterialCacheDirty)
00872     {
00873         // Must test if same as in cache
00874         if( _VPMaterialCacheEmissive == mat.getEmissive().getPacked() &&
00875             _VPMaterialCacheAmbient == mat.getAmbient().getPacked() &&
00876             _VPMaterialCacheDiffuse == mat.getDiffuse().getPacked() )
00877         {
00878             // Same Diffuse part, test if same specular if necessary
00879             if( !_VPSupportSpecular ||
00880                 ( _VPMaterialCacheSpecular == mat.getSpecular().getPacked() &&
00881                   _VPMaterialCacheShininess == mat.getShininess() )  )
00882             {
00883                 // Then ok, skip.
00884                 return;
00885             }
00886         }
00887     }
00888 
00889     // If not skiped, cache now. cache all for simplification
00890     _VPMaterialCacheDirty= false;
00891     _VPMaterialCacheEmissive= mat.getEmissive().getPacked();
00892     _VPMaterialCacheAmbient= mat.getDiffuse().getPacked();
00893     _VPMaterialCacheDiffuse= mat.getDiffuse().getPacked();
00894     _VPMaterialCacheSpecular= mat.getSpecular().getPacked();
00895     _VPMaterialCacheShininess= mat.getShininess();
00896 
00897     // Setup constants
00898     CRGBAF  color;
00899     uint    i;
00900     CRGBAF  matDiff= mat.getDiffuse();
00901     CRGBAF  matSpec= mat.getSpecular();
00902     float   specExp= mat.getShininess();
00903 
00904     uint strongestLightIndex = excludeStrongest ? getStrongestLightIndex() : _VPNumLights;
00905 
00906     // setup Ambient + Emissive
00907     color= _VPFinalAmbient * mat.getAmbient();
00908     color+= mat.getEmissive();
00909     Driver->setConstant(_VPCurrentCtStart+0, 1, &color.R);
00910 
00911 
00912     // is the strongest light is not excluded, its index should have been setup to _VPNumLights
00913 
00914     // setup Diffuse.
00915     for(i = 0; i < strongestLightIndex; ++i)
00916     {
00917         color= _VPLightDiffuse[i] * matDiff;
00918         Driver->setConstant(_VPCurrentCtStart+1+i, 1, &color.R);
00919     }
00920 
00921 
00922     if (i != _VPNumLights)
00923     {
00924         color= _VPLightDiffuse[i] * matDiff;
00925         _StrongestLightDiffuse.set((uint8) (255.f * color.R), (uint8) (255.f * color.G), (uint8) (255.f * color.B), (uint8) (255.f * color.A));
00926         // setup strongest light to black for the gouraud part
00927         Driver->setConstant(_VPCurrentCtStart + 1 + i, 0.f, 0.f, 0.f, 0.f);
00928         ++i;
00929         // setup other lights
00930         for(; i < _VPNumLights; i++)
00931         {
00932             color= _VPLightDiffuse[i] * matDiff;
00933             Driver->setConstant(_VPCurrentCtStart + 1 + i, 1, &color.R);
00934         }
00935     }
00936 
00937     // setup Specular
00938     if(_VPSupportSpecular)
00939     {
00940         for(i = 0; i < strongestLightIndex; ++i)
00941         {
00942             color= _VPLightSpecular[i] * matSpec;
00943             color.A= specExp;
00944             Driver->setConstant(_VPCurrentCtStart+5+i, 1, &color.R);
00945         }
00946 
00947         if (i != _VPNumLights)
00948         {
00949             color= _VPLightSpecular[i] * matSpec;
00950             _StrongestLightSpecular.set((uint8) (255.f * color.R), (uint8) (255.f * color.G), (uint8) (255.f * color.B), (uint8) (255.f * color.A));
00951 
00952             // setup strongest light to black (for gouraud part)
00953             Driver->setConstant(_VPCurrentCtStart + 5 + i, 0.f, 0.f, 0.f, 0.f);
00954             ++i;
00955             // setup other lights
00956             for(; i < _VPNumLights; i++)
00957             {
00958                 color= _VPLightSpecular[i] * matSpec;
00959                 color.A= specExp;
00960                 Driver->setConstant(_VPCurrentCtStart + 5 + i, 1, &color.R);
00961             }
00962         }
00963     }
00964 
00965     // setup alpha.
00966     static  float   alphaCte[4]= {0,0,1,0};
00967     alphaCte[3]= matDiff.A;
00968     // setup at good place
00969     if(_VPSupportSpecular)
00970             Driver->setConstant(_VPCurrentCtStart+10, 1, alphaCte);
00971     else
00972             Driver->setConstant(_VPCurrentCtStart+9, 1, alphaCte);
00973 }
00974 
00975 // ***************************************************************************
00976 sint CRenderTrav::getStrongestLightIndex() const
00977 {
00978     if (!_StrongestLightTouched) return -1;
00979     uint vpNumLights = min(_NumLightEnabled, (uint)MaxVPLight);
00980     // If there is only a directionnal light, use it
00981     // If there is any point light, use the nearest, or the directionnal light if it is brighter
00982     if (vpNumLights == 0) return -1;
00983     if (vpNumLights == 1) return 0;
00984     // First point light is brightest ?
00985     float lumDir = _VPLightDiffuse[0].R + _VPLightDiffuse[0].G + _VPLightDiffuse[0].B + _VPLightDiffuse[0].A
00986                    + _VPLightSpecular[0].R + _VPLightSpecular[0].G + _VPLightSpecular[0].B + _VPLightSpecular[0].A;
00987     float lumOmni = _VPLightDiffuse[1].R + _VPLightDiffuse[1].G + _VPLightDiffuse[1].B + _VPLightDiffuse[1].A
00988                    + _VPLightSpecular[1].R + _VPLightSpecular[1].G + _VPLightSpecular[1].B + _VPLightSpecular[1].A;
00989     return lumDir > lumOmni ? 0 : 1;
00990 }
00991 
00992 // ***************************************************************************
00993 void    CRenderTrav::getStrongestLightColors(NLMISC::CRGBA &diffuse, NLMISC::CRGBA &specular)
00994 {
00995     sint strongestLightIndex = getStrongestLightIndex();
00996     if (strongestLightIndex == -1)
00997     {
00998         diffuse = specular = NLMISC::CRGBA::Black;
00999     }
01000     else
01001     {
01002         diffuse = _StrongestLightDiffuse;
01003         specular = _StrongestLightSpecular;
01004     }
01005 }
01006 
01007 
01008 // ***************************************************************************
01009 static const char*  LightingVPFragmentNormalize=
01010 "   # normalize normal                                                                  \n\
01011     DP3 R6.w, R6, R6;                                                                   \n\
01012     RSQ R6.w, R6.w;                                                                     \n\
01013     MUL R6, R6, R6.w;                                                                   \n\
01014 ";
01015 
01016 
01017 // ***************************************************************************
01018 // NB: all CTS+x are replaced with good cte index.
01019 static const char*  LightingVPFragmentNoSpecular_Begin=
01020 "                                                                                       \n\
01021     # Global Ambient.                                                                   \n\
01022     MOV R2, c[CTS+0];                                                                   \n\
01023                                                                                         \n\
01024     # Diffuse Sun                                                                       \n\
01025     DP3 R0.x, R6, c[CTS+5];         # R0.x= normal*-lightDir                            \n\
01026     LIT R0.y, R0.xxxx;              # R0.y= R0.x clamped                                \n\
01027     MAD R2, R0.y, c[CTS+1], R2;     # R2= summed vertex color.                          \n\
01028 ";
01029 
01030 // The 3 point Light code.
01031 static const char*  LightingVPFragmentNoSpecular_PL[]=
01032 {
01033 "   # Diffuse PointLight 0.                                                             \n\
01034     ADD R0, c[CTS+6], -R5;          # R0= lightPos-vertex                               \n\
01035     DP3 R0.w, R0, R0;               # normalize R0.                                     \n\
01036     RSQ R0.w, R0.w;                                                                     \n\
01037     MUL R0, R0, R0.w;                                                                   \n\
01038     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01039     LIT R0.y, R0.xxxx;              # R0.y= R0.x clamped                                \n\
01040     MAD R2, R0.y, c[CTS+2], R2;     # R2= summed vertex color.                          \n\
01041 ",
01042 "   # Diffuse PointLight 1.                                                             \n\
01043     ADD R0, c[CTS+7], -R5;          # R0= lightPos-vertex                               \n\
01044     DP3 R0.w, R0, R0;               # normalize R0.                                     \n\
01045     RSQ R0.w, R0.w;                                                                     \n\
01046     MUL R0, R0, R0.w;                                                                   \n\
01047     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01048     LIT R0.y, R0;                   # R0.y= R0.x clamped                                \n\
01049     MAD R2, R0.y, c[CTS+3], R2;     # R2= summed vertex color.                          \n\
01050 ",
01051 "   # Diffuse PointLight 2.                                                             \n\
01052     ADD R0, c[CTS+8], -R5;          # R0= lightPos-vertex                               \n\
01053     DP3 R0.w, R0, R0;               # normalize R0.                                     \n\
01054     RSQ R0.w, R0.w;                                                                     \n\
01055     MUL R0, R0, R0.w;                                                                   \n\
01056     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01057     LIT R0.y, R0;                   # R0.y= R0.x clamped                                \n\
01058     MAD R2, R0.y, c[CTS+4], R2;     # R2= summed vertex color.                          \n\
01059 "
01060 };
01061 
01062 // The End code.
01063 static const char*  LightingVPFragmentNoSpecular_End=
01064 "   # output to o[COL0] only, replacing alpha with material alpha.                      \n\
01065     MAD o[COL0], R2, c[CTS+9].zzzx, c[CTS+9].xxxw;                                      \n\
01066 ";
01067 
01068 
01069 // ***************************************************************************
01070 // NB: all CTS+x are replaced with good cte index.
01071 static const char*  LightingVPFragmentSpecular_Begin=
01072 "                                                                                       \n\
01073     # Global Ambient.                                                                   \n\
01074     MOV R2, c[CTS+0];                                                                   \n\
01075                                                                                         \n\
01076     # Always keep Specular exponent in R0.w                                             \n\
01077     MOV R0.w, c[CTS+5].w;                                                               \n\
01078                                                                                         \n\
01079     # Compute vertex-to-eye vector normed.                                              \n\
01080     ADD R4, c[CTS+11], -R5;                                                             \n\
01081     DP3 R4.w, R4, R4;                                                                   \n\
01082     RSQ R4.w, R4.w;                                                                     \n\
01083     MUL R4, R4, R4.w;                                                                   \n\
01084                                                                                         \n\
01085     # Diffuse-Specular Sun                                                              \n\
01086     # Compute R1= halfAngleVector= (lightDir+R4).normed().                              \n\
01087     ADD R1.xyz, c[CTS+9], R4;       # R1= halfAngleVector                               \n\
01088     DP3 R1.w, R1, R1;               # normalize R1.                                     \n\
01089     RSQ R1.w, R1.w;                                                                     \n\
01090     MUL R1.xyz, R1, R1.w;                                                               \n\
01091     # Compute Factors and colors.                                                       \n\
01092     DP3 R0.x, R6, c[CTS+9];         # R0.x= normal*-lightDir                            \n\
01093     DP3 R0.yz, R6, R1;              # R0.yz= normal*halfAngleVector                     \n\
01094     LIT R0.yz, R0;                  # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp   \n\
01095     MAD R2, R0.y, c[CTS+1], R2;     # R2= summed vertex color.                          \n\
01096     MUL R3, R0.z, c[CTS+5];         # R3= specular color.                               \n\
01097 ";
01098 
01099 // The 3 point Light code.
01100 static const char*  LightingVPFragmentSpecular_PL[]=
01101 {
01102 "   # Diffuse-Specular PointLight 0.                                                    \n\
01103     # Compute R0= (lightPos-vertex).normed().                                           \n\
01104     ADD R0.xyz, c[CTS+12], -R5;     # R0= lightPos-vertex                               \n\
01105     DP3 R1.w, R0, R0;               # normalize R0.                                     \n\
01106     RSQ R1.w, R1.w;                                                                     \n\
01107     MUL R0.xyz, R0, R1.w;                                                               \n\
01108     # Compute R1= halfAngleVector= (R0+R4).normed().                                    \n\
01109     ADD R1.xyz, R0, R4;             # R1= halfAngleVector                               \n\
01110     DP3 R1.w, R1, R1;               # normalize R1.                                     \n\
01111     RSQ R1.w, R1.w;                                                                     \n\
01112     MUL R1.xyz, R1, R1.w;                                                               \n\
01113     # Compute Factors and colors.                                                       \n\
01114     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01115     DP3 R0.yz, R6, R1;              # R0.yz= normal*halfAngleVector                     \n\
01116     LIT R0.yz, R0;                  # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp   \n\
01117     MAD R2, R0.y, c[CTS+2], R2;     # R2= summed vertex color.                          \n\
01118     MAD R3, R0.z, c[CTS+6], R3;     # R3= summed specular color.                        \n\
01119 ",
01120 "   # Diffuse-Specular PointLight 1.                                                    \n\
01121     # Compute R0= (lightPos-vertex).normed().                                           \n\
01122     ADD R0.xyz, c[CTS+13], -R5;     # R0= lightPos-vertex                               \n\
01123     DP3 R1.w, R0, R0;               # normalize R0.                                     \n\
01124     RSQ R1.w, R1.w;                                                                     \n\
01125     MUL R0.xyz, R0, R1.w;                                                               \n\
01126     # Compute R1= halfAngleVector= (R0+R4).normed().                                    \n\
01127     ADD R1.xyz, R0, R4;             # R1= halfAngleVector                               \n\
01128     DP3 R1.w, R1, R1;               # normalize R1.                                     \n\
01129     RSQ R1.w, R1.w;                                                                     \n\
01130     MUL R1.xyz, R1, R1.w;                                                               \n\
01131     # Compute Factors and colors.                                                       \n\
01132     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01133     DP3 R0.yz, R6, R1;              # R0.yz= normal*halfAngleVector                     \n\
01134     LIT R0.yz, R0;                  # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp   \n\
01135     MAD R2, R0.y, c[CTS+3], R2;     # R2= summed vertex color.                          \n\
01136     MAD R3, R0.z, c[CTS+7], R3;     # R3= summed specular color.                        \n\
01137 ",
01138 "   # Diffuse-Specular PointLight 2.                                                    \n\
01139     # Compute R0= (lightPos-vertex).normed().                                           \n\
01140     ADD R0.xyz, c[CTS+14], -R5;     # R0= lightPos-vertex                               \n\
01141     DP3 R1.w, R0, R0;               # normalize R0.                                     \n\
01142     RSQ R1.w, R1.w;                                                                     \n\
01143     MUL R0.xyz, R0, R1.w;                                                               \n\
01144     # Compute R1= halfAngleVector= (R0+R4).normed().                                    \n\
01145     ADD R1.xyz, R0, R4;             # R1= halfAngleVector                               \n\
01146     DP3 R1.w, R1, R1;               # normalize R1.                                     \n\
01147     RSQ R1.w, R1.w;                                                                     \n\
01148     MUL R1.xyz, R1, R1.w;                                                               \n\
01149     # Compute Factors and colors.                                                       \n\
01150     DP3 R0.x, R6, R0;               # R0.x= normal*lightDir                             \n\
01151     DP3 R0.yz, R6, R1;              # R0.yz= normal*halfAngleVector                     \n\
01152     LIT R0.yz, R0;                  # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp   \n\
01153     MAD R2, R0.y, c[CTS+4], R2;     # R2= summed vertex color.                          \n\
01154 "
01155 };
01156 
01157 
01158 // The End code.
01159 static const char*  LightingVPFragmentSpecular_End=
01160 "   # output directly to secondary color.                                               \n\
01161     MAD o[COL1], R0.z, c[CTS+8], R3;    # final summed specular color.                  \n\
01162                                                                                         \n\
01163     # output diffuse to o[COL0], replacing alpha with material alpha.                   \n\
01164     MAD o[COL0], R2, c[CTS+10].zzzx, c[CTS+10].xxxw;                                    \n\
01165 ";
01166 
01167 // ***************************************************************************
01168 static  void    strReplaceAll(string &strInOut, const string &tokenSrc, const string &tokenDst)
01169 {
01170     string::size_type pos;
01171     string::difference_type srcLen= tokenSrc.size();
01172     while( (pos=strInOut.find(tokenSrc)) != string::npos)
01173     {
01174         strInOut.replace(pos, srcLen, tokenDst);
01175     }
01176 }
01177 
01178 // ***************************************************************************
01179 std::string     CRenderTrav::getLightVPFragment(uint numActivePointLights, uint ctStart, bool supportSpecular, bool normalize)
01180 {
01181     string  ret;
01182 
01183     // Code frag written for 4 light max.
01184     nlassert(MaxVPLight==4);
01185     nlassert(numActivePointLights<=MaxVPLight-1);
01186 
01187     // Add LightingVPFragmentNormalize fragment?
01188     if(normalize)
01189         ret+= LightingVPFragmentNormalize;
01190 
01191     // Which fragment to use...
01192     if(supportSpecular)
01193     {
01194         // Add start of VP.
01195         ret+= LightingVPFragmentSpecular_Begin;
01196 
01197         // Add needed pointLights.
01198         for(uint i=0;i<numActivePointLights;i++)
01199         {
01200             ret+= LightingVPFragmentSpecular_PL[i];
01201         }
01202 
01203         // Add end of VP.
01204         ret+= LightingVPFragmentSpecular_End;
01205     }
01206     else
01207     {
01208         // Add start of VP.
01209         ret+= LightingVPFragmentNoSpecular_Begin;
01210 
01211         // Add needed pointLights.
01212         for(uint i=0;i<numActivePointLights;i++)
01213         {
01214             ret+= LightingVPFragmentNoSpecular_PL[i];
01215         }
01216 
01217         // Add end of VP.
01218         ret+= LightingVPFragmentNoSpecular_End;
01219     }
01220 
01221     // Replace all CTS+x with good index. do it for 15 possible indices: 0 to 14 if specular.
01222     // run from 14 to 0 so CTS+14 will not be taken for a CTS+1 !!
01223     for(sint i=14; i>=0; i--)
01224     {
01225         char    tokenSrc[256];
01226         sprintf(tokenSrc, "CTS+%d", i);
01227         char    tokenDst[256];
01228         sprintf(tokenDst, "%d", ctStart+i);
01229         // replace all in the string
01230         strReplaceAll(ret, tokenSrc, tokenDst);
01231     }
01232 
01233     // verify no CTS+ leaved... (not all ctes parsed!!!)
01234     nlassert( ret.find("CTS+")==string::npos );
01235 
01236     return ret;
01237 }
01238 
01239 
01240 // ***************************************************************************
01241 // ***************************************************************************
01242 // ***************************************************************************
01243 // ***************************************************************************
01244 
01245 // ***************************************************************************
01246 void            CRenderTrav::clearRenderLandscapeList()
01247 {
01248     _LandscapeRenderList.clear();
01249 }
01250 
01251 // ***************************************************************************
01252 void            CRenderTrav::addRenderLandscape(CLandscapeModel *model)
01253 {
01254     _LandscapeRenderList.push_back(model);
01255 }
01256 
01257 // ***************************************************************************
01258 void            CRenderTrav::renderLandscapes()
01259 {
01260     // Render Each Landscapes.
01261     for(uint i=0;i<_LandscapeRenderList.size();i++)
01262     {
01263         _LandscapeRenderList[i]->clipAndRenderLandscape();
01264     }
01265 }
01266 
01267 // ***************************************************************************
01268 void CRenderTrav::setupTransparencySorting(uint8 maxPriority /*=0*/,uint NbDistanceEntries /*=1024*/)
01269 {
01270     NLMISC::contReset(_OrderTransparentListByPriority); // avoid useless object copy when vector is resized (every element is reseted anyway)
01271     _OrderTransparentListByPriority.resize((uint) maxPriority + 1);
01272     for(uint k = 0; k < _OrderTransparentListByPriority.size(); ++k)
01273     {
01274         _OrderTransparentListByPriority[k].init(NbDistanceEntries);
01275         if (k != 0) _OrderTransparentListByPriority[k].shareAllocator(_OrderTransparentListByPriority[0]); // node allocator is shared between all layers
01276     }
01277     _MaxTransparencyPriority = maxPriority;
01278 }
01279 
01280 // ***************************************************************************
01281 void CRenderTrav::clearWaterModelList()
01282 {
01283     while (_FirstWaterModel)
01284     {
01285         _FirstWaterModel->unlink();
01286     }
01287 }
01288 
01289 // ***************************************************************************
01290 void CRenderTrav::debugWaterModelMemory(const char *tag, bool dumpList)
01291 {
01292     // Test Memory of water model render list (because someone crash it...)
01293     // Yoyo: this crash seems to be fixed, but i leave the code, in case of.....
01294 
01295     if(dumpList)
01296         _DebugWaterModelList.clear();
01297 
01298     CWaterModel     *curr= _FirstWaterModel;
01299     while(curr)
01300     {
01301         // the model in the list Must have not empty clipped poly
01302         CWaterModelDump     dmp;
01303         dmp.Address= (void*)curr;
01304         curr->debugDumpMem(dmp.ClippedPolyBegin, dmp.ClippedPolyEnd);
01305         // if same ptr (begin==end), error!!
01306         if(dmp.ClippedPolyBegin==dmp.ClippedPolyEnd)
01307         {
01308             // Before crash, do some log
01309             nlwarning("******* WaterModelList crash after %s", tag);
01310             nlwarning("Current: Ptr:%x. List:%x/%x", (ptrdiff_t)dmp.Address, (ptrdiff_t)dmp.ClippedPolyBegin, (ptrdiff_t)dmp.ClippedPolyEnd);
01311             // Log also the list bkuped (to do comparisons)
01312             for(uint i=0;i<_DebugWaterModelList.size();i++)
01313             {
01314                 CWaterModelDump     &bkup= _DebugWaterModelList[i];
01315                 nlwarning("List%02d: Ptr:%x. Array:%x/%x", i, (ptrdiff_t)bkup.Address, (ptrdiff_t)bkup.ClippedPolyBegin, (ptrdiff_t)bkup.ClippedPolyEnd);
01316             }
01317 
01318             // crash (assert not stop for clearness)
01319             nlassert(dmp.ClippedPolyBegin!=dmp.ClippedPolyEnd);
01320         }
01321 
01322         // bkup infos for future log
01323         if(dumpList)
01324             _DebugWaterModelList.push_back(dmp);
01325 
01326         // next
01327         curr= curr->_Next;
01328     }
01329 }
01330 
01331 }
01332 
01333 
01334 
01335 
01336 
01337 
01338 
01339 
01340 
01341 
01342 
01343 
01344 
01345 
01346 
01347 
01348 
01349 
01350 
01351 
01352 
01353 
01354 
01355 
01356 
01357 
01358 
01359 
01360 
01361 
01362 
01363 
01364 
01365 
01366 
01367 
01368 
01369 
01370 
01371 
01372 
01373 
01374 
01375 

Generated on Thu Jan 7 08:26:30 2010 for NeL by  doxygen 1.6.1