Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / instance_lighter.cpp
blob3b1887bb4e7d291a10193d5c63d91d63d0c39de1
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/instance_lighter.h"
23 #include "nel/3d/mesh_multi_lod.h"
24 #include "nel/misc/file.h"
25 #include "nel/misc/path.h"
26 #include "nel/3d/visual_collision_manager.h"
27 #include "nel/3d/visual_collision_entity.h"
28 #include "nel/3d/ig_surface_light_build.h"
31 using namespace std;
32 using namespace NLMISC;
34 #ifdef DEBUG_NEW
35 #define new DEBUG_NEW
36 #endif
38 namespace NL3D {
41 // Bad coded: don't set too big else it allocates too much memory.
42 #define NL3D_INSTANCE_LIGHTER_CUBE_GRID_SIZE 16
45 // ***************************************************************************
46 // ***************************************************************************
47 // Setup part
48 // ***************************************************************************
49 // ***************************************************************************
52 // ***************************************************************************
53 CInstanceLighter::CLightDesc::CLightDesc ()
55 LightDirection.set (1, 1, -1);
56 GridSize=512;
57 GridCellSize=4;
58 Shadow= true;
59 OverSampling= 0;
60 DisableSunContribution= false;
63 // ***************************************************************************
64 CInstanceLighter::CInstanceLighter()
66 _IGSurfaceLightBuild= NULL;
69 // ***************************************************************************
70 void CInstanceLighter::init ()
74 // ***************************************************************************
75 void CInstanceLighter::addTriangles (CLandscape &landscape, std::vector<uint> &listZone, uint order, std::vector<CTriangle>& triangleArray)
77 // Lamed from CZoneLighter.
78 // Set all to refine
79 excludeAllPatchFromRefineAll (landscape, listZone, false);
81 // Setup the landscape
82 landscape.setThreshold (0);
83 landscape.setTileMaxSubdivision (order);
85 // Refine it
86 landscape.refineAll (CVector (0, 0, 0));
88 // Dump tesselated triangles
89 std::vector<const CTessFace*> leaves;
90 landscape.getTessellationLeaves(leaves);
92 // Number of leaves
93 uint leavesCount=(uint)leaves.size();
95 // Reserve the array
96 triangleArray.reserve (triangleArray.size()+leavesCount);
98 // Scan each leaves
99 for (uint leave=0; leave<leavesCount; leave++)
101 // Leave
102 const CTessFace *face=leaves[leave];
104 // Add a triangle. -1 because not an instance from an IG
105 triangleArray.push_back (CTriangle (NLMISC::CTriangle (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos), -1 ));
108 // Setup the landscape
109 landscape.setThreshold (1000);
110 landscape.setTileMaxSubdivision (0);
112 // Remove all triangles
113 landscape.refineAll (CVector (0, 0, 0));
114 landscape.refineAll (CVector (0, 0, 0));
115 landscape.refineAll (CVector (0, 0, 0));
116 landscape.refineAll (CVector (0, 0, 0));
117 landscape.refineAll (CVector (0, 0, 0));
118 landscape.refineAll (CVector (0, 0, 0));
119 landscape.refineAll (CVector (0, 0, 0));
120 landscape.refineAll (CVector (0, 0, 0));
121 landscape.refineAll (CVector (0, 0, 0));
122 landscape.refineAll (CVector (0, 0, 0));
126 // ***************************************************************************
127 void CInstanceLighter::addTriangles (const IShape &shape, const NLMISC::CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
129 // Lamed from CZoneLighter.
131 // Cast to CMesh
132 const CMesh *mesh=dynamic_cast<const CMesh*>(&shape);
134 // Cast to CMeshMultiLod
135 const CMeshMultiLod *meshMulti=dynamic_cast<const CMeshMultiLod*>(&shape);
137 // Cast to CMeshMultiLod
138 const CMeshMRM *meshMRM=dynamic_cast<const CMeshMRM*>(&shape);
140 // It is a mesh ?
141 if (mesh)
143 // Add its triangles
144 addTriangles (mesh->getMeshGeom (), modelMT, triangleArray, instanceId);
146 // It is a CMeshMultiLod ?
147 else if (meshMulti)
149 // Get the first geommesh
150 const IMeshGeom *meshGeom=&meshMulti->getMeshGeom (0);
152 // Dynamic cast
153 const CMeshGeom *geomMesh=dynamic_cast<const CMeshGeom*>(meshGeom);
154 if (geomMesh)
156 addTriangles (*geomMesh, modelMT, triangleArray, instanceId);
159 // Dynamic cast
160 const CMeshMRMGeom *mrmGeomMesh=dynamic_cast<const CMeshMRMGeom*>(meshGeom);
161 if (mrmGeomMesh)
163 addTriangles (*mrmGeomMesh, modelMT, triangleArray, instanceId);
166 // It is a CMeshMultiLod ?
167 else if (meshMRM)
169 // Get the first lod mesh geom
170 addTriangles (meshMRM->getMeshGeom (), modelMT, triangleArray, instanceId);
175 // ***************************************************************************
177 void CInstanceLighter::addTriangles (const CMeshGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
179 // Get the vertex buffer
180 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
181 CVertexBufferRead vba;
182 vb.lock (vba);
184 // For each matrix block
185 uint numBlock=meshGeom.getNbMatrixBlock();
186 for (uint block=0; block<numBlock; block++)
188 // For each render pass
189 uint numRenderPass=meshGeom.getNbRdrPass(block);
190 for (uint pass=0; pass<numRenderPass; pass++)
192 // Get the primitive block
193 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( block, pass);
195 // Dump triangles
196 CIndexBufferRead iba;
197 primitive.lock (iba);
198 uint numTri=primitive.getNumIndexes ()/3;
199 uint tri;
200 if (primitive.getFormat() == CIndexBuffer::Indices16)
202 const uint16* triIndex=(uint16*)iba.getPtr ();
203 for (tri=0; tri<numTri; tri++)
205 // Vertex
206 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
207 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
208 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
210 // Make a triangle
211 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
214 else
216 const uint32* triIndex=(uint32*)iba.getPtr ();
217 for (tri=0; tri<numTri; tri++)
219 // Vertex
220 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
221 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
222 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
224 // Make a triangle
225 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
232 // ***************************************************************************
234 void CInstanceLighter::addTriangles (const CMeshMRMGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray, sint instanceId)
236 // Get the vertex buffer
237 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
238 CVertexBufferRead vba;
239 vb.lock (vba);
241 // For each render pass
242 uint numRenderPass=meshGeom.getNbRdrPass(0);
243 for (uint pass=0; pass<numRenderPass; pass++)
245 // Get the primitive block
246 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( 0, pass);
248 // Dump triangles
249 CIndexBufferRead iba;
250 primitive.lock (iba);
251 uint numTri=primitive.getNumIndexes ()/3;
252 uint tri;
253 if (primitive.getFormat() == CIndexBuffer::Indices16)
255 const uint16* triIndex=(uint16*)iba.getPtr ();
256 for (tri=0; tri<numTri; tri++)
258 // Vertex
259 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
260 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
261 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
263 // Make a triangle
264 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
267 else
269 const uint32* triIndex=(uint32*)iba.getPtr ();
270 for (tri=0; tri<numTri; tri++)
272 // Vertex
273 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
274 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
275 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
277 // Make a triangle
278 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), instanceId));
284 // ***************************************************************************
286 void CInstanceLighter::excludeAllPatchFromRefineAll (CLandscape &landscape, vector<uint> &listZone, bool exclude)
288 // For each zone
289 for (uint zone=0; zone<listZone.size(); zone++)
291 // Get num patches
292 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
294 // For each patches
295 for (uint patch=0; patch<patchCount; patch++)
297 // Exclude all the patches from refine all
298 landscape.excludePatchFromRefineAll (listZone[zone], patch, exclude);
304 // ***************************************************************************
305 // ***************************************************************************
306 // light part
307 // ***************************************************************************
308 // ***************************************************************************
312 // ***************************************************************************
313 void CInstanceLighter::light (const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc,
314 std::vector<CTriangle>& obstacles, CLandscape *landscape, CIGSurfaceLightBuild *igSurfaceLightBuild)
316 sint i;
317 CVector outGlobalPos;
318 std::vector<CCluster> outClusters;
319 std::vector<CPortal> outPortals;
320 std::vector<CPointLightNamed> pointLightList;
322 nlassert(lightDesc.OverSampling==0 || lightDesc.OverSampling==2 || lightDesc.OverSampling==4
323 || lightDesc.OverSampling==8 || lightDesc.OverSampling==16);
325 // Setup.
326 //========
328 // Prepare IGSurfaceLight lighting
329 //-----------
330 // Bkup SurfaceLightBuild to know if must light the surfaces, in differents part of the process.
331 _IGSurfaceLightBuild= igSurfaceLightBuild;
332 // Prepare _IGRetrieverGridMap.
333 _IGRetrieverGridMap.clear();
334 if(_IGSurfaceLightBuild)
336 _TotalCellNumber= 0;
337 CIGSurfaceLightBuild::ItRetrieverGridMap itSrc;
338 itSrc= _IGSurfaceLightBuild->RetrieverGridMap.begin();
339 // For all retrievers Infos in _IGSurfaceLightBuild
340 while(itSrc!=_IGSurfaceLightBuild->RetrieverGridMap.end())
342 uint numSurfaces= (uint)itSrc->second.Grids.size();
343 // If !empty retriever.
344 if(numSurfaces>0)
346 // Add it to the map,
347 CIGSurfaceLight::CRetrieverLightGrid &rlgDst= _IGRetrieverGridMap[itSrc->first];
348 // resize Array of surfaces.
349 rlgDst.Grids.resize(numSurfaces);
350 // For all surfaces, init them in rlgDst.
351 for(uint i=0; i<numSurfaces; i++)
353 CIGSurfaceLightBuild::CSurface &surfSrc= itSrc->second.Grids[i];
354 CSurfaceLightGrid &surfDst= rlgDst.Grids[i];
355 // Init Cells with a default CellCorner
356 CSurfaceLightGrid::CCellCorner defaultCellCorner;
357 defaultCellCorner.SunContribution= 0;
358 defaultCellCorner.Light[0]= 0xFF;
359 defaultCellCorner.Light[1]= 0xFF;
360 defaultCellCorner.LocalAmbientId= 0xFF;
362 // Init the grid.
363 surfDst.Origin= surfSrc.Origin;
364 surfDst.Width= surfSrc.Width;
365 surfDst.Height= surfSrc.Height;
366 surfDst.Cells.resize((uint32)surfSrc.Cells.size());
367 surfDst.Cells.fill(defaultCellCorner);
368 // The grid must be valid an not empty
369 nlassert( surfDst.Cells.size() == surfDst.Width*surfDst.Height );
370 nlassert( surfDst.Width>= 2 );
371 nlassert( surfDst.Height>= 2 );
373 _TotalCellNumber+= surfDst.Cells.size();
377 // Next localRetriever info.
378 itSrc++;
381 // Reset cell iteration.
382 _IsEndCell= true;
385 // Retrieve info from igIn.
386 //-----------
387 igIn.retrieve (outGlobalPos, _Instances, outClusters, outPortals, pointLightList);
390 // set All Instances StaticLightEnabled= true, and Build _InstanceInfos.
391 //-----------
392 // Map of shape
393 std::map<string, IShape*> shapeMap;
394 _InstanceInfos.resize(_Instances.size());
395 for(i=0; i<(sint)_Instances.size();i++)
397 // Avoid StaticLight precomputing??
398 if(_Instances[i].AvoidStaticLightPreCompute)
400 _Instances[i].StaticLightEnabled= false;
401 // Next instance.
402 continue;
405 // Else let's do it.
406 _Instances[i].StaticLightEnabled= true;
409 // Get the shape centerPos;
410 //------------
411 CVector shapeCenterPos;
412 CVector overSamples[MaxOverSamples];
414 // Get the instance shape name
415 string name= _Instances[i].Name;
416 bool shapeFound= true;
418 if (toLowerAscii (CFile::getExtension (name)) == "pacs_prim")
420 nlwarning("EXPORT BUG: Can't read %s (not a shape), should not be part of .ig!", name.c_str());
421 continue;
424 // Try to find the shape in the UseShapeMap.
425 std::map<string, IShape*>::const_iterator iteMap= lightDesc.UserShapeMap.find (name);
427 // If not found in userShape map, try to load it from the temp loaded ShapeBank.
428 if( iteMap == lightDesc.UserShapeMap.end() )
430 // Add a .shape at the end ?
431 if (name.find('.') == std::string::npos)
432 name += ".shape";
434 // Get the instance shape name
435 string nameLookup = CPath::lookup (name, false, false);
436 if (!nameLookup.empty())
437 name = nameLookup;
439 // Find the shape in the bank
440 iteMap= shapeMap.find (name);
441 if (iteMap==shapeMap.end())
443 // Input file
444 CIFile inputFile;
446 if (!name.empty() && inputFile.open (name))
448 // Load it
449 CShapeStream stream;
450 stream.serial (inputFile);
452 // Get the pointer
453 iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
455 else
457 // Error
458 nlwarning ("WARNING can't load shape %s\n", name.c_str());
459 shapeFound= false;
465 // Last chance to skip it: fully LightMapped ??
466 //-----------
467 if(shapeFound)
469 CMeshBase *mesh= dynamic_cast<CMeshBase*>(iteMap->second);
470 if(mesh)
472 // If this mesh is not lightable (fully lightMapped)
473 if(!mesh->isLightable())
475 // Force Avoid StaticLight precomputing
476 _Instances[i].AvoidStaticLightPreCompute= true;
477 // Disable static lighting.
478 _Instances[i].StaticLightEnabled= false;
479 // Next instance.
480 continue;
486 // Compute pos and OverSamples
487 //-----------
489 // Compute bbox, or default bbox
490 CAABBox bbox;
491 if(!shapeFound)
493 bbox.setCenter(CVector::Null);
494 bbox.setHalfSize(CVector::Null);
496 else
498 iteMap->second->getAABBox(bbox);
500 // get pos
501 shapeCenterPos= bbox.getCenter();
504 // Compute overSamples
505 float qx= bbox.getHalfSize().x/2;
506 float qy= bbox.getHalfSize().y/2;
507 float qz= bbox.getHalfSize().z/2;
508 // No OverSampling => just copy.
509 if(lightDesc.OverSampling==0)
510 overSamples[0]= shapeCenterPos;
511 else if(lightDesc.OverSampling==2)
513 // Prefer Z Axis.
514 overSamples[0]= shapeCenterPos + CVector(0, 0, qz);
515 overSamples[1]= shapeCenterPos - CVector(0, 0, qz);
517 else if(lightDesc.OverSampling==4)
519 // Apply an overSampling such that we see 4 points if we look on each side of the bbox.
520 overSamples[0]= shapeCenterPos + CVector(-qx, -qy, -qz);
521 overSamples[1]= shapeCenterPos + CVector(+qx, -qy, +qz);
522 overSamples[2]= shapeCenterPos + CVector(-qx, +qy, +qz);
523 overSamples[3]= shapeCenterPos + CVector(+qx, +qy, -qz);
525 else if(lightDesc.OverSampling==8 || lightDesc.OverSampling==16)
527 // 8x is the best overSampling shceme for bbox
528 overSamples[0]= shapeCenterPos + CVector(-qx, -qy, -qz);
529 overSamples[1]= shapeCenterPos + CVector(+qx, -qy, -qz);
530 overSamples[2]= shapeCenterPos + CVector(-qx, +qy, -qz);
531 overSamples[3]= shapeCenterPos + CVector(+qx, +qy, -qz);
532 overSamples[4]= shapeCenterPos + CVector(-qx, -qy, +qz);
533 overSamples[5]= shapeCenterPos + CVector(+qx, -qy, +qz);
534 overSamples[6]= shapeCenterPos + CVector(-qx, +qy, +qz);
535 overSamples[7]= shapeCenterPos + CVector(+qx, +qy, +qz);
537 // 16x => use this setup, and decal from 1/8
538 if(lightDesc.OverSampling==16)
540 CVector decal(qx/2, qy/2, qz/2);
541 for(uint sample=0; sample<8; sample++)
543 // Copy and decal
544 overSamples[sample+8]= overSamples[sample] + decal;
545 // neg decal me
546 overSamples[sample]-= decal;
553 // Compute pos of the instance
554 //------------
555 CMatrix matInst;
556 matInst.setPos(_Instances[i].Pos);
557 matInst.setRot(_Instances[i].Rot);
558 matInst.scale(_Instances[i].Scale);
559 _InstanceInfos[i].CenterPos= matInst * shapeCenterPos;
560 // Apply matInst to samples.
561 uint nSamples= max(1U, lightDesc.OverSampling);
562 for(uint sample=0; sample<nSamples; sample++)
564 _InstanceInfos[i].OverSamples[sample]= matInst * overSamples[sample];
568 // Clean Up shapes.
569 //-----------
570 std::map<string, IShape*>::iterator iteMap;
571 iteMap= shapeMap.begin();
572 while(iteMap!= shapeMap.end())
574 // delte shape
575 delete iteMap->second;
576 // delete entry in map
577 shapeMap.erase(iteMap);
578 // next
579 iteMap= shapeMap.begin();
582 // Build all obstacles plane.
583 //-----------
584 for(i=0; i<(sint)obstacles.size();i++)
586 CInstanceLighter::CTriangle& triangle=obstacles[i];
587 // Calc the plane
588 triangle.Plane.make (triangle.Triangle.V0, triangle.Triangle.V1, triangle.Triangle.V2);
592 // Lighting
593 //========
594 // Light With Sun: build the grid, and do it on all _Instances, using _InstanceInfos
595 // Compute also Lighting on surface.
596 computeSunContribution(lightDesc, obstacles, landscape);
598 // Light With PointLights
599 // build the cubeGrids
600 compilePointLightRT(lightDesc.GridSize, lightDesc.GridCellSize, obstacles, lightDesc.Shadow);
601 // kill pointLightList, because will use mine.
602 pointLightList.clear();
603 // Light for all _Instances, using _InstanceInfos
604 // Compute also Lighting on surface.
605 processIGPointLightRT(pointLightList);
607 // If _IGSurfaceLightBuild, then dilate lighting
608 if(_IGSurfaceLightBuild)
610 dilateLightingOnSurfaceCells();
614 // Build result.
615 //========
616 if(_IGSurfaceLightBuild)
618 // build with IGSurfaceLight lighting
619 igOut.build(outGlobalPos, _Instances, outClusters, outPortals, pointLightList,
620 &_IGRetrieverGridMap, _IGSurfaceLightBuild->CellSize);
622 else
624 // build without IGSurfaceLight lighting
625 igOut.build(outGlobalPos, _Instances, outClusters, outPortals, pointLightList);
631 // ***************************************************************************
632 static void NEL3DCalcBase (CVector &direction, CMatrix& matrix)
634 direction.normalize();
635 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);
636 CVector K=-direction;
637 CVector J=K^I;
638 J.normalize();
639 I=J^K;
640 I.normalize();
641 matrix.identity();
642 matrix.setRot(I,J,K, true);
647 // ***************************************************************************
648 void CInstanceLighter::computeSunContribution(const CLightDesc &lightDesc, std::vector<CTriangle>& obstacles, CLandscape *landscape)
650 sint i;
651 // Use precoputed landscape SunContribution
652 CVisualCollisionManager *VCM= NULL;
653 CVisualCollisionEntity *VCE= NULL;
654 if(landscape)
656 // create a CVisualCollisionManager and a CVisualCollisionEntity
657 VCM= new CVisualCollisionManager;
658 VCM->setLandscape(landscape);
659 VCE= VCM->createEntity();
661 std::vector<CPointLightInfluence> dummyPointLightFromLandscape;
662 dummyPointLightFromLandscape.reserve(1024);
665 // If DisableSunContribution, easy,
666 if(lightDesc.DisableSunContribution)
668 // Light all instances.
669 //==========
670 for(i=0; i<(sint)_Instances.size(); i++)
672 // If staticLight not enabled, skip.
673 if( !_Instances[i].StaticLightEnabled )
674 continue;
676 // fill SunContribution to 0
677 _Instances[i].SunContribution= 0;
680 // Light SurfaceGrid Cells.
681 //==========
682 if(_IGSurfaceLightBuild)
684 // Begin cell iteration
685 beginCell();
686 // For all surface cell corners
687 while( !isEndCell() )
689 // get the current cell and cellInfo iterated.
690 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
691 CSurfaceLightGrid::CCellCorner &cell= getCurrentCell();
693 // if the cell corner lies in the polygon surface.
694 if(cellInfo.InSurface)
696 // fill SunContribution to 0
697 cell.SunContribution= 0;
698 // copy it to cellInfo
699 cellInfo.SunContribution= cell.SunContribution;
702 // next cell
703 nextCell();
707 // If no Raytrace Shadow, easy,
708 else if(!lightDesc.Shadow)
710 // Light all instances.
711 //==========
712 for(i=0; i<(sint)_Instances.size(); i++)
714 progress ("Compute SunContribution on Instances", i / float(_Instances.size()) );
716 // If staticLight not enabled, skip.
717 if( !_Instances[i].StaticLightEnabled )
718 continue;
720 // by default, fill SunContribution to 255
721 _Instances[i].SunContribution= 255;
722 // Try to get landscape SunContribution (better)
723 if(landscape)
725 CVector pos= _InstanceInfos[i].CenterPos;
726 uint8 landSunContribution;
727 dummyPointLightFromLandscape.clear();
728 // If find faces under me
729 NLMISC::CRGBA dummyAmbient;
730 if(VCE->getStaticLightSetup(NLMISC::CRGBA::Black, pos, dummyPointLightFromLandscape, landSunContribution, dummyAmbient) )
732 _Instances[i].SunContribution= landSunContribution;
737 // Light SurfaceGrid Cells.
738 //==========
739 if(_IGSurfaceLightBuild)
741 // Begin cell iteration
742 beginCell();
743 // For all surface cell corners
744 while( !isEndCell() )
746 progressCell("Compute SunContribution on Surfaces");
748 // get the current cell and cellInfo iterated.
749 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
750 CSurfaceLightGrid::CCellCorner &cell= getCurrentCell();
752 // if the cell corner lies in the polygon surface.
753 if(cellInfo.InSurface)
755 // Just init SunContribution to 255, since no shadowing.
756 cell.SunContribution= 255;
757 // copy it to cellInfo
758 cellInfo.SunContribution= cell.SunContribution;
761 // next cell
762 nextCell();
766 else
768 // Compute rayBasis
769 CVector rayDir= lightDesc.LightDirection;
770 CMatrix rayBasis;
771 rayDir.normalize();
772 NEL3DCalcBase(rayDir, rayBasis);
773 CMatrix invRayBasis;
774 invRayBasis= rayBasis.inverted();
776 // Build QuadGrid of obstacles.
777 //=========
778 // setup quadGrid
779 CQuadGrid<const CTriangle*> quadGrid;
780 quadGrid.changeBase (invRayBasis);
781 quadGrid.create(lightDesc.GridSize, lightDesc.GridCellSize);
782 // Insert all obstacles in quadGrid
783 for(i=0; i<(sint)obstacles.size(); i++)
785 CAABBox triBBox;
786 // Compute the bbox in rayBasis.
787 triBBox.setCenter(invRayBasis * obstacles[i].Triangle.V0);
788 triBBox.extend(invRayBasis * obstacles[i].Triangle.V1);
789 triBBox.extend(invRayBasis * obstacles[i].Triangle.V2);
790 // And set the coord in our world, because will be multiplied with invRayBasis in insert()
791 quadGrid.insert(rayBasis * triBBox.getMin(), rayBasis * triBBox.getMax(), &obstacles[i]);
794 // For all instances, light them.
795 //=========
796 for(i=0; i<(sint)_Instances.size(); i++)
798 progress ("Compute SunContribution on Instances", i / float(_Instances.size()) );
800 // If staticLight not enabled, skip.
801 if( !_Instances[i].StaticLightEnabled )
802 continue;
804 // try to use landscape SunContribution.
805 bool landUsed= false;
806 if(landscape)
808 CVector pos= _InstanceInfos[i].CenterPos;
809 uint8 landSunContribution;
810 dummyPointLightFromLandscape.clear();
811 // If find faces under me
812 NLMISC::CRGBA dummyAmbient;
813 if(VCE->getStaticLightSetup(NLMISC::CRGBA::Black, pos, dummyPointLightFromLandscape, landSunContribution, dummyAmbient) )
815 _Instances[i].SunContribution= landSunContribution;
816 landUsed= true;
820 // If failed to use landscape SunContribution, rayTrace
821 if(!landUsed)
823 // number of samples (1 if no overSampling)
824 uint nSamples= max(1U, lightDesc.OverSampling);
826 // Default is full lighted.
827 uint sunAccum= 255*nSamples;
829 // For all samples
830 for(uint sample=0; sample<nSamples; sample++)
832 // pos to rayTrace against
833 CVector pos= _InstanceInfos[i].OverSamples[sample];
835 // rayTrace from this pos.
836 CVector lightPos= pos-(rayDir*1000.f);
837 // Select an element with the X axis as a 3d ray
838 quadGrid.select (lightPos, lightPos);
839 // For each triangle selected
840 CQuadGrid<const CTriangle*>::CIterator it=quadGrid.begin();
841 while (it!=quadGrid.end())
843 const CTriangle *tri= *it;
845 // If same instanceId, skip
846 if(tri->InstanceId != i)
848 CVector hit;
849 // If triangle occlude the ray, no sun Contribution
850 if(tri->Triangle.intersect(lightPos, pos, hit, tri->Plane))
852 // The sample is not touched by sun. sub his contribution
853 sunAccum-= 255;
854 // End
855 break;
859 it++;
863 // Average samples
864 _Instances[i].SunContribution= sunAccum / nSamples;
870 // Light SurfaceGrid Cells.
871 //==========
872 if(_IGSurfaceLightBuild)
874 // No instance currenlty computed, since we compute surface cells.
875 _CurrentInstanceComputed= -1;
877 // Begin cell iteration
878 beginCell();
879 // For all surface cell corners
880 while( !isEndCell() )
882 progressCell("Compute SunContribution on Surfaces");
884 // get the current cell and cellInfo iterated.
885 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
886 CSurfaceLightGrid::CCellCorner &cell= getCurrentCell();
888 // if the cell corner lies in the polygon surface.
889 if(cellInfo.InSurface)
891 // number of samples (at least 1 if no overSampling)
892 uint nSamples= cellInfo.NumOverSamples;
893 nlassert(nSamples>=1);
895 // Default is full lighted.
896 uint sunAccum= 255*nSamples;
898 // For all samples
899 for(uint sample=0; sample<nSamples; sample++)
901 // Get pos to rayTrace.
902 CVector pos= cellInfo.OverSamples[sample];
904 // rayTrace from the pos of this Cell sample.
905 CVector lightPos= pos-(rayDir*1000.f);
906 // Select an element with the X axis as a 3d ray
907 quadGrid.select (lightPos, lightPos);
908 // For each triangle selected
909 CQuadGrid<const CTriangle*>::CIterator it=quadGrid.begin();
910 while (it!=quadGrid.end())
912 const CTriangle *tri= *it;
914 CVector hit;
915 // If triangle occlude the ray, no sun Contribution
916 if(tri->Triangle.intersect(lightPos, pos, hit, tri->Plane))
918 // The cell sample is not touched by sun. sub his contribution
919 sunAccum-= 255;
920 // End
921 break;
924 it++;
928 // Average SunContribution
929 cell.SunContribution= sunAccum / nSamples;
931 // copy it to cellInfo
932 cellInfo.SunContribution= cell.SunContribution;
935 // next cell
936 nextCell();
942 // Clean VCM and VCE
943 if(landscape)
945 // delete CVisualCollisionManager and CVisualCollisionEntity
946 VCM->deleteEntity(VCE);
947 delete VCM;
954 // ***************************************************************************
955 // ***************************************************************************
956 // PointLights part
957 // ***************************************************************************
958 // ***************************************************************************
961 // ***************************************************************************
962 CInstanceLighter::CPointLightRT::CPointLightRT()
964 RefCount= 0;
968 // ***************************************************************************
969 bool CInstanceLighter::CPointLightRT::testRaytrace(const CVector &v, sint instanceComputed)
971 CVector dummy;
973 if(!BSphere.include(v))
974 return false;
976 // If Ambient light, just skip
977 if(PointLight.getType()== CPointLight::AmbientLight)
978 return false;
980 // If SpotLight verify in angle radius.
981 if(PointLight.getType()== CPointLight::SpotLight)
983 float att= PointLight.computeLinearAttenuation(v);
984 if (att==0)
985 return false;
989 // Select in the cubeGrid
990 FaceCubeGrid.select(v);
991 // For all faces selected
992 while(!FaceCubeGrid.isEndSel())
994 const CTriangle *tri= FaceCubeGrid.getSel();
996 // If the triangle is not a triangle of the instance currenlty lighted
997 if( instanceComputed<0 || tri->InstanceId != instanceComputed )
999 // If intersect, the point is occluded.
1000 if( tri->Triangle.intersect(BSphere.Center, v, dummy, tri->getPlane()) )
1001 return false;
1004 // next
1005 FaceCubeGrid.nextSel();
1008 // Ok the point is visilbe from the light
1009 return true;
1013 // ***************************************************************************
1014 void CInstanceLighter::addStaticPointLight(const CPointLightNamed &pln, const char *igName)
1016 // NB: adding light more than 255 is allowed here, since the important thing is to not overflow really useful lights
1018 // build the plRT.
1019 CPointLightRT plRT;
1020 plRT.PointLight= pln;
1021 // compute plRT.OODeltaAttenuation
1022 plRT.OODeltaAttenuation= pln.getAttenuationEnd() - pln.getAttenuationBegin();
1023 if(plRT.OODeltaAttenuation <=0 )
1024 plRT.OODeltaAttenuation= 1e10f;
1025 else
1026 plRT.OODeltaAttenuation= 1.0f / plRT.OODeltaAttenuation;
1027 // compute plRT.BSphere
1028 plRT.BSphere.Center= pln.getPosition();
1029 plRT.BSphere.Radius= pln.getAttenuationEnd();
1030 // NB: FaceCubeGrid will be computed during light()
1032 // add the plRT
1033 _StaticPointLights.push_back(plRT);
1037 // ***************************************************************************
1038 void CInstanceLighter::compilePointLightRT(uint gridSize, float gridCellSize, std::vector<CTriangle>& obstacles, bool doShadow)
1040 uint i;
1042 // Fill the quadGrid of Lights.
1043 // ===========
1044 _StaticPointLightQuadGrid.create(gridSize, gridCellSize);
1045 for(i=0; i<_StaticPointLights.size();i++)
1047 CPointLightRT &plRT= _StaticPointLights[i];
1049 // Compute the bbox of the light
1050 CAABBox bbox;
1051 bbox.setCenter(plRT.BSphere.Center);
1052 float hl= plRT.BSphere.Radius;
1053 bbox.setHalfSize(CVector(hl,hl,hl));
1055 // Insert the pointLight in the quadGrid.
1056 _StaticPointLightQuadGrid.insert(bbox.getMin(), bbox.getMax(), &plRT);
1060 // Append triangles to cubeGrid ??
1061 if(doShadow)
1063 // For all obstacles, Fill a quadGrid.
1064 // ===========
1065 CQuadGrid<CTriangle*> obstacleGrid;
1066 obstacleGrid.create(gridSize, gridCellSize);
1067 uint size= (uint)obstacles.size();
1068 for(i=0; i<size; i++)
1070 // bbox of triangle
1071 CAABBox bbox;
1072 bbox.setCenter(obstacles[i].Triangle.V0);
1073 bbox.extend(obstacles[i].Triangle.V1);
1074 bbox.extend(obstacles[i].Triangle.V2);
1075 // insert triangle in quadGrid.
1076 obstacleGrid.insert(bbox.getMin(), bbox.getMax(), &obstacles[i]);
1080 // For all PointLights, fill his CubeGrid
1081 // ===========
1082 for(i=0; i<_StaticPointLights.size();i++)
1084 // progress
1085 progress ("Compute Influences of PointLights 1/2", i / (float)_StaticPointLights.size());
1087 CPointLightRT &plRT= _StaticPointLights[i];
1088 // Create the cubeGrid
1089 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), NL3D_INSTANCE_LIGHTER_CUBE_GRID_SIZE);
1091 // AmbiantLIghts: do nothing.
1092 if(plRT.PointLight.getType()!=CPointLight::AmbientLight)
1094 // Select only obstacle Faces around the light. Other are not useful
1095 CAABBox bbox;
1096 bbox.setCenter(plRT.PointLight.getPosition());
1097 float hl= plRT.PointLight.getAttenuationEnd();
1098 bbox.setHalfSize(CVector(hl,hl,hl));
1099 obstacleGrid.select(bbox.getMin(), bbox.getMax());
1101 // For all faces, fill the cubeGrid.
1102 CQuadGrid<CTriangle*>::CIterator itObstacle;
1103 itObstacle= obstacleGrid.begin();
1104 while( itObstacle!=obstacleGrid.end() )
1106 CTriangle &tri= *(*itObstacle);
1107 /* Don't Test BackFace culling Here (unlike in CZoneLighter !!).
1108 For objects:
1109 AutoOccluding problem is avoided with _CurrentInstanceComputed scheme.
1110 Also, With pointLights, there is no multiSampling (since no factor stored)
1111 Hence we are sure that no Object samples will lies under floor, and that the center of the
1112 object is far away.
1113 For IGSurface lighting:
1114 notice that we already add 20cm in height because of "stairs problem" so
1115 floor/surface auto_shadowing is not a problem here...
1117 // Insert the triangle in the CubeGrid
1118 plRT.FaceCubeGrid.insert( tri.Triangle, &tri);
1120 itObstacle++;
1124 // Compile the CubeGrid.
1125 plRT.FaceCubeGrid.compile();
1127 // And Reset RefCount.
1128 plRT.RefCount= 0;
1131 // else, just build empty grid
1132 else
1134 for(i=0; i<_StaticPointLights.size();i++)
1136 // progress
1137 progress ("Compute Influences of PointLights 1/2", i / (float)_StaticPointLights.size());
1139 CPointLightRT &plRT= _StaticPointLights[i];
1140 // Create a dummy empty cubeGrid => no rayTrace :)
1141 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), 4);
1143 // Compile the CubeGrid.
1144 plRT.FaceCubeGrid.compile();
1146 // And Reset RefCount.
1147 plRT.RefCount= 0;
1154 // ***************************************************************************
1155 bool CInstanceLighter::CPredPointLightToPoint::operator() (CPointLightRT *pla, CPointLightRT *plb) const
1157 float ra= (pla->BSphere.Center - Point).norm();
1158 float rb= (plb->BSphere.Center - Point).norm();
1159 float infA= (pla->PointLight.getAttenuationEnd() - ra) * pla->OODeltaAttenuation;
1160 float infB= (plb->PointLight.getAttenuationEnd() - rb) * plb->OODeltaAttenuation;
1161 // It is important to clamp, else strange results...
1162 clamp(infA, 0.f, 1.f);
1163 clamp(infB, 0.f, 1.f);
1164 // return which light impact the most.
1165 // If same impact
1166 if(infA==infB)
1167 // return nearest
1168 return ra < rb;
1169 else
1170 // return better impact
1171 return infA > infB;
1175 // ***************************************************************************
1176 void CInstanceLighter::processIGPointLightRT(std::vector<CPointLightNamed> &listPointLight)
1178 uint i;
1179 vector<CPointLightRT*> lightInfs;
1180 lightInfs.reserve(1024);
1182 // clear result list
1183 listPointLight.clear();
1186 // Compute each Instance
1187 //===========
1188 for(i=0; i<_InstanceInfos.size(); i++)
1190 // If staticLight not enabled, skip.
1191 if( !_Instances[i].StaticLightEnabled )
1192 continue;
1194 CInstanceInfo &inst= _InstanceInfos[i];
1195 // Avoid autoShadowing
1196 _CurrentInstanceComputed= i;
1198 // progress
1199 progress ("Compute Influences of PointLights 2/2", i / (float)_InstanceInfos.size());
1201 // get the point of the instance.
1202 CVector pos= inst.CenterPos;
1204 // Default: takes no LocalAmbientLight;
1205 inst.LocalAmbientLight= NULL;
1206 float furtherAmbLight= 0;
1208 // Compute Which light influences him.
1209 //---------
1210 lightInfs.clear();
1211 // Search possible lights around the position.
1212 _StaticPointLightQuadGrid.select(pos, pos);
1213 // For all of them, get the ones which touch this point.
1214 CQuadGrid<CPointLightRT*>::CIterator it= _StaticPointLightQuadGrid.begin();
1215 while(it != _StaticPointLightQuadGrid.end())
1217 CPointLightRT *pl= *it;
1219 // Test if really in the radius of the light, no occlusion, not an ambient, and in Spot Angle setup
1220 if( pl->testRaytrace(pos, _CurrentInstanceComputed) )
1222 // Ok, add the light to the lights which influence the instance
1223 lightInfs.push_back(pl);
1226 // Ambient Light ??
1227 if( pl->PointLight.getType() == CPointLight::AmbientLight )
1229 // If the instance is in radius of the ambiant light.
1230 float dRadius= pl->BSphere.Radius - (pl->BSphere.Center - pos).norm();
1231 if(dRadius>0)
1233 // Take the best ambient light: the one which is further from the circumference
1234 if(dRadius > furtherAmbLight)
1236 furtherAmbLight= dRadius;
1237 inst.LocalAmbientLight= pl;
1242 // next
1243 it++;
1246 // If ambientLight chosen, inc Ref count of it
1247 if(inst.LocalAmbientLight)
1248 inst.LocalAmbientLight->RefCount++;
1250 // Choose the Best ones.
1251 //---------
1252 CPredPointLightToPoint predPLTP;
1253 predPLTP.Point= pos;
1254 // sort.
1255 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
1256 // truncate.
1257 lightInfs.resize( min((uint)lightInfs.size(), (uint)CInstanceGroup::NumStaticLightPerInstance) );
1260 // For each of them, fill instance
1261 //---------
1262 uint lightInfId;
1263 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
1265 CPointLightRT *pl= lightInfs[lightInfId];
1267 // copy light.
1268 inst.Light[lightInfId]= pl;
1270 // Inc RefCount of the light.
1271 pl->RefCount++;
1273 // Reset any empty slot to NULL.
1274 for(; lightInfId<CInstanceGroup::NumStaticLightPerInstance; lightInfId++)
1276 inst.Light[lightInfId]= NULL;
1282 // Compute Lighting on SurfaceLightGrid
1283 //===========
1284 // Must do it before compression !!
1285 // NB: big copy/Past from above
1286 if(_IGSurfaceLightBuild)
1288 // No instance currenlty computed, since we compute surface cells.
1289 _CurrentInstanceComputed= -1;
1291 // Begin cell iteration
1292 beginCell();
1293 // For all surface cell corners
1294 while( !isEndCell() )
1296 progressCell("Compute PointLights on Surfaces");
1298 // get the current cellInfo iterated.
1299 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
1301 // if the cell corner lies in the polygon surface.
1302 if(cellInfo.InSurface)
1304 // get the point of the cell.
1305 CVector pos= cellInfo.CenterPos;
1307 // Default: takes no LocalAmbientLight;
1308 cellInfo.LocalAmbientLight= NULL;
1309 float furtherAmbLight= 0;
1311 // Compute Which light influences him.
1312 //---------
1313 lightInfs.clear();
1314 // Search possible lights around the position.
1315 _StaticPointLightQuadGrid.select(pos, pos);
1316 // For all of them, get the ones which touch this point.
1317 CQuadGrid<CPointLightRT*>::CIterator it= _StaticPointLightQuadGrid.begin();
1318 while(it != _StaticPointLightQuadGrid.end())
1320 CPointLightRT *pl= *it;
1322 // Test if really in the radius of the light, no occlusion, not an ambient, and in Spot Angle setup
1323 if( pl->testRaytrace(pos, _CurrentInstanceComputed) )
1325 // Ok, add the light to the lights which influence the cell
1326 lightInfs.push_back(pl);
1329 // Ambient Light ??
1330 if( pl->PointLight.getType() == CPointLight::AmbientLight )
1332 // If the instance is in radius of the ambiant light.
1333 float dRadius= pl->BSphere.Radius - (pl->BSphere.Center - pos).norm();
1334 if(dRadius>0)
1336 // Take the best ambient light: the one which is further from the circumference
1337 if(dRadius > furtherAmbLight)
1339 furtherAmbLight= dRadius;
1340 cellInfo.LocalAmbientLight= pl;
1345 // next
1346 it++;
1349 // If ambientLight chosen, inc Ref count of it
1350 if(cellInfo.LocalAmbientLight)
1351 ((CPointLightRT*)cellInfo.LocalAmbientLight)->RefCount++;
1354 // Choose the Best ones.
1355 //---------
1356 CPredPointLightToPoint predPLTP;
1357 predPLTP.Point= pos;
1358 // sort.
1359 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
1360 // truncate.
1361 lightInfs.resize( min((uint)lightInfs.size(), (uint)CSurfaceLightGrid::NumLightPerCorner) );
1364 // For each of them, fill cellInfo
1365 //---------
1366 uint lightInfId;
1367 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
1369 CPointLightRT *pl= lightInfs[lightInfId];
1371 // copy light.
1372 cellInfo.LightInfo[lightInfId]= pl;
1374 // Inc RefCount of the light.
1375 pl->RefCount++;
1377 // Reset any empty slot to NULL.
1378 for(; lightInfId<CSurfaceLightGrid::NumLightPerCorner; lightInfId++)
1380 cellInfo.LightInfo[lightInfId]= NULL;
1385 // next cell
1386 nextCell();
1392 // Compress and setup _Instances with compressed data.
1393 //===========
1394 uint plId= 0;
1395 // Process each pointLights
1396 for(i=0; i<_StaticPointLights.size(); i++)
1398 CPointLightRT &plRT= _StaticPointLights[i];
1399 // If this light is used.
1400 if(plRT.RefCount > 0)
1402 // Valid light ?
1403 if (plId <=0xFF)
1405 // Must Copy it into Ig.
1406 listPointLight.push_back(plRT.PointLight);
1407 plRT.DstId= plId++;
1408 // If index >= 255, too many lights (NB: => because 255 is a NULL code).
1410 else
1412 nlwarning("ERROR: Too many Static Point Lights influence the IG!!");
1413 // Set 0xFF. Special code indicating that the light CAN'T BE USED => any instance using
1414 // it is buggy (won't be lighted by this light).
1415 plRT.DstId= plId++;
1420 // For each instance, compress Point light info
1421 for(i=0; i<_Instances.size(); i++)
1423 // If staticLight not enabled, skip.
1424 if( !_Instances[i].StaticLightEnabled )
1425 continue;
1427 CInstanceInfo &instSrc= _InstanceInfos[i];
1428 CInstanceGroup::CInstance &instDst= _Instances[i];
1430 // Do it for PointLights
1431 for(uint lightId= 0; lightId<CInstanceGroup::NumStaticLightPerInstance; lightId++)
1433 if(instSrc.Light[lightId] == NULL)
1435 // Mark as unused.
1436 instDst.Light[lightId]= 0xFF;
1438 else
1440 // Get index. NB: may still be 0xFF if 'Too many static light' bug.
1441 instDst.Light[lightId]= instSrc.Light[lightId]->DstId;
1445 // Ensure that all FF are at end of the list (possible because of the TooManyStaticLight bug).
1446 // But don't do a full sort, to preserve order due to influence...
1447 nlctassert(CInstanceGroup::NumStaticLightPerInstance==2);
1448 if(instDst.Light[0] == 0xFF) swap(instDst.Light[0], instDst.Light[1]);
1450 // Do it for Ambientlight
1451 if(instSrc.LocalAmbientLight == NULL)
1452 instDst.LocalAmbientId= 0xFF;
1453 else
1454 // NB: may still be 0xFF if 'Too many static light' bug.
1455 instDst.LocalAmbientId= instSrc.LocalAmbientLight->DstId;
1458 // For each cell, compress Point light info
1459 if(_IGSurfaceLightBuild)
1461 // Begin cell iteration
1462 beginCell();
1463 // For all surface cell corners
1464 while( !isEndCell() )
1466 // get the current cell and cellInfo iterated.
1467 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
1468 CSurfaceLightGrid::CCellCorner &cell= getCurrentCell();
1470 if(cellInfo.InSurface)
1472 // Do it for PointLights
1473 for(uint lightId= 0; lightId<CSurfaceLightGrid::NumLightPerCorner; lightId++)
1475 if(cellInfo.LightInfo[lightId] == NULL)
1477 // Mark as unused.
1478 cell.Light[lightId]= 0xFF;
1480 else
1482 // Get index. NB: may still be 0xFF if 'Too many static light' bug.
1483 cell.Light[lightId]= reinterpret_cast<CPointLightRT*>(cellInfo.LightInfo[lightId])->DstId;
1487 // Ensure that all FF are at end of the list (possible because of the TooManyStaticLight bug).
1488 // But don't do a full sort, to preserve order due to influence...
1489 nlctassert(CInstanceGroup::NumStaticLightPerInstance==2);
1490 if(cell.Light[0] == 0xFF) swap(cell.Light[0], cell.Light[1]);
1492 // Do it for Ambientlight
1493 if(cellInfo.LocalAmbientLight == NULL)
1494 cell.LocalAmbientId= 0xFF;
1495 else
1496 // NB: may still be 0xFF if 'Too many static light' bug.
1497 cell.LocalAmbientId= ((CPointLightRT*)cellInfo.LocalAmbientLight)->DstId;
1500 // next cell
1501 nextCell();
1509 // ***************************************************************************
1510 // ***************************************************************************
1511 // lightIgSimple
1512 // ***************************************************************************
1513 // ***************************************************************************
1516 // ***************************************************************************
1517 void CInstanceLighter::lightIgSimple(CInstanceLighter &instLighter, const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc, const char *igName)
1519 sint i;
1522 // Setup.
1523 //=======
1524 // Init
1525 instLighter.init();
1527 // Add obstacles.
1528 std::vector<CInstanceLighter::CTriangle> obstacles;
1529 // only if Shadowing On.
1530 if(lightDesc.Shadow)
1532 // Map of shape to load
1533 std::map<string, IShape*> shapeMap;
1535 // For all instances of igIn.
1536 for(i=0; i<(sint)igIn.getNumInstance();i++)
1538 // progress
1539 instLighter.progress("Loading Shapes obstacles", float(i)/igIn.getNumInstance());
1541 // Skip it??
1542 if(igIn.getInstance(i).DontCastShadow)
1543 continue;
1545 // Get the instance shape name
1546 string name= igIn.getShapeName(i);
1547 bool shapeFound= true;
1549 // Try to find the shape in the UseShapeMap.
1550 std::map<string, IShape*>::const_iterator iteMap= lightDesc.UserShapeMap.find (name);
1552 // If not found in userShape map, try to load it from the temp loaded ShapeBank.
1553 if( iteMap == lightDesc.UserShapeMap.end() )
1555 // Add a .shape at the end ?
1556 if (name.find('.') == std::string::npos)
1557 name += ".shape";
1559 // Get the instance shape name
1560 string nameLookup = CPath::lookup (name, false, false);
1561 if (!nameLookup.empty())
1562 name = nameLookup;
1564 // Find the shape in the bank
1565 iteMap= shapeMap.find (name);
1566 if (iteMap==shapeMap.end())
1568 // Input file
1569 CIFile inputFile;
1571 if (!name.empty() && inputFile.open (name))
1573 // Load it
1574 CShapeStream stream;
1575 stream.serial (inputFile);
1577 // Get the pointer
1578 iteMap=shapeMap.insert (std::map<string, IShape*>::value_type (name, stream.getShapePointer ())).first;
1580 else
1582 // Error
1583 nlwarning ("WARNING can't load shape %s\n", name.c_str());
1584 shapeFound= false;
1589 if(shapeFound)
1591 CMatrix matInst;
1592 matInst.setPos(igIn.getInstancePos(i));
1593 matInst.setRot(igIn.getInstanceRot(i));
1594 matInst.scale(igIn.getInstanceScale(i));
1595 // Add triangles of this shape
1596 CInstanceLighter::addTriangles(*iteMap->second, matInst, obstacles, i);
1601 // Clean Up shapes.
1602 //-----------
1603 std::map<string, IShape*>::iterator iteMap;
1604 iteMap= shapeMap.begin();
1605 while(iteMap!= shapeMap.end())
1607 // delte shape
1608 delete iteMap->second;
1609 // delete entry in map
1610 shapeMap.erase(iteMap);
1611 // next
1612 iteMap= shapeMap.begin();
1616 // Add pointLights of the IG.
1617 for(i=0; i<(sint)igIn.getPointLightList().size();i++)
1619 instLighter.addStaticPointLight( igIn.getPointLightList()[i], igName );
1623 // Run.
1624 //=======
1625 instLighter.light(igIn, igOut, lightDesc, obstacles);
1630 // ***************************************************************************
1631 // ***************************************************************************
1632 // Cell Iteration
1633 // ***************************************************************************
1634 // ***************************************************************************
1637 // ***************************************************************************
1638 void CInstanceLighter::progressCell(const char *message)
1640 float cp= getCurrentCellNumber() / float(getTotalCellNumber());
1641 if( cp > _LastCellProgress+0.05f)
1643 progress(message, cp);
1644 _LastCellProgress= cp;
1649 // ***************************************************************************
1650 void CInstanceLighter::beginCell()
1652 if(_IGSurfaceLightBuild)
1654 _ItRetriever= _IGRetrieverGridMap.begin();
1655 if(_ItRetriever != _IGRetrieverGridMap.end() )
1657 _ItRetrieverInfo= _IGSurfaceLightBuild->RetrieverGridMap.find(_ItRetriever->first);
1658 nlassert(_ItRetrieverInfo != _IGSurfaceLightBuild->RetrieverGridMap.end() );
1659 // We are suze here that the retriever is not empty, and that the grid herself is not empty too
1660 _ItSurfId= 0;
1661 _ItCellId= 0;
1662 _ItCurrentCellNumber= 0;
1663 _IsEndCell= false;
1664 _LastCellProgress= 0;
1666 else
1668 _IsEndCell= true;
1671 else
1673 _IsEndCell= true;
1677 // ***************************************************************************
1678 void CInstanceLighter::nextCell()
1680 nlassert(!isEndCell());
1682 // Next Cell.
1683 _ItCellId++;
1684 _ItCurrentCellNumber++;
1686 // If end of Cells, next surface.
1687 if(_ItCellId >= _ItRetriever->second.Grids[_ItSurfId].Cells.size() )
1689 _ItCellId= 0;
1690 _ItSurfId ++;
1693 // If end of surface, next retriever.
1694 if(_ItSurfId >= _ItRetriever->second.Grids.size() )
1696 _ItSurfId= 0;
1697 _ItRetriever++;
1698 if(_ItRetriever != _IGRetrieverGridMap.end())
1700 // Get info.
1701 _ItRetrieverInfo= _IGSurfaceLightBuild->RetrieverGridMap.find(_ItRetriever->first);
1702 nlassert(_ItRetrieverInfo != _IGSurfaceLightBuild->RetrieverGridMap.end() );
1706 // If end of retreiver, End.
1707 if(_ItRetriever == _IGRetrieverGridMap.end())
1709 _IsEndCell= true;
1713 // ***************************************************************************
1714 bool CInstanceLighter::isEndCell()
1716 return _IsEndCell;
1719 // ***************************************************************************
1720 CSurfaceLightGrid::CCellCorner &CInstanceLighter::getCurrentCell()
1722 nlassert(!isEndCell());
1724 // return ref on Cell.
1725 return _ItRetriever->second.Grids[_ItSurfId].Cells[_ItCellId];
1728 // ***************************************************************************
1729 CIGSurfaceLightBuild::CCellCorner &CInstanceLighter::getCurrentCellInfo()
1731 nlassert(!isEndCell());
1733 // return ref on CellInfo.
1734 return _ItRetrieverInfo->second.Grids[_ItSurfId].Cells[_ItCellId];
1738 // ***************************************************************************
1739 bool CInstanceLighter::isCurrentNeighborCellInSurface(sint xnb, sint ynb)
1741 nlassert(!isEndCell());
1743 // get a ref on the current grid.
1744 CSurfaceLightGrid &surfGrid= _ItRetriever->second.Grids[_ItSurfId];
1745 // copute coordinate of the current cellCorner.
1746 sint xCell, yCell;
1747 xCell= _ItCellId%surfGrid.Width;
1748 yCell= _ItCellId/surfGrid.Width;
1749 // compute coordinate of the neighbor cell corner
1750 xCell+= xnb;
1751 yCell+= ynb;
1753 // check if in the surfaceGrid
1754 if(xCell<0 || xCell>=(sint)surfGrid.Width)
1755 return false;
1756 if(yCell<0 || yCell>=(sint)surfGrid.Height)
1757 return false;
1759 // compute the neighbor id
1760 uint nbId= yCell*surfGrid.Width + xCell;
1762 // Now check in the cellInfo if this cell is InSurface.
1763 if( !_ItRetrieverInfo->second.Grids[_ItSurfId].Cells[nbId].InSurface )
1764 return false;
1766 // Ok, the neighbor cell is valid.
1768 return true;
1771 // ***************************************************************************
1772 CSurfaceLightGrid::CCellCorner &CInstanceLighter::getCurrentNeighborCell(sint xnb, sint ynb)
1774 nlassert(isCurrentNeighborCellInSurface(xnb, ynb));
1776 // get a ref on the current grid.
1777 CSurfaceLightGrid &surfGrid= _ItRetriever->second.Grids[_ItSurfId];
1778 // copute coordinate of the current cellCorner.
1779 sint xCell, yCell;
1780 xCell= _ItCellId%surfGrid.Width;
1781 yCell= _ItCellId/surfGrid.Width;
1782 // compute coordinate of the neighbor cell corner
1783 xCell+= xnb;
1784 yCell+= ynb;
1785 // compute the neighbor id
1786 uint nbId= yCell*surfGrid.Width + xCell;
1788 // then return a ref on it
1789 return surfGrid.Cells[nbId];
1793 // ***************************************************************************
1794 CIGSurfaceLightBuild::CCellCorner &CInstanceLighter::getCurrentNeighborCellInfo(sint xnb, sint ynb)
1796 nlassert(isCurrentNeighborCellInSurface(xnb, ynb));
1798 // get a ref on the current grid.
1799 CIGSurfaceLightBuild::CSurface &surfGrid= _ItRetrieverInfo->second.Grids[_ItSurfId];
1800 // copute coordinate of the current cellCorner.
1801 sint xCell, yCell;
1802 xCell= _ItCellId%surfGrid.Width;
1803 yCell= _ItCellId/surfGrid.Width;
1804 // compute coordinate of the neighbor cell corner
1805 xCell+= xnb;
1806 yCell+= ynb;
1807 // compute the neighbor id
1808 uint nbId= yCell*surfGrid.Width + xCell;
1810 // then return a ref on it
1811 return surfGrid.Cells[nbId];
1815 // ***************************************************************************
1816 void CInstanceLighter::dilateLightingOnSurfaceCells()
1818 // Begin cell iteration
1819 beginCell();
1820 // For all surface cell corners
1821 while( !isEndCell() )
1823 progressCell("Dilate Surfaces grids");
1825 // get the current cell and cellInfo iterated.
1826 CIGSurfaceLightBuild::CCellCorner &cellInfo= getCurrentCellInfo();
1827 CSurfaceLightGrid::CCellCorner &cell= getCurrentCell();
1829 // if the cell is not in the polygon surface, try to get from his neighbors.
1830 if(!cellInfo.InSurface)
1832 // Add Weighted influence of SunContribution, and get one of the PointLightContribution (random).
1833 uint wgtSunContribution= 0;
1834 uint wgtSunCount= 0;
1835 // search if one of 8 neighbors is InSurface.
1836 for(sint ynb= -1; ynb<= 1; ynb++)
1838 for(sint xnb= -1; xnb<= 1; xnb++)
1840 // center => skip.
1841 if( xnb==0 && ynb==0 )
1842 continue;
1843 // If the neighbor point is not out of the grid, and if in Surface.
1844 if( isCurrentNeighborCellInSurface(xnb, ynb) )
1846 // get the neighbor cell
1847 CIGSurfaceLightBuild::CCellCorner &nbCellInfo= getCurrentNeighborCellInfo(xnb, ynb);
1848 CSurfaceLightGrid::CCellCorner &nbCell= getCurrentNeighborCell(xnb, ynb);
1849 // Add SunContribution.
1850 wgtSunContribution+= nbCell.SunContribution;
1851 wgtSunCount++;
1852 // Just Copy PointLight info.
1853 for(uint lightId= 0; lightId<CSurfaceLightGrid::NumLightPerCorner; lightId++)
1854 cell.Light[lightId]= nbCell.Light[lightId];
1855 // Just Copy AmbientLight info.
1856 cell.LocalAmbientId= nbCell.LocalAmbientId;
1859 // For debug mesh only, copy z from nb cellInfo
1860 cellInfo.CenterPos.z= nbCellInfo.CenterPos.z;
1864 // average SunContribution.
1865 if(wgtSunCount>0)
1867 cell.SunContribution= wgtSunContribution / wgtSunCount;
1869 // For debug mesh only, copy SunContribution into cellInfo
1870 cellInfo.SunContribution= cell.SunContribution;
1871 cellInfo.Dilated= true;
1875 // next cell
1876 nextCell();
1882 } // NL3D