1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
32 using namespace NLMISC
;
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 // ***************************************************************************
48 // ***************************************************************************
49 // ***************************************************************************
52 // ***************************************************************************
53 CInstanceLighter::CLightDesc::CLightDesc ()
55 LightDirection
.set (1, 1, -1);
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.
79 excludeAllPatchFromRefineAll (landscape
, listZone
, false);
81 // Setup the landscape
82 landscape
.setThreshold (0);
83 landscape
.setTileMaxSubdivision (order
);
86 landscape
.refineAll (CVector (0, 0, 0));
88 // Dump tesselated triangles
89 std::vector
<const CTessFace
*> leaves
;
90 landscape
.getTessellationLeaves(leaves
);
93 uint leavesCount
=(uint
)leaves
.size();
96 triangleArray
.reserve (triangleArray
.size()+leavesCount
);
99 for (uint leave
=0; leave
<leavesCount
; 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.
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
);
144 addTriangles (mesh
->getMeshGeom (), modelMT
, triangleArray
, instanceId
);
146 // It is a CMeshMultiLod ?
149 // Get the first geommesh
150 const IMeshGeom
*meshGeom
=&meshMulti
->getMeshGeom (0);
153 const CMeshGeom
*geomMesh
=dynamic_cast<const CMeshGeom
*>(meshGeom
);
156 addTriangles (*geomMesh
, modelMT
, triangleArray
, instanceId
);
160 const CMeshMRMGeom
*mrmGeomMesh
=dynamic_cast<const CMeshMRMGeom
*>(meshGeom
);
163 addTriangles (*mrmGeomMesh
, modelMT
, triangleArray
, instanceId
);
166 // It is a CMeshMultiLod ?
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
;
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
);
196 CIndexBufferRead iba
;
197 primitive
.lock (iba
);
198 uint numTri
=primitive
.getNumIndexes ()/3;
200 if (primitive
.getFormat() == CIndexBuffer::Indices16
)
202 const uint16
* triIndex
=(uint16
*)iba
.getPtr ();
203 for (tri
=0; tri
<numTri
; tri
++)
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]));
211 triangleArray
.push_back (CTriangle (NLMISC::CTriangle (v0
, v1
, v2
), instanceId
));
216 const uint32
* triIndex
=(uint32
*)iba
.getPtr ();
217 for (tri
=0; tri
<numTri
; tri
++)
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]));
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
;
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
);
249 CIndexBufferRead iba
;
250 primitive
.lock (iba
);
251 uint numTri
=primitive
.getNumIndexes ()/3;
253 if (primitive
.getFormat() == CIndexBuffer::Indices16
)
255 const uint16
* triIndex
=(uint16
*)iba
.getPtr ();
256 for (tri
=0; tri
<numTri
; tri
++)
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]));
264 triangleArray
.push_back (CTriangle (NLMISC::CTriangle (v0
, v1
, v2
), instanceId
));
269 const uint32
* triIndex
=(uint32
*)iba
.getPtr ();
270 for (tri
=0; tri
<numTri
; tri
++)
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]));
278 triangleArray
.push_back (CTriangle (NLMISC::CTriangle (v0
, v1
, v2
), instanceId
));
284 // ***************************************************************************
286 void CInstanceLighter::excludeAllPatchFromRefineAll (CLandscape
&landscape
, vector
<uint
> &listZone
, bool exclude
)
289 for (uint zone
=0; zone
<listZone
.size(); zone
++)
292 uint patchCount
=landscape
.getZone(listZone
[zone
])->getNumPatchs();
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 // ***************************************************************************
307 // ***************************************************************************
308 // ***************************************************************************
312 // ***************************************************************************
313 void CInstanceLighter::light (const CInstanceGroup
&igIn
, CInstanceGroup
&igOut
, const CLightDesc
&lightDesc
,
314 std::vector
<CTriangle
>& obstacles
, CLandscape
*landscape
, CIGSurfaceLightBuild
*igSurfaceLightBuild
)
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);
328 // Prepare IGSurfaceLight lighting
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
)
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.
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;
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.
381 // Reset cell iteration.
385 // Retrieve info from igIn.
387 igIn
.retrieve (outGlobalPos
, _Instances
, outClusters
, outPortals
, pointLightList
);
390 // set All Instances StaticLightEnabled= true, and Build _InstanceInfos.
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;
406 _Instances
[i
].StaticLightEnabled
= true;
409 // Get the shape centerPos;
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());
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
)
434 // Get the instance shape name
435 string nameLookup
= CPath::lookup (name
, false, false);
436 if (!nameLookup
.empty())
439 // Find the shape in the bank
440 iteMap
= shapeMap
.find (name
);
441 if (iteMap
==shapeMap
.end())
446 if (!name
.empty() && inputFile
.open (name
))
450 stream
.serial (inputFile
);
453 iteMap
=shapeMap
.insert (std::map
<string
, IShape
*>::value_type (name
, stream
.getShapePointer ())).first
;
458 nlwarning ("WARNING can't load shape %s\n", name
.c_str());
465 // Last chance to skip it: fully LightMapped ??
469 CMeshBase
*mesh
= dynamic_cast<CMeshBase
*>(iteMap
->second
);
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;
486 // Compute pos and OverSamples
489 // Compute bbox, or default bbox
493 bbox
.setCenter(CVector::Null
);
494 bbox
.setHalfSize(CVector::Null
);
498 iteMap
->second
->getAABBox(bbox
);
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)
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
++)
544 overSamples
[sample
+8]= overSamples
[sample
] + decal
;
546 overSamples
[sample
]-= decal
;
553 // Compute pos of the instance
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
];
570 std::map
<string
, IShape
*>::iterator iteMap
;
571 iteMap
= shapeMap
.begin();
572 while(iteMap
!= shapeMap
.end())
575 delete iteMap
->second
;
576 // delete entry in map
577 shapeMap
.erase(iteMap
);
579 iteMap
= shapeMap
.begin();
582 // Build all obstacles plane.
584 for(i
=0; i
<(sint
)obstacles
.size();i
++)
586 CInstanceLighter::CTriangle
& triangle
=obstacles
[i
];
588 triangle
.Plane
.make (triangle
.Triangle
.V0
, triangle
.Triangle
.V1
, triangle
.Triangle
.V2
);
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();
616 if(_IGSurfaceLightBuild
)
618 // build with IGSurfaceLight lighting
619 igOut
.build(outGlobalPos
, _Instances
, outClusters
, outPortals
, pointLightList
,
620 &_IGRetrieverGridMap
, _IGSurfaceLightBuild
->CellSize
);
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
;
642 matrix
.setRot(I
,J
,K
, true);
647 // ***************************************************************************
648 void CInstanceLighter::computeSunContribution(const CLightDesc
&lightDesc
, std::vector
<CTriangle
>& obstacles
, CLandscape
*landscape
)
651 // Use precoputed landscape SunContribution
652 CVisualCollisionManager
*VCM
= NULL
;
653 CVisualCollisionEntity
*VCE
= NULL
;
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.
670 for(i
=0; i
<(sint
)_Instances
.size(); i
++)
672 // If staticLight not enabled, skip.
673 if( !_Instances
[i
].StaticLightEnabled
)
676 // fill SunContribution to 0
677 _Instances
[i
].SunContribution
= 0;
680 // Light SurfaceGrid Cells.
682 if(_IGSurfaceLightBuild
)
684 // Begin cell iteration
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
;
707 // If no Raytrace Shadow, easy,
708 else if(!lightDesc
.Shadow
)
710 // Light all instances.
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
)
720 // by default, fill SunContribution to 255
721 _Instances
[i
].SunContribution
= 255;
722 // Try to get landscape SunContribution (better)
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.
739 if(_IGSurfaceLightBuild
)
741 // Begin cell iteration
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
;
769 CVector rayDir
= lightDesc
.LightDirection
;
772 NEL3DCalcBase(rayDir
, rayBasis
);
774 invRayBasis
= rayBasis
.inverted();
776 // Build QuadGrid of obstacles.
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
++)
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.
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
)
804 // try to use landscape SunContribution.
805 bool landUsed
= false;
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
;
820 // If failed to use landscape SunContribution, rayTrace
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
;
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
)
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
864 _Instances
[i
].SunContribution
= sunAccum
/ nSamples
;
870 // Light SurfaceGrid Cells.
872 if(_IGSurfaceLightBuild
)
874 // No instance currenlty computed, since we compute surface cells.
875 _CurrentInstanceComputed
= -1;
877 // Begin cell iteration
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
;
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
;
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
928 // Average SunContribution
929 cell
.SunContribution
= sunAccum
/ nSamples
;
931 // copy it to cellInfo
932 cellInfo
.SunContribution
= cell
.SunContribution
;
945 // delete CVisualCollisionManager and CVisualCollisionEntity
946 VCM
->deleteEntity(VCE
);
954 // ***************************************************************************
955 // ***************************************************************************
957 // ***************************************************************************
958 // ***************************************************************************
961 // ***************************************************************************
962 CInstanceLighter::CPointLightRT::CPointLightRT()
968 // ***************************************************************************
969 bool CInstanceLighter::CPointLightRT::testRaytrace(const CVector
&v
, sint instanceComputed
)
973 if(!BSphere
.include(v
))
976 // If Ambient light, just skip
977 if(PointLight
.getType()== CPointLight::AmbientLight
)
980 // If SpotLight verify in angle radius.
981 if(PointLight
.getType()== CPointLight::SpotLight
)
983 float att
= PointLight
.computeLinearAttenuation(v
);
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()) )
1005 FaceCubeGrid
.nextSel();
1008 // Ok the point is visilbe from the light
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
1020 plRT
.PointLight
= pln
;
1021 // compute plRT.OODeltaAttenuation
1022 plRT
.OODeltaAttenuation
= pln
.getAttenuationEnd() - pln
.getAttenuationBegin();
1023 if(plRT
.OODeltaAttenuation
<=0 )
1024 plRT
.OODeltaAttenuation
= 1e10f
;
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()
1033 _StaticPointLights
.push_back(plRT
);
1037 // ***************************************************************************
1038 void CInstanceLighter::compilePointLightRT(uint gridSize
, float gridCellSize
, std::vector
<CTriangle
>& obstacles
, bool doShadow
)
1042 // Fill the quadGrid of Lights.
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
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 ??
1063 // For all obstacles, Fill a quadGrid.
1065 CQuadGrid
<CTriangle
*> obstacleGrid
;
1066 obstacleGrid
.create(gridSize
, gridCellSize
);
1067 uint size
= (uint
)obstacles
.size();
1068 for(i
=0; i
<size
; i
++)
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
1082 for(i
=0; i
<_StaticPointLights
.size();i
++)
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
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 !!).
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
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
);
1124 // Compile the CubeGrid.
1125 plRT
.FaceCubeGrid
.compile();
1127 // And Reset RefCount.
1131 // else, just build empty grid
1134 for(i
=0; i
<_StaticPointLights
.size();i
++)
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.
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.
1170 // return better impact
1175 // ***************************************************************************
1176 void CInstanceLighter::processIGPointLightRT(std::vector
<CPointLightNamed
> &listPointLight
)
1179 vector
<CPointLightRT
*> lightInfs
;
1180 lightInfs
.reserve(1024);
1182 // clear result list
1183 listPointLight
.clear();
1186 // Compute each Instance
1188 for(i
=0; i
<_InstanceInfos
.size(); i
++)
1190 // If staticLight not enabled, skip.
1191 if( !_Instances
[i
].StaticLightEnabled
)
1194 CInstanceInfo
&inst
= _InstanceInfos
[i
];
1195 // Avoid autoShadowing
1196 _CurrentInstanceComputed
= i
;
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.
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
);
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();
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
;
1246 // If ambientLight chosen, inc Ref count of it
1247 if(inst
.LocalAmbientLight
)
1248 inst
.LocalAmbientLight
->RefCount
++;
1250 // Choose the Best ones.
1252 CPredPointLightToPoint predPLTP
;
1253 predPLTP
.Point
= pos
;
1255 sort(lightInfs
.begin(), lightInfs
.end(), predPLTP
);
1257 lightInfs
.resize( min((uint
)lightInfs
.size(), (uint
)CInstanceGroup::NumStaticLightPerInstance
) );
1260 // For each of them, fill instance
1263 for(lightInfId
=0; lightInfId
<lightInfs
.size(); lightInfId
++)
1265 CPointLightRT
*pl
= lightInfs
[lightInfId
];
1268 inst
.Light
[lightInfId
]= pl
;
1270 // Inc RefCount of the light.
1273 // Reset any empty slot to NULL.
1274 for(; lightInfId
<CInstanceGroup::NumStaticLightPerInstance
; lightInfId
++)
1276 inst
.Light
[lightInfId
]= NULL
;
1282 // Compute Lighting on SurfaceLightGrid
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
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.
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
);
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();
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
;
1349 // If ambientLight chosen, inc Ref count of it
1350 if(cellInfo
.LocalAmbientLight
)
1351 ((CPointLightRT
*)cellInfo
.LocalAmbientLight
)->RefCount
++;
1354 // Choose the Best ones.
1356 CPredPointLightToPoint predPLTP
;
1357 predPLTP
.Point
= pos
;
1359 sort(lightInfs
.begin(), lightInfs
.end(), predPLTP
);
1361 lightInfs
.resize( min((uint
)lightInfs
.size(), (uint
)CSurfaceLightGrid::NumLightPerCorner
) );
1364 // For each of them, fill cellInfo
1367 for(lightInfId
=0; lightInfId
<lightInfs
.size(); lightInfId
++)
1369 CPointLightRT
*pl
= lightInfs
[lightInfId
];
1372 cellInfo
.LightInfo
[lightInfId
]= pl
;
1374 // Inc RefCount of the light.
1377 // Reset any empty slot to NULL.
1378 for(; lightInfId
<CSurfaceLightGrid::NumLightPerCorner
; lightInfId
++)
1380 cellInfo
.LightInfo
[lightInfId
]= NULL
;
1392 // Compress and setup _Instances with compressed data.
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)
1405 // Must Copy it into Ig.
1406 listPointLight
.push_back(plRT
.PointLight
);
1408 // If index >= 255, too many lights (NB: => because 255 is a NULL code).
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).
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
)
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
)
1436 instDst
.Light
[lightId
]= 0xFF;
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;
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
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
)
1478 cell
.Light
[lightId
]= 0xFF;
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;
1496 // NB: may still be 0xFF if 'Too many static light' bug.
1497 cell
.LocalAmbientId
= ((CPointLightRT
*)cellInfo
.LocalAmbientLight
)->DstId
;
1509 // ***************************************************************************
1510 // ***************************************************************************
1512 // ***************************************************************************
1513 // ***************************************************************************
1516 // ***************************************************************************
1517 void CInstanceLighter::lightIgSimple(CInstanceLighter
&instLighter
, const CInstanceGroup
&igIn
, CInstanceGroup
&igOut
, const CLightDesc
&lightDesc
, const char *igName
)
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
++)
1539 instLighter
.progress("Loading Shapes obstacles", float(i
)/igIn
.getNumInstance());
1542 if(igIn
.getInstance(i
).DontCastShadow
)
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
)
1559 // Get the instance shape name
1560 string nameLookup
= CPath::lookup (name
, false, false);
1561 if (!nameLookup
.empty())
1564 // Find the shape in the bank
1565 iteMap
= shapeMap
.find (name
);
1566 if (iteMap
==shapeMap
.end())
1571 if (!name
.empty() && inputFile
.open (name
))
1574 CShapeStream stream
;
1575 stream
.serial (inputFile
);
1578 iteMap
=shapeMap
.insert (std::map
<string
, IShape
*>::value_type (name
, stream
.getShapePointer ())).first
;
1583 nlwarning ("WARNING can't load shape %s\n", name
.c_str());
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
);
1603 std::map
<string
, IShape
*>::iterator iteMap
;
1604 iteMap
= shapeMap
.begin();
1605 while(iteMap
!= shapeMap
.end())
1608 delete iteMap
->second
;
1609 // delete entry in map
1610 shapeMap
.erase(iteMap
);
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
);
1625 instLighter
.light(igIn
, igOut
, lightDesc
, obstacles
);
1630 // ***************************************************************************
1631 // ***************************************************************************
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
1662 _ItCurrentCellNumber
= 0;
1664 _LastCellProgress
= 0;
1677 // ***************************************************************************
1678 void CInstanceLighter::nextCell()
1680 nlassert(!isEndCell());
1684 _ItCurrentCellNumber
++;
1686 // If end of Cells, next surface.
1687 if(_ItCellId
>= _ItRetriever
->second
.Grids
[_ItSurfId
].Cells
.size() )
1693 // If end of surface, next retriever.
1694 if(_ItSurfId
>= _ItRetriever
->second
.Grids
.size() )
1698 if(_ItRetriever
!= _IGRetrieverGridMap
.end())
1701 _ItRetrieverInfo
= _IGSurfaceLightBuild
->RetrieverGridMap
.find(_ItRetriever
->first
);
1702 nlassert(_ItRetrieverInfo
!= _IGSurfaceLightBuild
->RetrieverGridMap
.end() );
1706 // If end of retreiver, End.
1707 if(_ItRetriever
== _IGRetrieverGridMap
.end())
1713 // ***************************************************************************
1714 bool CInstanceLighter::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.
1747 xCell
= _ItCellId
%surfGrid
.Width
;
1748 yCell
= _ItCellId
/surfGrid
.Width
;
1749 // compute coordinate of the neighbor cell corner
1753 // check if in the surfaceGrid
1754 if(xCell
<0 || xCell
>=(sint
)surfGrid
.Width
)
1756 if(yCell
<0 || yCell
>=(sint
)surfGrid
.Height
)
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
)
1766 // Ok, the neighbor cell is valid.
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.
1780 xCell
= _ItCellId
%surfGrid
.Width
;
1781 yCell
= _ItCellId
/surfGrid
.Width
;
1782 // compute coordinate of the neighbor cell corner
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.
1802 xCell
= _ItCellId
%surfGrid
.Width
;
1803 yCell
= _ItCellId
/surfGrid
.Width
;
1804 // compute coordinate of the neighbor cell corner
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
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
++)
1841 if( xnb
==0 && ynb
==0 )
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
;
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.
1867 cell
.SunContribution
= wgtSunContribution
/ wgtSunCount
;
1869 // For debug mesh only, copy SunContribution into cellInfo
1870 cellInfo
.SunContribution
= cell
.SunContribution
;
1871 cellInfo
.Dilated
= true;