# 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  

render_trav.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/render_trav.h"
00029 #include "3d/hrc_trav.h"
00030 #include "3d/clip_trav.h"
00031 #include "3d/light_trav.h"
00032 #include "3d/driver.h"
00033 #include "3d/light.h"
00034 #include "3d/skeleton_model.h"
00035 #include "3d/scene.h"
00036 #include "3d/coarse_mesh_manager.h"
00037 #include "3d/lod_character_manager.h"
00038 #include "nel/misc/hierarchical_timer.h"
00039 
00040 #include "3d/transform.h"
00041 #include "3d/fast_floor.h"
00042 #include "3d/mesh_skin_manager.h"
00043 
00044 using namespace std;
00045 using namespace NLMISC;
00046 
00047 
00048 namespace       NL3D
00049 {
00050 
00051 
00052 // ***************************************************************************
00053 // ***************************************************************************
00054 // CRenderTrav
00055 // ***************************************************************************
00056 // ***************************************************************************
00057 
00058 
00059 // ***************************************************************************
00060 CRenderTrav::CRenderTrav()
00061 {
00062         RenderList.reserve(1024);
00063         OrderOpaqueList.init(1024);
00064         OrderTransparentList.init(1024);
00065         Driver = NULL;
00066         _CurrentPassOpaque = true;
00067 
00068         _CacheLightContribution= NULL;
00069 
00070         // Default light Setup.
00071         LightingSystemEnabled= false;
00072         AmbientGlobal= CRGBA(50, 50, 50);
00073         SunAmbient= CRGBA::Black;
00074         SunDiffuse= SunSpecular= CRGBA::White;
00075         _SunDirection.set(0, 0.5, -0.5);
00076         _SunDirection.normalize();
00077 
00078         _StrongestLightTouched = true;
00079 
00080         _MeshSkinManager= NULL;
00081 
00082         _LayersRenderingOrder= true;
00083 }
00084 // ***************************************************************************
00085 IObs            *CRenderTrav::createDefaultObs() const
00086 {
00087         return new CDefaultRenderObs;
00088 }
00089 // ***************************************************************************
00090 void            CRenderTrav::traverse()
00091 {
00092         H_AUTO( NL3D_TravRender );
00093 
00094         ITravCameraScene::update();
00095 
00096         // Bind to Driver.
00097         getDriver()->setFrustum(Left, Right, Bottom, Top, Near, Far, Perspective);
00098         // Use setupViewMatrixEx() for ZBuffer precision.
00099         getDriver()->setupViewMatrixEx(ViewMatrix, CamPos);
00100         getDriver()->setupViewport(_Viewport);
00101 
00102         // reset the light setup, and set global ambient.
00103         resetLightSetup();
00104 
00105 
00106         // reset the Skin manager, if needed
00107         if(_MeshSkinManager)
00108         {
00109                 if(Driver!=_MeshSkinManager->getDriver())
00110                 {
00111                         _MeshSkinManager->release();
00112                         _MeshSkinManager->init(Driver, NL3D_MESH_SKIN_MANAGER_VERTEXFORMAT, NL3D_MESH_SKIN_MANAGER_MAXVERTICES);
00113                 }
00114         }
00115 
00116 
00117         // Fill OT with observers, for both Opaque and transparent pass
00118         // =============================
00119 
00120         // Sort the observers by distance from camera
00121         // This is done here and not in the addRenderObs because of the LoadBalancing traversal which can modify
00122         // the transparency flag (multi lod for instance)
00123 
00124         // clear the OTs, and prepare to allocate max element space
00125         OrderOpaqueList.reset(RenderList.size());
00126         OrderTransparentList.reset(RenderList.size());
00127 
00128         // fill the OTs.
00129         IBaseRenderObs          **itRdrObs= NULL;
00130         uint32                          nNbObs = RenderList.size();
00131         if(nNbObs)      
00132                 itRdrObs= &RenderList[0];
00133         float   rPseudoZ, rPseudoZ2;
00134 
00135         // Some precalc
00136         float   OOFar= 1.0f / this->Far;
00137         uint32  opaqueOtSize= OrderOpaqueList.getSize();
00138         uint32  opaqueOtMax= OrderOpaqueList.getSize()-1;
00139         uint32  transparentOtSize= OrderTransparentList.getSize();
00140         uint32  transparentOtMax= OrderTransparentList.getSize()-1;
00141         uint32  otId;
00142         // fast floor
00143         OptFastFloorBegin();
00144         // For all rdr observers
00145         for( ; nNbObs>0; itRdrObs++, nNbObs-- )
00146         {
00147                 IBaseRenderObs          *pObs= *itRdrObs;
00148                 // Only rdrObserver of transform models can be inserted!! It's a requirement
00149                 CTransform                      *pTransform = safe_cast<CTransform*>(pObs->Model);
00150                 CTransformHrcObs        *trHrcObs= safe_cast<CTransformHrcObs*>(pObs->HrcObs);
00151 
00152                 // Yoyo: skins are rendered through skeletons, so models WorldMatrix are all good here (even sticked objects)
00153                 rPseudoZ = (trHrcObs->WorldMatrix.getPos() - CamPos).norm();
00154 
00155                 // rPseudoZ from 0.0 -> 1.0
00156                 rPseudoZ =  sqrtf( rPseudoZ * OOFar );
00157 
00158                 if( pTransform->isOpaque() )
00159                 {
00160                         // since norm, we are sure that rPseudoZ>=0
00161                         rPseudoZ2 = rPseudoZ * opaqueOtSize;
00162                         otId= OptFastFloor(rPseudoZ2);
00163                         otId= min(otId, opaqueOtMax);
00164                         OrderOpaqueList.insert( otId, pObs );
00165                 }
00166                 if( pTransform->isTransparent() )
00167                 {
00168                         // since norm, we are sure that rPseudoZ>=0
00169                         rPseudoZ2 = rPseudoZ * transparentOtSize;
00170                         otId= OptFastFloor(rPseudoZ2);
00171                         otId= min(otId, transparentOtMax);
00172                         // must invert id, because transparent, sort from back to front
00173                         OrderTransparentList.insert( pTransform->getOrderingLayer(), pObs, transparentOtMax-otId );
00174                 }
00175 
00176         }
00177         // fast floor
00178         OptFastFloorEnd();
00179 
00180 
00181         // Standard traverse (maybe not used)
00182         // =============================
00183 
00184         // First traverse the root.
00185         if(Root)
00186                 Root->traverse(NULL);
00187 
00188 
00189 
00190         // Render Opaque stuff.
00191         // =============================
00192 
00193         // TestYoyo
00194         //OrderOpaqueList.reset(0);
00195         //OrderTransparentList.reset(0);
00196 
00197         // Start LodCharacter Manager render.
00198         CLodCharacterManager    *clodMngr= Scene->getLodCharacterManager();
00199         if(clodMngr)
00200                 clodMngr->beginRender(getDriver(), CamPos);
00201 
00202         // Render the opaque materials
00203         _CurrentPassOpaque = true;
00204         OrderOpaqueList.begin();
00205         IBaseRenderObs *pBRO;
00206         while( OrderOpaqueList.get() != NULL )
00207         {
00208                 pBRO = OrderOpaqueList.get();
00209                 pBRO->traverse(NULL);
00210                 OrderOpaqueList.next();
00211         }
00212 
00213         /* Render MeshBlock Manager. 
00214                 Some Meshs may be render per block. Interesting to remove VertexBuffer and Material setup overhead.
00215                 Faster if rendered before lods, for ZBuffer optimisation: render first near objects then far. 
00216                 Lods are usually far objects.
00217         */
00218         MeshBlockManager.flush(Driver, Scene, this);
00219 
00220 
00221         // End LodCharacter Manager render.
00222         if(clodMngr)
00223                 clodMngr->endRender();
00224 
00225 
00226         /* Render Scene CoarseMeshManager. 
00227                 Important to render them at end of Opaque rendering, because coarses instances are created/removed during
00228                 this model opaque rendering pass.
00229         */
00230         // Render dynamic one.
00231         Scene->getDynamicCoarseMeshManager()->render(Driver);
00232         // Render static one.
00233         Scene->getStaticCoarseMeshManager()->render(Driver);
00234 
00235 
00236         // Render Transparent stuff.
00237         // =============================
00238 
00239          // Render transparent materials
00240         _CurrentPassOpaque = false;
00241         OrderTransparentList.begin(_LayersRenderingOrder);      
00242         while( OrderTransparentList.get() != NULL )
00243         {                               
00244                 pBRO = OrderTransparentList.get();
00245                 pBRO->traverse(NULL);
00246                 OrderTransparentList.next();
00247         }
00248 
00249 
00250         // END!
00251         // =============================
00252 
00253         // clean: reset the light setup
00254         resetLightSetup();
00255 
00256 }
00257 // ***************************************************************************
00258 void            CRenderTrav::clearRenderList()
00259 {
00260         RenderList.clear();
00261 }
00262 // ***************************************************************************
00263 void            CRenderTrav::addRenderObs(IBaseRenderObs *o)
00264 {
00265         RenderList.push_back(o);
00266 }
00267 
00268 
00269 // ***************************************************************************
00270 void            CRenderTrav::setSunDirection(const CVector &dir)
00271 {
00272         _SunDirection= dir;
00273         _SunDirection.normalize();
00274 }
00275 
00276 
00277 // ***************************************************************************
00278 void            CRenderTrav::setMeshSkinManager(CMeshSkinManager *msm)
00279 {
00280         _MeshSkinManager= msm;
00281 }
00282 
00283 
00284 // ***************************************************************************
00285 // ***************************************************************************
00286 // LightSetup
00287 // ***************************************************************************
00288 // ***************************************************************************
00289 
00290 
00291 // ***************************************************************************
00292 void            CRenderTrav::resetLightSetup()
00293 {
00294         // If lighting System disabled, skip
00295         if(!LightingSystemEnabled)
00296         {
00297                 // Dont modify Driver lights, but setup default lighting For VertexProgram Lighting.
00298                 _NumLightEnabled= 1;
00299                 // Setup A default directionnal.
00300                 CVector         defDir(-0.5f, 0.0, -0.85f);
00301                 defDir.normalize();
00302                 CRGBA           aday= CRGBA(130,  105,  119);
00303                 CRGBA           dday= CRGBA(238, 225, 204);
00304                 _DriverLight[0].setupDirectional(aday, dday, dday, defDir);
00305 
00306                 return;
00307         }
00308         else
00309         {
00310                 uint i;
00311 
00312                 // Disable all lights.
00313                 for(i=0; i<Driver->getMaxLight(); i++)
00314                 {
00315                         Driver->enableLight(i, false);
00316                 }
00317 
00318 
00319                 // setup the precise cache, and setup lights according to this cache?
00320                 // setup blackSun (factor==0).
00321                 _LastSunFactor= 0;
00322                 _LastSunAmbient.set(0,0,0,255);
00323                 _DriverLight[0].setupDirectional(CRGBA::Black, CRGBA::Black, CRGBA::Black, _SunDirection);
00324                 Driver->setLight(0, _DriverLight[0]);
00325                 // setup NULL point lights (=> cache will fail), so no need to setup other lights in Driver.
00326                 for(i=0; i<NL3D_MAX_LIGHT_CONTRIBUTION; i++)
00327                 {
00328                         _LastPointLight[i]= NULL;
00329                 }
00330 
00331 
00332                 // setup the precise cache, and setup lights according to this cache?
00333                 // setup blackSun (factor==0).
00334                 _LastSunFactor= 0;
00335                 _LastSunAmbient.set(0,0,0,255);
00336                 CLight          light;
00337                 light.setupDirectional(CRGBA::Black, CRGBA::Black, CRGBA::Black, _SunDirection);
00338                 _DriverLight[0].setupDirectional(CRGBA::Black, CRGBA::Black, CRGBA::Black, _SunDirection);
00339                 Driver->setLight(0, light);
00340                 // setup NULL point lights (=> cache will fail), so no need to setup other lights in Driver.
00341                 for(i=0; i<NL3D_MAX_LIGHT_CONTRIBUTION; i++)
00342                 {
00343                         _LastPointLight[i]= NULL;
00344                 }
00345 
00346                 // Set the global ambientColor
00347                 Driver->setAmbientColor(AmbientGlobal);
00348 
00349 
00350                 // clear the cache.
00351                 _CacheLightContribution= NULL;
00352                 _NumLightEnabled= 0;
00353 
00354                 _StrongestLightTouched = true;
00355         }
00356 }
00357 
00358 
00359 // ***************************************************************************
00360 void            CRenderTrav::changeLightSetup(CLightContribution        *lightContribution, bool useLocalAttenuation)
00361 {
00362         // If lighting System disabled, skip
00363         if(!LightingSystemEnabled)
00364                 return;
00365 
00366         uint            i;
00367 
00368         // if same lightContribution, no-op.
00369         if(_CacheLightContribution == lightContribution &&  _LastLocalAttenuation == useLocalAttenuation)
00370                 return;
00371         // else, must setup the lights into driver.
00372         else
00373         {
00374                 _StrongestLightTouched = true;
00375                 // if the setup is !NULL
00376                 if(lightContribution)
00377                 {
00378                         // Compute SunAmbient / LocalAmbient
00379                         //-----------
00380                         CRGBA   finalAmbient;
00381                         // Different case if the contribution is frozen or not.
00382                         if(lightContribution->FrozenStaticLightSetup)
00383                         {
00384                                 // Any FrozenAmbientLight provided??
00385                                 if(lightContribution->FrozenAmbientLight)
00386                                         // Take his current (maybe animated) ambient
00387                                         finalAmbient= lightContribution->FrozenAmbientLight->getAmbient();
00388                                 else
00389                                         // Take the sun ones.
00390                                         finalAmbient= SunAmbient;
00391                         }
00392                         else
00393                         {
00394                                 // must interpolate between SunAmbient and localAmbient
00395                                 uint    uAmbFactor= lightContribution->LocalAmbient.A;
00396                                 // expand 0..255 to 0..256, to avoid loss of precision.
00397                                 uAmbFactor+= uAmbFactor>>7;
00398                                 // Blend, but LocalAmbient.r/g/b is already multiplied by a.
00399                                 finalAmbient.modulateFromuiRGBOnly(SunAmbient, 256 - uAmbFactor);
00400                                 finalAmbient.addRGBOnly(finalAmbient, lightContribution->LocalAmbient);
00401                         }
00402                         // Force Alpha to 255 for good cache test.
00403                         finalAmbient.A= 255;
00404 
00405 
00406                         // Setup the directionnal Sunlight.
00407                         //-----------
00408                         // expand 0..255 to 0..256, to avoid loss of precision.
00409                         uint    ufactor= lightContribution->SunContribution;
00410                         //      different SunLight as in cache ??
00411                         //      NB: sunSetup can't change during renderPass, so need only to test factor.
00412                         if(ufactor != _LastSunFactor || finalAmbient != _LastSunAmbient)
00413                         {
00414                                 // cache (before expanding!!)
00415                                 _LastSunFactor= ufactor;
00416                                 // Cache final ambient light
00417                                 _LastSunAmbient= finalAmbient;
00418 
00419                                 // expand to 0..256.
00420                                 ufactor+= ufactor>>7;   // add 0 or 1.
00421                                 // modulate color with factor of the lightContribution.
00422                                 CRGBA   sunDiffuse, sunSpecular;
00423                                 sunDiffuse.modulateFromuiRGBOnly(SunDiffuse, ufactor);
00424                                 sunSpecular.modulateFromuiRGBOnly(SunSpecular, ufactor);
00425                                 // setup driver light
00426                                 _DriverLight[0].setupDirectional(finalAmbient, sunDiffuse, sunSpecular, _SunDirection);
00427                                 Driver->setLight(0, _DriverLight[0]);
00428                         }
00429 
00430 
00431                         // Setup other point lights
00432                         //-----------
00433                         uint    plId=0;
00434                         // for the list of light.
00435                         while(lightContribution->PointLight[plId]!=NULL)
00436                         {
00437                                 CPointLight             *pl= lightContribution->PointLight[plId];
00438                                 uint                    inf;
00439                                 if(useLocalAttenuation)
00440                                         inf= lightContribution->Factor[plId];
00441                                 else
00442                                         inf= lightContribution->AttFactor[plId];
00443 
00444                                 // different PointLight setup than in cache??
00445                                 // NB: pointLight setup can't change during renderPass, so need only to test pointer, 
00446                                 // attenuation mode and factor.
00447                                 if( pl!=_LastPointLight[plId] || 
00448                                         inf!=_LastPointLightFactor[plId] ||
00449                                         useLocalAttenuation!=_LastPointLightLocalAttenuation[plId] )
00450                                 {
00451                                         // need to resetup the light. Cache it.
00452                                         _LastPointLight[plId]= pl;
00453                                         _LastPointLightFactor[plId]= inf;
00454                                         _LastPointLightLocalAttenuation[plId]= useLocalAttenuation;
00455 
00456                                         // compute the driver light
00457                                         if(useLocalAttenuation)
00458                                                 pl->setupDriverLight(_DriverLight[plId+1], inf);
00459                                         else
00460                                                 // Compute it with user Attenuation
00461                                                 pl->setupDriverLightUserAttenuation(_DriverLight[plId+1], inf);
00462 
00463                                         // setup driver. decal+1 because of sun.
00464                                         Driver->setLight(plId+1, _DriverLight[plId+1]);
00465                                 }
00466 
00467                                 // next light?
00468                                 plId++;
00469                                 if(plId>=NL3D_MAX_LIGHT_CONTRIBUTION)
00470                                         break;
00471                         }
00472 
00473 
00474                         // Disable olds, enable news, and cache.
00475                         //-----------
00476                         // count new number of light enabled.
00477                         uint    newNumLightEnabled;
00478                         // number of pointLight + the sun 
00479                         newNumLightEnabled= plId + 1;
00480 
00481                         // enable lights which are used now and were not before.
00482                         for(i=_NumLightEnabled; i<newNumLightEnabled; i++)
00483                         {
00484                                 Driver->enableLight(i, true);
00485                         }
00486 
00487                         // disable lights which are no more used.
00488                         for(i=newNumLightEnabled; i<_NumLightEnabled; i++)
00489                         {
00490                                 Driver->enableLight(i, false);
00491                         }
00492 
00493                         // cache the setup.
00494                         _CacheLightContribution = lightContribution;
00495                         _NumLightEnabled= newNumLightEnabled;
00496                         _LastLocalAttenuation= useLocalAttenuation;
00497                 }
00498                 else
00499                 {
00500                         // Disable old lights, and cache.
00501                         //-----------
00502                         // disable lights which are no more used.
00503                         for(i=0; i<_NumLightEnabled; i++)
00504                         {
00505                                 Driver->enableLight(i, false);
00506                         }
00507 
00508                         // cache the setup.
00509                         _CacheLightContribution = NULL;
00510                         _NumLightEnabled= 0;
00511                 }
00512 
00513 
00514         }
00515 }
00516 
00517 // ***************************************************************************
00518 // ***************************************************************************
00519 // VertexProgram LightSetup
00520 // ***************************************************************************
00521 // ***************************************************************************
00522 
00523 
00524 // ***************************************************************************
00525 void            CRenderTrav::beginVPLightSetup(uint ctStart, bool supportSpecular, const CMatrix &invObjectWM)
00526 {       
00527         uint    i;               
00528         nlassert(MaxVPLight==4);
00529         _VPNumLights= min(_NumLightEnabled, (uint)MaxVPLight);
00530         _VPCurrentCtStart= ctStart;
00531         _VPSupportSpecular= supportSpecular;
00532         
00533         // Prepare Colors (to be multiplied by material)
00534         //================
00535         // Ambient. _VPCurrentCtStart+0
00536         _VPFinalAmbient= AmbientGlobal;
00537         for(i=0; i<_VPNumLights; i++)
00538         {
00539                 _VPFinalAmbient+= _DriverLight[i].getAmbiant();         
00540         }
00541         // Diffuse. _VPCurrentCtStart+1 to 4
00542         for(i=0; i<_VPNumLights; i++)
00543         {
00544                 _VPLightDiffuse[i]= _DriverLight[i].getDiffuse();
00545         }
00546         // reset other to 0.
00547         for(; i<MaxVPLight; i++)
00548         {
00549                 _VPLightDiffuse[i]= CRGBA::Black;
00550                 Driver->setConstant(_VPCurrentCtStart+1+i, 0.f, 0.f, 0.f, 0.f);
00551         }
00552         // Specular. _VPCurrentCtStart+5 to 8 (only if supportSpecular)
00553         if(supportSpecular)
00554         {
00555                 for(i=0; i<_VPNumLights; i++)
00556                 {
00557                         _VPLightSpecular[i]= _DriverLight[i].getSpecular();
00558                 }
00559                 // reset other to 0.
00560                 for(; i<MaxVPLight; i++)
00561                 {
00562                         _VPLightSpecular[i]= CRGBA::Black;
00563                         Driver->setConstant(_VPCurrentCtStart+5+i, 0.f, 0.f, 0.f, 0.f);
00564                 }
00565         }
00566 
00567 
00568         // Compute Eye position in Object space.
00569         CVector         eye= invObjectWM * CamPos;
00570 
00571 
00572         // Setup Sun Directionnal light.
00573         //================
00574         CVector         lightDir;
00575         // in objectSpace.
00576         lightDir= invObjectWM.mulVector(_DriverLight[0].getDirection());
00577         lightDir.normalize();
00578         lightDir= -lightDir; 
00579         if(supportSpecular)
00580         {
00581                 // Setup lightDir.
00582                 Driver->setConstant(_VPCurrentCtStart+9, lightDir);
00583         }
00584         else
00585         {
00586                 // Setup lightDir. NB: no specular color!
00587                 Driver->setConstant(_VPCurrentCtStart+5, lightDir);
00588         }
00589 
00590 
00591         // Setup PointLights
00592         //================
00593         uint            startPLPos;
00594         if(supportSpecular)
00595         {
00596                 // Setup eye in objectSpace for localViewer
00597                 Driver->setConstant(_VPCurrentCtStart+11, eye);
00598                 // Start at 12.
00599                 startPLPos= 12;
00600         }
00601         else
00602         {
00603                 // Start at 6.
00604                 startPLPos= 6;
00605         }
00606         // For all pointLight enabled (other are black: don't matter)
00607         for(i=1; i<_VPNumLights; i++)
00608         {
00609                 // Setup position of light.
00610                 CVector         lightPos;
00611                 lightPos= invObjectWM * _DriverLight[i].getPosition();
00612                 Driver->setConstant(_VPCurrentCtStart+startPLPos+(i-1), lightPos);
00613         }
00614 
00615 
00616         // Must force real light setup at least the first time, in changeVPLightSetupMaterial()
00617         _VPMaterialCacheDirty= true;
00618 }
00619 
00620 // ***************************************************************************
00621 void            CRenderTrav::changeVPLightSetupMaterial(const CMaterial &mat, bool excludeStrongest)
00622 {
00623         // Must test if at least done one time.
00624         if(!_VPMaterialCacheDirty)
00625         {
00626                 // Must test if same as in cache
00627                 if( _VPMaterialCacheEmissive == mat.getEmissive().getPacked() &&
00628                         _VPMaterialCacheAmbient == mat.getAmbient().getPacked() &&
00629                         _VPMaterialCacheDiffuse == mat.getDiffuse().getPacked() )
00630                 {
00631                         // Same Diffuse part, test if same specular if necessary
00632                         if( !_VPSupportSpecular ||
00633                                 ( _VPMaterialCacheSpecular == mat.getSpecular().getPacked() &&
00634                                   _VPMaterialCacheShininess == mat.getShininess() )  )
00635                         {
00636                                 // Then ok, skip.
00637                                 return;
00638                         }
00639                 }
00640         }
00641 
00642         // If not skiped, cache now. cache all for simplification
00643         _VPMaterialCacheDirty= false;
00644         _VPMaterialCacheEmissive= mat.getEmissive().getPacked();
00645         _VPMaterialCacheAmbient= mat.getDiffuse().getPacked();
00646         _VPMaterialCacheDiffuse= mat.getDiffuse().getPacked();
00647         _VPMaterialCacheSpecular= mat.getSpecular().getPacked();
00648         _VPMaterialCacheShininess= mat.getShininess();
00649 
00650         // Setup constants
00651         CRGBAF  color;
00652         uint    i;
00653         CRGBAF  matDiff= mat.getDiffuse();
00654         CRGBAF  matSpec= mat.getSpecular();
00655         float   specExp= mat.getShininess();
00656         
00657         uint strongestLightIndex = excludeStrongest ? getStrongestLightIndex() : _VPNumLights;
00658 
00659         // setup Ambient + Emissive
00660         color= _VPFinalAmbient * mat.getAmbient();
00661         color+= mat.getEmissive();
00662         Driver->setConstant(_VPCurrentCtStart+0, 1, &color.R);
00663         
00664 
00665         // is the strongest light is not excluded, its index should have been setup to _VPNumLights
00666 
00667         // setup Diffuse.
00668         for(i = 0; i < strongestLightIndex; ++i)
00669         {
00670                 color= _VPLightDiffuse[i] * matDiff;
00671                 Driver->setConstant(_VPCurrentCtStart+1+i, 1, &color.R);
00672         }
00673 
00674         
00675         if (i != _VPNumLights)
00676         {
00677                 color= _VPLightDiffuse[i] * matDiff;
00678                 _StrongestLightDiffuse.set((uint8) (255.f * color.R), (uint8) (255.f * color.G), (uint8) (255.f * color.B), (uint8) (255.f * color.A));
00679                 // setup strongest light to black for the gouraud part
00680                 Driver->setConstant(_VPCurrentCtStart + 1 + i, 0.f, 0.f, 0.f, 0.f);
00681                 ++i;
00682                 // setup other lights
00683                 for(; i < _VPNumLights; i++)
00684                 {
00685                         color= _VPLightDiffuse[i] * matDiff;
00686                         Driver->setConstant(_VPCurrentCtStart + 1 + i, 1, &color.R);
00687                 }
00688         }
00689 
00690         // setup Specular
00691         if(_VPSupportSpecular)
00692         {
00693                 for(i = 0; i < strongestLightIndex; ++i)
00694                 {
00695                         color= _VPLightSpecular[i] * matSpec;
00696                         color.A= specExp;
00697                         Driver->setConstant(_VPCurrentCtStart+5+i, 1, &color.R);
00698                 }
00699 
00700                 if (i != _VPNumLights)
00701                 {
00702                         color= _VPLightSpecular[i] * matSpec;
00703                         _StrongestLightSpecular.set((uint8) (255.f * color.R), (uint8) (255.f * color.G), (uint8) (255.f * color.B), (uint8) (255.f * color.A));
00704 
00705                         // setup strongest light to black (for gouraud part)
00706                         Driver->setConstant(_VPCurrentCtStart + 5 + i, 0.f, 0.f, 0.f, 0.f);
00707                         ++i;
00708                         // setup other lights
00709                         for(; i < _VPNumLights; i++)
00710                         {
00711                                 color= _VPLightSpecular[i] * matSpec;
00712                                 color.A= specExp;
00713                                 Driver->setConstant(_VPCurrentCtStart + 5 + i, 1, &color.R);
00714                         }
00715                 }
00716         }
00717 
00718         // setup alpha.
00719         static  float   alphaCte[4]= {0,0,1,0};
00720         alphaCte[3]= matDiff.A;
00721         // setup at good place
00722         if(_VPSupportSpecular)
00723                         Driver->setConstant(_VPCurrentCtStart+10, 1, alphaCte);
00724         else
00725                         Driver->setConstant(_VPCurrentCtStart+9, 1, alphaCte);
00726 }
00727 
00728 // ***************************************************************************
00729 sint CRenderTrav::getStrongestLightIndex() const
00730 {
00731         if (!_StrongestLightTouched) return -1;
00732         uint vpNumLights = min(_NumLightEnabled, (uint)MaxVPLight);
00733         // If there is only a directionnal light, use it
00734         // If there is any point light, use the nearest, or the directionnal light if it is brighter
00735         if (vpNumLights == 0) return -1;
00736         if (vpNumLights == 1) return 0;
00737         // First point light is brightest ?
00738         float lumDir = _VPLightDiffuse[0].R + _VPLightDiffuse[0].G + _VPLightDiffuse[0].B + _VPLightDiffuse[0].A
00739                                    + _VPLightSpecular[0].R + _VPLightSpecular[0].G + _VPLightSpecular[0].B + _VPLightSpecular[0].A;
00740         float lumOmni = _VPLightDiffuse[1].R + _VPLightDiffuse[1].G + _VPLightDiffuse[1].B + _VPLightDiffuse[1].A
00741                                    + _VPLightSpecular[1].R + _VPLightSpecular[1].G + _VPLightSpecular[1].B + _VPLightSpecular[1].A;
00742         return lumDir > lumOmni ? 0 : 1;
00743 }
00744 
00745 // ***************************************************************************
00746 void    CRenderTrav::getStrongestLightColors(NLMISC::CRGBA &diffuse, NLMISC::CRGBA &specular)
00747 {
00748         sint strongestLightIndex = getStrongestLightIndex();
00749         if (strongestLightIndex == -1)
00750         {
00751                 diffuse = specular = NLMISC::CRGBA::Black;              
00752         }
00753         else
00754         {
00755                 diffuse = _StrongestLightDiffuse;
00756                 specular = _StrongestLightSpecular;             
00757         }
00758 }
00759 
00760 
00761 // ***************************************************************************
00762 static const char*      LightingVPFragmentNormalize=
00763 "       # normalize normal                                                                                                                                      \n\
00764         DP3     R6.w, R6, R6;                                                                                                                                   \n\
00765         RSQ     R6.w, R6.w;                                                                                                                                             \n\
00766         MUL     R6, R6, R6.w;                                                                                                                                   \n\
00767 ";
00768 
00769 
00770 // ***************************************************************************
00771 // NB: all CTS+x are replaced with good cte index.
00772 static const char*      LightingVPFragmentNoSpecular_Begin=
00773 "                                                                                                                                                                               \n\
00774         # Global Ambient.                                                                                                                                       \n\
00775         MOV     R2, c[CTS+0];                                                                                                                                   \n\
00776                                                                                                                                                                                 \n\
00777         # Diffuse Sun                                                                                                                                           \n\
00778         DP3     R0.x, R6, c[CTS+5];                     # R0.x= normal*-lightDir                                                        \n\
00779         LIT     R0.y, R0.xxxx;                          # R0.y= R0.x clamped                                                            \n\
00780         MAD     R2, R0.y, c[CTS+1], R2;         # R2= summed vertex color.                                                      \n\
00781 ";
00782 
00783 // The 3 point Light code.
00784 static const char*      LightingVPFragmentNoSpecular_PL[]=
00785 {
00786 "       # Diffuse PointLight 0.                                                                                                                         \n\
00787         ADD     R0, c[CTS+6], -R5;                      # R0= lightPos-vertex                                                           \n\
00788         DP3     R0.w, R0, R0;                           # normalize R0.                                                                         \n\
00789         RSQ     R0.w, R0.w;                                                                                                                                             \n\
00790         MUL     R0, R0, R0.w;                                                                                                                                   \n\
00791         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00792         LIT     R0.y, R0.xxxx;                          # R0.y= R0.x clamped                                                            \n\
00793         MAD     R2, R0.y, c[CTS+2], R2;         # R2= summed vertex color.                                                      \n\
00794 ",
00795 "       # Diffuse PointLight 1.                                                                                                                         \n\
00796         ADD     R0, c[CTS+7], -R5;                      # R0= lightPos-vertex                                                           \n\
00797         DP3     R0.w, R0, R0;                           # normalize R0.                                                                         \n\
00798         RSQ     R0.w, R0.w;                                                                                                                                             \n\
00799         MUL     R0, R0, R0.w;                                                                                                                                   \n\
00800         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00801         LIT     R0.y, R0;                                       # R0.y= R0.x clamped                                                            \n\
00802         MAD     R2, R0.y, c[CTS+3], R2;         # R2= summed vertex color.                                                      \n\
00803 ",
00804 "       # Diffuse PointLight 2.                                                                                                                         \n\
00805         ADD     R0, c[CTS+8], -R5;                      # R0= lightPos-vertex                                                           \n\
00806         DP3     R0.w, R0, R0;                           # normalize R0.                                                                         \n\
00807         RSQ     R0.w, R0.w;                                                                                                                                             \n\
00808         MUL     R0, R0, R0.w;                                                                                                                                   \n\
00809         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00810         LIT     R0.y, R0;                                       # R0.y= R0.x clamped                                                            \n\
00811         MAD     R2, R0.y, c[CTS+4], R2;         # R2= summed vertex color.                                                      \n\
00812 "
00813 };
00814 
00815 // The End code.
00816 static const char*      LightingVPFragmentNoSpecular_End=
00817 "       # output to o[COL0] only, replacing alpha with material alpha.                                          \n\
00818         MAD     o[COL0], R2, c[CTS+9].zzzx, c[CTS+9].xxxw;                                                                              \n\
00819 ";
00820 
00821 
00822 // ***************************************************************************
00823 // NB: all CTS+x are replaced with good cte index.
00824 static const char*      LightingVPFragmentSpecular_Begin=
00825 "                                                                                                                                                                               \n\
00826         # Global Ambient.                                                                                                                                       \n\
00827         MOV     R2, c[CTS+0];                                                                                                                                   \n\
00828                                                                                                                                                                                 \n\
00829         # Always keep Specular exponent in R0.w                                                                                         \n\
00830         MOV     R0.w, c[CTS+5].w;                                                                                                                               \n\
00831                                                                                                                                                                                 \n\
00832         # Compute vertex-to-eye vector normed.                                                                                          \n\
00833         ADD     R4, c[CTS+11], -R5;                                                                                                                             \n\
00834         DP3     R4.w, R4, R4;                                                                                                                                   \n\
00835         RSQ     R4.w, R4.w;                                                                                                                                             \n\
00836         MUL R4, R4, R4.w;                                                                                                                                       \n\
00837                                                                                                                                                                                 \n\
00838         # Diffuse-Specular Sun                                                                                                                          \n\
00839         # Compute R1= halfAngleVector= (lightDir+R4).normed().                                                          \n\
00840         ADD     R1.xyz, c[CTS+9], R4;           # R1= halfAngleVector                                                           \n\
00841         DP3     R1.w, R1, R1;                           # normalize R1.                                                                         \n\
00842         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00843         MUL     R1.xyz, R1, R1.w;                                                                                                                               \n\
00844         # Compute Factors and colors.                                                                                                           \n\
00845         DP3     R0.x, R6, c[CTS+9];                     # R0.x= normal*-lightDir                                                        \n\
00846         DP3     R0.yz, R6, R1;                          # R0.yz= normal*halfAngleVector                                         \n\
00847         LIT     R0.yz, R0;                                      # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp       \n\
00848         MAD     R2, R0.y, c[CTS+1], R2;         # R2= summed vertex color.                                                      \n\
00849         MUL     R3, R0.z, c[CTS+5];                     # R3= specular color.                                                           \n\
00850 ";
00851 
00852 // The 3 point Light code.
00853 static const char*      LightingVPFragmentSpecular_PL[]=
00854 {
00855 "       # Diffuse-Specular PointLight 0.                                                                                                        \n\
00856         # Compute R0= (lightPos-vertex).normed().                                                                                       \n\
00857         ADD     R0.xyz, c[CTS+12], -R5;         # R0= lightPos-vertex                                                           \n\
00858         DP3     R1.w, R0, R0;                           # normalize R0.                                                                         \n\
00859         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00860         MUL     R0.xyz, R0, R1.w;                                                                                                                               \n\
00861         # Compute R1= halfAngleVector= (R0+R4).normed().                                                                        \n\
00862         ADD     R1.xyz, R0, R4;                         # R1= halfAngleVector                                                           \n\
00863         DP3     R1.w, R1, R1;                           # normalize R1.                                                                         \n\
00864         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00865         MUL     R1.xyz, R1, R1.w;                                                                                                                               \n\
00866         # Compute Factors and colors.                                                                                                           \n\
00867         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00868         DP3     R0.yz, R6, R1;                          # R0.yz= normal*halfAngleVector                                         \n\
00869         LIT     R0.yz, R0;                                      # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp       \n\
00870         MAD     R2, R0.y, c[CTS+2], R2;         # R2= summed vertex color.                                                      \n\
00871         MAD     R3, R0.z, c[CTS+6], R3;         # R3= summed specular color.                                            \n\
00872 ",
00873 "       # Diffuse-Specular PointLight 1.                                                                                                        \n\
00874         # Compute R0= (lightPos-vertex).normed().                                                                                       \n\
00875         ADD     R0.xyz, c[CTS+13], -R5;         # R0= lightPos-vertex                                                           \n\
00876         DP3     R1.w, R0, R0;                           # normalize R0.                                                                         \n\
00877         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00878         MUL     R0.xyz, R0, R1.w;                                                                                                                               \n\
00879         # Compute R1= halfAngleVector= (R0+R4).normed().                                                                        \n\
00880         ADD     R1.xyz, R0, R4;                         # R1= halfAngleVector                                                           \n\
00881         DP3     R1.w, R1, R1;                           # normalize R1.                                                                         \n\
00882         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00883         MUL     R1.xyz, R1, R1.w;                                                                                                                               \n\
00884         # Compute Factors and colors.                                                                                                           \n\
00885         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00886         DP3     R0.yz, R6, R1;                          # R0.yz= normal*halfAngleVector                                         \n\
00887         LIT     R0.yz, R0;                                      # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp       \n\
00888         MAD     R2, R0.y, c[CTS+3], R2;         # R2= summed vertex color.                                                      \n\
00889         MAD     R3, R0.z, c[CTS+7], R3;         # R3= summed specular color.                                            \n\
00890 ",
00891 "       # Diffuse-Specular PointLight 2.                                                                                                        \n\
00892         # Compute R0= (lightPos-vertex).normed().                                                                                       \n\
00893         ADD     R0.xyz, c[CTS+14], -R5;         # R0= lightPos-vertex                                                           \n\
00894         DP3     R1.w, R0, R0;                           # normalize R0.                                                                         \n\
00895         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00896         MUL     R0.xyz, R0, R1.w;                                                                                                                               \n\
00897         # Compute R1= halfAngleVector= (R0+R4).normed().                                                                        \n\
00898         ADD     R1.xyz, R0, R4;                         # R1= halfAngleVector                                                           \n\
00899         DP3     R1.w, R1, R1;                           # normalize R1.                                                                         \n\
00900         RSQ     R1.w, R1.w;                                                                                                                                             \n\
00901         MUL     R1.xyz, R1, R1.w;                                                                                                                               \n\
00902         # Compute Factors and colors.                                                                                                           \n\
00903         DP3     R0.x, R6, R0;                           # R0.x= normal*lightDir                                                         \n\
00904         DP3     R0.yz, R6, R1;                          # R0.yz= normal*halfAngleVector                                         \n\
00905         LIT     R0.yz, R0;                                      # R0.y= R0.x clamped, R0.z= pow(spec, R0.w) clamp       \n\
00906         MAD     R2, R0.y, c[CTS+4], R2;         # R2= summed vertex color.                                                      \n\
00907 "
00908 };
00909 
00910 
00911 // The End code.
00912 static const char*      LightingVPFragmentSpecular_End=
00913 "       # output directly to secondary color.                                                                                           \n\
00914         MAD     o[COL1], R0.z, c[CTS+8], R3;    # final summed specular color.                                  \n\
00915                                                                                                                                                                                 \n\
00916         # output diffuse to o[COL0], replacing alpha with material alpha.                                       \n\
00917         MAD     o[COL0], R2, c[CTS+10].zzzx, c[CTS+10].xxxw;                                                                    \n\
00918 ";
00919 
00920 // ***************************************************************************
00921 static  void    strReplaceAll(string &strInOut, const string &tokenSrc, const string &tokenDst)
00922 {
00923         uint32  pos;
00924         sint    srcLen= tokenSrc.size();
00925         while( (pos=strInOut.find(tokenSrc)) != string::npos)
00926         {
00927                 strInOut.replace(pos, srcLen, tokenDst);
00928         }
00929 }
00930 
00931 // ***************************************************************************
00932 std::string             CRenderTrav::getLightVPFragment(uint numActivePointLights, uint ctStart, bool supportSpecular, bool normalize)
00933 {
00934         string  ret;
00935 
00936         // Code frag written for 4 light max.
00937         nlassert(MaxVPLight==4);
00938         nlassert(numActivePointLights<=MaxVPLight-1);
00939 
00940         // Add LightingVPFragmentNormalize fragment?
00941         if(normalize)
00942                 ret+= LightingVPFragmentNormalize;
00943 
00944         // Which fragment to use...
00945         if(supportSpecular)
00946         {
00947                 // Add start of VP.
00948                 ret+= LightingVPFragmentSpecular_Begin;
00949 
00950                 // Add needed pointLights.
00951                 for(uint i=0;i<numActivePointLights;i++)
00952                 {
00953                         ret+= LightingVPFragmentSpecular_PL[i];
00954                 }
00955 
00956                 // Add end of VP.
00957                 ret+= LightingVPFragmentSpecular_End;
00958         }
00959         else
00960         {
00961                 // Add start of VP.
00962                 ret+= LightingVPFragmentNoSpecular_Begin;
00963 
00964                 // Add needed pointLights.
00965                 for(uint i=0;i<numActivePointLights;i++)
00966                 {
00967                         ret+= LightingVPFragmentNoSpecular_PL[i];
00968                 }
00969 
00970                 // Add end of VP.
00971                 ret+= LightingVPFragmentNoSpecular_End;
00972         }
00973 
00974         // Replace all CTS+x with good index. do it for 15 possible indices: 0 to 14 if specular.
00975         // run from 14 to 0 so CTS+14 will not be taken for a CTS+1 !!
00976         for(sint i=14; i>=0; i--)
00977         {
00978                 char    tokenSrc[256];
00979                 sprintf(tokenSrc, "CTS+%d", i);
00980                 char    tokenDst[256];
00981                 sprintf(tokenDst, "%d", ctStart+i);
00982                 // replace all in the string
00983                 strReplaceAll(ret, tokenSrc, tokenDst);
00984         }
00985 
00986         // verify no CTS+ leaved... (not all ctes parsed!!!)
00987         nlassert( ret.find("CTS+")==string::npos );
00988 
00989         return ret;
00990 }
00991 
00992 
00993 }