# 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  

instance_lighter.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 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/instance_lighter.h"
00029 #include "3d/mesh_multi_lod.h"
00030 #include "nel/misc/file.h"
00031 #include "nel/misc/path.h"
00032 #include "3d/visual_collision_manager.h"
00033 #include "3d/visual_collision_entity.h"
00034 #include "3d/ig_surface_light_build.h"
00035 
00036 
00037 using namespace std;
00038 using namespace NLMISC;
00039 
00040 namespace NL3D {
00041 
00042 
00043 // Bad coded: don't set too big else it allocates too much memory.
00044 #define NL3D_INSTANCE_LIGHTER_CUBE_GRID_SIZE    16
00045 
00046 
00047 // ***************************************************************************
00048 // ***************************************************************************
00049 // Setup part
00050 // ***************************************************************************
00051 // ***************************************************************************
00052 
00053 
00054 // ***************************************************************************
00055 CInstanceLighter::CLightDesc::CLightDesc ()
00056 {
00057         LightDirection.set (1, 1, -1);
00058         GridSize=512;
00059         GridCellSize=4;
00060         Shadow= true;
00061         OverSampling= 0;
00062         DisableSunContribution= false;
00063 }
00064 
00065 // ***************************************************************************
00066 CInstanceLighter::CInstanceLighter()
00067 {
00068         _IGSurfaceLightBuild= NULL;
00069 }
00070 
00071 // ***************************************************************************
00072 void CInstanceLighter::init ()
00073 {
00074 }
00075 
00076 // ***************************************************************************
00077 void CInstanceLighter::addTriangles (CLandscape &landscape, std::vector<uint> &listZone, uint order, std::vector<CTriangle>& triangleArray)
00078 {
00079         // Lamed from CZoneLighter.
00080         // Set all to refine
00081         excludeAllPatchFromRefineAll (landscape, listZone, false);
00082 
00083         // Setup the landscape
00084         landscape.setThreshold (0);
00085         landscape.setTileMaxSubdivision (order);
00086 
00087         // Refine it
00088         landscape.refineAll (CVector (0, 0, 0));
00089 
00090         // Dump tesselated triangles
00091         std::vector<const CTessFace*> leaves;
00092         landscape.getTessellationLeaves(leaves);
00093 
00094         // Number of leaves
00095         uint leavesCount=leaves.size();
00096 
00097         // Reserve the array
00098         triangleArray.reserve (triangleArray.size()+leavesCount);
00099 
00100         // Scan each leaves
00101         for (uint leave=0; leave<leavesCount; leave++)
00102         {
00103                 // Leave
00104                 const CTessFace *face=leaves[leave];
00105 
00106                 // Add a triangle. -1 because not an instance from an IG
00107                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos), -1 ));
00108         }
00109 
00110         // Setup the landscape
00111         landscape.setThreshold (1000);
00112         landscape.setTileMaxSubdivision (0);
00113 
00114         // Remove all triangles
00115         landscape.refineAll (CVector (0, 0, 0));
00116         landscape.refineAll (CVector (0, 0, 0));
00117         landscape.refineAll (CVector (0, 0, 0));
00118         landscape.refineAll (CVector (0, 0, 0));
00119         landscape.refineAll (CVector (0, 0, 0));
00120         landscape.refineAll (CVector (0, 0, 0));
00121         landscape.refineAll (CVector (0, 0, 0));
00122         landscape.refineAll (CVector (0, 0, 0));
00123         landscape.refineAll (CVector (0, 0, 0));
00124         landscape.refineAll (CVector (0, 0, 0));
00125 
00126 }
00127 
00128 // ***************************************************************************
00129 void CInstanceLighter::addTriangles (const IShape &shape, const NLMISC::CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
00130 {
00131         // Lamed from CZoneLighter.
00132 
00133         // Cast to CMesh
00134         const CMesh *mesh=dynamic_cast<const CMesh*>(&shape);
00135 
00136         // Cast to CMeshMultiLod
00137         const CMeshMultiLod *meshMulti=dynamic_cast<const CMeshMultiLod*>(&shape);
00138 
00139         // Cast to CMeshMultiLod
00140         const CMeshMRM *meshMRM=dynamic_cast<const CMeshMRM*>(&shape);
00141 
00142         // It is a mesh ?
00143         if (mesh)
00144         {
00145                 // Add its triangles
00146                 addTriangles (mesh->getMeshGeom (), modelMT, triangleArray, instanceId);
00147         }
00148         // It is a CMeshMultiLod ?
00149         else if (meshMulti)
00150         {
00151                 // Get the first geommesh
00152                 const IMeshGeom *meshGeom=&meshMulti->getMeshGeom (0);
00153 
00154                 // Dynamic cast
00155                 const CMeshGeom *geomMesh=dynamic_cast<const CMeshGeom*>(meshGeom);
00156                 if (geomMesh)
00157                 {
00158                         addTriangles (*geomMesh, modelMT, triangleArray, instanceId);
00159                 }
00160 
00161                 // Dynamic cast
00162                 const CMeshMRMGeom *mrmGeomMesh=dynamic_cast<const CMeshMRMGeom*>(meshGeom);
00163                 if (mrmGeomMesh)
00164                 {
00165                         addTriangles (*mrmGeomMesh, modelMT, triangleArray, instanceId);
00166                 }
00167         }
00168         // It is a CMeshMultiLod ?
00169         else if (meshMRM)
00170         {
00171                 // Get the first lod mesh geom
00172                 addTriangles (meshMRM->getMeshGeom (), modelMT, triangleArray, instanceId);
00173         }
00174 }
00175 
00176 
00177 // ***************************************************************************
00178 
00179 void CInstanceLighter::addTriangles (const CMeshGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
00180 {
00181         // Get the vertex buffer
00182         const CVertexBuffer &vb=meshGeom.getVertexBuffer();
00183 
00184         // For each matrix block
00185         uint numBlock=meshGeom.getNbMatrixBlock();
00186         for (uint block=0; block<numBlock; block++)
00187         {
00188                 // For each render pass
00189                 uint numRenderPass=meshGeom.getNbRdrPass(block);
00190                 for (uint pass=0; pass<numRenderPass; pass++)
00191                 {
00192                         // Get the primitive block
00193                         const CPrimitiveBlock &primitive=meshGeom.getRdrPassPrimitiveBlock ( block, pass);
00194 
00195                         // Dump triangles
00196                         const uint32* triIndex=primitive.getTriPointer ();
00197                         uint numTri=primitive.getNumTri ();
00198                         uint tri;
00199                         for (tri=0; tri<numTri; tri++)
00200                         {
00201                                 // Vertex
00202                                 CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3]));
00203                                 CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+1]));
00204                                 CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+2]));
00205 
00206                                 // Make a triangle
00207                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
00208                         }
00209 
00210                         // Dump quad
00211                         triIndex=primitive.getQuadPointer ();
00212                         numTri=primitive.getNumQuad ();
00213                         for (tri=0; tri<numTri; tri++)
00214                         {
00215                                 // Vertex
00216                                 CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4]));
00217                                 CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+1]));
00218                                 CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+2]));
00219                                 CVector v3=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+3]));
00220 
00221                                 // Make 2 triangles
00222                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
00223                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v2, v3), instanceId));
00224                         }
00225                 }
00226         }
00227 }
00228 
00229 // ***************************************************************************
00230 
00231 void CInstanceLighter::addTriangles (const CMeshMRMGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
00232 {
00233         // Get the vertex buffer
00234         const CVertexBuffer &vb=meshGeom.getVertexBuffer();
00235 
00236         // For each render pass
00237         uint numRenderPass=meshGeom.getNbRdrPass(0);
00238         for (uint pass=0; pass<numRenderPass; pass++)
00239         {
00240                 // Get the primitive block
00241                 const CPrimitiveBlock &primitive=meshGeom.getRdrPassPrimitiveBlock ( 0, pass);
00242 
00243                 // Dump triangles
00244                 const uint32* triIndex=primitive.getTriPointer ();
00245                 uint numTri=primitive.getNumTri ();
00246                 uint tri;
00247                 for (tri=0; tri<numTri; tri++)
00248                 {
00249                         // Vertex
00250                         CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3]));
00251                         CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+1]));
00252                         CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+2]));
00253 
00254                         // Make a triangle
00255                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
00256                 }
00257 
00258                 // Dump quad
00259                 triIndex=primitive.getQuadPointer ();
00260                 numTri=primitive.getNumQuad ();
00261                 for (tri=0; tri<numTri; tri++)
00262                 {
00263                         // Vertex
00264                         CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4]));
00265                         CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+1]));
00266                         CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+2]));
00267                         CVector v3=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+3]));
00268 
00269                         // Make 2 triangles
00270                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
00271                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v2, v3), instanceId));
00272                 }
00273         }
00274 }
00275 
00276 // ***************************************************************************
00277 
00278 void CInstanceLighter::excludeAllPatchFromRefineAll (CLandscape &landscape, vector<uint> &listZone, bool exclude)
00279 {
00280         // For each zone
00281         for (uint zone=0; zone<listZone.size(); zone++)
00282         {
00283                 // Get num patches
00284                 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
00285 
00286                 // For each patches
00287                 for (uint patch=0; patch<patchCount; patch++)
00288                 {
00289                         // Exclude all the patches from refine all
00290                         landscape.excludePatchFromRefineAll (listZone[zone], patch, exclude);
00291                 }
00292         }
00293 }
00294 
00295 
00296 // ***************************************************************************
00297 // ***************************************************************************
00298 // light part
00299 // ***************************************************************************
00300 // ***************************************************************************
00301 
00302 
00303 
00304 // ***************************************************************************
00305 void CInstanceLighter::light (const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc, 
00306         std::vector<CTriangle>& obstacles, CLandscape *landscape, CIGSurfaceLightBuild *igSurfaceLightBuild)
00307 {
00308         sint                                    i;
00309         CVector                                 outGlobalPos;
00310         std::vector<CCluster>   outClusters;
00311         std::vector<CPortal>    outPortals;
00312         std::vector<CPointLightNamed>   pointLightList;
00313 
00314         nlassert(lightDesc.OverSampling==0 || lightDesc.OverSampling==2 || lightDesc.OverSampling==4
00315                 || lightDesc.OverSampling==8 || lightDesc.OverSampling==16);
00316 
00317         // Setup.
00318         //========
00319 
00320         // Prepare IGSurfaceLight lighting
00321         //-----------
00322         // Bkup SurfaceLightBuild to know if must light the surfaces, in differents part of the process.
00323         _IGSurfaceLightBuild= igSurfaceLightBuild;
00324         // Prepare _IGRetrieverGridMap.
00325         _IGRetrieverGridMap.clear();
00326         if(_IGSurfaceLightBuild)
00327         {
00328                 _TotalCellNumber= 0;
00329                 CIGSurfaceLightBuild::ItRetrieverGridMap        itSrc;
00330                 itSrc= _IGSurfaceLightBuild->RetrieverGridMap.begin();
00331                 // For all retrievers Infos in _IGSurfaceLightBuild
00332                 while(itSrc!=_IGSurfaceLightBuild->RetrieverGridMap.end())
00333                 {
00334                         uint    numSurfaces= itSrc->second.Grids.size();
00335                         // If !empty retriever.
00336                         if(numSurfaces>0)
00337                         {
00338                                 // Add it to the map, 
00339                                 CIGSurfaceLight::CRetrieverLightGrid            &rlgDst= _IGRetrieverGridMap[itSrc->first];
00340                                 // resize Array of surfaces.
00341                                 rlgDst.Grids.resize(numSurfaces);
00342                                 // For all surfaces, init them in rlgDst.
00343                                 for(uint i=0; i<numSurfaces; i++)
00344                                 {
00345                                         CIGSurfaceLightBuild::CSurface          &surfSrc= itSrc->second.Grids[i];
00346                                         CSurfaceLightGrid                                       &surfDst= rlgDst.Grids[i];
00347                                         // Init Cells with a default CellCorner
00348                                         CSurfaceLightGrid::CCellCorner          defaultCellCorner;
00349                                         defaultCellCorner.SunContribution= 0;
00350                                         defaultCellCorner.Light[0]= 0xFF;
00351                                         defaultCellCorner.LocalAmbientId= 0xFF;
00352                                         
00353                                         // Init the grid.
00354                                         surfDst.Origin= surfSrc.Origin;
00355                                         surfDst.Width= surfSrc.Width;
00356                                         surfDst.Height= surfSrc.Height;
00357                                         surfDst.Cells.resize(surfSrc.Cells.size());
00358                                         surfDst.Cells.fill(defaultCellCorner);
00359                                         // The grid must be valid an not empty
00360                                         nlassert( surfDst.Cells.size() == surfDst.Width*surfDst.Height );
00361                                         nlassert( surfDst.Width>= 2 );
00362                                         nlassert( surfDst.Height>= 2 );
00363 
00364                                         _TotalCellNumber+= surfDst.Cells.size();
00365                                 }
00366                         }
00367 
00368                         // Next localRetriever info.
00369                         itSrc++;
00370                 }
00371         }
00372         // Reset cell iteration.
00373         _IsEndCell= true;
00374 
00375 
00376         // Retrieve info from igIn.
00377         //-----------
00378         igIn.retrieve (outGlobalPos, _Instances, outClusters, outPortals, pointLightList);
00379 
00380 
00381         // set All Instances StaticLightEnabled= true, and Build _InstanceInfos.
00382         //-----------
00383         // Map of shape
00384         std::map<string, IShape*> shapeMap;
00385         _InstanceInfos.resize(_Instances.size());
00386         for(i=0; i<(sint)_Instances.size();i++)
00387         {
00388                 // Avoid StaticLight precomputing??
00389                 if(_Instances[i].AvoidStaticLightPreCompute)
00390                 {
00391                         _Instances[i].StaticLightEnabled= false;
00392                         // Next instance.
00393                         continue;
00394                 }
00395 
00396                 // Else let's do it.
00397                 _Instances[i].StaticLightEnabled= true;
00398 
00399 
00400                 // Get the shape centerPos;
00401                 //------------
00402                 CVector shapeCenterPos;
00403                 CVector overSamples[MaxOverSamples];
00404 
00405                 // Get the instance shape name
00406                 string name= _Instances[i].Name;
00407                 bool    shapeFound= true;
00408 
00409                 // Try to find the shape in the UseShapeMap.
00410                 std::map<string, IShape*>::const_iterator iteMap= lightDesc.UserShapeMap.find (name);
00411 
00412                 // If not found in userShape map, try to load it from the temp loaded ShapeBank.
00413                 if( iteMap == lightDesc.UserShapeMap.end() )
00414                 {
00415                         // Add a .shape at the end ?
00416                         if (name.find('.') == std::string::npos)
00417                                 name += ".shape";
00418 
00419                         // Get the instance shape name
00420                         string nameLookup = CPath::lookup (name, false, false);
00421                         if (!nameLookup.empty())
00422                                 name = nameLookup;
00423 
00424                         // Find the shape in the bank
00425                         iteMap= shapeMap.find (name);
00426                         if (iteMap==shapeMap.end())
00427                         {
00428                                 // Input file
00429                                 CIFile inputFile;
00430 
00431                                 if (!name.empty() && inputFile.open (name))
00432                                 {
00433                                         // Load it
00434                                         CShapeStream stream;
00435                                         stream.serial (inputFile);
00436 
00437                                         // Get the pointer
00438                                         iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
00439                                 }
00440                                 else
00441                                 {
00442                                         // Error
00443                                         nlwarning ("WARNING can't load shape %s\n", name.c_str());
00444                                         shapeFound= false;
00445                                 }
00446                         }
00447                 }
00448 
00449 
00450                 // Last chance to skip it: fully LightMapped ??
00451                 //-----------
00452                 if(shapeFound)
00453                 {
00454                         CMeshBase       *mesh= dynamic_cast<CMeshBase*>(iteMap->second);
00455                         if(mesh)
00456                         {
00457                                 // If this mesh is not lightable (fully lightMapped)
00458                                 if(!mesh->isLightable())
00459                                 {
00460                                         // Force Avoid StaticLight precomputing
00461                                         _Instances[i].AvoidStaticLightPreCompute= true;
00462                                         // Disable static lighting.
00463                                         _Instances[i].StaticLightEnabled= false;
00464                                         // Next instance.
00465                                         continue;
00466                                 }
00467                         }
00468                 }
00469 
00470 
00471                 // Compute pos and OverSamples
00472                 //-----------
00473                 {
00474                         // Compute bbox, or default bbox
00475                         CAABBox         bbox;
00476                         if(!shapeFound)
00477                         {
00478                                 bbox.setCenter(CVector::Null);
00479                                 bbox.setHalfSize(CVector::Null);
00480                         }
00481                         else
00482                         {
00483                                 iteMap->second->getAABBox(bbox);
00484                         }
00485                         // get pos
00486                         shapeCenterPos= bbox.getCenter();
00487 
00488 
00489                         // Compute overSamples
00490                         float   qx= bbox.getHalfSize().x/2;
00491                         float   qy= bbox.getHalfSize().y/2;
00492                         float   qz= bbox.getHalfSize().z/2;
00493                         // No OverSampling => just copy.
00494                         if(lightDesc.OverSampling==0)
00495                                 overSamples[0]= shapeCenterPos;
00496                         else if(lightDesc.OverSampling==2)
00497                         {
00498                                 // Prefer Z Axis.
00499                                 overSamples[0]= shapeCenterPos + CVector(0, 0, qz);
00500                                 overSamples[1]= shapeCenterPos - CVector(0, 0, qz);
00501                         }
00502                         else if(lightDesc.OverSampling==4)
00503                         {
00504                                 // Apply an overSampling such that we see 4 points if we look on each side of the bbox.
00505                                 overSamples[0]= shapeCenterPos + CVector(-qx, -qy, -qz);
00506                                 overSamples[1]= shapeCenterPos + CVector(+qx, -qy, +qz);
00507                                 overSamples[2]= shapeCenterPos + CVector(-qx, +qy, +qz);
00508                                 overSamples[3]= shapeCenterPos + CVector(+qx, +qy, -qz);
00509                         }
00510                         else if(lightDesc.OverSampling==8 || lightDesc.OverSampling==16)
00511                         {
00512                                 // 8x is the best overSampling shceme for bbox
00513                                 overSamples[0]= shapeCenterPos + CVector(-qx, -qy, -qz);
00514                                 overSamples[1]= shapeCenterPos + CVector(+qx, -qy, -qz);
00515                                 overSamples[2]= shapeCenterPos + CVector(-qx, +qy, -qz);
00516                                 overSamples[3]= shapeCenterPos + CVector(+qx, +qy, -qz);
00517                                 overSamples[4]= shapeCenterPos + CVector(-qx, -qy, +qz);
00518                                 overSamples[5]= shapeCenterPos + CVector(+qx, -qy, +qz);
00519                                 overSamples[6]= shapeCenterPos + CVector(-qx, +qy, +qz);
00520                                 overSamples[7]= shapeCenterPos + CVector(+qx, +qy, +qz);
00521 
00522                                 // 16x => use this setup, and decal from 1/8
00523                                 if(lightDesc.OverSampling==16)
00524                                 {
00525                                         CVector         decal(qx/2, qy/2, qz/2);
00526                                         for(uint sample=0; sample<8; sample++)
00527                                         {
00528                                                 // Copy and decal
00529                                                 overSamples[sample+8]= overSamples[sample] + decal;
00530                                                 // neg decal me
00531                                                 overSamples[sample]-= decal;
00532                                         }
00533                                 }
00534                         }
00535                 }
00536 
00537 
00538                 // Compute pos of the instance
00539                 //------------
00540                 CMatrix         matInst;
00541                 matInst.setPos(_Instances[i].Pos);
00542                 matInst.setRot(_Instances[i].Rot);
00543                 matInst.scale(_Instances[i].Scale);
00544                 _InstanceInfos[i].CenterPos= matInst * shapeCenterPos;
00545                 // Apply matInst to samples.
00546                 uint    nSamples= max(1U, lightDesc.OverSampling);
00547                 for(uint sample=0; sample<nSamples; sample++)
00548                 {
00549                         _InstanceInfos[i].OverSamples[sample]= matInst * overSamples[sample];
00550                 }
00551         }
00552 
00553         // Clean Up shapes.
00554         //-----------
00555         std::map<string, IShape*>::iterator iteMap;
00556         iteMap= shapeMap.begin();
00557         while(iteMap!= shapeMap.end())
00558         {
00559                 // delte shape
00560                 delete  iteMap->second;
00561                 // delete entry in map
00562                 shapeMap.erase(iteMap);
00563                 // next
00564                 iteMap= shapeMap.begin();
00565         }
00566 
00567         // Build all obstacles plane.
00568         //-----------
00569         for(i=0; i<(sint)obstacles.size();i++)
00570         {
00571                 CInstanceLighter::CTriangle& triangle=obstacles[i];
00572                 // Calc the plane
00573                 triangle.Plane.make (triangle.Triangle.V0, triangle.Triangle.V1, triangle.Triangle.V2);
00574         }
00575 
00576 
00577         // Lighting
00578         //========
00579         // Light With Sun: build the grid, and do it on all _Instances, using _InstanceInfos
00580         // Compute also Lighting on surface.
00581         computeSunContribution(lightDesc, obstacles, landscape);
00582 
00583         // Light With PointLights
00584         // build the cubeGrids
00585         compilePointLightRT(lightDesc.GridSize, lightDesc.GridCellSize, obstacles, lightDesc.Shadow);
00586         // kill pointLightList, because will use mine.
00587         pointLightList.clear();
00588         // Light for all _Instances, using _InstanceInfos
00589         // Compute also Lighting on surface.
00590         processIGPointLightRT(pointLightList);
00591 
00592         // If _IGSurfaceLightBuild, then dilate lighting
00593         if(_IGSurfaceLightBuild)
00594         {
00595                 dilateLightingOnSurfaceCells();
00596         }
00597 
00598 
00599         // Build result.
00600         //========
00601         if(_IGSurfaceLightBuild)
00602         {
00603                 // build with IGSurfaceLight lighting
00604                 igOut.build(outGlobalPos, _Instances, outClusters, outPortals, pointLightList, 
00605                         &_IGRetrieverGridMap, _IGSurfaceLightBuild->CellSize);
00606         }
00607         else
00608         {
00609                 // build without IGSurfaceLight lighting
00610                 igOut.build(outGlobalPos, _Instances, outClusters, outPortals, pointLightList);
00611         }
00612 
00613 }
00614 
00615 
00616 // ***************************************************************************
00617 static void NEL3DCalcBase (CVector &direction, CMatrix& matrix)
00618 {
00619         direction.normalize();
00620         CVector         I=(fabs(direction*CVector(1.f,0,0))>0.99)?CVector(0.f,1.f,0.f):CVector(1.f,0.f,0.f);
00621         CVector         K=-direction;
00622         CVector         J=K^I;
00623         J.normalize();
00624         I=J^K;
00625         I.normalize();
00626         matrix.identity();
00627         matrix.setRot(I,J,K, true);
00628 }
00629 
00630 
00631 
00632 // ***************************************************************************
00633 void    CInstanceLighter::computeSunContribution(const CLightDesc &lightDesc, std::vector<CTriangle>& obstacles, CLandscape *landscape)
00634 {
00635         sint    i;
00636         // Use precoputed landscape SunContribution
00637         CVisualCollisionManager         *VCM= NULL;
00638         CVisualCollisionEntity          *VCE= NULL;
00639         if(landscape)
00640         {
00641                 // create a CVisualCollisionManager and a CVisualCollisionEntity
00642                 VCM= new CVisualCollisionManager;
00643                 VCM->setLandscape(landscape);
00644                 VCE= VCM->createEntity();
00645         }
00646         std::vector<CPointLightInfluence>       dummyPointLightFromLandscape;
00647         dummyPointLightFromLandscape.reserve(1024);
00648 
00649 
00650         // If DisableSunContribution, easy, 
00651         if(lightDesc.DisableSunContribution)
00652         {
00653                 // Light all instances.
00654                 //==========
00655                 for(i=0; i<(sint)_Instances.size(); i++)
00656                 {
00657                         // If staticLight not enabled, skip.
00658                         if( !_Instances[i].StaticLightEnabled )
00659                                 continue;
00660 
00661                         // fill SunContribution to 0
00662                         _Instances[i].SunContribution= 0;
00663                 }
00664 
00665                 // Light SurfaceGrid Cells.
00666                 //==========
00667                 if(_IGSurfaceLightBuild)
00668                 {
00669                         // Begin cell iteration
00670                         beginCell();
00671                         // For all surface cell corners
00672                         while( !isEndCell() )
00673                         {
00674                                 // get the current cell and cellInfo iterated.
00675                                 CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
00676                                 CSurfaceLightGrid::CCellCorner          &cell= getCurrentCell();
00677 
00678                                 // if the cell corner lies in the polygon surface.
00679                                 if(cellInfo.InSurface)
00680                                 {
00681                                         // fill SunContribution to 0
00682                                         cell.SunContribution= 0;
00683                                         // copy it to cellInfo
00684                                         cellInfo.SunContribution= cell.SunContribution;
00685                                 }
00686 
00687                                 // next cell
00688                                 nextCell();
00689                         }
00690                 }
00691         }
00692         // If no Raytrace Shadow, easy, 
00693         else if(!lightDesc.Shadow)
00694         {
00695                 // Light all instances.
00696                 //==========
00697                 for(i=0; i<(sint)_Instances.size(); i++)
00698                 {
00699                         progress ("Compute SunContribution on Instances", i / float(_Instances.size()) );
00700 
00701                         // If staticLight not enabled, skip.
00702                         if( !_Instances[i].StaticLightEnabled )
00703                                 continue;
00704 
00705                         // by default, fill SunContribution to 255
00706                         _Instances[i].SunContribution= 255;
00707                         // Try to get landscape SunContribution (better)
00708                         if(landscape)
00709                         {
00710                                 CVector         pos= _InstanceInfos[i].CenterPos;
00711                                 uint8   landSunContribution;
00712                                 dummyPointLightFromLandscape.clear();
00713                                 // If find faces under me
00714                                 NLMISC::CRGBA   dummyAmbient;
00715                                 if(VCE->getStaticLightSetup(pos, dummyPointLightFromLandscape, landSunContribution, dummyAmbient) )
00716                                 {
00717                                         _Instances[i].SunContribution= landSunContribution;
00718                                 }
00719                         }
00720                 }
00721 
00722                 // Light SurfaceGrid Cells.
00723                 //==========
00724                 if(_IGSurfaceLightBuild)
00725                 {
00726                         // Begin cell iteration
00727                         beginCell();
00728                         // For all surface cell corners
00729                         while( !isEndCell() )
00730                         {
00731                                 progressCell("Compute SunContribution on Surfaces");
00732 
00733                                 // get the current cell and cellInfo iterated.
00734                                 CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
00735                                 CSurfaceLightGrid::CCellCorner          &cell= getCurrentCell();
00736 
00737                                 // if the cell corner lies in the polygon surface.
00738                                 if(cellInfo.InSurface)
00739                                 {
00740                                         // Just init SunContribution to 255, since no shadowing.
00741                                         cell.SunContribution= 255;
00742                                         // copy it to cellInfo
00743                                         cellInfo.SunContribution= cell.SunContribution;
00744                                 }
00745 
00746                                 // next cell
00747                                 nextCell();
00748                         }
00749                 }
00750         }
00751         else
00752         {
00753                 // Compute rayBasis
00754                 CVector rayDir= lightDesc.LightDirection;
00755                 CMatrix rayBasis;
00756                 rayDir.normalize();
00757                 NEL3DCalcBase(rayDir, rayBasis);
00758                 CMatrix invRayBasis;
00759                 invRayBasis= rayBasis.inverted();
00760 
00761                 // Build QuadGrid of obstacles.
00762                 //=========
00763                 // setup quadGrid
00764                 CQuadGrid<const CTriangle*>             quadGrid;
00765                 quadGrid.changeBase (invRayBasis);
00766                 quadGrid.create(lightDesc.GridSize, lightDesc.GridCellSize);
00767                 // Insert all obstacles in quadGrid
00768                 for(i=0; i<(sint)obstacles.size(); i++)
00769                 {
00770                         CAABBox triBBox;
00771                         // Compute the bbox in rayBasis.
00772                         triBBox.setCenter(invRayBasis * obstacles[i].Triangle.V0);
00773                         triBBox.extend(invRayBasis * obstacles[i].Triangle.V1);
00774                         triBBox.extend(invRayBasis * obstacles[i].Triangle.V2);
00775                         // And set the coord in our world, because will be multiplied with invRayBasis in insert()
00776                         quadGrid.insert(rayBasis * triBBox.getMin(), rayBasis * triBBox.getMax(), &obstacles[i]);
00777                 }
00778 
00779                 // For all instances, light them.
00780                 //=========
00781                 for(i=0; i<(sint)_Instances.size(); i++)
00782                 {
00783                         progress ("Compute SunContribution on Instances", i / float(_Instances.size()) );
00784 
00785                         // If staticLight not enabled, skip.
00786                         if( !_Instances[i].StaticLightEnabled )
00787                                 continue;
00788 
00789                         // try to use landscape SunContribution.
00790                         bool    landUsed= false;
00791                         if(landscape)
00792                         {
00793                                 CVector         pos= _InstanceInfos[i].CenterPos;
00794                                 uint8   landSunContribution;
00795                                 dummyPointLightFromLandscape.clear();
00796                                 // If find faces under me
00797                                 NLMISC::CRGBA   dummyAmbient;
00798                                 if(VCE->getStaticLightSetup(pos, dummyPointLightFromLandscape, landSunContribution, dummyAmbient) )
00799                                 {
00800                                         _Instances[i].SunContribution= landSunContribution;
00801                                         landUsed= true;
00802                                 }
00803                         }
00804 
00805                         // If failed to use landscape SunContribution, rayTrace
00806                         if(!landUsed)
00807                         {
00808                                 // number of samples (1 if no overSampling)
00809                                 uint    nSamples= max(1U, lightDesc.OverSampling);
00810 
00811                                 // Default is full lighted.
00812                                 uint    sunAccum= 255*nSamples;
00813 
00814                                 // For all samples
00815                                 for(uint sample=0; sample<nSamples; sample++)
00816                                 {
00817                                         // pos to rayTrace against
00818                                         CVector         pos= _InstanceInfos[i].OverSamples[sample];
00819 
00820                                         // rayTrace from this pos.
00821                                         CVector         lightPos= pos-(rayDir*1000.f);
00822                                         // Select an element with the X axis as a 3d ray
00823                                         quadGrid.select (lightPos, lightPos);
00824                                         // For each triangle selected
00825                                         CQuadGrid<const CTriangle*>::CIterator  it=quadGrid.begin();
00826                                         while (it!=quadGrid.end())
00827                                         {
00828                                                 const CTriangle *tri= *it;
00829 
00830                                                 // If same instanceId, skip
00831                                                 if(tri->InstanceId != i)
00832                                                 {
00833                                                         CVector         hit;
00834                                                         // If triangle occlude the ray, no sun Contribution
00835                                                         if(tri->Triangle.intersect(lightPos, pos, hit, tri->Plane))
00836                                                         {
00837                                                                 // The sample is not touched by sun. sub his contribution
00838                                                                 sunAccum-= 255;
00839                                                                 // End
00840                                                                 break;
00841                                                         }
00842                                                 }
00843                                                 
00844                                                 it++;
00845                                         }
00846                                 }
00847 
00848                                 // Average samples
00849                                 _Instances[i].SunContribution= sunAccum / nSamples;
00850                         }
00851 
00852                 }
00853 
00854 
00855                 // Light SurfaceGrid Cells.
00856                 //==========
00857                 if(_IGSurfaceLightBuild)
00858                 {
00859                         // No instance currenlty computed, since we compute surface cells.
00860                         _CurrentInstanceComputed= -1;
00861 
00862                         // Begin cell iteration
00863                         beginCell();
00864                         // For all surface cell corners
00865                         while( !isEndCell() )
00866                         {
00867                                 progressCell("Compute SunContribution on Surfaces");
00868 
00869                                 // get the current cell and cellInfo iterated.
00870                                 CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
00871                                 CSurfaceLightGrid::CCellCorner          &cell= getCurrentCell();
00872 
00873                                 // if the cell corner lies in the polygon surface.
00874                                 if(cellInfo.InSurface)
00875                                 {
00876                                         // number of samples (at least 1 if no overSampling)
00877                                         uint    nSamples= cellInfo.NumOverSamples;
00878                                         nlassert(nSamples>=1);
00879 
00880                                         // Default is full lighted.
00881                                         uint    sunAccum= 255*nSamples;
00882 
00883                                         // For all samples
00884                                         for(uint sample=0; sample<nSamples; sample++)
00885                                         {
00886                                                 // Get pos to rayTrace.
00887                                                 CVector pos= cellInfo.OverSamples[sample];
00888 
00889                                                 // rayTrace from the pos of this Cell sample.
00890                                                 CVector         lightPos= pos-(rayDir*1000.f);
00891                                                 // Select an element with the X axis as a 3d ray
00892                                                 quadGrid.select (lightPos, lightPos);
00893                                                 // For each triangle selected
00894                                                 CQuadGrid<const CTriangle*>::CIterator  it=quadGrid.begin();
00895                                                 while (it!=quadGrid.end())
00896                                                 {
00897                                                         const CTriangle *tri= *it;
00898 
00899                                                         CVector         hit;
00900                                                         // If triangle occlude the ray, no sun Contribution
00901                                                         if(tri->Triangle.intersect(lightPos, pos, hit, tri->Plane))
00902                                                         {
00903                                                                 // The cell sample is not touched by sun. sub his contribution
00904                                                                 sunAccum-= 255;
00905                                                                 // End
00906                                                                 break;
00907                                                         }
00908                                                         
00909                                                         it++;
00910                                                 }
00911                                         }
00912 
00913                                         // Average SunContribution
00914                                         cell.SunContribution= sunAccum / nSamples;
00915 
00916                                         // copy it to cellInfo
00917                                         cellInfo.SunContribution= cell.SunContribution;
00918                                 }
00919 
00920                                 // next cell
00921                                 nextCell();
00922                         }
00923                 }
00924         }
00925 
00926 
00927         // Clean VCM and VCE
00928         if(landscape)
00929         {
00930                 // delete CVisualCollisionManager and CVisualCollisionEntity
00931                 VCM->deleteEntity(VCE);
00932                 delete VCM;
00933         }
00934 
00935 }
00936 
00937 
00938 
00939 // ***************************************************************************
00940 // ***************************************************************************
00941 // PointLights part
00942 // ***************************************************************************
00943 // ***************************************************************************
00944 
00945 
00946 // ***************************************************************************
00947 CInstanceLighter::CPointLightRT::CPointLightRT()
00948 {
00949         RefCount= 0;
00950 }
00951 
00952 
00953 // ***************************************************************************
00954 bool    CInstanceLighter::CPointLightRT::testRaytrace(const CVector &v, sint instanceComputed)
00955 {
00956         CVector dummy;
00957 
00958         if(!BSphere.include(v))
00959                 return false;
00960 
00961         // If Ambient light, just skip
00962         if(PointLight.getType()== CPointLight::AmbientLight)
00963                 return false;
00964 
00965         // If SpotLight verify in angle radius.
00966         if(PointLight.getType()== CPointLight::SpotLight)
00967         {
00968                 float   att= PointLight.computeLinearAttenuation(v);
00969                 if (att==0)
00970                         return false;
00971         }
00972 
00973 
00974         // Select in the cubeGrid
00975         FaceCubeGrid.select(v);
00976         // For all faces selected
00977         while(!FaceCubeGrid.isEndSel())
00978         {
00979                 const CTriangle *tri= FaceCubeGrid.getSel();
00980 
00981                 // If the triangle is not a triangle of the instance currenlty lighted
00982                 if( instanceComputed<0 || tri->InstanceId != instanceComputed )
00983                 {
00984                         // If intersect, the point is occluded.
00985                         if( tri->Triangle.intersect(BSphere.Center, v, dummy, tri->getPlane()) )
00986                                 return false;
00987                 }
00988 
00989                 // next
00990                 FaceCubeGrid.nextSel();
00991         }
00992 
00993         // Ok the point is visilbe from the light
00994         return true;
00995 }
00996 
00997 
00998 // ***************************************************************************
00999 void                    CInstanceLighter::addStaticPointLight(const CPointLightNamed &pln)
01000 {
01001         // build the plRT.
01002         CPointLightRT   plRT;
01003         plRT.PointLight= pln;
01004         // compute plRT.OODeltaAttenuation
01005         plRT.OODeltaAttenuation= pln.getAttenuationEnd() - pln.getAttenuationBegin();
01006         if(plRT.OODeltaAttenuation <=0 )
01007                 plRT.OODeltaAttenuation= 1e10f;
01008         else
01009                 plRT.OODeltaAttenuation= 1.0f / plRT.OODeltaAttenuation;
01010         // compute plRT.BSphere
01011         plRT.BSphere.Center= pln.getPosition();
01012         plRT.BSphere.Radius= pln.getAttenuationEnd();
01013         // NB: FaceCubeGrid will be computed during light()
01014 
01015         // add the plRT
01016         _StaticPointLights.push_back(plRT);
01017 
01018 }
01019 
01020 
01021 // ***************************************************************************
01022 void                    CInstanceLighter::compilePointLightRT(uint gridSize, float gridCellSize, std::vector<CTriangle>& obstacles, bool doShadow)
01023 {
01024         uint    i;
01025 
01026         // Fill the quadGrid of Lights.
01027         // ===========
01028         _StaticPointLightQuadGrid.create(gridSize, gridCellSize);
01029         for(i=0; i<_StaticPointLights.size();i++)
01030         {
01031                 CPointLightRT   &plRT= _StaticPointLights[i];
01032 
01033                 // Compute the bbox of the light
01034                 CAABBox         bbox;
01035                 bbox.setCenter(plRT.BSphere.Center);
01036                 float   hl= plRT.BSphere.Radius;
01037                 bbox.setHalfSize(CVector(hl,hl,hl));
01038 
01039                 // Insert the pointLight in the quadGrid.
01040                 _StaticPointLightQuadGrid.insert(bbox.getMin(), bbox.getMax(), &plRT);
01041         }
01042 
01043 
01044         // Append triangles to cubeGrid ??
01045         if(doShadow)
01046         {
01047                 // For all obstacles, Fill a quadGrid.
01048                 // ===========
01049                 CQuadGrid<CTriangle*>   obstacleGrid;
01050                 obstacleGrid.create(gridSize, gridCellSize);
01051                 uint    size= obstacles.size();
01052                 for(i=0; i<size; i++)
01053                 {
01054                         // bbox of triangle
01055                         CAABBox bbox;
01056                         bbox.setCenter(obstacles[i].Triangle.V0);
01057                         bbox.extend(obstacles[i].Triangle.V1);
01058                         bbox.extend(obstacles[i].Triangle.V2);
01059                         // insert triangle in quadGrid.
01060                         obstacleGrid.insert(bbox.getMin(), bbox.getMax(), &obstacles[i]);
01061                 }
01062 
01063 
01064                 // For all PointLights, fill his CubeGrid
01065                 // ===========
01066                 for(i=0; i<_StaticPointLights.size();i++)
01067                 {
01068                         // progress
01069                         progress ("Compute Influences of PointLights 1/2", i / (float)_StaticPointLights.size());
01070 
01071                         CPointLightRT   &plRT= _StaticPointLights[i];
01072                         // Create the cubeGrid
01073                         plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), NL3D_INSTANCE_LIGHTER_CUBE_GRID_SIZE);
01074 
01075                         // AmbiantLIghts: do nothing.
01076                         if(plRT.PointLight.getType()!=CPointLight::AmbientLight)
01077                         {
01078                                 // Select only obstacle Faces around the light. Other are not usefull
01079                                 CAABBox bbox;
01080                                 bbox.setCenter(plRT.PointLight.getPosition());
01081                                 float   hl= plRT.PointLight.getAttenuationEnd();
01082                                 bbox.setHalfSize(CVector(hl,hl,hl));
01083                                 obstacleGrid.select(bbox.getMin(), bbox.getMax());
01084 
01085                                 // For all faces, fill the cubeGrid.
01086                                 CQuadGrid<CTriangle*>::CIterator        itObstacle;
01087                                 itObstacle= obstacleGrid.begin();
01088                                 while( itObstacle!=obstacleGrid.end() )
01089                                 {
01090                                         CTriangle       &tri= *(*itObstacle);
01091                                         /* Don't Test BackFace culling Here (unlike in CZoneLighter !!).
01092                                            For objects:
01093                                                 AutoOccluding problem is avoided with _CurrentInstanceComputed scheme.
01094                                                 Also, With pointLights, there is no multiSampling (since no factor stored)
01095                                                 Hence we are sure that no Object samples will lies under floor, and that the center of the 
01096                                                 object is far away.
01097                                            For IGSurface lighting:
01098                                                 notice that we already add 20cm in height because of "stairs problem" so
01099                                                 floor/surface auto_shadowing is not a problem here...
01100                                         */
01101                                         // Insert the triangle in the CubeGrid
01102                                         plRT.FaceCubeGrid.insert( tri.Triangle, &tri);
01103 
01104                                         itObstacle++;
01105                                 }
01106                         }
01107 
01108                         // Compile the CubeGrid.
01109                         plRT.FaceCubeGrid.compile();
01110 
01111                         // And Reset RefCount.
01112                         plRT.RefCount= 0;
01113                 }
01114         }
01115         // else, just build empty grid
01116         else
01117         {
01118                 for(i=0; i<_StaticPointLights.size();i++)
01119                 {
01120                         // progress
01121                         progress ("Compute Influences of PointLights 1/2", i / (float)_StaticPointLights.size());
01122 
01123                         CPointLightRT   &plRT= _StaticPointLights[i];
01124                         // Create a dummy empty cubeGrid => no rayTrace :)
01125                         plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), 4);
01126 
01127                         // Compile the CubeGrid.
01128                         plRT.FaceCubeGrid.compile();
01129 
01130                         // And Reset RefCount.
01131                         plRT.RefCount= 0;
01132                 }
01133         }
01134 
01135 }
01136 
01137 
01138 // ***************************************************************************
01139 bool    CInstanceLighter::CPredPointLightToPoint::operator() (CPointLightRT *pla, CPointLightRT *plb) const
01140 {
01141         float   ra= (pla->BSphere.Center - Point).norm();
01142         float   rb= (plb->BSphere.Center - Point).norm();
01143         float   infA= (pla->PointLight.getAttenuationEnd() - ra) * pla->OODeltaAttenuation;
01144         float   infB= (plb->PointLight.getAttenuationEnd() - rb) * plb->OODeltaAttenuation;
01145         // It is important to clamp, else strange results...
01146         clamp(infA, 0.f, 1.f);
01147         clamp(infB, 0.f, 1.f);
01148         // return which light impact the most.
01149         // If same impact
01150         if(infA==infB)
01151                 // return nearest
01152                 return ra < rb;
01153         else
01154                 // return better impact
01155                 return  infA > infB;
01156 }
01157 
01158 
01159 // ***************************************************************************
01160 void                    CInstanceLighter::processIGPointLightRT(std::vector<CPointLightNamed> &listPointLight)
01161 {
01162         uint    i;
01163         vector<CPointLightRT*>          lightInfs;
01164         lightInfs.reserve(1024);
01165 
01166         // clear result list
01167         listPointLight.clear();
01168 
01169 
01170         // Compute each Instance
01171         //===========
01172         for(i=0; i<_InstanceInfos.size(); i++)
01173         {
01174                 // If staticLight not enabled, skip.
01175                 if( !_Instances[i].StaticLightEnabled )
01176                         continue;
01177 
01178                 CInstanceInfo   &inst= _InstanceInfos[i];
01179                 // Avoid autoShadowing
01180                 _CurrentInstanceComputed= i;
01181 
01182                 // progress
01183                 progress ("Compute Influences of PointLights 2/2", i / (float)_InstanceInfos.size());
01184 
01185                 // get the point of the instance.
01186                 CVector         pos= inst.CenterPos;
01187                 
01188                 // Default: takes no LocalAmbientLight;
01189                 inst.LocalAmbientLight= NULL;
01190                 float   furtherAmbLight= 0;
01191 
01192                 // Compute Which light influences him.
01193                 //---------
01194                 lightInfs.clear();
01195                 // Search possible lights around the position.
01196                 _StaticPointLightQuadGrid.select(pos, pos);
01197                 // For all of them, get the ones which touch this point.
01198                 CQuadGrid<CPointLightRT*>::CIterator    it= _StaticPointLightQuadGrid.begin();
01199                 while(it != _StaticPointLightQuadGrid.end())
01200                 {
01201                         CPointLightRT   *pl= *it;
01202 
01203                         // Test if really in the radius of the light, no occlusion, not an ambient, and in Spot Angle setup
01204                         if( pl->testRaytrace(pos, _CurrentInstanceComputed) )
01205                         {
01206                                 // Ok, add the light to the lights which influence the instance
01207                                 lightInfs.push_back(pl);
01208                         }
01209 
01210                         // Ambient Light ??
01211                         if( pl->PointLight.getType() == CPointLight::AmbientLight )
01212                         {
01213                                 // If the instance is in radius of the ambiant light.
01214                                 float   dRadius= pl->BSphere.Radius - (pl->BSphere.Center - pos).norm();
01215                                 if(dRadius>0)
01216                                 {
01217                                         // Take the best ambient light: the one which is further from the circumference
01218                                         if(dRadius > furtherAmbLight)
01219                                         {
01220                                                 furtherAmbLight= dRadius;
01221                                                 inst.LocalAmbientLight= pl;
01222                                         }
01223                                 }
01224                         }
01225 
01226                         // next
01227                         it++;
01228                 }
01229 
01230                 // If ambientLight chosen, inc Ref count of it
01231                 if(inst.LocalAmbientLight)
01232                         inst.LocalAmbientLight->RefCount++;
01233 
01234                 // Choose the Best ones.
01235                 //---------
01236                 CPredPointLightToPoint  predPLTP;
01237                 predPLTP.Point= pos;
01238                 // sort.
01239                 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
01240                 // truncate.
01241                 lightInfs.resize( min(lightInfs.size(), (uint)CInstanceGroup::NumStaticLightPerInstance) );
01242 
01243 
01244                 // For each of them, fill instance
01245                 //---------
01246                 uint                                    lightInfId;
01247                 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
01248                 {
01249                         CPointLightRT   *pl= lightInfs[lightInfId];
01250 
01251                         // copy light.
01252                         inst.Light[lightInfId]= pl;
01253 
01254                         // Inc RefCount of the light.
01255                         pl->RefCount++;
01256                 }
01257                 // Reset any empty slot to NULL.
01258                 for(; lightInfId<CInstanceGroup::NumStaticLightPerInstance; lightInfId++)
01259                 {
01260                         inst.Light[lightInfId]= NULL;
01261                 }
01262 
01263         }
01264 
01265 
01266         // Compute Lighting on SurfaceLightGrid
01267         //===========
01268         // Must do it before compression !!
01269         // NB: big copy/Past from above
01270         if(_IGSurfaceLightBuild)
01271         {
01272                 // No instance currenlty computed, since we compute surface cells.
01273                 _CurrentInstanceComputed= -1;
01274 
01275                 // Begin cell iteration
01276                 beginCell();
01277                 // For all surface cell corners
01278                 while( !isEndCell() )
01279                 {
01280                         progressCell("Compute PointLights on Surfaces");
01281 
01282                         // get the current cellInfo iterated.
01283                         CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
01284 
01285                         // if the cell corner lies in the polygon surface.
01286                         if(cellInfo.InSurface)
01287                         {
01288                                 // get the point of the cell.
01289                                 CVector         pos= cellInfo.CenterPos;
01290                                 
01291                                 // Default: takes no LocalAmbientLight;
01292                                 cellInfo.LocalAmbientLight= NULL;
01293                                 float   furtherAmbLight= 0;
01294 
01295                                 // Compute Which light influences him.
01296                                 //---------
01297                                 lightInfs.clear();
01298                                 // Search possible lights around the position.
01299                                 _StaticPointLightQuadGrid.select(pos, pos);
01300                                 // For all of them, get the ones which touch this point.
01301                                 CQuadGrid<CPointLightRT*>::CIterator    it= _StaticPointLightQuadGrid.begin();
01302                                 while(it != _StaticPointLightQuadGrid.end())
01303                                 {
01304                                         CPointLightRT   *pl= *it;
01305 
01306                                         // Test if really in the radius of the light, no occlusion, not an ambient, and in Spot Angle setup
01307                                         if( pl->testRaytrace(pos, _CurrentInstanceComputed) )
01308                                         {
01309                                                 // Ok, add the light to the lights which influence the cell
01310                                                 lightInfs.push_back(pl);
01311                                         }
01312 
01313                                         // Ambient Light ??
01314                                         if( pl->PointLight.getType() == CPointLight::AmbientLight )
01315                                         {
01316                                                 // If the instance is in radius of the ambiant light.
01317                                                 float   dRadius= pl->BSphere.Radius - (pl->BSphere.Center - pos).norm();
01318                                                 if(dRadius>0)
01319                                                 {
01320                                                         // Take the best ambient light: the one which is further from the circumference
01321                                                         if(dRadius > furtherAmbLight)
01322                                                         {
01323                                                                 furtherAmbLight= dRadius;
01324                                                                 cellInfo.LocalAmbientLight= pl;
01325                                                         }
01326                                                 }
01327                                         }
01328 
01329                                         // next
01330                                         it++;
01331                                 }
01332 
01333                                 // If ambientLight chosen, inc Ref count of it
01334                                 if(cellInfo.LocalAmbientLight)
01335                                         ((CPointLightRT*)cellInfo.LocalAmbientLight)->RefCount++;
01336 
01337 
01338                                 // Choose the Best ones.
01339                                 //---------
01340                                 CPredPointLightToPoint  predPLTP;
01341                                 predPLTP.Point= pos;
01342                                 // sort.
01343                                 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
01344                                 // truncate.
01345                                 lightInfs.resize( min(lightInfs.size(), (uint)CSurfaceLightGrid::NumLightPerCorner) );
01346 
01347 
01348                                 // For each of them, fill cellInfo
01349                                 //---------
01350                                 uint                                    lightInfId;
01351                                 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
01352                                 {
01353                                         CPointLightRT   *pl= lightInfs[lightInfId];
01354 
01355                                         // copy light.
01356                                         cellInfo.LightInfo[lightInfId]= pl;
01357 
01358                                         // Inc RefCount of the light.
01359                                         pl->RefCount++;
01360                                 }
01361                                 // Reset any empty slot to NULL.
01362                                 for(; lightInfId<CSurfaceLightGrid::NumLightPerCorner; lightInfId++)
01363                                 {
01364                                         cellInfo.LightInfo[lightInfId]= NULL;
01365                                 }
01366 
01367                         }
01368 
01369                         // next cell
01370                         nextCell();
01371                 }
01372         }
01373 
01374 
01375 
01376         // Compress and setup _Instances with compressed data.
01377         //===========
01378         uint    plId= 0;
01379         // Process each pointLights
01380         for(i=0; i<_StaticPointLights.size(); i++)
01381         {
01382                 CPointLightRT   &plRT= _StaticPointLights[i];
01383                 // If this light is used.
01384                 if(plRT.RefCount > 0)
01385                 {
01386                         // Must Copy it into Ig.
01387                         listPointLight.push_back(plRT.PointLight);
01388                         plRT.DstId= plId++;
01389                         // If index >= 255, too many lights (NB: => because 255 is a NULL code).
01390                         if(plId>=0xFF)
01391                         {
01392                                 throw Exception("Too many Static Point Lights influence the IG!!");
01393                         }
01394                 }
01395         }
01396 
01397         // For each instance, compress Point light info
01398         for(i=0; i<_Instances.size(); i++)
01399         {
01400                 // If staticLight not enabled, skip.
01401                 if( !_Instances[i].StaticLightEnabled )
01402                         continue;
01403 
01404                 CInstanceInfo                           &instSrc= _InstanceInfos[i];
01405                 CInstanceGroup::CInstance       &instDst= _Instances[i];
01406 
01407                 // Do it for PointLights
01408                 for(uint lightId= 0; lightId<CInstanceGroup::NumStaticLightPerInstance; lightId++)
01409                 {
01410                         if(instSrc.Light[lightId] == NULL)
01411                         {
01412                                 // Mark as unused.
01413                                 instDst.Light[lightId]= 0xFF;
01414                         }
01415                         else
01416                         {
01417                                 // Get index.
01418                                 instDst.Light[lightId]= instSrc.Light[lightId]->DstId;
01419                         }
01420                 }
01421 
01422                 // Do it for Ambientlight
01423                 if(instSrc.LocalAmbientLight == NULL)
01424                         instDst.LocalAmbientId= 0xFF;
01425                 else
01426                         instDst.LocalAmbientId= instSrc.LocalAmbientLight->DstId;
01427         }
01428 
01429         // For each cell, compress Point light info
01430         if(_IGSurfaceLightBuild)
01431         {
01432                 // Begin cell iteration
01433                 beginCell();
01434                 // For all surface cell corners
01435                 while( !isEndCell() )
01436                 {
01437                         // get the current cell and cellInfo iterated.
01438                         CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
01439                         CSurfaceLightGrid::CCellCorner          &cell= getCurrentCell();
01440 
01441                         if(cellInfo.InSurface)
01442                         {
01443                                 // Do it for PointLights
01444                                 for(uint lightId= 0; lightId<CSurfaceLightGrid::NumLightPerCorner; lightId++)
01445                                 {
01446                                         if(cellInfo.LightInfo[lightId] == NULL)
01447                                         {
01448                                                 // Mark as unused.
01449                                                 cell.Light[lightId]= 0xFF;
01450                                         }
01451                                         else
01452                                         {
01453                                                 // Get index.
01454                                                 cell.Light[lightId]= reinterpret_cast<CPointLightRT*>(cellInfo.LightInfo[lightId])->DstId;
01455                                         }
01456                                 }
01457 
01458                                 // Do it for Ambientlight
01459                                 if(cellInfo.LocalAmbientLight == NULL)
01460                                         cell.LocalAmbientId= 0xFF;
01461                                 else
01462                                         cell.LocalAmbientId= ((CPointLightRT*)cellInfo.LocalAmbientLight)->DstId;
01463                         }
01464 
01465                         // next cell
01466                         nextCell();
01467                 }
01468         }
01469 
01470 
01471 }
01472 
01473 
01474 // ***************************************************************************
01475 // ***************************************************************************
01476 // lightIgSimple
01477 // ***************************************************************************
01478 // ***************************************************************************
01479 
01480 
01481 // ***************************************************************************
01482 void    CInstanceLighter::lightIgSimple(CInstanceLighter &instLighter, const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc)
01483 {
01484         sint                            i;
01485 
01486 
01487         // Setup.
01488         //=======
01489         // Init
01490         instLighter.init();
01491 
01492         // Add obstacles.
01493         std::vector<CInstanceLighter::CTriangle>        obstacles;
01494         // only if Shadowing On.
01495         if(lightDesc.Shadow)
01496         {
01497                 // Map of shape to load
01498                 std::map<string, IShape*> shapeMap;
01499 
01500                 // For all instances of igIn.
01501                 for(i=0; i<(sint)igIn.getNumInstance();i++)
01502                 {
01503                         // progress
01504                         instLighter.progress("Loading Shapes obstacles", float(i)/igIn.getNumInstance());
01505 
01506                         // Skip it??
01507                         if(igIn.getInstance(i).DontCastShadow)
01508                                 continue;
01509 
01510                         // Get the instance shape name
01511                         string name= igIn.getShapeName(i);
01512                         bool    shapeFound= true;
01513 
01514                         // Try to find the shape in the UseShapeMap.
01515                         std::map<string, IShape*>::const_iterator iteMap= lightDesc.UserShapeMap.find (name);
01516 
01517                         // If not found in userShape map, try to load it from the temp loaded ShapeBank.
01518                         if( iteMap == lightDesc.UserShapeMap.end() )
01519                         {
01520                                 // Add a .shape at the end ?
01521                                 if (name.find('.') == std::string::npos)
01522                                         name += ".shape";
01523 
01524                                 // Get the instance shape name
01525                                 string nameLookup = CPath::lookup (name, false, false);
01526                                 if (!nameLookup.empty())
01527                                         name = nameLookup;
01528 
01529                                 // Find the shape in the bank
01530                                 iteMap= shapeMap.find (name);
01531                                 if (iteMap==shapeMap.end())
01532                                 {
01533                                         // Input file
01534                                         CIFile inputFile;
01535 
01536                                         if (!name.empty() && inputFile.open (name))
01537                                         {
01538                                                 // Load it
01539                                                 CShapeStream stream;
01540                                                 stream.serial (inputFile);
01541 
01542                                                 // Get the pointer
01543                                                 iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
01544                                         }
01545                                         else
01546                                         {
01547                                                 // Error
01548                                                 nlwarning ("WARNING can't load shape %s\n", name.c_str());
01549                                                 shapeFound= false;
01550                                         }
01551                                 }
01552                         }
01553                         
01554                         if(shapeFound)
01555                         {
01556                                 CMatrix         matInst;
01557                                 matInst.setPos(igIn.getInstancePos(i));
01558                                 matInst.setRot(igIn.getInstanceRot(i));
01559                                 matInst.scale(igIn.getInstanceScale(i));
01560                                 // Add triangles of this shape
01561                                 CInstanceLighter::addTriangles(*iteMap->second, matInst, obstacles, i);
01562                         }
01563 
01564                 }
01565 
01566                 // Clean Up shapes.
01567                 //-----------
01568                 std::map<string, IShape*>::iterator iteMap;
01569                 iteMap= shapeMap.begin();
01570                 while(iteMap!= shapeMap.end())
01571                 {
01572                         // delte shape
01573                         delete  iteMap->second;
01574                         // delete entry in map
01575                         shapeMap.erase(iteMap);
01576                         // next
01577                         iteMap= shapeMap.begin();
01578                 }
01579         }
01580 
01581         // Add pointLights of the IG.
01582         for(i=0; i<(sint)igIn.getPointLightList().size();i++)
01583         {
01584                 instLighter.addStaticPointLight( igIn.getPointLightList()[i] );
01585         }
01586 
01587 
01588         // Run.
01589         //=======
01590         instLighter.light(igIn, igOut, lightDesc, obstacles);
01591 
01592 }
01593 
01594 
01595 // ***************************************************************************
01596 // ***************************************************************************
01597 // Cell Iteration
01598 // ***************************************************************************
01599 // ***************************************************************************
01600 
01601 
01602 // ***************************************************************************
01603 void                    CInstanceLighter::progressCell(const char *message)
01604 {
01605         float   cp= getCurrentCellNumber() / float(getTotalCellNumber());
01606         if( cp > _LastCellProgress+0.05f)
01607         {
01608                 progress(message, cp);
01609                 _LastCellProgress= cp;
01610         }
01611 }
01612 
01613 
01614 // ***************************************************************************
01615 void                    CInstanceLighter::beginCell()
01616 {
01617         if(_IGSurfaceLightBuild)
01618         {
01619                 _ItRetriever= _IGRetrieverGridMap.begin();
01620                 if(_ItRetriever != _IGRetrieverGridMap.end() )
01621                 {
01622                         _ItRetrieverInfo= _IGSurfaceLightBuild->RetrieverGridMap.find(_ItRetriever->first);
01623                         nlassert(_ItRetrieverInfo != _IGSurfaceLightBuild->RetrieverGridMap.end() );
01624                         // We are suze here that the retriever is not empty, and that the grid herself is not empty too
01625                         _ItSurfId= 0;
01626                         _ItCellId= 0;
01627                         _ItCurrentCellNumber= 0;
01628                         _IsEndCell= false;
01629                         _LastCellProgress= 0;
01630                 }
01631                 else
01632                 {
01633                         _IsEndCell= true;
01634                 }
01635         }
01636         else
01637         {
01638                 _IsEndCell= true;
01639         }
01640 }
01641 
01642 // ***************************************************************************
01643 void                    CInstanceLighter::nextCell()
01644 {
01645         nlassert(!isEndCell());
01646 
01647         // Next Cell.
01648         _ItCellId++;
01649         _ItCurrentCellNumber++;
01650 
01651         // If end of Cells, next surface.
01652         if(_ItCellId >= _ItRetriever->second.Grids[_ItSurfId].Cells.size() )
01653         {
01654                 _ItCellId= 0;
01655                 _ItSurfId ++;
01656         }
01657 
01658         // If end of surface, next retriever.
01659         if(_ItSurfId >= _ItRetriever->second.Grids.size() )
01660         {
01661                 _ItSurfId= 0;
01662                 _ItRetriever++;
01663                 if(_ItRetriever != _IGRetrieverGridMap.end())
01664                 {
01665                         // Get info.
01666                         _ItRetrieverInfo= _IGSurfaceLightBuild->RetrieverGridMap.find(_ItRetriever->first);
01667                         nlassert(_ItRetrieverInfo != _IGSurfaceLightBuild->RetrieverGridMap.end() );
01668                 }
01669         }
01670 
01671         // If end of retreiver, End.
01672         if(_ItRetriever == _IGRetrieverGridMap.end())
01673         {
01674                 _IsEndCell= true;
01675         }
01676 }
01677 
01678 // ***************************************************************************
01679 bool                    CInstanceLighter::isEndCell()
01680 {
01681         return _IsEndCell;
01682 }
01683 
01684 // ***************************************************************************
01685 CSurfaceLightGrid::CCellCorner          &CInstanceLighter::getCurrentCell()
01686 {
01687         nlassert(!isEndCell());
01688 
01689         // return ref on Cell.
01690         return  _ItRetriever->second.Grids[_ItSurfId].Cells[_ItCellId];
01691 }
01692 
01693 // ***************************************************************************
01694 CIGSurfaceLightBuild::CCellCorner       &CInstanceLighter::getCurrentCellInfo()
01695 {
01696         nlassert(!isEndCell());
01697 
01698         // return ref on CellInfo.
01699         return _ItRetrieverInfo->second.Grids[_ItSurfId].Cells[_ItCellId];
01700 }
01701 
01702 
01703 // ***************************************************************************
01704 bool                    CInstanceLighter::isCurrentNeighborCellInSurface(sint xnb, sint ynb)
01705 {
01706         nlassert(!isEndCell());
01707 
01708         // get a ref on the current grid.
01709         CSurfaceLightGrid       &surfGrid= _ItRetriever->second.Grids[_ItSurfId];
01710         // copute coordinate of the current cellCorner.
01711         sint    xCell, yCell;
01712         xCell= _ItCellId%surfGrid.Width;
01713         yCell= _ItCellId/surfGrid.Width;
01714         // compute coordinate of the neighbor cell corner
01715         xCell+= xnb;
01716         yCell+= ynb;
01717 
01718         // check if in the surfaceGrid
01719         if(xCell<0 || xCell>=(sint)surfGrid.Width)
01720                 return false;
01721         if(yCell<0 || yCell>=(sint)surfGrid.Height)
01722                 return false;
01723 
01724         // compute the neighbor id
01725         uint    nbId= yCell*surfGrid.Width + xCell;
01726 
01727         // Now check in the cellInfo if this cell is InSurface.
01728         if( !_ItRetrieverInfo->second.Grids[_ItSurfId].Cells[nbId].InSurface )
01729                 return false;
01730 
01731         // Ok, the neighbor cell is valid.
01732 
01733         return true;
01734 }
01735 
01736 // ***************************************************************************
01737 CSurfaceLightGrid::CCellCorner          &CInstanceLighter::getCurrentNeighborCell(sint xnb, sint ynb)
01738 {
01739         nlassert(isCurrentNeighborCellInSurface(xnb, ynb));
01740 
01741         // get a ref on the current grid.
01742         CSurfaceLightGrid       &surfGrid= _ItRetriever->second.Grids[_ItSurfId];
01743         // copute coordinate of the current cellCorner.
01744         sint    xCell, yCell;
01745         xCell= _ItCellId%surfGrid.Width;
01746         yCell= _ItCellId/surfGrid.Width;
01747         // compute coordinate of the neighbor cell corner
01748         xCell+= xnb;
01749         yCell+= ynb;
01750         // compute the neighbor id
01751         uint    nbId= yCell*surfGrid.Width + xCell;
01752 
01753         // then return a ref on it
01754         return surfGrid.Cells[nbId];
01755 }
01756 
01757 
01758 // ***************************************************************************
01759 CIGSurfaceLightBuild::CCellCorner       &CInstanceLighter::getCurrentNeighborCellInfo(sint xnb, sint ynb)
01760 {
01761         nlassert(isCurrentNeighborCellInSurface(xnb, ynb));
01762 
01763         // get a ref on the current grid.
01764         CIGSurfaceLightBuild::CSurface  &surfGrid= _ItRetrieverInfo->second.Grids[_ItSurfId];
01765         // copute coordinate of the current cellCorner.
01766         sint    xCell, yCell;
01767         xCell= _ItCellId%surfGrid.Width;
01768         yCell= _ItCellId/surfGrid.Width;
01769         // compute coordinate of the neighbor cell corner
01770         xCell+= xnb;
01771         yCell+= ynb;
01772         // compute the neighbor id
01773         uint    nbId= yCell*surfGrid.Width + xCell;
01774 
01775         // then return a ref on it
01776         return surfGrid.Cells[nbId];
01777 }
01778 
01779 
01780 // ***************************************************************************
01781 void                    CInstanceLighter::dilateLightingOnSurfaceCells()
01782 {
01783         // Begin cell iteration
01784         beginCell();
01785         // For all surface cell corners
01786         while( !isEndCell() )
01787         {
01788                 progressCell("Dilate Surfaces grids");
01789 
01790                 // get the current cell and cellInfo iterated.
01791                 CIGSurfaceLightBuild::CCellCorner       &cellInfo= getCurrentCellInfo();
01792                 CSurfaceLightGrid::CCellCorner          &cell= getCurrentCell();
01793 
01794                 // if the cell is not in the polygon surface, try to get from his neighbors.
01795                 if(!cellInfo.InSurface)
01796                 {
01797                         // Add Weighted influence of SunContribution, and get one of the PointLightContribution (random).
01798                         uint    wgtSunContribution= 0;
01799                         uint    wgtSunCount= 0;
01800                         // search if one of 8 neighbors is InSurface.
01801                         for(sint ynb= -1; ynb<= 1; ynb++)
01802                         {
01803                                 for(sint xnb= -1; xnb<= 1; xnb++)
01804                                 {
01805                                         // center => skip.
01806                                         if( xnb==0 && ynb==0 )
01807                                                 continue;
01808                                         // If the neighbor point is not out of the grid, and if in Surface.
01809                                         if( isCurrentNeighborCellInSurface(xnb, ynb) )
01810                                         {
01811                                                 // get the neighbor cell
01812                                                 CIGSurfaceLightBuild::CCellCorner       &nbCellInfo= getCurrentNeighborCellInfo(xnb, ynb);
01813                                                 CSurfaceLightGrid::CCellCorner          &nbCell= getCurrentNeighborCell(xnb, ynb);
01814                                                 // Add SunContribution.
01815                                                 wgtSunContribution+= nbCell.SunContribution;
01816                                                 wgtSunCount++;
01817                                                 // Just Copy PointLight info.
01818                                                 for(uint lightId= 0; lightId<CSurfaceLightGrid::NumLightPerCorner; lightId++)
01819                                                         cell.Light[lightId]= nbCell.Light[lightId];
01820                                                 // Just Copy AmbientLight info.
01821                                                 cell.LocalAmbientId= nbCell.LocalAmbientId;
01822 
01823 
01824                                                 // For debug mesh only, copy z from nb cellInfo
01825                                                 cellInfo.CenterPos.z= nbCellInfo.CenterPos.z;
01826                                         }
01827                                 }
01828                         }
01829                         // average SunContribution.
01830                         if(wgtSunCount>0)
01831                         {
01832                                 cell.SunContribution= wgtSunContribution / wgtSunCount;
01833 
01834                                 // For debug mesh only, copy SunContribution into cellInfo
01835                                 cellInfo.SunContribution= cell.SunContribution;
01836                                 cellInfo.Dilated= true;
01837                         }
01838                 }
01839 
01840                 // next cell
01841                 nextCell();
01842         }
01843 }
01844 
01845 
01846 
01847 } // NL3D