Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / zone_lighter.cpp
blob55019259dc1f5b96bd1a89bc602bb3b9bf760046
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) 2013-2021 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/zone_lighter.h"
23 #include "nel/3d/landscape.h"
24 #include "nel/3d/patchuv_locator.h"
25 #include "nel/3d/shape.h"
26 #include "nel/3d/mesh.h"
27 #include "nel/3d/mesh_multi_lod.h"
28 #include "nel/3d/mesh_mrm.h"
29 #include "nel/3d/transform_shape.h"
30 #include "nel/3d/water_shape.h"
31 #include "nel/3d/texture_file.h"
33 #include "nel/misc/common.h"
34 #include "nel/misc/thread.h"
35 #include "nel/misc/path.h"
36 #include "nel/misc/file.h"
37 #include "nel/misc/aabbox.h"
38 #include "nel/misc/algo.h"
41 #ifdef NL_OS_WINDOWS
42 # define WIN32_LEAN_AND_MEAN
43 # ifndef NL_COMP_MINGW
44 # define NOMINMAX
45 # endif
46 # include <windows.h>
47 # include <winbase.h>
48 #endif // NL_OS_WINDOWS
50 using namespace NLMISC;
51 using namespace NL3D;
52 using namespace std;
54 // Define this to render the zbuffers into a bitmap zbuffer and save it into a jpeg
55 // #define SAVE_ZBUFFER "c:/temp"
57 #ifdef DEBUG_NEW
58 #define new DEBUG_NEW
59 #endif
61 #define DEFAULT_JITTER 0.4f
62 #define DEFAULT_ZBUFFER_LANDSCAPE_SIZE 32768
63 #define DEFAULT_ZBUFFER_OBJECT_SIZE (32768*3)
64 #define DEFAULT_SUN_DISTANCE 50000
65 #define DEFAULT_SUN_FOV (NLMISC::Pi/6)
66 #define DEFAULT_SUN_CENTER (CVector (0, 0, 0))
67 #define DEFAULT_SUN_RADIUS 5000
68 #define DEFAULT_SUN_SRQT_SAMPLES 4
70 // Bad coded: don't set too big else it allocates too much memory.
71 #define NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE 16
73 // ***************************************************************************
76 Documentation:
79 To light a zone, you must first adding shadow caster triangles using the addTriangle() methods.
80 Triangles can come from landscape zones or IG meshes. Then call the lighting process with ligth().
82 addTriangle ()
83 - Add landscape triangles to shadow caster triangle list
84 - Tesselate the landscape to shadow accuracy (2 meters)
85 - Add others triangles to shadow caster triangle list (trees, building)
86 - AlphaTest textures can be used here
88 light ()
89 The lighting process uses a software zbuffers render to compute shadow attenuation of the zone.
90 CRenderZBuffer () (multithread)
91 - Render shadow caster triangles into the light zbuffers for shadows. Each z value is tested and
92 written in the pixel and in the 8 neighbor pixels.
93 - There is a zbuffer per landscape softshadow sample and an additionnal zbuffer for objects. So
94 landscape triangles cast softshadows and object (trees and building) cast antialiased shadows.
96 - Render shadow caster triangles into a heightfield used for radiosity
98 buildZoneInformation ()
100 - Tesselate the landscape to shadow accuracy (2 meters)
102 - Compute lumel positions.
103 Lumel position is the average of lumel triangles center overlapping
104 the lumel but using the shadow accuracy triangle position because
105 we need the same triangles than shadow caster polygons.
106 Border lumel position are extended to fit the patch border.
108 - Tesselate to lumel accuracy (0.5 meter)
110 - Compute lumel normal
111 - Lumel normal is the average of lumel triangles normals. The normals
112 comes from the lumel accuracy to get more precise lighting. So normals
113 are interpolated from the center of the lumel but they will be rendered
114 on the patch border. Unlike the position, we can extand the normal to the
115 border without loosing normal precision because normal interpolation is
116 aligned with the tesselation. So we need some border normal smoothing.
118 - Border normal smoothing
119 - Normals on the border of the patches are smoothed with neighbor normals.
121 CLightRunnable () (multithread)
123 - For each patches and for each lumels
125 attenuation ()
126 - Compute shadow attenuation
127 - Get an antialised attenuation value in each lansdcape softshadow zbuffer.
128 Average it with jitter.
129 - Get an antialised attenuation value from the object zbuffer.
130 - Return the smaller value of the both.
132 - Compute sun lighting (dot product)
134 getSkyContribution ()
135 - Compute sky lighting (radiosity)
136 - Algorithm
137 - Get the lumel position in the heightfield
138 - Lookup in the 8 2d directions for max height
139 - Compute an approximation of the sky surface visible from
140 the lumel position
141 - Store final lumel luminosity
145 // ***************************************************************************
147 inline float easineasout(float x)
149 float y;
150 // cubic tq f(0)=0, f'(0)=0, f(1)=1, f'(1)=0.
151 float x2=x*x;
152 float x3=x2*x;
153 y= -2*x3 + 3*x2;
154 return y;
157 // ***************************************************************************
159 inline void transformVectorToZBuffer (const CZoneLighter::CZBuffer& zbuffer, const CVector &world, CVector &projected)
161 projected = zbuffer.WorldToZBuffer * world;
162 float temp = projected.z;
163 projected.z = projected.y;
164 projected.y = -temp;
165 projected = zbuffer.WorldToZBufferFrustum.project (projected);
167 // Scale to zbuffer size
168 projected.x *= zbuffer.ZBufferPixelSize;
169 projected.y *= zbuffer.ZBufferPixelSize;
170 projected.z = temp;
173 // ***********************************************************
175 static const sint DeltaZ[9][2]=
177 {0, 0},
178 {-1, 0},
179 {1, 0},
180 {0, -1},
181 {0, 1},
182 {-1, -1},
183 {1, 1},
184 {1, -1},
185 {-1, 1},
188 // ***************************************************************************
190 inline float testZPercentageCloserFilter (float x, float y, float z, CZoneLighter::CZBuffer &zbuffer, const CZoneLighter::CLightDesc &description, bool &zBufferOverflowFlag)
192 // See "Rendering Antialiased Shadows With Depth Maps" Reeves, Salesint, Cook, ACM 1987
194 // Bilinear filtering
196 float biliValues[2][2];
198 float ix = (float)floor (x-0.5f);
199 float factorX = x - (ix+0.5f);
200 nlassert (factorX>=0);
201 nlassert (factorX<=1);
203 float iy = (float)floor (y-0.5f);
204 float factorY = y - (iy+0.5f);
205 nlassert (factorY>=0);
206 nlassert (factorY<=1);
208 sint dx, dy;
209 for (dy=0; dy<2; dy++)
210 for (dx=0; dx<2; dx++)
212 const sint fx = dx + (sint)ix;
213 const sint fy = dy + (sint)iy;
214 if ((fx >= 0) && (fx < zbuffer.LocalZBufferWidth) && (fy >= 0) && (fy < zbuffer.LocalZBufferHeight))
216 const float zRed = zbuffer.Pixels[fx + (zbuffer.LocalZBufferHeight - 1 - fy) * zbuffer.LocalZBufferWidth];
218 biliValues[dx][dy] = (zRed < (-z)) ? 0.f : 1.f;
220 else
222 biliValues[dx][dy] = 1;
223 zBufferOverflowFlag = true;
227 // Bilinear
228 return (biliValues[0][0] * (1 - factorX) + biliValues[1][0] * factorX) * (1 - factorY) +
229 (biliValues[0][1] * (1 - factorX) + biliValues[1][1] * factorX) * factorY;
232 // ***************************************************************************
234 CZoneLighter::CZoneLighter () : _PatchComputed ("PatchComputed")
238 // ***************************************************************************
240 void CZoneLighter::init ()
242 // Precalc some values
243 for (uint i=0; i<8; i++)
245 // Precalc sinP and cosP
246 float sinP=(float)(sin((Pi/4)*(i+0.5))-sin((Pi/4)*(i-0.5)));
247 float cosP=(float)(cos((Pi/4)*(i-0.5))-cos((Pi/4)*(i+0.5)));
249 for (uint phi=0; phi<256; phi++)
251 // Real phi
252 float fPhi=(float)((Pi/2)*phi/256.0);
254 // Tmp result
255 float tmp0=(float)(fPhi-sin(2*fPhi)/2);
256 float tmp1=(float)sin(fPhi);
258 // Calc K
259 _K[phi][i].set (tmp0*sinP, tmp0*cosP, (float)((Pi/4)*tmp1*tmp1));
263 // Init some containers
264 _ZBufferOverflow = false;
265 _Bitmaps.clear ();
268 // ***************************************************************************
270 // N - NW - W - SW - S - SE - E - NE
271 static const sint deltaDirection[8][2]=
273 {1, 0},
274 {1, 1},
275 {0, 1},
276 {-1, 1},
277 {-1, 0},
278 {-1, -1},
279 {0, -1},
280 {1, -1},
283 // ***************************************************************************
285 float CZoneLighter::calcSkyContribution (sint s, sint t, float height, float skyIntensity, const CVector& normal) const
287 // Sky contribution
288 float skyContribution;
290 // Calc k
291 CVector k (0, 0, 0);
293 // For the height direction
294 for (uint i=0; i<8; i++)
296 // Get phi for this point
297 uint8 phi=getMaxPhi (s, t, deltaDirection[i][0], deltaDirection[i][1], height);
299 // Add to k
300 k+=_K[phi][i];
303 // Finalize sky contribution
304 skyContribution=(float)(skyIntensity*(normal*k)/(2*Pi));
305 skyContribution=(float)(skyIntensity*(normal*k)/(2*Pi));
306 clamp (skyContribution, 0.f, 1.f);
307 return skyContribution;
310 // ***************************************************************************
312 void NEL3DCalcBase (CVector &direction, CMatrix& matrix)
314 direction.normalize();
315 CVector K=-direction;
316 CVector I=CVector::K^K;
317 CVector J=K^I;
318 J.normalize();
319 I=J^K;
320 I.normalize();
321 matrix.identity();
322 matrix.setRot(I,J,K, true);
325 // ***************************************************************************
327 void setCPUMask (IThread *thread, uint process)
329 // Set the processor mask
330 uint64 mask = IProcess::getCurrentProcess()->getCPUMask ();
332 // Mask must not be NULL
333 nlassert (mask != 0);
335 if (mask != 0)
337 uint i=0;
338 uint count = 0;
339 for(;;)
341 if (mask & (UINT64_CONSTANT(1)<<i))
343 if (count == process)
344 break;
345 count++;
347 i++;
348 if (i==64)
349 i = 0;
352 // Set the CPU mask
353 // thread->setCPUMask (1<<i);
357 // ***************************************************************************
359 class NL3D::CLightRunnable : public IRunnable
361 // Members
362 uint _Process;
363 CZoneLighter *_ZoneLighter;
364 const CZoneLighter::CLightDesc *_Description;
366 public:
367 IThread *Thread;
369 public:
370 // Ctor
371 CLightRunnable (uint process, CZoneLighter *zoneLighter, const CZoneLighter::CLightDesc *description)
373 _ZoneLighter = zoneLighter;
374 _Process = process;
375 _Description = description;
378 // Run method
379 void run()
381 // Set the CPU mask
382 // setCPUMask (Thread, _Process);
384 _ZoneLighter->processCalc (_Process, *_Description);
385 _ZoneLighter->_ProcessExitedMutex.enter();
386 _ZoneLighter->_ProcessExited++;
387 _ZoneLighter->_ProcessExitedMutex.leave();
392 // ***************************************************************************
394 class NL3D::CRenderZBuffer : public IRunnable
396 // Members
397 uint _Process;
398 CZoneLighter *_ZoneLighter;
400 // The lighting decription
401 const CZoneLighter::CLightDesc *_Description;
403 // Triangles to render
404 uint _FirstTriangle;
405 uint _NumTriangle;
406 const vector<CZoneLighter::CTriangle> *_Triangles;
408 public:
409 IThread *Thread;
411 public:
412 // Ctor
413 CRenderZBuffer (uint process, CZoneLighter *zoneLighter, const CZoneLighter::CLightDesc *description, uint firstTriangle, uint numTriangle, const vector<CZoneLighter::CTriangle> *triangles)
415 _ZoneLighter = zoneLighter;
416 _Description = description;
417 _Process = process;
418 _FirstTriangle = firstTriangle;
419 _NumTriangle = numTriangle;
420 _Triangles = triangles;
423 // Run method
424 virtual void run ();
427 // ***************************************************************************
429 #define CLIPPED_TOP 1
430 #define CLIPPED_BOTTOM 2
431 #define CLIPPED_RIGHT 3
432 #define CLIPPED_LEFT 4
433 #define CLIPPED_ALL (CLIPPED_TOP|CLIPPED_BOTTOM|CLIPPED_LEFT|CLIPPED_RIGHT)
435 void RenderTriangle (const CZoneLighter::CTriangle &triangle, const CZoneLighter::CLightDesc &description, CPolygon2D::TRasterVect &borders,
436 CFastMutex &mutex, CZoneLighter::CZBuffer &zbuffer, uint radius)
438 // *** Transform it in the zbuffer basis
440 // 2d polygon used for rasteriation
441 CPolygon2D zBasis;
442 zBasis.Vertices.resize (3);
444 // 3d polygon used for the gradient
445 NLMISC::CTriangle gradientTriangle;
447 // One over z value
448 float ooz[3];
450 // Clipping
451 uint8 in = 0;
453 // For each vertex
454 for (uint j=0; j<3; j++)
456 // Pointer on the vector
457 const CVector *pt = (&triangle.Triangle.V0)+j;
458 CVector *ptDest = (&gradientTriangle.V0)+j;
460 // Transform it in the zbuffer basis
461 transformVectorToZBuffer (zbuffer, *pt, *ptDest);
463 // Clip
464 if (ptDest->x >= zbuffer.LocalZBufferXMin)
465 in |= CLIPPED_LEFT;
466 if (ptDest->x <= zbuffer.LocalZBufferXMax)
467 in |= CLIPPED_RIGHT;
468 if (ptDest->y >= zbuffer.LocalZBufferYMin)
469 in |= CLIPPED_TOP;
470 if (ptDest->y <= zbuffer.LocalZBufferYMax)
471 in |= CLIPPED_BOTTOM;
473 // Set the 2d points
474 zBasis.Vertices[j].x = ptDest->x - (float)zbuffer.LocalZBufferXMin;
475 zBasis.Vertices[j].y = ptDest->y - (float)zbuffer.LocalZBufferYMin;
476 ooz[j] = 1.f / ptDest->z;
478 // No z
479 ptDest->z = 0;
482 // Not clipped ?
483 if (in == CLIPPED_ALL)
485 // Rasterise
486 sint minimumY;
487 borders.clear ();
488 zBasis.computeBorders (borders, minimumY);
490 // Compute the gradient for one over z
491 CVector ozzGradient;
492 gradientTriangle.computeGradient (ooz[0], ooz[1], ooz[2], ozzGradient);
494 // Need uv ?
495 bool needUV = triangle.Texture != NULL;
497 // Compute the gradient for uv
498 CVector uGradient;
499 CVector vGradient;
500 if (needUV)
502 gradientTriangle.computeGradient (triangle.U[0], triangle.U[1], triangle.U[2], uGradient);
503 gradientTriangle.computeGradient (triangle.V[0], triangle.V[1], triangle.V[2], vGradient);
506 // Texture information
507 uint width=0;
508 uint height=0;
509 const CObjectVector<uint8> *pixels = 0;
510 if (needUV)
512 // Get pixels
513 pixels = &triangle.Texture->getPixels ();
515 // Get width and height
516 width = triangle.Texture->getWidth ();
517 height = triangle.Texture->getHeight ();
520 // For each scanlines
521 sint y = std::max (minimumY, 0);
522 sint yMax = std::min ((sint)(minimumY+borders.size ()), zbuffer.LocalZBufferHeight);
523 for (; y<yMax; y++)
525 // Ref on the raster
526 const CPolygon2D::TRaster &raster = borders[y-minimumY];
528 // Gradient y for ooz, u and v
529 const float deltaY = (float)y - zBasis.Vertices[0].y;
530 const float oozGradientY = deltaY * ozzGradient.y;
531 float uGradientY=0.0f;
532 float vGradientY=0.0f;
533 if (needUV)
535 uGradientY = deltaY * uGradient.y;
536 vGradientY = deltaY * vGradient.y;
539 // Clip it
540 sint x = std::max (raster.first, 0);
541 sint xMax = std::min (raster.second+1, zbuffer.LocalZBufferWidth);
542 for (; x<xMax; x++)
544 // Gradient x for ooz, u and v
545 const float deltaX = (float)x - zBasis.Vertices[0].x;
546 const float oozGradientX = deltaX * ozzGradient.x;
547 float uGradientX=0.0f;
548 float vGradientX=0.0f;
549 if (needUV)
551 uGradientX = deltaX * uGradient.x;
552 vGradientX = deltaX * vGradient.x;
555 // Calc z
556 float z = - 1.f / (ooz[0] + oozGradientX + oozGradientY);
558 // Calc u & v
559 float u;
560 float v;
561 bool alphaTest = true;
562 if (needUV)
564 // Compute uv
565 u = triangle.U[0] + uGradientX + uGradientY;
566 v = triangle.V[0] + vGradientX + vGradientY;
568 // Clamp or wrap ?
569 if (triangle.Flags & CZoneLighter::CTriangle::ClampU)
570 clamp (u, 0.f, 1.f);
571 else
572 u -= (float)floor (u);
573 if (triangle.Flags & CZoneLighter::CTriangle::ClampV)
574 clamp (v, 0.f, 1.f);
575 else
576 v -= (float)floor (v);
578 // Lookup in the texture
579 u *= width;
580 v *= height;
581 clamp (u, 0, width-1);
582 clamp (v, 0, height-1);
583 uint8 alpha = ((const CRGBA*)&((*pixels)[(((uint)u)+((uint)v)*width)*sizeof (CRGBA)]))->A;
585 // Alpha test
586 alphaTest = alpha >= triangle.AlphaTestThreshold;
589 // Good alpha test ?
590 if (alphaTest)
592 // Enter the mutex
593 mutex.enter ();
595 // Write Z around
596 uint d;
597 for (d=0; d<radius; d++)
599 // Ref in the zbuffer
600 sint fx = x + DeltaZ[d][0];
601 sint fy = y + DeltaZ[d][1];
602 if ( (fx >= 0) && (fx < zbuffer.LocalZBufferWidth) && (fy >= 0) && (fy < zbuffer.LocalZBufferHeight) )
604 float &zValue = zbuffer.Pixels[fx+(zbuffer.LocalZBufferHeight-fy-1)*zbuffer.LocalZBufferWidth];
606 // Z test
607 if (z < zValue)
609 // Render z in zbuffer
610 zValue = z;
615 // Leave the mutex
616 mutex.leave ();
624 void NL3D::CRenderZBuffer::run()
626 // Set the CPU mask
627 // setCPUMask (Thread, _Process);
629 // Span array
630 CPolygon2D::TRasterVect borders;
632 // For each triangles
633 uint i;
634 for (i=_FirstTriangle; i<_FirstTriangle+_NumTriangle; i++)
636 // Triangle reference
637 const CZoneLighter::CTriangle &triangle = (*_Triangles)[i];
639 // Keep backface and doublesided polygons
640 if ((triangle.Flags & CZoneLighter::CTriangle::DoubleSided) || ((triangle.getPlane ().getNormal() * _ZoneLighter->_SunDirection) > 0))
642 // Landscape triangle ?
643 if (triangle.Flags & CZoneLighter::CTriangle::Landscape)
645 // For each landscape zbuffer
646 uint sample;
647 const uint samples = _Description->SoftShadowSamplesSqrt*_Description->SoftShadowSamplesSqrt;
648 for (sample=0; sample<samples; sample++)
650 RenderTriangle (triangle, *_Description, borders, _ZoneLighter->_Mutex, _ZoneLighter->_ZBufferLandscape[sample], 9);
653 else
655 // Render in a high resolution zbuffer
656 RenderTriangle (triangle, *_Description, borders, _ZoneLighter->_Mutex, _ZoneLighter->_ZBufferObject, 1);
659 _ZoneLighter->_NumberOfPatchComputed++;
662 // Exit
663 _ZoneLighter->_ProcessExitedMutex.enter();
664 _ZoneLighter->_ProcessExited++;
665 _ZoneLighter->_ProcessExitedMutex.leave();
668 // ***************************************************************************
670 class NL3D::CCalcLightableShapeRunnable : public IRunnable
672 public:
673 CCalcLightableShapeRunnable(uint process,
674 CZoneLighter *zoneLighter,
675 const CZoneLighter::CLightDesc *description,
676 CZoneLighter::TShapeVect *shapeToLit,
677 uint firstShape,
678 uint lastShape
681 _ZoneLighter(zoneLighter),
682 _Description(description),
683 _ShapesToLit(shapeToLit),
684 _FirstShape(firstShape),
685 _LastShape(lastShape),
686 _Process(process)
689 void run()
691 _ZoneLighter->processLightableShapeCalc(_Process, _ShapesToLit, _FirstShape, _LastShape, *_Description);
692 _ZoneLighter->_ProcessExitedMutex.enter();
693 _ZoneLighter->_ProcessExited++;
694 _ZoneLighter->_ProcessExitedMutex.leave();
696 private:
697 CZoneLighter *_ZoneLighter;
698 const CZoneLighter::CLightDesc *_Description;
699 CZoneLighter::TShapeVect *_ShapesToLit;
700 uint _FirstShape, _LastShape;
701 uint _Process;
705 // ***************************************************************************
707 void draw2dLine (CBitmap &bitmap, float x0, float y0, float x1, float y1, const CRGBA &color)
709 static vector< std::pair<sint, sint> > lines;
710 drawFullLine (x0, y0, x1, y1, lines);
712 // Bitmap pixels
713 CRGBA *pixels = (CRGBA*)&(bitmap.getPixels ()[0]);
715 // Bitmap size
716 sint width = (sint)bitmap.getWidth ();
717 sint height = (sint)bitmap.getHeight ();
719 // Draw the line
720 uint i;
721 for (i=0; i<lines.size (); i++)
723 sint x = lines[i].first;
724 sint y = lines[i].second;
726 // Clip
727 if ( (x >= 0) && (x < width) && (y >= 0) && (y < height) )
729 pixels[x+(height-y-1)*width] = color;
734 // ***************************************************************************
736 void InitZBuffer (CZoneLighter::CZBuffer &zbuffer, const CVector &SunPosition, const CMatrix &rayBasis, const CAABBoxExt &zoneBB, uint zBufferPixelSize, const CZoneLighter::CLightDesc& description)
738 // Clac the zbuffer world size
739 const float zBufferWorldSize = (float)(tan (description.SunFOV/2)*description.SunDistance*2);
741 // ** Compute the zbuffer basis
742 zbuffer.WorldToZBuffer.identity ();
744 zbuffer.WorldToZBuffer = rayBasis;
745 zbuffer.WorldToZBuffer.setPos (SunPosition);
746 zbuffer.WorldToZBuffer.invert ();
747 zbuffer.WorldToZBufferFrustum.init ((float)zBufferWorldSize, (float)zBufferWorldSize, description.SunDistance, description.SunDistance*2);
749 // Zbuffer size
750 zbuffer.ZBufferPixelSize = zBufferPixelSize;
752 // Evaluate the size of the local zbuffer
754 // The zone bounding box
755 CVector bMin = zoneBB.getMin ();
756 CVector bMax = zoneBB.getMax ();
757 transformVectorToZBuffer (zbuffer, CVector (bMin.x, bMax.y, bMin.z), zbuffer.BoundingBoxVectors[0]);
758 transformVectorToZBuffer (zbuffer, CVector (bMin.x, bMin.y, bMin.z), zbuffer.BoundingBoxVectors[1]);
759 transformVectorToZBuffer (zbuffer, CVector (bMax.x, bMin.y, bMin.z), zbuffer.BoundingBoxVectors[2]);
760 transformVectorToZBuffer (zbuffer, CVector (bMax.x, bMax.y, bMin.z), zbuffer.BoundingBoxVectors[3]);
761 transformVectorToZBuffer (zbuffer, CVector (bMin.x, bMax.y, bMax.z), zbuffer.BoundingBoxVectors[4]);
762 transformVectorToZBuffer (zbuffer, CVector (bMin.x, bMin.y, bMax.z), zbuffer.BoundingBoxVectors[5]);
763 transformVectorToZBuffer (zbuffer, CVector (bMax.x, bMin.y, bMax.z), zbuffer.BoundingBoxVectors[6]);
764 transformVectorToZBuffer (zbuffer, CVector (bMax.x, bMax.y, bMax.z), zbuffer.BoundingBoxVectors[7]);
766 // Get the min and max
767 zbuffer.LocalZBufferXMin = 0x7fffffff;
768 zbuffer.LocalZBufferYMin = 0x7fffffff;
769 zbuffer.LocalZBufferXMax = 0x80000000;
770 zbuffer.LocalZBufferYMax = 0x80000000;
771 zbuffer.LocalZBufferZMin = FLT_MAX;
772 zbuffer.LocalZBufferZMax = -FLT_MAX;
773 uint j;
774 for (j=0; j<8; j++)
776 sint minX = (sint)floor (zbuffer.BoundingBoxVectors[j].x);
777 sint maxX = (sint)ceil (zbuffer.BoundingBoxVectors[j].x);
778 sint minY = (sint)floor (zbuffer.BoundingBoxVectors[j].y);
779 sint maxY = (sint)ceil (zbuffer.BoundingBoxVectors[j].y);
780 if (minX<zbuffer.LocalZBufferXMin)
781 zbuffer.LocalZBufferXMin = minX;
782 if (maxX>zbuffer.LocalZBufferXMax)
783 zbuffer.LocalZBufferXMax = maxX;
784 if (minY<zbuffer.LocalZBufferYMin)
785 zbuffer.LocalZBufferYMin = minY;
786 if (maxY>zbuffer.LocalZBufferYMax)
787 zbuffer.LocalZBufferYMax = maxY;
788 if ((-zbuffer.BoundingBoxVectors[j].z)<zbuffer.LocalZBufferZMin)
789 zbuffer.LocalZBufferZMin = -zbuffer.BoundingBoxVectors[j].z;
790 if ((-zbuffer.BoundingBoxVectors[j].z)>zbuffer.LocalZBufferZMax)
791 zbuffer.LocalZBufferZMax = -zbuffer.BoundingBoxVectors[j].z;
794 // Expand the zbuffer
795 zbuffer.LocalZBufferXMax++;
796 zbuffer.LocalZBufferXMin--;
797 zbuffer.LocalZBufferYMax++;
798 zbuffer.LocalZBufferYMin--;
800 zbuffer.LocalZBufferWidth = zbuffer.LocalZBufferXMax-zbuffer.LocalZBufferXMin;
801 zbuffer.LocalZBufferHeight = zbuffer.LocalZBufferYMax-zbuffer.LocalZBufferYMin;
803 // Resize and clear the zbuffer
804 zbuffer.Pixels.resize (0);
805 zbuffer.Pixels.resize (zbuffer.LocalZBufferWidth*zbuffer.LocalZBufferHeight, FLT_MAX);
808 // ***************************************************************************
810 #ifdef SAVE_ZBUFFER
811 void SaveZBuffer (CZoneLighter::CZBuffer &zbuffer, const char *filename)
813 // Resize the bitmap
814 CBitmap bitmap;
815 bitmap.resize (zbuffer.LocalZBufferWidth, zbuffer.LocalZBufferHeight, CBitmap::Luminance);
817 // Get pixels
818 CObjectVector<uint8> &pixels = bitmap.getPixels ();
820 // Draw it
821 uint samples = zbuffer.LocalZBufferWidth*zbuffer.LocalZBufferHeight;
822 for (uint i=0; i<samples; i++)
824 // Get the value
825 float value = (zbuffer.Pixels[i] - zbuffer.LocalZBufferZMin) * 255 / (zbuffer.LocalZBufferZMax - zbuffer.LocalZBufferZMin);
826 clamp (value, 0, 255);
827 pixels[i] = (uint8)value;
830 // Convert to RGBA
831 bitmap.convertToType (CBitmap::RGBA);
833 // Draw some red lines
834 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[0].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[0].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[1].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[1].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
835 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[0].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[0].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[3].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[3].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
836 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[2].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[2].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[1].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[1].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
837 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[2].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[2].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[3].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[3].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
838 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[4].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[4].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[5].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[5].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
839 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[4].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[4].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[7].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[7].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
840 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[6].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[6].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[5].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[5].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
841 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[6].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[6].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[7].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[7].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
842 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[0].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[0].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[4].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[4].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
843 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[1].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[1].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[5].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[5].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
844 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[2].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[2].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[6].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[6].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
845 draw2dLine (bitmap, zbuffer.BoundingBoxVectors[3].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[3].y-(float)zbuffer.LocalZBufferYMin, zbuffer.BoundingBoxVectors[7].x-(float)zbuffer.LocalZBufferXMin, zbuffer.BoundingBoxVectors[7].y-(float)zbuffer.LocalZBufferYMin, CRGBA::Red);
847 // Render it
848 COFile outputZFile;
850 // Open it
851 if (outputZFile.open (filename))
853 // Save the new zone
856 // Convert to RGBA
857 bitmap.convertToType (CBitmap::RGBA);
859 // Save it
860 bitmap.writeJPG (outputZFile, 128);
862 catch (const Exception& except)
864 // Error message
865 nlwarning ("ERROR writing %s: %s\n", filename, except.what());
868 else
870 // Error can't open the file
871 nlwarning ("ERROR Can't open %s for writing\n", filename);
874 #endif // SAVE_ZBUFFER
876 // ***************************************************************************
878 void FilterZBuffer (CZoneLighter::CZBuffer &zbuffer, uint filterRadius)
880 // Resize the temp buffer
881 static std::vector<float> tempPixels;
882 tempPixels = zbuffer.Pixels;
884 sint x, y;
885 for (y=0; y<zbuffer.LocalZBufferHeight; y++)
886 for (x=0; x<zbuffer.LocalZBufferWidth; x++)
888 // The Value
889 float &newValue = tempPixels[x+y*zbuffer.LocalZBufferWidth];
891 uint n;
892 for (n=1; n<filterRadius; n++)
894 const sint fx = x + DeltaZ[n][0];
895 const sint fy = y + DeltaZ[n][1];
897 // Clip
898 if ( (fx>=0) && (fx < zbuffer.LocalZBufferWidth) && (fy>=0) && (fy < zbuffer.LocalZBufferHeight) )
900 const float &testValue = zbuffer.Pixels[fx+fy*zbuffer.LocalZBufferWidth];
901 if (testValue < newValue)
902 newValue = testValue;
908 // Copy the new zbuffer
909 zbuffer.Pixels = tempPixels;
912 // ***************************************************************************
914 void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight, const CLightDesc& description, std::vector<CTriangle>& obstacles, vector<uint> &listZone)
917 * Lighting algorithm
918 * ------------------
920 * - Create a quad grid to store shadow casting triangles
921 * - Create a heightfield used for global illumination. Cells are initialized with -FLT_MAX
922 * - Insert each shadow casting triangles in the quad grid and fill the heightfield's cells overlapped by the bounding box of the triangle with
923 * the max height of the triangle if its height is > than the current height in the heightfield's cell.
927 // Backup thread mask
928 IThread *currentThread = IThread::getCurrentThread ();
929 uint64 threadMask = currentThread->getCPUMask();
930 // currentThread->setCPUMask (1);
932 // Calc the ray basis
933 _SunDirection=description.SunDirection;
934 NEL3DCalcBase (_SunDirection, _RayBasis);
936 // Zone to light
937 _ZoneToLight=zoneToLight;
939 // Landscape
940 _Landscape=&landscape;
942 // Process count
943 _ProcessCount=description.NumCPU;
944 if (_ProcessCount==0)
946 // Create a doomy thread
947 IProcess *pProcess=IProcess::getCurrentProcess ();
948 _CPUMask = pProcess->getCPUMask();
949 _ProcessCount = 0;
950 uint64 i;
951 for (i=0; i<64; i++)
953 if (_CPUMask&((uint64)1<<i))
954 _ProcessCount++;
957 if (_ProcessCount>MAX_CPU_PROCESS)
958 _ProcessCount=MAX_CPU_PROCESS;
960 // Number of obstacle polygones
961 nlinfo ("Obstacle polygones : %u", (uint)obstacles.size ());
963 // Number of CPUS used
964 nlinfo ("Number of CPU used: %u", _ProcessCount);
966 // Zone pointer
967 CZone *pZone=landscape.getZone (_ZoneToLight);
968 if (pZone)
970 // *** Compute center of the object
972 // Get the zone bounding box
973 const CAABBoxExt &zoneBB=pZone->getZoneBB();
975 // Get the center
976 CVector center = zoneBB.getCenter ();
978 // *** Compute planes
979 const uint size=(uint)obstacles.size();
980 uint triangleId;
981 for (triangleId=0; triangleId<size; triangleId++)
983 // Triangle ref
984 CZoneLighter::CTriangle& triangle=obstacles[triangleId];
986 // Calc the plane
987 triangle._Plane.make (triangle.Triangle.V0, triangle.Triangle.V1, triangle.Triangle.V2);
990 // Create landscape zbuffers
991 _ZBufferLandscape.resize (description.SoftShadowSamplesSqrt*description.SoftShadowSamplesSqrt);
993 uint sampleX;
994 uint sampleY;
995 for (sampleY=0; sampleY<description.SoftShadowSamplesSqrt; sampleY++)
996 for (sampleX=0; sampleX<description.SoftShadowSamplesSqrt; sampleX++)
998 // *** Render the light zbuffer
999 CZBuffer &zbuffer = _ZBufferLandscape[sampleX + sampleY*description.SoftShadowSamplesSqrt];
1001 // Delta pos for area light
1002 float deltaX = ( (float)sampleX + 0.5f - (float)description.SoftShadowSamplesSqrt / 2.f) / (float)description.SoftShadowSamplesSqrt;
1003 float deltaY = ( (float)sampleY + 0.5f - (float)description.SoftShadowSamplesSqrt / 2.f) / (float)description.SoftShadowSamplesSqrt;
1004 CVector lightPos = _RayBasis.getI () * ((float)description.SunRadius * deltaX) + _RayBasis.getJ () * ((float)description.SunRadius * deltaY);
1005 lightPos = description.SunCenter - (description.SunDirection * description.SunDistance) + lightPos;
1007 InitZBuffer (zbuffer, lightPos, _RayBasis, zoneBB, description.ZBufferLandscapeSize, description);
1008 nlinfo ("Zbuffer %d size : %d x %d", sampleX+sampleY*description.SoftShadowSamplesSqrt, zbuffer.LocalZBufferWidth, zbuffer.LocalZBufferHeight);
1012 // *** Init the zbuffer for the vegetation
1013 CVector lightPos = description.SunCenter - (description.SunDirection * description.SunDistance);
1014 InitZBuffer (_ZBufferObject, lightPos, _RayBasis, zoneBB, description.ZBufferObjectSize, description);
1015 nlinfo ("Zbuffer object size : %d x %d", _ZBufferObject.LocalZBufferWidth, _ZBufferObject.LocalZBufferHeight);
1018 // Compute the zbuffer in multi thread
1019 _ProcessExited = 0;
1021 // Number of triangle to render per thread
1022 uint numTriangle = ((uint)obstacles.size () / _ProcessCount) + 1;
1024 // First triangle for the thread
1025 uint firstTriangle = 0;
1027 // Count
1028 _NumberOfPatchComputed = 0;
1030 for (uint process=0; process<_ProcessCount; process++)
1032 // Get list of triangles to render
1033 uint lastTriangle=firstTriangle+numTriangle;
1034 if (lastTriangle>obstacles.size ())
1035 lastTriangle=(uint)obstacles.size ();
1037 // Create a thread
1038 CRenderZBuffer *runnable = new CRenderZBuffer (process, this, &description, firstTriangle, lastTriangle - firstTriangle, &obstacles);
1039 IThread *pThread=IThread::create (runnable);
1040 runnable->Thread = pThread;
1042 // New first patch
1043 firstTriangle = lastTriangle;
1045 // Launch
1046 pThread->start();
1049 // Wait for others processes
1050 while (_ProcessExited!=_ProcessCount)
1052 nlSleep (1000);
1054 // Call the progress callback
1055 progress ("Render triangles", (float)_NumberOfPatchComputed/(float)obstacles.size());
1058 // * Save the zbuffer
1059 uint sample;
1060 const uint samples = description.SoftShadowSamplesSqrt*description.SoftShadowSamplesSqrt;
1061 #ifdef SAVE_ZBUFFER
1062 for (sample=0; sample<samples; sample++)
1064 // *** The zbuffer
1065 CZBuffer &zbuffer = _ZBufferLandscape[sample];
1067 string zbufferFilename = SAVE_ZBUFFER"/zbuffer_landscape_" + toString (sample) + ".jpg";
1069 SaveZBuffer (zbuffer, zbufferFilename.c_str ());
1072 // Save the object zbuffer
1073 SaveZBuffer (_ZBufferObject, SAVE_ZBUFFER"/zbuffer_object.jpg");
1074 #endif // SAVE_ZBUFFER
1076 // *** Filter the zbuffer
1077 for (sample=0; sample<samples; sample++)
1079 // For landscape zbuffer, expand the z to neighbor
1080 FilterZBuffer (_ZBufferLandscape[sample], 5);
1083 // Change the quadGrid basis
1084 CMatrix invRayBasis=_RayBasis;
1085 invRayBasis.invert ();
1087 // Init the heightfield
1088 _HeightfieldCellSize=description.HeightfieldCellSize;
1089 _HeightFieldCellCount=(sint)(description.HeightfieldSize/_HeightfieldCellSize);
1090 nlassert (_HeightFieldCellCount!=0);
1091 _OrigineHeightField=zoneBB.getCenter ()-CVector (description.HeightfieldSize/2, description.HeightfieldSize/2, 0);
1092 _HeightField.resize (_HeightFieldCellCount*_HeightFieldCellCount, -FLT_MAX);
1094 // Fill the quadGrid and the heightField
1095 for (triangleId=0; triangleId<size; triangleId++)
1097 // Progress bar
1098 if ( (triangleId&0xff) == 0)
1099 progress ("Build quadtree and heightfield", (float)triangleId/(float)size);
1101 // Triangle ref
1102 CZoneLighter::CTriangle& triangle=obstacles[triangleId];
1104 // Look for the min coordinate, in World Basis
1105 CVector minv;
1106 minv.minof (triangle.Triangle.V0, triangle.Triangle.V1);
1107 minv.minof (minv, triangle.Triangle.V2);
1109 // Look for the max coordinate, in World Basis
1110 CVector maxv;
1111 maxv.maxof (triangle.Triangle.V0, triangle.Triangle.V1);
1112 maxv.maxof (maxv, triangle.Triangle.V2);
1114 // Lanscape tri ?
1115 if (triangle.Flags & CTriangle::Landscape)
1117 // Fill the heightfield
1118 sint minX=std::max (0, (sint)floor (0.5f+(minv.x-_OrigineHeightField.x)/_HeightfieldCellSize));
1119 sint maxX=std::min (_HeightFieldCellCount, (sint)floor (0.5f+(maxv.x-_OrigineHeightField.x)/_HeightfieldCellSize));
1120 sint minY=std::max (0, (sint)floor (0.5f+(minv.y-_OrigineHeightField.y)/_HeightfieldCellSize));
1121 sint maxY=std::min (_HeightFieldCellCount, (sint)floor (0.5f+(maxv.y-_OrigineHeightField.y)/_HeightfieldCellSize));
1123 // Calc position in the heightfield
1124 for (sint y=minY; y<maxY; y++)
1125 for (sint x=minX; x<maxX; x++)
1127 // Valid position, try to insert it
1128 if (maxv.z>_HeightField[x+y*_HeightFieldCellCount])
1130 // New height in this cell
1131 _HeightField[x+y*_HeightFieldCellCount]=maxv.z;
1137 // Retrieve the zone to fill its shaded value
1138 pZone->retrieve (_PatchInfo, _BorderVertices);
1140 // Number of patch
1141 uint patchCount=(uint)_PatchInfo.size();
1143 // Bit array to know if the lumel is shadowed
1144 if (description.Shadow)
1145 _ShadowArray.resize (patchCount);
1147 // A lumel vector by patch
1148 vector<vector<CLumelDescriptor> > lumels;
1149 lumels.resize (patchCount);
1151 // Build zone information
1152 buildZoneInformation (landscape,
1153 listZone,
1154 description);
1158 // Number of patch
1159 uint patchCount=(uint)_PatchInfo.size();
1161 // Reset patch count
1163 CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
1164 access.value().resize (0);
1165 access.value().resize (patchCount, false);
1168 // Patch by thread
1169 uint patchCountByThread = patchCount/_ProcessCount;
1170 patchCountByThread++;
1172 // Patch to allocate
1173 uint firstPatch=0;
1174 _NumberOfPatchComputed = 0;
1176 // Reset exited process
1177 _ProcessExited=0;
1179 // Set the thread state
1180 _LastPatchComputed.resize (_ProcessCount);
1182 if (patchCount)
1184 // Launch threads
1185 uint process;
1186 for (process = 0; process < _ProcessCount; process++)
1188 // Last patch
1189 uint lastPatch = firstPatch + patchCountByThread;
1190 lastPatch %= patchCount;
1192 // Last patch computed
1193 _LastPatchComputed[process] = firstPatch;
1195 // Create a thread
1196 CLightRunnable *runnable = new CLightRunnable(process, this, &description);
1197 IThread *pThread = IThread::create(runnable);
1198 runnable->Thread = pThread;
1200 // New first patch
1201 firstPatch = lastPatch;
1203 // Launch
1204 pThread->start();
1207 // Wait for others processes
1208 while (_ProcessExited != _ProcessCount)
1210 nlSleep(1000);
1212 // Call the progress callback
1213 progress("Lighting patches", (float)_NumberOfPatchComputed / (float)_PatchInfo.size());
1216 else
1218 nlwarning("Empty zone");
1221 // Reset old thread mask
1222 // currentThread->setCPUMask (threadMask);
1224 // overflow ?
1225 if (_ZBufferOverflow)
1226 nlwarning ("Error : zbuffer overflow");
1228 // Progress bar
1229 progress ("Compute Influences of PointLights", 0.f);
1231 // Compute PointLight influences on zone.
1232 // Some precalc.
1233 compilePointLightRT(description.GridSize, description.GridCellSize, obstacles, description.Shadow);
1234 // Influence patchs and get light list of interest
1235 std::vector<CPointLightNamed> listPointLight;
1236 processZonePointLightRT(listPointLight);
1239 // Rebuild the zone
1241 // Progress bar
1242 progress ("Compress the lightmap", 0.6f);
1244 // Build, with list of lights.
1245 CZoneInfo zinfo;
1246 zinfo.ZoneId= _ZoneToLight;
1247 zinfo.Patchs= _PatchInfo;
1248 zinfo.BorderVertices= _BorderVertices;
1249 zinfo.PointLights= listPointLight;
1250 output.build (zinfo);
1252 /// copy the tiles flags from the zone to light to the output zone
1253 copyTileFlags(output, *(landscape.getZone(zoneToLight)));
1255 /// Perform lightning of some ig's of the current zone (if any)
1256 lightShapes(zoneToLight, description);
1260 // *************************************************************************************
1261 void CZoneLighter::copyTileFlags(CZone &destZone, const CZone &srcZone)
1263 nlassert(destZone.getZoneId() == srcZone.getZoneId());
1264 nlassert(destZone.getNumPatchs() == srcZone.getNumPatchs());
1265 for (sint k = 0; k < srcZone.getNumPatchs(); ++k)
1267 destZone.copyTilesFlags(k, srcZone.getPatch(k));
1271 // ***************************************************************************
1272 float CZoneLighter::getSkyContribution(const CVector &pos, const CVector &normal, float skyIntensity) const
1274 float s=(pos.x-_OrigineHeightField.x)/_HeightfieldCellSize;
1275 float t=(pos.y-_OrigineHeightField.y)/_HeightfieldCellSize;
1276 sint sInt=(sint)(floor (s+0.5f));
1277 sint tInt=(sint)(floor (t+0.5f));
1279 // Bilinear
1280 float skyContributionTab[2][2];
1281 skyContributionTab[0][0] = calcSkyContribution (sInt-1, tInt-1, pos.z, skyIntensity, normal);
1282 skyContributionTab[1][0] = calcSkyContribution (sInt, tInt-1, pos.z, skyIntensity, normal);
1283 skyContributionTab[1][1] = calcSkyContribution (sInt, tInt, pos.z, skyIntensity, normal);
1284 skyContributionTab[0][1] = calcSkyContribution (sInt-1, tInt, pos.z, skyIntensity, normal);
1286 float sFact=s+0.5f-sInt;
1287 float tFact=t+0.5f-tInt;
1288 return (skyContributionTab[0][0]*(1.f-sFact) + skyContributionTab[1][0]*sFact)*(1.f-tFact) +
1289 (skyContributionTab[0][1]*(1.f-sFact) + skyContributionTab[1][1]*sFact)*tFact;
1293 // ***************************************************************************
1294 void CZoneLighter::processCalc (uint process, const CLightDesc& description)
1296 // *** Raytrace each patches
1298 // Get a patch
1299 uint patch = getAPatch (process);
1300 while (patch != 0xffffffff)
1302 // For each patch
1303 if (description.Shadow)
1305 // Lumels
1306 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
1308 // Lumel count
1309 uint lumelCount=(uint)lumels.size();
1310 CPatchInfo &patchInfo=_PatchInfo[patch];
1311 nlassert (patchInfo.Lumels.size()==lumelCount);
1313 // Resize shadow array
1314 _ShadowArray[patch].resize (lumelCount);
1316 // For each lumel
1317 for (uint lumel=0; lumel<lumelCount; lumel++)
1319 float factor=0;
1320 factor = attenuation (lumels[lumel].Position, description);
1321 patchInfo.Lumels[lumel]=(uint)(factor*255);
1324 else
1326 // Lumels
1327 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
1329 // Lumel count
1330 uint lumelCount=(uint)lumels.size();
1331 CPatchInfo &patchInfo=_PatchInfo[patch];
1332 nlassert (patchInfo.Lumels.size()==lumelCount);
1334 // For each lumel
1335 for (uint lumel=0; lumel<lumelCount; lumel++)
1337 // Not shadowed
1338 patchInfo.Lumels[lumel]=255;
1342 // *** Lighting
1344 // Get the patch info
1345 CPatchInfo &patchInfo=_PatchInfo[patch];
1347 // ** Pointer on arries
1348 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
1350 // Go for light each lumel
1351 for (uint lumel=0; lumel<lumels.size(); lumel++)
1353 // Sky contribution
1354 float skyContribution;
1356 if (description.SkyContribution)
1358 skyContribution = getSkyContribution(lumels[lumel].Position, lumels[lumel].Normal, description.SkyIntensity);
1360 else
1362 skyContribution = 0.f;
1365 // Sun contribution
1366 float sunContribution;
1367 if (description.SunContribution)
1369 sunContribution=(-lumels[lumel].Normal*_SunDirection)-skyContribution;
1370 clamp (sunContribution, 0.f, 1.f);
1372 else
1373 sunContribution=0;
1375 // Final lighting
1376 sint finalLighting=(sint)(255.f*(((float)patchInfo.Lumels[lumel])*sunContribution/255.f+skyContribution));
1377 clamp (finalLighting, 0, 255);
1378 patchInfo.Lumels[lumel]=finalLighting;
1381 // Next patch
1382 patch = getAPatch (process);
1386 // ***************************************************************************
1388 uint8 CZoneLighter::getMaxPhi (sint s, sint t, sint deltaS, sint deltaT, float heightPos) const
1390 // Start position
1391 s+=deltaS;
1392 t+=deltaT;
1394 // Distance increment
1395 float stepDistance=CVector (deltaS*_HeightfieldCellSize, deltaT*_HeightfieldCellSize,0).norm ();
1397 // Current distance
1398 float distance=stepDistance;
1400 // Max height
1401 float maxHeight=0;
1402 float maxTanTeta=0;
1404 // For all the line
1405 while ((s<_HeightFieldCellCount)&&(t<_HeightFieldCellCount)&&(s>=0)&&(t>=0))
1407 // Get height
1408 float height=_HeightField[s+t*_HeightFieldCellCount];
1409 height-=heightPos;
1411 // Better ?
1412 if (height>maxHeight)
1414 // Calc sin teta
1415 float tanTeta=height/distance;
1416 nlassert (tanTeta>=0);
1418 // Better ?
1419 if (tanTeta>maxTanTeta)
1421 // New max height
1422 maxHeight=height;
1423 maxTanTeta=tanTeta;
1426 s+=deltaS;
1427 t+=deltaT;
1428 distance+=stepDistance;
1431 // return phi
1432 float teta=(float)atan (maxTanTeta);
1433 nlassert (teta>=0);
1434 nlassert (teta<=Pi/2);
1435 clamp (teta, 0.f, (float)Pi/2);
1436 sint res=(sint)((Pi/2-teta)*256/(Pi/2));
1437 clamp (res, 0, 255);
1438 return (uint8)res;
1441 // ***************************************************************************
1443 #define AllFront 0
1444 #define AllBack 1
1445 #define Clipped 2
1447 // ***************************************************************************
1449 bool CZoneLighter::isLumelOnEdgeMustBeOversample (uint patch, uint edge, sint s, sint t, const vector<bool> &binded,
1450 const vector<bool> &oversampleEdges, vector<CPatchUVLocator> &locator,
1451 uint8 shadowed, vector<vector<uint8> >& shadowBuffer)
1453 // Must force oversampling of this edge ?
1454 if (oversampleEdges[edge])
1455 return true;
1456 else
1458 // binded ?
1459 if (binded[edge])
1461 // Lumel coord
1462 CVector2f lumelCoord (((float)(s+_GetNormalDeltaS[edge])+0.5f)/4.f, ((float)(t+_GetNormalDeltaT[edge])+0.5f)/4.f);
1463 uint otherPatch=locator[edge].selectPatch(lumelCoord);
1465 // Get uv
1466 CVector2f neighborUV;
1467 CPatch *patchOut;
1468 locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
1470 // Is the same shadowed flag ?
1471 sint ss=(sint)(neighborUV.x*4.f);
1472 sint tt=(sint)(neighborUV.y*4.f);
1473 return (shadowBuffer[patchOut->getPatchId()][ss+(patchOut->getOrderS()<<2)*tt]!=shadowed);
1475 else
1477 // Not oversample if not binded
1478 return false;
1483 // ***************************************************************************
1485 float easineasoutC2(float x)
1487 float y;
1488 // 5-nome tq f(0)=0, f'(0)=0, f''(0)=0, f(1)=1, f'(1)=0, f''(1)=0.
1489 float x3=x*x*x;
1490 float x4=x3*x;
1491 float x5=x4*x;
1492 y= 6*x5 -15*x4 +10*x3;
1493 return y;
1496 // ***************************************************************************
1499 sint16 CZoneLighter::_GetNormalDeltaS[4]={ -1, 0, 1, 0 };
1500 sint16 CZoneLighter::_GetNormalDeltaT[4]={ 0, 1, 0, -1 };
1502 // ***************************************************************************
1504 void CZoneLighter::getNormal (const CPatch *pPatch, sint16 lumelS, sint16 lumelT, vector<CPatchUVLocator> &locator,
1505 const vector<CPatch::CBindInfo> &bindInfo, const vector<bool> &binded, set<uint64>& visited,
1506 float deltaS, float deltaT, uint rotation, const CBezierPatch &bezierPatch, uint lastEdge)
1508 // Build a desc srructure
1509 uint64 id=(uint64)lumelS|(((uint64)lumelT)<<16)|(((uint64)pPatch->getPatchId())<<32)|(((uint64)pPatch->getZone()->getZoneId())<<48);
1511 // Insert it
1512 if (visited.insert (id).second)
1514 // Clip
1515 float sqDist=deltaS*deltaS+deltaT*deltaT;
1516 if ( sqDist < 1 )
1518 // Continue...
1520 sint orderSx4=pPatch->getOrderS()<<2;
1521 sint orderTx4=pPatch->getOrderT()<<2;
1523 sint16 _GetNormalBorderS[4]={ 0, -10, 1, -10 };
1524 sint16 _GetNormalBorderT[4]={ -10, 1, -10, 0 };
1525 _GetNormalBorderS[2]=orderSx4-1;
1526 _GetNormalBorderT[1]=orderTx4-1;
1528 // Add normal
1529 _GetNormalNormal+=bezierPatch.evalNormal ( ((float)lumelS+0.5f)/(float)orderSx4, ((float)lumelT+0.5f)/(float)orderTx4 );
1531 // For the four neighbors
1532 for (uint edge=0; edge<4; edge++)
1534 // Not last edge ?
1535 if (edge!=lastEdge)
1537 // Direction
1538 uint globalDirection=(edge+(4-rotation))&0x3;
1540 // Neighbor
1541 if ( (lumelS==_GetNormalBorderS[edge]) || (lumelT==_GetNormalBorderT[edge]) )
1543 // Binded ?
1544 bool bind=binded[edge];
1545 bool smooth=pPatch->getSmoothFlag (edge);
1546 if (bind&&smooth)
1548 // Lumel coord
1549 CVector2f lumelCoord ( ((float)(lumelS+_GetNormalDeltaS[edge])+0.5f)/4,
1550 ((float)(lumelT+_GetNormalDeltaT[edge])+0.5f)/4 );
1552 // Get neighbor pixel
1553 uint otherPatch=locator[edge].selectPatch(lumelCoord);
1555 // Get uv
1556 CVector2f neighborUV;
1557 CPatch *patchOut;
1558 locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
1560 // New coordinates
1561 sint16 newLumelS=(sint16)(4.f*neighborUV.x);
1562 sint16 newLumelT=(sint16)(4.f*neighborUV.y);
1564 // Zone id
1565 uint16 patchId=patchOut->getPatchId();
1566 uint16 zoneId=_ZoneId[patchOut->getZone()->getZoneId ()];
1568 // Get edge
1569 uint newEdge=0;
1570 uint i;
1571 for (i=0; i<=(uint)bindInfo[edge].NPatchs; i++)
1573 // Good patch ?
1574 if (bindInfo[edge].Next[i]==patchOut)
1576 // Get its edge
1577 newEdge=bindInfo[edge].Edge[i];
1578 break;
1582 // Rotation
1583 uint newRotation=(2-edge+rotation+newEdge)&0x3;
1585 // Must found it
1586 nlassert (i!=(uint)bindInfo[edge].NPatchs);
1588 // Get the bezier patch
1589 CBezierPatch &NewBezierPatch=_BezierPatch[zoneId][patchId];
1591 // Next lumel
1592 getNormal (patchOut, newLumelS, newLumelT, _Locator[zoneId][patchId], _BindInfo[zoneId][patchId],
1593 _Binded[zoneId][patchId], visited, deltaS+_GetNormalDeltaS[globalDirection],
1594 deltaT+_GetNormalDeltaT[globalDirection], newRotation, NewBezierPatch, newEdge);
1597 else
1599 // Left internal
1600 getNormal (pPatch, lumelS+_GetNormalDeltaS[edge], lumelT+_GetNormalDeltaT[edge], locator, bindInfo, binded, visited,
1601 deltaS+_GetNormalDeltaS[globalDirection], deltaT+_GetNormalDeltaT[globalDirection], rotation, bezierPatch, (edge+2)&0x3);
1609 // ***************************************************************************
1611 void CZoneLighter::addTriangles (CLandscape &landscape, vector<uint> &listZone, uint order, std::vector<CTriangle>& triangleArray)
1613 // Set all to refine
1614 excludeAllPatchFromRefineAll (landscape, listZone, false);
1616 // Setup the landscape
1617 landscape.setThreshold (0);
1618 landscape.setTileMaxSubdivision (order);
1620 // Refine it
1621 landscape.refineAll (CVector (0, 0, 0));
1623 // Dump tesselated triangles
1624 std::vector<const CTessFace*> leaves;
1625 landscape.getTessellationLeaves(leaves);
1627 // Number of leaves
1628 uint leavesCount=(uint)leaves.size();
1630 // Reserve the array
1631 triangleArray.reserve (triangleArray.size()+leavesCount);
1633 // Scan each leaves
1634 for (uint leave=0; leave<leavesCount; leave++)
1636 // Leave
1637 const CTessFace *face=leaves[leave];
1639 // Add a triangle
1640 triangleArray.push_back (CTriangle (NLMISC::CTriangle (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos)));
1643 // Setup the landscape
1644 landscape.setThreshold (1000);
1645 landscape.setTileMaxSubdivision (0);
1647 // Remove all triangles
1648 landscape.refineAll (CVector (0, 0, 0));
1649 landscape.refineAll (CVector (0, 0, 0));
1650 landscape.refineAll (CVector (0, 0, 0));
1651 landscape.refineAll (CVector (0, 0, 0));
1652 landscape.refineAll (CVector (0, 0, 0));
1653 landscape.refineAll (CVector (0, 0, 0));
1654 landscape.refineAll (CVector (0, 0, 0));
1655 landscape.refineAll (CVector (0, 0, 0));
1656 landscape.refineAll (CVector (0, 0, 0));
1657 landscape.refineAll (CVector (0, 0, 0));
1660 // ***************************************************************************
1662 void CZoneLighter::addTriangles (const IShape &shape, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
1664 // Cast to CMesh
1665 const CMesh *mesh=dynamic_cast<const CMesh*>(&shape);
1667 // Cast to CMeshMultiLod
1668 const CMeshMultiLod *meshMulti=dynamic_cast<const CMeshMultiLod*>(&shape);
1670 // Cast to CMeshMultiLod
1671 const CMeshMRM *meshMRM=dynamic_cast<const CMeshMRM*>(&shape);
1673 // It is a mesh ?
1674 if (mesh)
1676 // Add its triangles
1677 addTriangles (*mesh, mesh->getMeshGeom (), modelMT, triangleArray);
1679 // It is a CMeshMultiLod ?
1680 else if (meshMulti)
1682 // Get the first geommesh
1683 const IMeshGeom *meshGeom=&meshMulti->getMeshGeom (0);
1685 // Dynamic cast
1686 const CMeshGeom *geomMesh=dynamic_cast<const CMeshGeom*>(meshGeom);
1687 if (geomMesh)
1689 addTriangles (*meshMulti, *geomMesh, modelMT, triangleArray);
1692 // Dynamic cast
1693 const CMeshMRMGeom *mrmGeomMesh=dynamic_cast<const CMeshMRMGeom*>(meshGeom);
1694 if (mrmGeomMesh)
1696 addTriangles (*meshMulti, *mrmGeomMesh, modelMT, triangleArray);
1699 // It is a CMeshMultiLod ?
1700 else if (meshMRM)
1702 // Get the first lod mesh geom
1703 addTriangles (*meshMRM, meshMRM->getMeshGeom (), modelMT, triangleArray);
1707 // ***************************************************************************
1709 void CZoneLighter::addTriangles (const CMeshBase &meshBase, const CMeshGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
1711 // Get the vertex buffer
1712 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
1713 CVertexBufferRead vba;
1714 vb.lock (vba);
1716 // For each matrix block
1717 uint numBlock=meshGeom.getNbMatrixBlock();
1718 for (uint block=0; block<numBlock; block++)
1720 // For each render pass
1721 uint numRenderPass=meshGeom.getNbRdrPass(block);
1722 for (uint pass=0; pass<numRenderPass; pass++)
1724 // Get the primitive block
1725 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( block, pass);
1727 // Get the material
1728 const CMaterial &material = meshBase.getMaterial (meshGeom.getRdrPassMaterial ( block, pass));
1730 // ** Get the bitmap
1732 // Texture information, not NULL only if texture is used for alpha test
1733 CBitmap *texture;
1734 bool clampU;
1735 bool clampV;
1736 uint8 alphaTestThreshold;
1737 bool doubleSided;
1738 if (getTexture (material, texture, clampU, clampV, alphaTestThreshold, doubleSided))
1740 // Dump triangles
1741 CIndexBufferRead iba;
1742 primitive.lock (iba);
1743 if (iba.getFormat() == CIndexBuffer::Indices32)
1745 const uint32* triIndex= (const uint32*) iba.getPtr ();
1746 uint numTri=primitive.getNumIndexes ()/3;
1747 uint tri;
1748 for (tri=0; tri<numTri; tri++)
1750 // Vertex
1751 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
1752 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
1753 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
1755 // UV
1756 float u[3] = { 0.f };
1757 float v[3] = { 0.f };
1758 for (uint i=0; i<3; i++)
1760 // Get UV coordinates
1761 const float *uv = (const float*)vba.getTexCoordPointer (triIndex[tri*3+i], 0);
1762 if (uv)
1764 // Copy it
1765 u[i] = uv[0];
1766 v[i] = uv[1];
1770 // Make a triangle
1771 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), doubleSided, texture, clampU, clampV, u, v,
1772 alphaTestThreshold));
1775 else if (iba.getFormat() == CIndexBuffer::Indices16)
1777 const uint16* triIndex=(const uint16*)iba.getPtr ();
1778 uint numTri=primitive.getNumIndexes ()/3;
1779 uint tri;
1780 for (tri=0; tri<numTri; tri++)
1782 // Vertex
1783 CVector v0=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3]));
1784 CVector v1=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+1]));
1785 CVector v2=modelMT*(*vba.getVertexCoordPointer (triIndex[tri*3+2]));
1787 // UV
1788 float u[3] = { 0.f };
1789 float v[3] = { 0.f };
1790 for (uint i=0; i<3; i++)
1792 // Get UV coordinates
1793 const float *uv = (const float*)vba.getTexCoordPointer (triIndex[tri*3+i], 0);
1794 if (uv)
1796 // Copy it
1797 u[i] = uv[0];
1798 v[i] = uv[1];
1802 // Make a triangle
1803 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2), doubleSided, texture, clampU, clampV, u, v,
1804 alphaTestThreshold));
1807 else
1809 nlerror("Invalid index buffer format");
1816 // ***************************************************************************
1818 bool CZoneLighter::getTexture (const CMaterial &material, CBitmap *&result, bool &clampU, bool &clampV, uint8 &alphaTestThreshold, bool &doubleSided)
1820 // Texture information, not NULL only if texture is used for alpha test
1821 result = NULL;
1822 clampU = false;
1823 clampV = false;
1825 // Alpha test threashold
1826 float alphaTestThresholdF = material.getAlphaTestThreshold () * 255;
1827 clamp (alphaTestThresholdF, 0.f, 255.f);
1828 alphaTestThreshold = (uint8)alphaTestThresholdF;
1830 // Drawable material ?
1831 if (material.getBlend ())
1832 return false;
1834 // Use alpha test ?
1835 if (material.getAlphaTest ())
1837 // Get the texture
1838 ITexture *texture = material.getTexture (0);
1840 // Is texture shared ?
1841 if (texture && texture->supportSharing ())
1843 // Share name
1844 string name = texture->getShareName();
1846 // Texture exist ?
1847 std::map<string, NLMISC::CBitmap>::iterator ite = _Bitmaps.find (name);
1848 if (ite != _Bitmaps.end ())
1850 // Yes
1851 result = &(ite->second);
1853 else
1855 // No, add it
1856 ite = _Bitmaps.insert (std::map<string, NLMISC::CBitmap>::value_type (name, CBitmap())).first;
1857 result = &(ite->second);
1859 // Generate the texture
1860 texture->generate ();
1862 // Convert to RGBA
1863 texture->convertToType (CBitmap::RGBA);
1865 // Copy it
1866 *result = *texture;
1868 // Release the texture
1869 texture->release ();
1872 // Wrap flags
1873 clampU = texture->getWrapS () == ITexture::Clamp;
1874 clampV = texture->getWrapT () == ITexture::Clamp;
1878 // Get double sided flag
1879 doubleSided = material.getDoubleSided ();
1880 return true;
1883 // ***************************************************************************
1885 void CZoneLighter::addTriangles (const CMeshBase &meshBase, const CMeshMRMGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
1887 // Get the vertex buffer
1888 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
1889 CVertexBufferRead vba;
1890 vb.lock (vba);
1892 // For each render pass
1893 uint numRenderPass=meshGeom.getNbRdrPass(0);
1894 for (uint pass=0; pass<numRenderPass; pass++)
1896 // Get the primitive block
1897 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( 0, pass);
1899 // Get the material
1900 const CMaterial &material = meshBase.getMaterial (meshGeom.getRdrPassMaterial (0, pass));
1902 // ** Get the bitmap
1904 // Texture information, not NULL only if texture is used for alpha test
1905 CBitmap *texture;
1906 bool clampU;
1907 bool clampV;
1908 uint8 alphaTestThreshold;
1909 bool doubleSided;
1910 if (getTexture (material, texture, clampU, clampV, alphaTestThreshold, doubleSided))
1912 // Dump triangles
1913 CIndexBufferRead iba;
1914 primitive.lock (iba);
1915 if (iba.getFormat() == CIndexBuffer::Indices32)
1917 const uint32 *triIndex = (const uint32 *)iba.getPtr();
1918 uint numTri = primitive.getNumIndexes() / 3;
1919 uint tri;
1920 for (tri = 0; tri < numTri; tri++)
1922 // Vertex
1923 CVector v0 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3]));
1924 CVector v1 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3 + 1]));
1925 CVector v2 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3 + 2]));
1927 // UV
1928 float u[3] = { 0.f };
1929 float v[3] = { 0.f };
1930 for (uint i = 0; i < 3; i++)
1932 // Get UV coordinates
1933 float *uv = (float *)vba.getTexCoordPointer(triIndex[tri * 3 + i], 0);
1934 if (uv)
1936 // Copy it
1937 u[i] = uv[0];
1938 v[i] = uv[1];
1942 // Make a triangle
1943 triangleArray.push_back(CTriangle(NLMISC::CTriangle(v0, v1, v2), doubleSided, texture, clampU, clampV, u, v,
1944 alphaTestThreshold));
1947 else if (iba.getFormat() == CIndexBuffer::Indices16)
1949 const uint16 *triIndex = (const uint16 *)iba.getPtr();
1950 uint numTri = primitive.getNumIndexes() / 3;
1951 uint tri;
1952 for (tri = 0; tri < numTri; tri++)
1954 // Vertex
1955 CVector v0 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3]));
1956 CVector v1 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3 + 1]));
1957 CVector v2 = modelMT * (*vba.getVertexCoordPointer(triIndex[tri * 3 + 2]));
1959 // UV
1960 float u[3] = { 0.f };
1961 float v[3] = { 0.f };
1962 for (uint i = 0; i < 3; i++)
1964 // Get UV coordinates
1965 float *uv = (float *)vba.getTexCoordPointer(triIndex[tri * 3 + i], 0);
1966 if (uv)
1968 // Copy it
1969 u[i] = uv[0];
1970 v[i] = uv[1];
1974 // Make a triangle
1975 triangleArray.push_back(CTriangle(NLMISC::CTriangle(v0, v1, v2), doubleSided, texture, clampU, clampV, u, v,
1976 alphaTestThreshold));
1979 else
1981 nlerror("Invalid index buffer format");
1987 // ***************************************************************************
1989 void CZoneLighter::excludeAllPatchFromRefineAll (CLandscape &landscape, vector<uint> &listZone, bool exclude)
1991 // For each zone
1992 for (uint zone=0; zone<listZone.size(); zone++)
1994 // Get num patches
1995 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
1997 // For each patches
1998 for (uint patch=0; patch<patchCount; patch++)
2000 // Exclude all the patches from refine all
2001 landscape.excludePatchFromRefineAll (listZone[zone], patch, exclude);
2006 // ***************************************************************************
2008 const sint8 CZoneLighter::TriangleIndexes[10][2][3] =
2010 {{0, 11, 6}, {0, 6, 9}},
2011 {{9, 6, 4}, {4, 6, 14}},
2012 {{4, 14, 8}, {4, 8, 10}},
2013 {{10, 8, 1}, {-1, -1, -1}},
2014 {{11, 5, 6}, {5, 13, 6}},
2015 {{6, 13, 3}, {6, 3, 14}},
2016 {{3, 8, 14}, {-1, -1, -1}},
2017 {{5, 12, 7}, {5, 7, 13}},
2018 {{7, 3, 13}, {-1, -1, -1}},
2019 {{12, 2, 7}, {-1, -1, -1}}
2022 // ***************************************************************************
2024 // lumel vertex ID, tesselation edge ID (0 for base<->right, 1 for base<->left), tesselation edge vertex 0, tesselation edge vertex 1
2025 const sint8 CZoneLighter::VertexThanCanBeSnappedOnABorder[8][4] =
2027 {0, 0, 0, 9},
2028 {1, 0, 9, 4},
2029 {2, 0, 4, 10},
2030 {3, 0, 10, 1},
2031 {0, 1, 0, 11},
2032 {4, 1, 11, 5},
2033 {7, 1, 5, 12},
2034 {9, 1, 12, 2},
2037 // ***************************************************************************
2039 // lumel vertex ID, tesselation corner vertex
2040 const sint8 CZoneLighter::VertexThanCanBeSnappedOnACorner[3][2] =
2042 {0, 0},
2043 {3, 1},
2044 {9, 2},
2047 // ***************************************************************************
2049 void CZoneLighter::buildZoneInformation (CLandscape &landscape, const vector<uint> &listZone, const CLightDesc &lightDesc)
2051 // Bool visit
2052 vector<vector<uint> > visited;
2054 // Zone count
2055 uint zoneCount=(uint)listZone.size();
2057 // Resize arries
2058 _Locator.resize (zoneCount);
2059 _Binded.resize (zoneCount);
2060 _BindInfo.resize (zoneCount);
2061 _BezierPatch.resize (zoneCount);
2063 // For each zone
2064 for (uint zone=0; zone<zoneCount; zone++)
2066 // Get num patches
2067 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
2069 // Insert zone id
2070 _ZoneId.insert (map<uint, uint>::value_type (listZone[zone], zone));
2072 // This is the zone to light ?
2073 if (listZone[zone]==_ZoneToLight)
2075 // Resize the arraies
2076 _Lumels.resize(patchCount);
2077 // _LumelCorners.resize(patchCount);
2078 // _BezierPatch.resize(patchCount);
2079 _OversampleEdges.resize(patchCount);
2080 visited.resize(patchCount);
2083 // Common arries
2084 _Locator[zone].resize(patchCount);
2085 _Binded[zone].resize(patchCount);
2086 _BindInfo[zone].resize(patchCount);
2087 _BezierPatch[zone].resize(patchCount);
2089 // For each patch
2090 uint patch;
2091 for (patch=0; patch<patchCount; patch++)
2093 // Get a patch pointer
2094 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(listZone[zone])))->getPatch (patch);
2096 // Progress bar
2097 progress ("Scan all patches", (float)patch/(float)patchCount);
2099 // Get pointer on arries
2100 vector<bool> &binded=_Binded[zone][patch];
2101 vector<CPatch::CBindInfo> &bindInfo=_BindInfo[zone][patch];
2102 vector<CPatchUVLocator> &locator=_Locator[zone][patch];
2103 CBezierPatch &bezierPatch=_BezierPatch[zone][patch];
2104 binded.resize (4, false);
2105 bindInfo.resize (4);
2106 locator.resize (4);
2108 // Contruct the patch
2109 bezierPatch=*pPatch->unpackIntoCache();
2111 // Same zone ?
2112 if (listZone[zone]==_ZoneToLight)
2114 // oversample this edge
2115 _OversampleEdges[patch].resize (4, false);
2118 // *** Build bind info
2120 // *** Build neighboorhood information
2121 uint edge;
2122 for (edge=0; edge<4; edge++)
2124 // Bond neighbor
2125 pPatch->getBindNeighbor (edge, bindInfo[edge]);
2127 // Patch binded
2128 if (bindInfo[edge].NPatchs>0)
2130 // This edeg is binded
2131 binded[edge]=true;
2133 // Same zone ?
2134 if ((listZone[zone]==_ZoneToLight)&&(bindInfo[edge].Zone->getZoneId()!=_ZoneToLight))
2136 // oversample this edge
2137 _OversampleEdges[patch][edge]=true;
2139 locator[edge].build (pPatch, edge, bindInfo[edge]);
2141 else
2143 if (listZone[zone]==_ZoneToLight)
2145 // oversample this edge
2146 _OversampleEdges[patch][edge]=true;
2151 // This is the zone to light ?
2152 if (listZone[zone]==_ZoneToLight)
2154 // *** Resize lumel array for this patch
2156 // Get patch order
2157 uint orderS=pPatch->getOrderS();
2158 uint orderT=pPatch->getOrderT();
2160 // Number of lumels
2161 uint lumelCount = orderS*orderT*16;
2163 // Resize the lumel descriptor
2164 CLumelDescriptor descriptor;
2165 descriptor.Normal.set (0,0,0);
2166 descriptor.Position.set (0,0,0);
2167 descriptor.S=0;
2168 descriptor.T=0;
2169 _Lumels[patch].resize (lumelCount, descriptor);
2170 visited[patch].resize (lumelCount, 0);
2171 // _LumelCorners[patch].resize (lumelCornerCount);
2174 // *** Unexclude this patch
2176 // Exclude all the patches from refine all
2177 landscape.excludePatchFromRefineAll (listZone[zone], patch, false);
2179 else
2181 // Exclude all the patches from refine all
2182 landscape.excludePatchFromRefineAll (listZone[zone], patch, true);
2187 // *** Now tesselate this zone to shadow casters accuracy
2189 // Setup the landscape
2190 landscape.setThreshold (0);
2191 landscape.setTileMaxSubdivision (0);
2193 // Refine all
2194 progress ("Refine landscape to shadow accuracy", 0.5f);
2195 landscape.refineAll (CVector (0, 0, 0));
2197 // Get tesselated faces
2198 std::vector<const CTessFace*> leaves;
2199 landscape.getTessellationLeaves(leaves);
2204 if (_WaterShapes.size() != 0) // any water shape in this zone ?
2206 /// make a quad grid of each water shape
2207 makeQuadGridFromWaterShapes(landscape.getZone(_ZoneToLight)->getZoneBB().getAABBox());
2209 /// check for each tile if it is above / below water
2210 computeTileFlagsForPositionTowardWater(lightDesc, leaves);
2212 else
2214 setTileFlagsToDefault(leaves);
2218 // Id of this zone in the array
2219 uint zoneNumber=_ZoneId[_ZoneToLight];
2221 // Scan each leaves
2222 uint leavesCount=(uint)leaves.size();
2223 uint leave;
2224 for (leave=0; leave<leavesCount; leave++)
2226 // Progress bar
2227 if ( (leave&0xff) == 0)
2228 progress ("Precompute lumel position", (float)leave/(float)leavesCount);
2230 // Leave
2231 const CTessFace *face=leaves[leave];
2233 // Get zone id
2234 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
2236 // Get a patch pointer
2237 const CPatch* pPatch=face->Patch;
2239 // Get order
2240 uint orderS=pPatch->getOrderS();
2241 uint orderT=pPatch->getOrderT();
2243 // *** Base Coordinates
2245 CVector pos[15];
2246 pos[0]=face->VBase->EndPos; // p0
2247 pos[1]=face->VRight->EndPos;
2248 pos[2]=face->VLeft->EndPos; // p2
2249 pos[3]=(pos[1]+pos[2])/2;
2250 pos[4]=(pos[0]+pos[1])/2; // p4
2251 pos[5]=(pos[0]+pos[2])/2;
2252 pos[6]=(pos[0]+pos[3])/2; // p6
2253 pos[7]=(pos[2]+pos[3])/2;
2254 pos[8]=(pos[1]+pos[3])/2; // p8
2255 pos[9]=(pos[0]+pos[4])/2;
2256 pos[10]=(pos[1]+pos[4])/2; // p10
2257 pos[11]=(pos[0]+pos[5])/2;
2258 pos[12]=(pos[2]+pos[5])/2; // p12
2259 pos[13]=(pos[3]+pos[5])/2;
2260 pos[14]=(pos[3]+pos[4])/2; // p14
2262 float s0=face->PVBase.getS();
2263 float s1=face->PVRight.getS();
2264 float s2=face->PVLeft.getS();
2265 float s3=(s1+s2)/2;
2266 float s4=(s0+s1)/2;
2267 float s5=(s0+s2)/2;
2268 float s6=(s4+s5)/2;
2269 float s7=(s2+s3)/2;
2270 float s8=(s1+s3)/2;
2272 float t0=face->PVBase.getT();
2273 float t1=face->PVRight.getT();
2274 float t2=face->PVLeft.getT();
2275 float t3=(t1+t2)/2;
2276 float t4=(t0+t1)/2;
2277 float t5=(t0+t2)/2;
2278 float t6=(t4+t5)/2;
2279 float t7=(t2+t3)/2;
2280 float t8=(t1+t3)/2;
2282 // *** Interpolated value
2283 CVector interpolatedP[10]=
2285 (pos[0]+pos[6])/2,
2286 (pos[4]+pos[6])/2,
2287 (pos[4]+pos[8])/2,
2288 (pos[1]+pos[8])/2,
2289 (pos[5]+pos[6])/2,
2290 (pos[3]+pos[6])/2,
2291 (pos[3]+pos[8])/2,
2292 (pos[5]+pos[7])/2,
2293 (pos[3]+pos[7])/2,
2294 (pos[2]+pos[7])/2,
2297 // Does the border are snapped ?
2298 uint sBase = (uint)floor ((float)orderS * face->PVBase.getS() + 0.5);
2299 uint tBase = (uint)floor ((float)orderT * face->PVBase.getT() + 0.5);
2300 uint sLeft = (uint)floor ((float)orderS * face->PVLeft.getS() + 0.5);
2301 uint tLeft = (uint)floor ((float)orderT * face->PVLeft.getT() + 0.5);
2302 uint sRight = (uint)floor ((float)orderS * face->PVRight.getS() + 0.5);
2303 uint tRight = (uint)floor ((float)orderT * face->PVRight.getT() + 0.5);
2304 bool snapedLeft[2]=
2306 (sBase == 0) && (sRight == 0),
2307 (sBase == 0) && (sLeft == 0),
2309 bool snapedRight[2]=
2311 (sBase == orderS) && (sRight == orderS),
2312 (sBase == orderS) && (sLeft == orderS),
2314 bool snapedTop[2]=
2316 (tBase == 0) && (tRight == 0),
2317 (tBase == 0) && (tLeft == 0),
2319 bool snapedBottom[2]=
2321 (tBase == orderT) && (tRight == orderT),
2322 (tBase == orderT) && (tLeft == orderT),
2324 bool snapedBorder[2]=
2326 snapedLeft[0]||snapedRight[0]||snapedTop[0]||snapedBottom[0],
2327 snapedLeft[1]||snapedRight[1]||snapedTop[1]||snapedBottom[1],
2330 bool snapedCorner[3]=
2332 ((sBase == 0) && ((tBase == 0) || (tBase == orderT))) ||
2333 ((sBase == orderS) && ((tBase == 0) || (tBase == orderT))),
2334 ((sRight == 0) && ((tRight == 0) || (tRight == orderT))) ||
2335 ((sRight == orderS) && ((tRight == 0) || (tRight == orderT))),
2336 ((sLeft == 0) && ((tLeft == 0) || (tLeft == orderT))) ||
2337 ((sLeft == orderS) && ((tLeft == 0) || (tLeft == orderT))),
2340 // Snap on the border
2341 uint i;
2342 for (i=0; i<8; i++)
2344 // Snaped on left ?
2345 if (snapedBorder[VertexThanCanBeSnappedOnABorder[i][1]])
2347 // Compute the border vertex
2348 interpolatedP[VertexThanCanBeSnappedOnABorder[i][0]] = (pos[VertexThanCanBeSnappedOnABorder[i][2]]
2349 + pos[VertexThanCanBeSnappedOnABorder[i][3]])/2;
2353 // Snap on the corner
2354 for (i=0; i<3; i++)
2356 // Snaped on a corner ?
2357 uint tesselCornerIndex = VertexThanCanBeSnappedOnACorner[i][1];
2358 if ( snapedCorner[tesselCornerIndex] )
2360 // Compute the border vertex
2361 interpolatedP[VertexThanCanBeSnappedOnACorner[i][0]] = pos[tesselCornerIndex];
2365 float interpolatedS[10]=
2367 (s0+s6)/2,
2368 (s4+s6)/2,
2369 (s4+s8)/2,
2370 (s1+s8)/2,
2371 (s5+s6)/2,
2372 (s3+s6)/2,
2373 (s3+s8)/2,
2374 (s5+s7)/2,
2375 (s3+s7)/2,
2376 (s2+s7)/2,
2379 float interpolatedT[10]=
2381 (t0+t6)/2,
2382 (t4+t6)/2,
2383 (t4+t8)/2,
2384 (t1+t8)/2,
2385 (t5+t6)/2,
2386 (t3+t6)/2,
2387 (t3+t8)/2,
2388 (t5+t7)/2,
2389 (t3+t7)/2,
2390 (t2+t7)/2,
2393 for (i=0; i<10; i++)
2395 sint s=(sint)((float)orderS*4*interpolatedS[i]);
2396 sint t=(sint)((float)orderT*4*interpolatedT[i]);
2398 if ((s>=0)&&(s<(sint)orderS*4)&&(t>=0)&&(t<(sint)orderT*4))
2400 // Triangle index
2401 uint index=s+t*orderS*4;
2403 // Ge tthe patch id
2404 uint patchId=pPatch->getPatchId();
2406 // Get lumel array
2407 vector<CLumelDescriptor> &lumels=_Lumels[patchId];
2409 // Visited
2410 visited[patchId][index]++;
2412 // Position
2413 lumels[index].Position+=interpolatedP[i];
2419 // *** Now, finalise patch information for shadow source positions
2421 // For each patches
2422 uint patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
2423 uint patch;
2424 for (patch=0; patch<patchCount; patch++)
2426 // Info
2427 progress ("Finalize lumel positions", (float)patch/(float)patchCount);
2429 // *** Resize lumel array for this patch
2431 // Get a patch pointer
2432 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(_ZoneToLight)))->getPatch (patch);
2433 uint orderS=pPatch->getOrderS();
2434 uint orderT=pPatch->getOrderT();
2436 // Get lumel array
2437 vector<CLumelDescriptor> &lumels=_Lumels[patch];
2439 // *** Average position
2441 // Renormalize
2442 nlassert (isPowerOf2 (orderS));
2443 nlassert (isPowerOf2 (orderT));
2444 uint lumelS=4<<getPowerOf2 (orderS);
2445 uint lumelT=4<<getPowerOf2 (orderT);
2447 for (uint t=0; t<lumelT; t++)
2448 for (uint s=0; s<lumelS; s++)
2450 // Lumel index
2451 uint lumelIndex=s+t*lumelS;
2453 // *** Number of visit
2454 uint visitedCount=visited[patch][lumelIndex];
2456 // If visited, renormalise other values
2457 if (visitedCount)
2459 // Normalise position
2460 lumels[lumelIndex].Position/=(float)visitedCount;
2463 // Not visited for next pass
2464 visited[patch][lumelIndex]=false;
2468 // *** Now tesselate this zone to shadow receivers accuracy
2470 // Setup the landscape
2471 landscape.setThreshold (0);
2472 landscape.setTileMaxSubdivision (4);
2474 // Refine all
2475 progress ("Refine landscape to lumels", 0.5f);
2476 landscape.refineAll (CVector (0, 0, 0));
2478 // Get tesselated faces
2479 leaves.clear ();
2480 landscape.getTessellationLeaves(leaves);
2482 // Scan each leaves
2483 leavesCount=(uint)leaves.size();
2484 for (leave=0; leave<leavesCount; leave++)
2486 // Progress bar
2487 if ( (leave&0xff) == 0)
2488 progress ("Precompute tesselation", (float)leave/(float)leavesCount);
2490 // Leave
2491 const CTessFace *face=leaves[leave];
2493 // Get zone id
2494 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
2496 // Get a patch pointer
2497 const CPatch* pPatch=face->Patch;
2499 // Get order
2500 uint orderS=pPatch->getOrderS();
2501 uint orderT=pPatch->getOrderT();
2503 // Coordinates
2504 float fS=(face->PVBase.getS()+face->PVLeft.getS()+face->PVRight.getS())/3.f;
2505 float fT=(face->PVBase.getT()+face->PVLeft.getT()+face->PVRight.getT())/3.f;
2506 uint s=(uint)((float)orderS*4*fS);
2507 uint t=(uint)((float)orderT*4*fT);
2508 //nlassert (s>=0);
2509 nlassert (s<orderS*4);
2510 //nlassert (t>=0);
2511 nlassert (t<orderT*4);
2513 // Triangle index
2514 uint index=s+t*orderS*4;
2516 // Ge tthe patch id
2517 uint patchId=pPatch->getPatchId();
2519 // Get lumel array
2520 vector<CLumelDescriptor> &lumels=_Lumels[patchId];
2522 // Visited
2523 visited[patchId][index]++;
2525 // Lumel s and t
2526 lumels[index].S+=fS;
2527 lumels[index].T+=fT;
2529 // Normal
2530 CPlane plane;
2531 plane.make (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos);
2532 lumels[index].Normal+=plane.getNormal();
2536 // *** Now, finalise patch information
2538 // For each patches
2539 patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
2540 for (patch=0; patch<patchCount; patch++)
2542 // Info
2543 progress ("Finalize patches", (float)patch/(float)patchCount);
2545 // *** Resize lumel array for this patch
2547 // Get a patch pointer
2548 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(_ZoneToLight)))->getPatch (patch);
2549 uint orderS=pPatch->getOrderS();
2550 uint orderT=pPatch->getOrderT();
2552 // Get lumel array
2553 vector<CLumelDescriptor> &lumels=_Lumels[patch];
2555 // *** Compute an interpolated normal
2557 // Get pointer on arries
2558 vector<bool> &binded=_Binded[zoneNumber][patch];
2559 vector<CPatchUVLocator> &locator=_Locator[zoneNumber][patch];
2560 vector<CPatch::CBindInfo> &bindInfo=_BindInfo[zoneNumber][patch];
2561 CBezierPatch &bezierPatch=_BezierPatch[zoneNumber][patch];
2563 // Renormalize
2564 nlassert (isPowerOf2 (orderS));
2565 nlassert (isPowerOf2 (orderT));
2566 uint powerS=getPowerOf2 (orderS);
2567 uint powerT=getPowerOf2 (orderT);
2568 uint lumelS=4<<powerS;
2569 uint lumelT=4<<powerT;
2571 // Sample edge normal
2572 CVector normals[NL_MAX_TILES_BY_PATCH_EDGE*NL_LUMEL_BY_TILE+1][4];
2573 uint sFixed[4] = { 0, 0xffffffff, lumelS-1, 0xffffffff };
2574 uint tFixed[4] = { 0xffffffff, lumelT-1, 0xffffffff, 0 };
2575 float sOri[4] = { 0, -1, (float)lumelS, -1 };
2576 float tOri[4] = { -1, (float)lumelT, -1, 0 };
2577 for (uint edge=0; edge<4; edge++)
2579 // s and t
2580 uint count=(edge&1)?lumelS:lumelT;
2581 for (uint lumel=0; lumel<=count; lumel++)
2583 // Start coordinates
2584 float origineS;
2585 float origineT;
2586 uint startS;
2587 uint startT;
2588 if (edge&1)
2590 if (lumel==count)
2591 startS=count-1;
2592 else
2593 startS=lumel;
2594 startT=tFixed[edge];
2595 origineS=(float)lumel;
2596 origineT=tOri[edge];
2598 else
2600 if (lumel==count)
2601 startT=count-1;
2602 else
2603 startT=lumel;
2604 startS=sFixed[edge];
2605 origineT=(float)lumel;
2606 origineS=sOri[edge];
2608 _GetNormalNormal=CVector::Null;
2609 set<uint64> visitedLumels;
2610 getNormal (pPatch, startS, startT, locator, bindInfo, binded, visitedLumels,
2611 startS+0.5f-origineS, startT+0.5f-origineT, 0, bezierPatch);
2612 _GetNormalNormal.normalize ();
2613 normals[lumel][edge]=_GetNormalNormal;
2616 // Smooth the corners
2617 #define BLUR_SIZE 4
2618 for (uint i=1; i<BLUR_SIZE; i++)
2620 float value=(float)i/BLUR_SIZE;
2621 value=easineasout(value);
2622 normals[i][edge]=normals[0][edge]*(1-value)+normals[i][edge]*value;
2623 normals[i][edge].normalize();
2624 normals[count-i][edge]=normals[count][edge]*(1-value)+normals[count-i][edge]*value;
2625 normals[count-i][edge].normalize();
2629 for (uint t=0; t<lumelT; t++)
2630 for (uint s=0; s<lumelS; s++)
2632 // Lumel index
2633 uint lumelIndex=s+t*lumelS;
2635 // *** Calc the smoothed normal
2637 // For each edge
2638 CVector normalS=bezierPatch.evalNormal (((float)s+0.5f)/(float)lumelS, ((float)t+0.5f)/(float)lumelT);
2639 float sFactor=0;
2640 CVector normalT=normalS;
2641 float tFactor=0;
2642 bool sGood=false, tGood=false;
2643 if (s<BLUR_SIZE)
2645 sGood=true;
2646 // Average the two normals
2647 CVector average=normals[t][0];
2648 average+=normals[t+1][0];
2649 average/=2;
2651 // Blend
2652 float value=s+0.5f;
2653 sFactor=BLUR_SIZE-value;
2654 value/=BLUR_SIZE;
2655 value=easineasout(value);
2656 normalS=(normalS*value+average*(1-value));
2657 normalS.normalize();
2659 if (s>=lumelS-BLUR_SIZE)
2661 sGood=true;
2662 // Average the two normals
2663 CVector average=normals[t][2];
2664 average+=normals[t+1][2];
2665 average/=2;
2667 // Blend
2668 float value=s+0.5f;
2669 sFactor=BLUR_SIZE-(lumelS-value);
2670 value=(lumelS-value)/BLUR_SIZE;
2671 value=easineasout(value);
2672 normalS=(normalS*value+average*(1-value));
2673 normalS.normalize();
2675 if (t<BLUR_SIZE)
2677 tGood=true;
2678 // Average the two normals
2679 CVector average=normals[s][3];
2680 average+=normals[s+1][3];
2681 average/=2;
2683 // Blend
2684 float value=t+0.5f;
2685 tFactor=BLUR_SIZE-value;
2686 value/=BLUR_SIZE;
2687 value=easineasout(value);
2688 normalT=(normalT*value+average*(1-value));
2689 normalT.normalize();
2691 if (t>=lumelT-BLUR_SIZE)
2693 tGood=true;
2694 // Average the two normals
2695 CVector average=normals[s][1];
2696 average+=normals[s+1][1];
2697 average/=2;
2699 // Blend
2700 float value=t+0.5f;
2701 tFactor=BLUR_SIZE-(lumelT-value);
2702 value=((lumelT)-value)/BLUR_SIZE;
2703 value=easineasout(value);
2704 normalT=(normalT*value+average*(1-value));
2705 normalT.normalize();
2708 // The smooth normal
2709 CVector smoothNormal;
2711 if ((sGood)&&(tGood))
2713 if ((sFactor!=BLUR_SIZE)||(tFactor!=BLUR_SIZE))
2714 smoothNormal=normalS*(BLUR_SIZE-tFactor)+normalT*(BLUR_SIZE-sFactor);
2715 else
2716 smoothNormal=normalS+normalT;
2718 else if (sGood)
2719 smoothNormal=normalS;
2720 else
2721 smoothNormal=normalT;
2723 // Normalize it
2724 smoothNormal.normalize();
2726 // The pure normal
2727 CVector purNormal=bezierPatch.evalNormal (((float)s+0.5f)/(float)lumelS, ((float)t+0.5f)/(float)lumelT);
2729 // Normalize the noisy normal
2730 lumels[lumelIndex].Normal.normalize();
2732 // Final normal
2733 lumels[lumelIndex].Normal=lumels[lumelIndex].Normal-purNormal+smoothNormal;
2734 lumels[lumelIndex].Normal.normalize ();
2736 // *** Number of visit
2737 uint visitedCount=visited[patch][lumelIndex];
2739 // Some lumel have not been found in tesselation
2740 //nlassert (visitedCount==2);
2742 // If visited, renormalise other values
2743 if (visitedCount)
2745 // Normalise position
2746 lumels[lumelIndex].S/=(float)visitedCount;
2747 lumels[lumelIndex].T/=(float)visitedCount;
2753 // ***************************************************************************
2754 void CZoneLighter::computeTileFlagsOnly (CLandscape &landscape, CZone& output, uint zoneToLight, const CLightDesc& description,
2755 std::vector<uint> &listZone)
2757 // Zone to light
2758 _ZoneToLight=zoneToLight;
2760 // Landscape
2761 _Landscape=&landscape;
2764 // Zone count
2765 uint zoneCount=(uint)listZone.size();
2767 // For each zone
2768 for (uint zone=0; zone<zoneCount; zone++)
2770 // Get num patches
2771 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
2773 // Insert zone id
2774 _ZoneId.insert (map<uint, uint>::value_type (listZone[zone], zone));
2776 // For each patch
2777 uint patch;
2778 for (patch=0; patch<patchCount; patch++)
2780 // Progress bar
2781 progress ("Scan all patches", (float)patch/(float)patchCount);
2783 // This is the zone to light ?
2784 if (listZone[zone]==_ZoneToLight)
2786 // unExclude all the patches from refine all
2787 landscape.excludePatchFromRefineAll (listZone[zone], patch, false);
2789 else
2791 // Exclude all the patches from refine all
2792 landscape.excludePatchFromRefineAll (listZone[zone], patch, true);
2797 // *** Now tesselate this zone to max accuracy
2799 // Setup the landscape
2800 landscape.setThreshold (0);
2801 landscape.setTileMaxSubdivision (0);
2803 // Refine all
2804 progress ("Refine landscape to maximum", 0.5f);
2805 landscape.refineAll (CVector (0, 0, 0));
2807 // Get tesselated faces
2808 std::vector<const CTessFace*> leaves;
2809 landscape.getTessellationLeaves(leaves);
2812 // compute only the water states
2813 if (_WaterShapes.size() != 0) // any water shape in this zone ?
2815 /// make a quad grid of each water shape
2816 makeQuadGridFromWaterShapes(landscape.getZone(_ZoneToLight)->getZoneBB().getAABBox());
2818 /// check for each tile if it is above / below water
2819 computeTileFlagsForPositionTowardWater(description, leaves);
2821 else
2823 setTileFlagsToDefault(leaves);
2826 /// verify that the zonew and the zonel (output) are compatible
2827 bool ok= true;
2828 CZone &zonew= *(landscape.getZone(zoneToLight));
2829 if(zonew.getNumPatchs() == output.getNumPatchs())
2831 // verify for each patch that the tile array are same
2832 for(uint i=0;i<(uint)zonew.getNumPatchs();i++)
2834 const CPatch &p0= *const_cast<const CZone&>(zonew).getPatch(i);
2835 const CPatch &p1= *const_cast<const CZone&>(output).getPatch(i);
2836 if( p0.getOrderS()!=p1.getOrderS() || p0.getOrderT()!=p1.getOrderT() )
2838 ok= false;
2839 break;
2843 else
2844 ok= false;
2846 // can't copy tile flags
2847 if(!ok)
2848 throw Exception("The input zonew, and output zonel are too different: not same patchs!!");
2850 /// copy the tiles flags from the zone to light to the output zone
2851 copyTileFlags(output, zonew);
2854 // ***************************************************************************
2856 CZoneLighter::CLightDesc::CLightDesc ()
2858 SunDirection.set (1, 1, -1);
2859 GridSize=512;
2860 GridCellSize=4;
2861 HeightfieldSize=200;
2862 HeightfieldCellSize=20;
2863 SkyContribution=true;
2864 SkyIntensity=0.25;
2866 ZBufferLandscapeSize = DEFAULT_ZBUFFER_LANDSCAPE_SIZE;
2867 ZBufferObjectSize = DEFAULT_ZBUFFER_OBJECT_SIZE;
2868 SoftShadowJitter = DEFAULT_JITTER;
2869 SunDistance = DEFAULT_SUN_DISTANCE;
2870 SunFOV = (float)DEFAULT_SUN_FOV;
2871 SunCenter = DEFAULT_SUN_CENTER;
2872 SunRadius = DEFAULT_SUN_RADIUS;
2873 SoftShadowSamplesSqrt = DEFAULT_SUN_SRQT_SAMPLES;
2876 // ***************************************************************************
2877 void CZoneLighter::addLightableShape(IShape *shape, const NLMISC::CMatrix& MT)
2879 CShapeInfo lsi;
2880 lsi.MT = MT;
2881 lsi.Shape = shape;
2882 _LightableShapes.push_back(lsi);
2886 // ***************************************************************************
2887 bool CZoneLighter::isLightableShape(IShape &shape)
2889 /// for now, the only shape that we lit are water shapes
2890 if (dynamic_cast<CWaterShape *>(&shape) != NULL)
2892 // check that this water surface has a diffuse map that is a CTextureFile (we must be able to save it !)
2893 CWaterShape *ws = static_cast<CWaterShape *>(&shape);
2894 const ITexture *tex = ws->getColorMap();
2895 if (dynamic_cast<const CTextureFile *>(tex) != NULL)
2897 return ws->isLightMappingEnabled();
2900 return false;
2903 // ***************************************************************************
2904 void CZoneLighter::lightShapes(uint zoneID, const CLightDesc& description)
2906 /// compute light for the lightable shapes in the given zone
2907 if (_LightableShapes.empty()) return;
2909 uint numShapePerThread = 1 + ((uint)_LightableShapes.size() / _ProcessCount);
2910 uint currShapeIndex = 0;
2911 uint process = 0;
2912 _ProcessExited = 0;
2914 _NumLightableShapesProcessed = 0;
2917 progress("Processing lightable shapes", 0);
2919 for (uint k = 0; k < _LightableShapes.size(); ++k, ++process)
2921 uint lastShapeIndex = currShapeIndex + numShapePerThread;
2922 lastShapeIndex = std::min((uint)_LightableShapes.size(), lastShapeIndex);
2923 IThread *pThread = IThread::create (new CCalcLightableShapeRunnable(process, this, &description, &_LightableShapes, currShapeIndex, lastShapeIndex));
2924 pThread->start();
2925 currShapeIndex = lastShapeIndex;
2928 /// wait for other process
2929 while (_ProcessExited != _ProcessCount)
2931 nlSleep (10);
2938 // ***************************************************************************
2940 void CZoneLighter::processLightableShapeCalc (uint process,
2941 TShapeVect *shapesToLit,
2942 uint firstShape,
2943 uint lastShape,
2944 const CLightDesc& description)
2946 // for each lightable shape
2947 for (uint k = firstShape; k < lastShape; ++k)
2949 nlassert(isLightableShape(* (*shapesToLit)[k].Shape)); // make sure it is a lightable shape
2950 lightSingleShape((*shapesToLit)[k], description, process);
2955 // ***************************************************************************
2956 void CZoneLighter::lightSingleShape(CShapeInfo &si, const CLightDesc& description, uint cpu)
2958 /// we compute the lighting for one single shape
2959 if (dynamic_cast<CWaterShape *>(si.Shape))
2961 lightWater(* static_cast<CWaterShape *>(si.Shape), si.MT, description, cpu);
2963 ++_NumLightableShapesProcessed;
2964 progress("Processing lightable shapes", (float) _NumLightableShapesProcessed / _LightableShapes.size());
2965 return;
2970 // ***************************************************************************
2971 // utility function to get the directory of a fileName
2972 static std::string getDir (const std::string& path)
2974 char tmpPath[512];
2975 strcpy (tmpPath, path.c_str());
2976 char* slash=strrchr (tmpPath, '/');
2977 if (!slash)
2979 slash=strrchr (tmpPath, '\\');
2982 if (!slash)
2983 return "";
2985 slash++;
2986 *slash=0;
2987 return tmpPath;
2991 // ***************************************************************************
2992 // utility function to get a file name fdrom a path
2993 static std::string getName (const std::string& path)
2995 std::string dir=getDir (path);
2997 char tmpPath[512];
2998 strcpy (tmpPath, path.c_str());
3000 char *name=tmpPath;
3001 nlassert (dir.length()<=strlen(tmpPath));
3002 name+=dir.length();
3004 char* point=strrchr (name, '.');
3005 if (point)
3006 *point=0;
3008 return name;
3012 // ***************************************************************************
3013 // utility function to get the extension of a fileName
3014 static std::string getExt (const std::string& path)
3016 std::string dir = getDir (path);
3017 std::string name = getName (path);
3019 char tmpPath[512];
3020 strcpy (tmpPath, path.c_str());
3022 char *ext=tmpPath;
3023 nlassert (dir.length()+name.length()<=strlen(tmpPath));
3024 ext+=dir.length()+name.length();
3026 return ext;
3030 // ***************************************************************************
3031 void CZoneLighter::lightWater(CWaterShape &ws, const CMatrix &MT, const CLightDesc& description, uint cpu)
3035 /// get the diffuse map
3036 CTextureFile *diffuseTex = NLMISC::safe_cast<CTextureFile *>(ws.getColorMap());
3037 std::string texFileName = CPath::lookup(diffuseTex->getFileName());
3038 diffuseTex->generate();
3039 const uint width = diffuseTex->getWidth();
3040 const uint height = diffuseTex->getHeight();
3042 /// build a matrix to convert from water space to uv space
3043 NLMISC::CMatrix worldSpaceToUVs;
3044 NLMISC::CVector2f col0, col1, pos;
3045 ws.getColorMapMat(col0, col1, pos);
3046 worldSpaceToUVs.setRot(NLMISC::CVector(col0.x * width, col0.y * height, 0),
3047 NLMISC::CVector(col1.x * width, col1.y * height, 0),
3048 NLMISC::CVector::K);
3049 worldSpaceToUVs.setPos(NLMISC::CVector(pos.x * width, pos.y * height, 0));
3051 /// get min and max uvs
3052 NLMISC::CPolygon p;
3053 ws.getShapeInWorldSpace(p);
3055 float minU, maxU;
3056 float minV, maxV;
3058 NLMISC::CVector uvs = worldSpaceToUVs * p.Vertices[0];
3059 minU = maxU = uvs.x;
3060 minV = maxV = uvs.y;
3063 for (uint k = 1; k < (uint) p.getNumVertices(); ++k)
3065 uvs = worldSpaceToUVs * p.Vertices[k];
3066 minU = std::min(uvs.x, minU);
3067 minV = std::min(uvs.y, minV);
3068 maxU = std::max(uvs.x, maxU);
3069 maxV = std::max(uvs.y, maxV);
3075 sint iMinU = (sint) minU;
3076 sint iMaxU = (sint) maxU;
3077 sint iMinV = (sint) minV;
3078 sint iMaxV = (sint) maxV;
3080 NLMISC::clamp(iMinU, 0, (sint) width);
3081 NLMISC::clamp(iMaxU, 0, (sint) width);
3082 NLMISC::clamp(iMinV, 0, (sint) height);
3083 NLMISC::clamp(iMaxV, 0, (sint) height);
3085 // matrix to go from uv space to worldspace
3086 NLMISC::CMatrix UVSpaceToWorldSpace = worldSpaceToUVs.inverted();
3088 CObjectVector<uint8> &pixs8 = diffuseTex->getPixels();
3089 NLMISC::CRGBA *rgbPixs = (NLMISC::CRGBA *) &pixs8[0];
3092 /// raytrace each texel
3093 for (sint x = iMinU; x < iMaxU; ++x)
3095 for (sint y = iMinV; y < iMaxV; ++y)
3097 float factor;
3098 NLMISC::CVector pos = UVSpaceToWorldSpace * NLMISC::CVector( x + 0.5f, y + 0.5f, 0 )
3099 + description.WaterShadowBias * NLMISC::CVector::K;
3100 if (description.Shadow)
3102 factor = attenuation (pos, description);
3104 else
3106 factor = - NLMISC::CVector::K * description.SunDirection;
3108 clamp(factor, 0.f, 1.f);
3109 factor = factor * description.WaterDiffuse + description.WaterAmbient;
3110 if (description.SkyContributionForWater)
3112 factor += getSkyContribution(pos, NLMISC::CVector::K, description.SkyIntensity);
3114 clamp(factor, 0.f, 1.f);
3115 uint intensity = (uint8) (255 * factor);
3116 NLMISC::CRGBA srcCol(intensity,
3117 intensity,
3118 intensity,
3119 255);
3121 if (!description.ModulateWaterColor)
3123 rgbPixs[x + y * width] = srcCol;
3125 else
3127 NLMISC::CRGBA &col = rgbPixs[x + y * width];
3128 col.modulateFromColor(col, srcCol);
3133 /// now, save the result
3134 if (getExt(texFileName) != ".tga")
3136 nlwarning("Zone lighter : error when lighting a water surface : input bitmap is not a tga file");
3138 else
3142 COFile of;
3143 of.open(texFileName);
3144 diffuseTex->writeTGA(of, 24);
3145 of.close();
3147 catch (const NLMISC::Exception &)
3149 nlwarning("Zone lighter : while lighting a water shape, writing %s failed! ", texFileName.c_str());
3153 catch(const NLMISC::Exception &e)
3155 nlwarning("Water shape lighting failed !");
3156 nlwarning(e.what());
3160 // ***********************************************************
3161 void CZoneLighter::addWaterShape(CWaterShape *shape, const NLMISC::CMatrix &MT)
3163 /// make sure it hasn't been inserted twice
3164 CShapeInfo ci;
3165 ci.Shape = shape;
3166 ci.MT = MT;
3167 _WaterShapes.push_back(ci);
3170 // ***********************************************************
3171 void CZoneLighter::makeQuadGridFromWaterShapes(NLMISC::CAABBox zoneBBox)
3173 if (_WaterShapes.empty()) return;
3175 NLMISC::CAABBox tmpBox;
3177 /// the number of cells we want in the quad grid
3178 const uint numCells = 16;
3180 /// get the dimension
3181 float width = zoneBBox.getMax().x - zoneBBox.getMin().x;
3182 float height = zoneBBox.getMax().y - zoneBBox.getMin().y;
3184 float dim = std::max(width, height);
3187 /// init the quad grid
3188 _WaterShapeQuadGrid.create(numCells, dim / numCells);
3191 uint count = 0, totalCount = (uint)_WaterShapes.size();
3193 /// now, insert all water shapes
3194 for (TShapeVect::iterator it = _WaterShapes.begin(); it != _WaterShapes.end(); ++it, ++count)
3196 /// get the current shape bbox in the world
3197 it->Shape->getAABBox(tmpBox);
3198 NLMISC::CAABBox currBB = NLMISC::CAABBox::transformAABBox(it->MT, tmpBox);
3200 /// test if it intesect the zone bbox
3201 if (zoneBBox.intersect(currBB))
3203 _WaterShapeQuadGrid.insert(currBB.getMin(), currBB.getMax(), *it);
3205 progress("Building quadtree from water surfaces", (float) count / totalCount);
3208 /// free the vector of water shapes
3209 NLMISC::contReset(_WaterShapes);
3213 //==================================================================
3215 /// a struct that helps us to know which tile we've processed
3216 struct CTileOfPatch
3218 uint8 TileId;
3219 CPatch *Patch;
3220 CTileOfPatch();
3221 CTileOfPatch(uint8 tileId, CPatch *patch) : TileId(tileId), Patch(patch)
3228 // ***************************************************************************
3229 // ***************************************************************************
3230 // Static point lights.
3231 // ***************************************************************************
3232 // ***************************************************************************
3235 // ***************************************************************************
3236 CZoneLighter::CPointLightRT::CPointLightRT()
3238 RefCount= 0;
3242 // ***************************************************************************
3243 bool CZoneLighter::CPointLightRT::testRaytrace(const CVector &v)
3245 CVector dummy;
3247 if(!BSphere.include(v))
3248 return false;
3250 // If Ambient light, just skip
3251 if(PointLight.getType()== CPointLight::AmbientLight)
3252 return false;
3254 // If SpotLight verify in angle radius.
3255 if(PointLight.getType()== CPointLight::SpotLight)
3257 float att= PointLight.computeLinearAttenuation(v);
3258 if (att==0)
3259 return false;
3262 // Select in the cubeGrid
3263 FaceCubeGrid.select(v);
3264 // For all faces selected
3265 while(!FaceCubeGrid.isEndSel())
3267 const CTriangle *tri= FaceCubeGrid.getSel();
3269 // If intersect, the point is occluded.
3270 if( tri->Triangle.intersect(BSphere.Center, v, dummy, tri->getPlane()) )
3271 return false;
3273 // next
3274 FaceCubeGrid.nextSel();
3277 // Ok the point is visilbe from the light
3278 return true;
3282 // ***************************************************************************
3283 void CZoneLighter::addStaticPointLight(const CPointLightNamed &pln)
3285 // build the plRT.
3286 CPointLightRT plRT;
3287 plRT.PointLight= pln;
3288 // compute plRT.OODeltaAttenuation
3289 plRT.OODeltaAttenuation= pln.getAttenuationEnd() - pln.getAttenuationBegin();
3290 if(plRT.OODeltaAttenuation <=0 )
3291 plRT.OODeltaAttenuation= 0;
3292 else
3293 plRT.OODeltaAttenuation= 1.0f / plRT.OODeltaAttenuation;
3294 // compute plRT.BSphere
3295 plRT.BSphere.Center= pln.getPosition();
3296 plRT.BSphere.Radius= pln.getAttenuationEnd();
3297 // NB: FaceCubeGrid will be computed during light()
3299 // add the plRT
3300 _StaticPointLights.push_back(plRT);
3305 // ***************************************************************************
3306 void CZoneLighter::compilePointLightRT(uint gridSize, float gridCellSize, std::vector<CTriangle>& obstacles, bool doShadow)
3308 uint i;
3310 // Fill the quadGrid of Lights.
3311 // ===========
3312 _StaticPointLightQuadGrid.create(gridSize, gridCellSize);
3313 for(i=0; i<_StaticPointLights.size();i++)
3315 CPointLightRT &plRT= _StaticPointLights[i];
3317 // Compute the bbox of the light
3318 CAABBox bbox;
3319 bbox.setCenter(plRT.BSphere.Center);
3320 float hl= plRT.BSphere.Radius;
3321 bbox.setHalfSize(CVector(hl,hl,hl));
3323 // Insert the pointLight in the quadGrid.
3324 _StaticPointLightQuadGrid.insert(bbox.getMin(), bbox.getMax(), &plRT);
3328 // Append triangles to cubeGrid ??
3329 if(doShadow)
3331 // Point lights ?
3332 if (!_StaticPointLights.empty ())
3334 // For all obstacles, Fill a quadGrid.
3335 // ===========
3336 CQuadGrid<CTriangle*> obstacleGrid;
3337 obstacleGrid.create(gridSize, gridCellSize);
3338 uint size= (uint)obstacles.size();
3339 for(i=0; i<size; i++)
3341 // bbox of triangle
3342 CAABBox bbox;
3343 bbox.setCenter(obstacles[i].Triangle.V0);
3344 bbox.extend(obstacles[i].Triangle.V1);
3345 bbox.extend(obstacles[i].Triangle.V2);
3346 // insert triangle in quadGrid.
3347 obstacleGrid.insert(bbox.getMin(), bbox.getMax(), &obstacles[i]);
3351 // For all PointLights, fill his CubeGrid
3352 // ===========
3353 for(i=0; i<_StaticPointLights.size();i++)
3355 // progress
3356 progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
3358 CPointLightRT &plRT= _StaticPointLights[i];
3359 // Create the cubeGrid
3360 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE);
3362 // AmbiantLIghts: do nothing.
3363 if(plRT.PointLight.getType()!=CPointLight::AmbientLight)
3365 // Select only obstacle Faces around the light. Other are not useful
3366 CAABBox bbox;
3367 bbox.setCenter(plRT.PointLight.getPosition());
3368 float hl= plRT.PointLight.getAttenuationEnd();
3369 bbox.setHalfSize(CVector(hl,hl,hl));
3370 obstacleGrid.select(bbox.getMin(), bbox.getMax());
3372 // For all faces, fill the cubeGrid.
3373 CQuadGrid<CTriangle*>::CIterator itObstacle;
3374 itObstacle= obstacleGrid.begin();
3375 while( itObstacle!=obstacleGrid.end() )
3377 CTriangle &tri= *(*itObstacle);
3379 // Triangle bounding box
3380 CAABBox triBbox;
3381 triBbox.setCenter (tri.Triangle.V0);
3382 triBbox.extend (tri.Triangle.V1);
3383 triBbox.extend (tri.Triangle.V2);
3385 // Triangle in the light
3386 if (triBbox.intersect (bbox))
3388 // Test BackFace culling. Only faces which are BackFace the point light are inserted.
3389 // This is to avoid AutoOccluding problems
3390 if( tri.getPlane() * plRT.BSphere.Center < 0)
3392 // Insert the triangle in the CubeGrid
3393 plRT.FaceCubeGrid.insert( tri.Triangle, &tri);
3397 itObstacle++;
3401 // Compile the CubeGrid.
3402 plRT.FaceCubeGrid.compile();
3404 // And Reset RefCount.
3405 plRT.RefCount= 0;
3409 // else, just build empty grid
3410 else
3412 for(i=0; i<_StaticPointLights.size();i++)
3414 // progress
3415 progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
3417 CPointLightRT &plRT= _StaticPointLights[i];
3418 // Create a dummy empty cubeGrid => no rayTrace :)
3419 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), 4);
3421 // Compile the CubeGrid.
3422 plRT.FaceCubeGrid.compile();
3424 // And Reset RefCount.
3425 plRT.RefCount= 0;
3432 // ***************************************************************************
3433 bool CZoneLighter::CPredPointLightToPoint::operator() (CPointLightRT *pla, CPointLightRT *plb) const
3435 float ra= (pla->BSphere.Center - Point).norm();
3436 float rb= (plb->BSphere.Center - Point).norm();
3437 float infA= (pla->PointLight.getAttenuationEnd() - ra) * pla->OODeltaAttenuation;
3438 float infB= (plb->PointLight.getAttenuationEnd() - rb) * plb->OODeltaAttenuation;
3439 // return which light impact the most.
3440 // If same impact
3441 if(infA==infB)
3442 // return nearest
3443 return ra < rb;
3444 else
3445 // return better impact
3446 return infA > infB;
3449 // ***************************************************************************
3450 void CZoneLighter::processZonePointLightRT(vector<CPointLightNamed> &listPointLight)
3452 uint i;
3453 vector<CPointLightRT*> lightInfs;
3454 lightInfs.reserve(1024);
3456 // clear result list
3457 listPointLight.clear();
3459 // zoneToLight
3460 CZone *zoneToLight= _Landscape->getZone(_ZoneToLight);
3461 if(!zoneToLight)
3462 return;
3464 // Build patchForPLs
3465 //===========
3466 vector<CPatchForPL> patchForPLs;
3467 patchForPLs.resize(_PatchInfo.size());
3468 for(i=0; i<patchForPLs.size(); i++)
3470 // Get OrderS/OrderT
3471 patchForPLs[i].OrderS= _PatchInfo[i].OrderS;
3472 patchForPLs[i].OrderT= _PatchInfo[i].OrderT;
3473 // resize TileLightInfluences
3474 uint w= patchForPLs[i].WidthTLI= patchForPLs[i].OrderS/2 +1 ;
3475 uint h= patchForPLs[i].HeightTLI= patchForPLs[i].OrderT/2 +1;
3476 patchForPLs[i].TileLightInfluences.resize(w*h);
3480 // compute each TileLightInfluence
3481 //===========
3482 for(i=0; i<patchForPLs.size(); i++)
3484 // progress
3485 progress ("Compute Influences of PointLights", 0.5f + 0.5f*i / (float)patchForPLs.size());
3487 CPatchForPL &pfpl= patchForPLs[i];
3488 const CPatch *patch= const_cast<const CZone*>(zoneToLight)->getPatch(i);
3490 uint x, y;
3491 for(y= 0; y<pfpl.HeightTLI; y++)
3493 for(x= 0; x<pfpl.WidthTLI; x++)
3495 // compute the point and normal (normalized) where the TLI lies.
3496 //---------
3497 CVector pos, normal;
3498 float s, t;
3499 s= (float)x / (pfpl.WidthTLI-1);
3500 t= (float)y / (pfpl.HeightTLI-1);
3501 // Compute the Vertex, with Noise information (important for accurate raytracing).
3502 pos= patch->computeVertex(s, t);
3503 // Use UnNoised normal from BezierPatch, because the lighting does not need to be so precise.
3504 CBezierPatch *bp= patch->unpackIntoCache();
3505 normal= bp->evalNormal(s, t);
3508 // Compute Which light influences him.
3509 //---------
3510 lightInfs.clear();
3511 // Search possible lights around the position.
3512 _StaticPointLightQuadGrid.select(pos, pos);
3513 // For all of them, get the ones which touch this point.
3514 CQuadGrid<CPointLightRT*>::CIterator it= _StaticPointLightQuadGrid.begin();
3515 while(it != _StaticPointLightQuadGrid.end())
3517 CPointLightRT *pl= *it;
3519 // a light influence a TLI only if this one is FrontFaced to the light !!
3520 if( ( pl->BSphere.Center - pos ) * normal > 0)
3522 // Add 5cm else it fails in some case where ( pl->BSphere.Center - pos ) * normal is
3523 // nearly 0 and the point should be occluded.
3524 const float deltaY= 0.05f;
3525 CVector posToRT= pos + normal * deltaY;
3526 // Test if really in the radius of the light, if no occlusion, and if in SpotAngle
3527 if( pl->testRaytrace(posToRT) )
3529 // Ok, add the light to the lights which influence the TLI
3530 lightInfs.push_back(pl);
3534 // next
3535 it++;
3538 // Choose the Best ones.
3539 //---------
3540 CPredPointLightToPoint predPLTP;
3541 predPLTP.Point= pos;
3542 // sort.
3543 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
3544 // truncate.
3545 lightInfs.resize( min((uint)lightInfs.size(), (uint)CTileLightInfluence::NumLightPerCorner) );
3548 // For each of them, fill TLI
3549 //---------
3550 CTileLightInfUnpack tli;
3551 uint lightInfId;
3552 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
3554 CPointLightRT *pl= lightInfs[lightInfId];
3556 // copy light.
3557 tli.Light[lightInfId]= pl;
3558 // Compute light Diffuse factor.
3559 CVector dir= pl->BSphere.Center - pos;
3560 dir.normalize();
3561 tli.LightFactor[lightInfId]= dir * normal;
3562 clamp(tli.LightFactor[lightInfId], 0.f, 1.f);
3563 // modulate by light attenuation.
3564 tli.LightFactor[lightInfId]*= pl->PointLight.computeLinearAttenuation(pos);
3566 // Inc RefCount of the light.
3567 pl->RefCount++;
3569 // Reset any empty slot to NULL.
3570 for(; lightInfId<CTileLightInfluence::NumLightPerCorner; lightInfId++)
3572 tli.Light[lightInfId]= NULL;
3576 // Set TLI in patch.
3577 //---------
3578 pfpl.TileLightInfluences[y*pfpl.WidthTLI + x]= tli;
3584 // compress and setup _PatchInfo with compressed data.
3585 //===========
3586 uint plId= 0;
3587 // Process each pointLights
3588 for(i=0; i<_StaticPointLights.size(); i++)
3590 CPointLightRT &plRT= _StaticPointLights[i];
3591 // If this light is used.
3592 if(plRT.RefCount > 0)
3594 // Must Copy it into Zone.
3595 listPointLight.push_back(plRT.PointLight);
3596 plRT.DstId= plId++;
3597 // If index >= 255, too many lights (NB: => because 255 is a NULL code).
3598 if(plId>=0xFF)
3600 throw Exception("Too many Static Point Lights influence the zone!!");
3605 // For each patch, compress TLI in PatchInfo.
3606 for(i=0; i<patchForPLs.size(); i++)
3608 CPatchForPL &pfpl= patchForPLs[i];
3609 CPatchInfo &pInfo= _PatchInfo[i];
3611 uint w= pfpl.WidthTLI;
3612 uint h= pfpl.HeightTLI;
3614 // Fill pInfo.TileLightInfluences
3615 pInfo.TileLightInfluences.resize(w*h);
3616 uint x, y;
3617 for(y= 0; y<h; y++)
3619 for(x= 0; x<w; x++)
3621 uint tliId= y*w + x;
3622 // For all light slot
3623 for(uint lightId= 0; lightId<CTileLightInfluence::NumLightPerCorner; lightId++)
3625 CTileLightInfUnpack &tliSrc= pfpl.TileLightInfluences[tliId];
3626 CTileLightInfluence &tliDst= pInfo.TileLightInfluences[tliId];
3627 if(tliSrc.Light[lightId] == NULL)
3629 // Mark as unused.
3630 tliDst.Light[lightId]= 0xFF;
3632 else
3634 // Get index.
3635 tliDst.Light[lightId]= tliSrc.Light[lightId]->DstId;
3636 // Get Diffuse Factor.
3637 tliDst.setDiffuseLightFactor(lightId, (uint8)(tliSrc.LightFactor[lightId]*255));
3647 // ***********************************************************
3648 // ***********************************************************
3649 // TileFlagsForPositionTowardWater
3650 // ***********************************************************
3651 // ***********************************************************
3654 //==================================================================
3655 /// for map insertion of CTileOfPatch structs
3656 static inline bool operator < (const CTileOfPatch &lhs, const CTileOfPatch &rhs)
3658 return lhs.Patch == rhs.Patch ?
3659 lhs.TileId < rhs.TileId :
3660 lhs.Patch < rhs.Patch;
3663 /// A set of tiles from patch and their bbox
3664 typedef std::map<CTileOfPatch, NLMISC::CAABBox> TTileOfPatchMap;
3666 // ***********************************************************
3667 void CZoneLighter::computeTileFlagsForPositionTowardWater(const CLightDesc &lightDesc,
3668 std::vector<const CTessFace*> &tessFaces
3671 uint numTileAbove = 0;
3672 uint numTileBelow = 0;
3673 uint numTileIntersect = 0;
3675 /// the tiles that we have setupped so far...
3676 TTileOfPatchMap tiles;
3678 ///////////////////////////////////////////
3679 // First, build the bbox for all tiles //
3680 ///////////////////////////////////////////
3682 uint triCount = 0, totalTriCount = (uint)tessFaces.size();
3684 nlinfo("Dealing with %d tessFaces", tessFaces.size());
3685 for (std::vector<const CTessFace*>::iterator it = tessFaces.begin(); it != tessFaces.end(); ++it, ++triCount)
3687 /// does the face belong to the zone to light ?
3688 if ((*it)->Patch->getZone()->getZoneId() != _ZoneToLight) continue;
3689 /// if the tile flags say that micro vegetation is disabled, just skip that
3690 if ((*it)->Patch->Tiles[(*it)->TileId].getVegetableState() == CTileElement::VegetableDisabled)
3691 continue;
3693 CTileOfPatch top((*it)->TileId, (*it)->Patch);
3694 TTileOfPatchMap::iterator tileIt = tiles.find(top);
3696 /// test whether we've seen face(s) from this tile before
3697 if (tileIt == tiles.end()) // first time ?
3699 /// build a bbox for this face
3700 NLMISC::CAABBox b;
3701 b.setMinMax((*it)->VBase->EndPos, (*it)->VLeft->EndPos);
3702 b.extend((*it)->VRight->EndPos);
3703 b.extend(b.getMax() + lightDesc.VegetableHeight * NLMISC::CVector::K); // adds vegetable height
3704 tiles[top] = b;
3706 else // extends the bbox with the given face
3708 NLMISC::CAABBox &b = tileIt->second;
3709 b.extend((*it)->VBase->EndPos);
3710 b.extend((*it)->VRight->EndPos);
3711 b.extend((*it)->VLeft->EndPos);
3714 if ((triCount % 100) == 0)
3716 progress("Building bbox from tiles", (float) triCount / totalTriCount);
3720 progress("Building bbox from tiles", 1.f);
3724 ////////////////////////////////////////////////////
3725 // Now, check each tile bbox against water shapes //
3726 ////////////////////////////////////////////////////
3727 NLMISC::CPolygon waterPoly;
3728 NLMISC::CPolygon2D tilePoly;
3729 tilePoly.Vertices.resize(4);
3731 uint tileCount = 0, totalTileCount = (uint)tiles.size();
3733 for (TTileOfPatchMap::iterator tileIt = tiles.begin(); tileIt != tiles.end(); ++tileIt, ++tileCount)
3735 const NLMISC::CVector v0 = tileIt->second.getMin();
3736 const NLMISC::CVector v1 = tileIt->second.getMax();
3738 /// build a top view from the bbox
3739 tilePoly.Vertices[0].set(v0.x, v0.y);
3740 tilePoly.Vertices[1].set(v1.x, v0.y);
3741 tilePoly.Vertices[2].set(v1.x, v1.y);
3742 tilePoly.Vertices[3].set(v0.x, v1.y);
3744 /// Select the candidate water shape from the quad grid
3745 _WaterShapeQuadGrid.clearSelection();
3746 _WaterShapeQuadGrid.select(tileIt->second.getMin(), tileIt->second.getMax());
3748 CTileElement &te = tileIt->first.Patch->Tiles[tileIt->first.TileId]; // alias to the current tile element
3750 /// test more accurate intersection for each water shape
3751 TWaterShapeQuadGrid::CIterator qgIt;
3752 for (qgIt = _WaterShapeQuadGrid.begin(); qgIt != _WaterShapeQuadGrid.end(); ++qgIt)
3754 CWaterShape *waterShape= safe_cast<CWaterShape*>((*qgIt).Shape);
3755 waterShape->getShapeInWorldSpace(waterPoly, (*qgIt).MT);
3756 NLMISC::CPolygon2D poly(waterPoly);
3757 if (poly.intersect(tilePoly)) // above or below a water surface ?
3759 /// height of water
3760 float waterHeight = waterPoly.Vertices[0].z;
3762 if (v1.z < waterHeight)
3764 // below
3765 te.setVegetableState(CTileElement::UnderWater);
3766 //nlassert(te.getVegetableState() == CTileElement::UnderWater);
3767 ++ numTileBelow;
3769 else if (v0. z > waterHeight)
3771 // above
3772 te.setVegetableState(CTileElement::AboveWater);
3773 //nlassert(te.getVegetableState() == CTileElement::AboveWater);
3774 ++ numTileAbove;
3776 else
3778 // intersect water
3779 te.setVegetableState(CTileElement::IntersectWater);
3780 //nlassert(te.getVegetableState() == CTileElement::IntersectWater);
3781 ++ numTileIntersect;
3783 break;
3787 if (qgIt == _WaterShapeQuadGrid.end()) // no intersection found ? if yes it's above water
3789 te.setVegetableState(CTileElement::AboveWater);
3790 //nlassert(te.getVegetableState() == CTileElement::AboveWater);
3791 ++ numTileAbove;
3794 if ((tileCount % 50) == 0)
3796 progress("Computing tile position towards water", (float) tileCount / totalTileCount);
3800 progress("Computing tile position towards water", 1.f);
3802 nlinfo(" %d tiles are above water.", numTileAbove);
3803 nlinfo(" %d tiles are below water.", numTileBelow);
3804 nlinfo(" %d tiles intersect water.", numTileIntersect);
3808 /// delete the quadgrid now
3809 NLMISC::contReset(_WaterShapeQuadGrid);
3812 // ***********************************************************
3814 void CZoneLighter::setTileFlagsToDefault(std::vector<const CTessFace*> &tessFaces)
3816 /// We may setup a tile several time, but this doesn't matter here...
3817 for (std::vector<const CTessFace*>::iterator it = tessFaces.begin(); it != tessFaces.end(); ++it)
3819 if ((*it)->Patch->getZone()->getZoneId() != _ZoneToLight) continue;
3820 CTileElement &te = (*it)->Patch->Tiles[(*it)->TileId];
3821 if (te.getVegetableState() != CTileElement::VegetableDisabled)
3823 te.setVegetableState(CTileElement::AboveWater);
3828 // ***********************************************************
3830 uint CZoneLighter::getAPatch (uint process)
3832 // Accessor
3833 CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
3835 // Current index
3836 uint index = _LastPatchComputed[process];
3837 uint firstIndex = index;
3839 nlassert(index < _PatchInfo.size());
3841 if (access.value().empty())
3842 // no more patches
3843 return 0xffffffff;
3845 while (access.value()[index])
3847 // Next patch
3848 index++;
3850 // Last patch ?
3851 if (index == _PatchInfo.size())
3852 index = 0;
3854 // First ?
3855 if (firstIndex == index)
3856 // no more patches
3857 return 0xffffffff;
3860 // Visited
3861 access.value()[index] = true;
3863 // Last index
3864 _LastPatchComputed[process] = index;
3865 _NumberOfPatchComputed++;
3867 // Return the index
3868 return index;
3871 // ***********************************************************
3873 float CZoneLighter::attenuation (const CVector &pos, const CZoneLighter::CLightDesc &description)
3875 // Clipped ?
3877 // *** Landscape attenuation
3879 // Current value
3880 float averageAttenuation = 0;
3881 float randomSum = 0;
3883 // For each sample
3884 uint sample;
3885 const uint samples = description.SoftShadowSamplesSqrt*description.SoftShadowSamplesSqrt;
3886 for (sample=0; sample<samples; sample++)
3888 // The zbuffer
3889 CZBuffer &zbuffer = _ZBufferLandscape[sample];
3891 // Get position in z buffer
3892 CVector zPos;
3893 transformVectorToZBuffer (zbuffer, pos, zPos);
3895 // Get the z
3896 float random = (float)_Random.rand () * description.SoftShadowJitter + _Random.RandMax * (1.f - description.SoftShadowJitter);
3897 averageAttenuation += random * testZPercentageCloserFilter (zPos.x-(float)zbuffer.LocalZBufferXMin, zPos.y-(float)zbuffer.LocalZBufferYMin, zPos.z, zbuffer, description, _ZBufferOverflow);
3898 randomSum += random;
3901 // Average landscape attenuation
3902 averageAttenuation /= randomSum;
3906 // *** Attenuation in the object zbuffer
3908 // Get position in z buffer
3909 CVector zPos;
3910 transformVectorToZBuffer (_ZBufferObject, pos, zPos);
3912 const float objectAttenuation = testZPercentageCloserFilter (zPos.x-(float)_ZBufferObject.LocalZBufferXMin, zPos.y-(float)_ZBufferObject.LocalZBufferYMin, zPos.z, _ZBufferObject, description, _ZBufferOverflow);
3915 // *** Return the min of the both
3916 return std::min (objectAttenuation, averageAttenuation);
3919 // ***********************************************************