From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- docs/doxygen/nel/zone__lighter_8cpp-source.html | 3428 +++++++++++++++++++++++ 1 file changed, 3428 insertions(+) create mode 100644 docs/doxygen/nel/zone__lighter_8cpp-source.html (limited to 'docs/doxygen/nel/zone__lighter_8cpp-source.html') diff --git a/docs/doxygen/nel/zone__lighter_8cpp-source.html b/docs/doxygen/nel/zone__lighter_8cpp-source.html new file mode 100644 index 00000000..bded90d6 --- /dev/null +++ b/docs/doxygen/nel/zone__lighter_8cpp-source.html @@ -0,0 +1,3428 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

zone_lighter.cpp

Go to the documentation of this file.
00001 
+00007 /* Copyright, 2000 Nevrax Ltd.
+00008  *
+00009  * This file is part of NEVRAX NEL.
+00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00011  * it under the terms of the GNU General Public License as published by
+00012  * the Free Software Foundation; either version 2, or (at your option)
+00013  * any later version.
+00014 
+00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00018  * General Public License for more details.
+00019 
+00020  * You should have received a copy of the GNU General Public License
+00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00023  * MA 02111-1307, USA.
+00024  */
+00025 
+00026 #include "std3d.h"
+00027 
+00028 #include "3d/zone_lighter.h"
+00029 #include "3d/landscape.h"
+00030 #include "3d/patchuv_locator.h"
+00031 #include "3d/shape.h"
+00032 #include "3d/mesh.h"
+00033 #include "3d/mesh_multi_lod.h"
+00034 #include "3d/mesh_mrm.h"
+00035 #include "3d/transform_shape.h"
+00036 #include "3d/water_shape.h"
+00037 #include "3d/texture_file.h"
+00038 
+00039 
+00040 
+00041 
+00042 
+00043 #include "nel/misc/common.h"
+00044 #include "nel/misc/thread.h"
+00045 #include "nel/misc/path.h"
+00046 #include "nel/misc/file.h"
+00047 #include "nel/misc/aabbox.h"
+00048 
+00049 
+00050 // Define this to use hardware soft shadows
+00051 //#define HARDWARE_SOFT_SHADOWS
+00052 
+00053 #ifdef HARDWARE_SOFT_SHADOWS
+00054 
+00055 #include "nel/3d/u_driver.h"
+00056 
+00057 #endif // HARDWARE_SOFT_SHADOWS
+00058 
+00059 
+00060 #ifdef NL_OS_WINDOWS
+00061 #  define WIN32_LEAN_AND_MEAN
+00062 #  include "windows.h"
+00063 #  include "winbase.h"
+00064 #  ifdef min
+00065 #    undef min
+00066 #  endif
+00067 #  ifdef max
+00068 #    undef max
+00069 #  endif
+00070 #endif // NL_OS_WINDOWS
+00071 
+00072 using namespace NLMISC;
+00073 using namespace NL3D;
+00074 using namespace std;
+00075 
+00076 #ifdef HARDWARE_SOFT_SHADOWS
+00077 
+00078 UDriver *drv=NULL;
+00079 
+00080 #define LIGHT_BUFFER_SIZE 16
+00081 
+00082 #endif // HARDWARE_SOFT_SHADOWS
+00083         
+00084 
+00085 // Bad coded: don't set too big else it allocates too much memory.
+00086 #define NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE 16
+00087 
+00088 
+00089 // ***************************************************************************
+00090 
+00091 
+00092 CZoneLighter::CZoneLighter () : _PatchComputed ("PatchComputed"), _TriangleListAllocateur(100000)
+00093 {
+00094         
+00095 }
+00096         
+00097 // ***************************************************************************
+00098 
+00099 void CZoneLighter::init ()
+00100 {
+00101         // Precalc some values
+00102         for (uint i=0; i<8; i++)
+00103         {
+00104                 // Precalc sinP and cosP
+00105                 float sinP=(float)(sin((Pi/4)*(i+0.5))-sin((Pi/4)*(i-0.5)));
+00106                 float cosP=(float)(cos((Pi/4)*(i-0.5))-cos((Pi/4)*(i+0.5)));
+00107 
+00108                 for (uint phi=0; phi<256; phi++)
+00109                 {
+00110                         // Real phi
+00111                         float fPhi=(float)((Pi/2)*phi/256.0);
+00112 
+00113                         // Tmp result
+00114                         float tmp0=(float)(fPhi-sin(2*fPhi)/2);
+00115                         float tmp1=(float)sin(fPhi);
+00116 
+00117                         // Calc K
+00118                         _K[phi][i].set (tmp0*sinP, tmp0*cosP, (float)((Pi/4)*tmp1*tmp1));
+00119                 }
+00120         }
+00121 
+00122 #ifdef HARDWARE_SOFT_SHADOWS
+00123         if (!drv)
+00124         {
+00125                 // Mode
+00126                 UDriver::CMode mode (LIGHT_BUFFER_SIZE, LIGHT_BUFFER_SIZE, 32, true);
+00127                 drv=UDriver::createDriver ();
+00128                 drv->setDisplay (mode);
+00129                 drv->setMatrixMode2D11 ();
+00130         }
+00131 #endif // HARDWARE_SOFT_SHADOWS
+00132 }
+00133 
+00134 // ***************************************************************************
+00135 
+00136 // N - NW - W - SW - S - SE - E - NE
+00137 static const sint deltaDirection[8][2]=
+00138 {
+00139         {1, 0},
+00140         {1, 1},
+00141         {0, 1},
+00142         {-1, 1},
+00143         {-1, 0},
+00144         {-1, -1},
+00145         {0, -1},
+00146         {1, -1},
+00147 };
+00148 
+00149 // ***************************************************************************
+00150 
+00151 float CZoneLighter::calcSkyContribution (sint s, sint t, float height, float skyIntensity, const CVector& normal) const
+00152 {
+00153         // Sky contribution
+00154         float skyContribution;
+00155 
+00156         // Calc k
+00157         CVector k (0, 0, 0);
+00158 
+00159         // For the height direction
+00160         for (uint i=0; i<8; i++)
+00161         {
+00162                 // Get phi for this point
+00163                 uint8 phi=getMaxPhi (s, t, deltaDirection[i][0], deltaDirection[i][1], height);
+00164 
+00165                 // Add to k
+00166                 k+=_K[phi][i];
+00167         }
+00168 
+00169         // Finalize sky contribution
+00170         skyContribution=(float)(skyIntensity*(normal*k)/(2*Pi));
+00171         clamp (skyContribution, 0.f, 1.f);
+00172         return skyContribution;
+00173 }
+00174 
+00175 // ***************************************************************************
+00176 
+00177 void NEL3DCalcBase (CVector &direction, CMatrix& matrix)
+00178 {
+00179         direction.normalize();
+00180         CVector         I=(fabs(direction*CVector(1.f,0,0))>0.99)?CVector(0.f,1.f,0.f):CVector(1.f,0.f,0.f);
+00181         CVector         K=-direction;
+00182         CVector         J=K^I;
+00183         J.normalize();
+00184         I=J^K;
+00185         I.normalize();
+00186         matrix.identity();
+00187         matrix.setRot(I,J,K, true);
+00188 }
+00189 
+00190 // ***************************************************************************
+00191 
+00192 class NL3D::CCalcRunnable : public IRunnable
+00193 {
+00194         // Members
+00195         uint                    _Process;
+00196         CZoneLighter    *_ZoneLighter;
+00197         const CZoneLighter::CLightDesc  *_Description;
+00198 
+00199 public:
+00200         IThread                 *Thread;
+00201 
+00202 public:
+00203         // Ctor
+00204         CCalcRunnable (uint process, CZoneLighter *zoneLighter, const CZoneLighter::CLightDesc *description)
+00205         {
+00206                 _ZoneLighter = zoneLighter;
+00207                 _Process = process;
+00208                 _Description = description;
+00209         }
+00210 
+00211         // Run method
+00212         void run()
+00213         {
+00214                 // Set the processor mask
+00215                 uint64 mask = IProcess::getCurrentProcess()->getCPUMask ();
+00216 
+00217                 // Mask must not be NULL
+00218                 nlassert (mask != 0);
+00219 
+00220                 if (mask != 0)
+00221                 {
+00222                         uint i=0;
+00223                         uint count = 0;
+00224                         while (1)
+00225                         {
+00226                                 if (mask & (1<<i))
+00227                                 {
+00228                                         if (count == _Process)
+00229                                                 break;
+00230                                         count++;
+00231                                 }
+00232                                 i++;
+00233                                 if (i==64)
+00234                                         i = 0;
+00235                         }
+00236                         
+00237                         // Set the CPU mask
+00238                         Thread->setCPUMask (1<<i);
+00239                 }
+00240 
+00241                 _ZoneLighter->processCalc (_Process, *_Description);
+00242                 _ZoneLighter->_ProcessExited++;
+00243         }
+00244 };
+00245 
+00246 
+00247 // ***************************************************************************
+00248 class NL3D::CCalcLightableShapeRunnable : public IRunnable
+00249 {
+00250 public:
+00251         CCalcLightableShapeRunnable(uint process,
+00252                                                                 CZoneLighter *zoneLighter,
+00253                                                                 const CZoneLighter::CLightDesc *description,
+00254                                                                 CZoneLighter::TShapeVect *shapeToLit,
+00255                                                                 uint firstShape,
+00256                                                                 uint lastShape
+00257                                                                 )
+00258                 : 
+00259                   _ZoneLighter(zoneLighter), 
+00260                   _Description(description),
+00261                   _ShapesToLit(shapeToLit),
+00262                   _FirstShape(firstShape),
+00263                   _LastShape(lastShape),
+00264                   _Process(process)
+00265         {
+00266         }
+00267         void run()
+00268         {
+00269                 _ZoneLighter->processLightableShapeCalc(_Process, _ShapesToLit, _FirstShape, _LastShape, *_Description);
+00270                 _ZoneLighter->_ProcessExited++;
+00271         }
+00272 private:
+00273         CZoneLighter                                            *_ZoneLighter;
+00274         const CZoneLighter::CLightDesc          *_Description;
+00275         CZoneLighter::TShapeVect        *_ShapesToLit;
+00276         uint                                                            _FirstShape, _LastShape;
+00277         uint                                                            _Process;
+00278 
+00279 };
+00280 
+00281 // ***************************************************************************
+00282 
+00283 void CZoneLighter::light (CLandscape &landscape, CZone& output, uint zoneToLight, const CLightDesc& description, std::vector<CTriangle>& obstacles, vector<uint> &listZone)
+00284 {
+00285         /*
+00286          * Lighting algorithm
+00287          * ------------------
+00288          *
+00289          * - Create a quad grid to store shadow casting triangles
+00290          * - Create a heightfield used for global illumination. Cells are initialized with -FLT_MAX
+00291          * - Insert each shadow casting triangles in the quad grid and fill the heightfield's cells overlapped by the bounding box of the triangle with
+00292          * the max height of the triangle if its height is > than the current height in the heightfield's cell.
+00293          * - 
+00294          */
+00295 
+00296         // Backup thread mask
+00297         IThread *currentThread = IThread::getCurrentThread ();
+00298         uint64 threadMask = currentThread->getCPUMask();
+00299         currentThread->setCPUMask (1);
+00300 
+00301         // Calc the ray basis
+00302         _LightDirection=description.LightDirection;
+00303         NEL3DCalcBase (_LightDirection, _RayBasis);
+00304 
+00305         // Zone to light
+00306         _ZoneToLight=zoneToLight;
+00307 
+00308         // Landscape 
+00309         _Landscape=&landscape;
+00310 
+00311         // Process count
+00312         _ProcessCount=description.NumCPU;
+00313         if (_ProcessCount==0)
+00314         {
+00315                 // Create a doomy thread
+00316                 IProcess *pProcess=IProcess::getCurrentProcess ();
+00317                 _CPUMask = pProcess->getCPUMask();
+00318                 _ProcessCount = 0;
+00319                 uint64 i;
+00320                 for (i=0; i<64; i++)
+00321                 {
+00322                         if (_CPUMask&((uint64)1<<i))
+00323                                 _ProcessCount++;
+00324                 }
+00325         }
+00326         if (_ProcessCount>MAX_CPU_PROCESS)
+00327                 _ProcessCount=MAX_CPU_PROCESS;
+00328 
+00329         // Number of CPUS used
+00330         printf ("Number of CPU used: %d\n", _ProcessCount);
+00331 
+00332         // Fallof distance
+00333         _FallofDistance=description.SoftshadowFallof;
+00334 
+00335         // Shadow bias
+00336         _ShadowBias=description.ShadowBias;
+00337 
+00338         // Resize the shape array
+00339         _Shape.NumVertex=description.SoftshadowShapeVertexCount;
+00340 
+00341         // Softshadow ?
+00342         _Softshadow=description.Softshadow;
+00343 
+00344         // Radius of the shape
+00345         _ShapeRadius=description.SoftshadowBlurSize;
+00346         _RayAdd=_RayBasis.getI();
+00347         _RayAdd+=_RayBasis.getJ();
+00348         _RayAdd.normalize();
+00349         _RayAdd*=1.5f*_ShapeRadius;
+00350         
+00351         // Build the shape
+00352         uint i;
+00353         for (i=0; i<_Shape.NumVertex; i++)
+00354         {
+00355                 // Shape is a smapled circle
+00356                 float angle=(float)((float)i*2*Pi/_Shape.NumVertex);
+00357                 _Shape.Vertices[i]=_RayBasis*CVector (_ShapeRadius*(float)cos (angle), _ShapeRadius*(float)sin (angle), 0);
+00358         }
+00359 
+00360         // Calculate the area of the shape
+00361         _ShapeArea=0;
+00362         for (i=0; i<_Shape.NumVertex; i++)
+00363         {
+00364                 // Sum area of each triangle
+00365                 _ShapeArea+=(_Shape.Vertices[i]^_Shape.Vertices[(i+1)%_Shape.NumVertex]).norm();
+00366         }
+00367 
+00368         // Zone pointer
+00369         CZone *pZone=landscape.getZone (_ZoneToLight);
+00370         if (pZone)
+00371         {
+00372                 // Change the quadGrid basis
+00373                 CMatrix invRayBasis=_RayBasis;
+00374                 invRayBasis.invert ();
+00375 
+00376                 uint cpu;
+00377                 for (cpu=0; cpu<_ProcessCount; cpu++)
+00378                 {
+00379                         _QuadGrid[cpu].changeBase (invRayBasis);
+00380 
+00381                         // Init the quadGrid
+00382                         _QuadGrid[cpu].create (description.GridSize, description.GridCellSize);
+00383                 }
+00384                 
+00385                 // Init the heightfield
+00386                 _HeightfieldCellSize=description.HeightfieldCellSize;
+00387                 _HeightFieldCellCount=(sint)(description.HeightfieldSize/_HeightfieldCellSize);
+00388                 nlassert (_HeightFieldCellCount!=0);
+00389                 const CAABBoxExt &zoneBB=pZone->getZoneBB();
+00390                 _OrigineHeightField=zoneBB.getCenter ()-CVector (description.HeightfieldSize/2, description.HeightfieldSize/2, 0);
+00391                 _HeightField.resize (_HeightFieldCellCount*_HeightFieldCellCount, -FLT_MAX);
+00392 
+00393                 // Fill the quadGrid and the heightField
+00394                 uint size=obstacles.size();
+00395                 for (uint triangleId=0; triangleId<size; triangleId++)
+00396                 {
+00397                         // Progress bar
+00398                         if ( (triangleId&0xff) == 0)
+00399                                 progress ("Build quadtree and heightfield", (float)triangleId/(float)size);
+00400 
+00401                         // Triangle ref
+00402                         CZoneLighter::CTriangle& triangle=obstacles[triangleId];
+00403 
+00404                         // Calc the plane
+00405                         triangle.Plane.make (triangle.Triangle.V0, triangle.Triangle.V1, triangle.Triangle.V2);
+00406 
+00407                         // Calc the clipping plane
+00408                         CVector edgeDirection[3];
+00409                         CVector point[3];
+00410                         point[0]=triangle.Triangle.V0;
+00411                         edgeDirection[0]=triangle.Triangle.V1-triangle.Triangle.V0;
+00412                         point[1]=triangle.Triangle.V1;
+00413                         edgeDirection[1]=triangle.Triangle.V2-triangle.Triangle.V1;
+00414                         point[2]=triangle.Triangle.V2;
+00415                         edgeDirection[2]=triangle.Triangle.V0-triangle.Triangle.V2;
+00416                         
+00417                         // Flip plane ?
+00418                         bool flip=((triangle.Plane.getNormal()*(-_LightDirection))<0);
+00419 
+00420                         // For each plane
+00421                         for (uint edge=0; edge<3; edge++)
+00422                         {
+00423                                 // Plane normal
+00424                                 edgeDirection[edge]=edgeDirection[edge]^(-_LightDirection);
+00425                                 edgeDirection[edge].normalize();
+00426                                 if (flip)
+00427                                         edgeDirection[edge]=-edgeDirection[edge];
+00428 
+00429                                 // Make a plane
+00430                                 triangle.ClippingPlanes[edge].make (edgeDirection[edge], point[edge]);
+00431                         }
+00432 
+00433                         // Look for the min coordinate, in the RayBasis
+00434                         CVector irbMinv;
+00435                         CVector         irbV0= invRayBasis * triangle.Triangle.V0;
+00436                         CVector         irbV1= invRayBasis * triangle.Triangle.V1;
+00437                         CVector         irbV2= invRayBasis * triangle.Triangle.V2;
+00438                         irbMinv.minof (irbV0, irbV1);
+00439                         irbMinv.minof (irbMinv, irbV2);
+00440 
+00441                         // Look for the max coordinate, in the RayBasis
+00442                         CVector irbMaxv;
+00443                         irbMaxv.maxof (irbV0, irbV1);
+00444                         irbMaxv.maxof (irbMaxv, irbV2);
+00445 
+00446                         // Insert in the quad grid
+00447                         for (cpu=0; cpu<_ProcessCount; cpu++)
+00448                                 // Set the coord in World Basis.
+00449                                 _QuadGrid[cpu].insert (_RayBasis * irbMinv, _RayBasis * irbMaxv, &triangle);
+00450 
+00451 
+00452                         // Look for the min coordinate, in World Basis
+00453                         CVector minv;
+00454                         minv.minof (triangle.Triangle.V0, triangle.Triangle.V1);
+00455                         minv.minof (minv, triangle.Triangle.V2);
+00456 
+00457                         // Look for the max coordinate, in World Basis
+00458                         CVector maxv;
+00459                         maxv.maxof (triangle.Triangle.V0, triangle.Triangle.V1);
+00460                         maxv.maxof (maxv, triangle.Triangle.V2);
+00461 
+00462 
+00463                         // Lanscape tri ?
+00464                         if (triangle.ZoneId!=0xffffffff)
+00465                         {
+00466                                 // Fill the heightfield
+00467                                 sint minX=std::max (0, (sint)floor (0.5f+(minv.x-_OrigineHeightField.x)/_HeightfieldCellSize));
+00468                                 sint maxX=std::min (_HeightFieldCellCount, (sint)floor (0.5f+(maxv.x-_OrigineHeightField.x)/_HeightfieldCellSize));
+00469                                 sint minY=std::max (0, (sint)floor (0.5f+(minv.y-_OrigineHeightField.y)/_HeightfieldCellSize));
+00470                                 sint maxY=std::min (_HeightFieldCellCount, (sint)floor (0.5f+(maxv.y-_OrigineHeightField.y)/_HeightfieldCellSize));
+00471 
+00472                                 // Calc position in the heightfield
+00473                                 for (sint y=minY; y<maxY; y++)
+00474                                 for (sint x=minX; x<maxX; x++)
+00475                                 {
+00476                                         // Valid position, try to insert it
+00477                                         if (maxv.z>_HeightField[x+y*_HeightFieldCellCount])
+00478                                         {
+00479                                                 // New height in this cell
+00480                                                 _HeightField[x+y*_HeightFieldCellCount]=maxv.z;
+00481                                         }
+00482                                 }
+00483                         }
+00484                 }
+00485 
+00486                 // Retrieve the zone to fill its shaded value
+00487                 pZone->retrieve (_PatchInfo, _BorderVertices);
+00488 
+00489                 // Number of patch
+00490                 uint patchCount=_PatchInfo.size();
+00491 
+00492                 // Bit array to know if the lumel is shadowed
+00493                 if (description.Shadow)
+00494                         _ShadowArray.resize (patchCount);
+00495 
+00496                 // A lumel vector by patch
+00497                 vector<vector<CLumelDescriptor> > lumels;
+00498                 lumels.resize (patchCount);
+00499 
+00500                 // Build zone informations
+00501                 buildZoneInformation (landscape,
+00502                                                           listZone,
+00503                                                           description.Oversampling!=CLightDesc::NoOverSampling,
+00504                                                           description);
+00505 
+00506         }
+00507 
+00508         // Number of patch
+00509         uint patchCount=_PatchInfo.size();
+00510 
+00511         // Reset patch count
+00512         {
+00513                 CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
+00514                 access.value().resize (0);
+00515                 access.value().resize (patchCount, false);
+00516         }
+00517 
+00518         // Patch by thread
+00519         uint patchCountByThread = patchCount/_ProcessCount;
+00520         patchCountByThread++;
+00521 
+00522         // Patch to allocate
+00523         uint firstPatch=0;
+00524         _NumberOfPatchComputed = 0;
+00525 
+00526         _ProcessExited=0;
+00527 
+00528         // Set the thread state
+00529         _LastPatchComputed.resize (_ProcessCount);
+00530 
+00531         // Launch threads
+00532         for (uint process=1; process<_ProcessCount; process++)
+00533         {
+00534                 // Last patch
+00535                 uint lastPatch=firstPatch+patchCountByThread;
+00536                 if (lastPatch>patchCount)
+00537                         lastPatch=patchCount;
+00538 
+00539                 // Last patch computed
+00540                 _LastPatchComputed[process] = firstPatch;
+00541 
+00542                 // Create a thread
+00543                 CCalcRunnable *runnable = new CCalcRunnable (process, this, &description);
+00544                 IThread *pThread=IThread::create (runnable);
+00545                 runnable->Thread = pThread;
+00546                 
+00547                 // New first patch
+00548                 firstPatch=lastPatch;
+00549 
+00550                 // Launch
+00551                 pThread->start();
+00552         }
+00553 
+00554         // My thread
+00555         uint lastPatch=firstPatch+patchCountByThread;
+00556         if (lastPatch>patchCount)
+00557                 lastPatch=patchCount;
+00558         _LastPatchComputed[0] = firstPatch;
+00559         CCalcRunnable thread (0, this, &description);
+00560         thread.Thread = currentThread;
+00561         thread.run();
+00562 
+00563         // Wait for others processes
+00564         while (_ProcessExited!=_ProcessCount)
+00565         {
+00566                 nlSleep (10);
+00567         }
+00568 
+00569         // Reset old thread mask
+00570         currentThread->setCPUMask (threadMask);
+00571 
+00572         // Progress bar
+00573         progress ("Compute Influences of PointLights", 0.f);
+00574 
+00575         // Compute PointLight influences on zone.
+00576         // Some precalc.
+00577         compilePointLightRT(description.GridSize, description.GridCellSize, obstacles, 
+00578                 description.Shadow || description.Softshadow );
+00579         // Influence patchs and get light list of interest
+00580         std::vector<CPointLightNamed>   listPointLight;
+00581         processZonePointLightRT(listPointLight);
+00582 
+00583 
+00584         // Rebuild the zone
+00585 
+00586         // Progress bar
+00587         progress ("Compress the lightmap", 0.6f);
+00588 
+00589         // Build, with list of lights.
+00590         CZoneInfo       zinfo;
+00591         zinfo.ZoneId= _ZoneToLight;
+00592         zinfo.Patchs= _PatchInfo;
+00593         zinfo.BorderVertices= _BorderVertices;
+00594         zinfo.PointLights= listPointLight;
+00595         output.build (zinfo);
+00596 
+00598         copyTileFlags(output, *(landscape.getZone(zoneToLight)));
+00599 
+00601         lightShapes(zoneToLight, description);
+00602 }
+00603 
+00604 
+00605 // *************************************************************************************
+00606 void CZoneLighter::copyTileFlags(CZone &destZone, const CZone &srcZone)
+00607 {
+00608         nlassert(destZone.getZoneId() == srcZone.getZoneId());
+00609         for (sint k = 0; k < srcZone.getNumPatchs(); ++k)
+00610         {
+00611                 destZone.copyTilesFlags(k, srcZone.getPatch(k));
+00612         }
+00613 }
+00614 
+00615 // ***************************************************************************
+00616 float CZoneLighter::getSkyContribution(const CVector &pos, const CVector &normal, float skyIntensity) const
+00617 {       
+00618         float s=(pos.x-_OrigineHeightField.x)/_HeightfieldCellSize;
+00619         float t=(pos.y-_OrigineHeightField.y)/_HeightfieldCellSize;
+00620         sint sInt=(sint)(floor (s+0.5f));
+00621         sint tInt=(sint)(floor (t+0.5f));
+00622 
+00623         // Bilinear
+00624         float skyContributionTab[2][2];
+00625         skyContributionTab[0][0] = calcSkyContribution (sInt-1, tInt-1, pos.z, skyIntensity, normal);
+00626         skyContributionTab[1][0] = calcSkyContribution (sInt, tInt-1, pos.z, skyIntensity, normal);
+00627         skyContributionTab[1][1] = calcSkyContribution (sInt, tInt, pos.z, skyIntensity, normal);
+00628         skyContributionTab[0][1] = calcSkyContribution (sInt-1, tInt, pos.z, skyIntensity, normal);
+00629         
+00630         float sFact=s+0.5f-sInt;
+00631         float tFact=t+0.5f-tInt;
+00632         return (skyContributionTab[0][0]*(1.f-sFact) + skyContributionTab[1][0]*sFact)*(1.f-tFact) +
+00633                 (skyContributionTab[0][1]*(1.f-sFact) + skyContributionTab[1][1]*sFact)*tFact;  
+00634 }
+00635 
+00636 
+00637 // ***************************************************************************
+00638 void CZoneLighter::processCalc (uint process, const CLightDesc& description)
+00639 {
+00640         // *** Raytrace each patches
+00641 
+00642         // Pointer on the zone
+00643         CZone *pZone=_Landscape->getZone (_ZoneToLight);
+00644 
+00645         // Get a patch
+00646         uint patch = getAPatch (process);
+00647         while (patch != 0xffffffff)
+00648         {
+00649                 // For each patch
+00650                 if (description.Shadow)
+00651                 {
+00652                         // Shape array
+00653                         CMultiShape *shapeArray=new CMultiShape;
+00654                         CMultiShape *shapeArrayTmp=new CMultiShape;
+00655                         shapeArray->Shapes.reserve (SHAPE_MAX);
+00656                         shapeArrayTmp->Shapes.reserve (SHAPE_MAX);
+00657 
+00658                         // Lumels
+00659                         std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
+00660                 
+00661                         // Lumel count
+00662                         uint lumelCount=lumels.size();
+00663                         CPatchInfo &patchInfo=_PatchInfo[patch];
+00664                         nlassert (patchInfo.Lumels.size()==lumelCount);
+00665 
+00666                         // Resize shadow array
+00667                         _ShadowArray[patch].resize (lumelCount);
+00668 
+00669                         // For each lumel
+00670                         for (uint lumel=0; lumel<lumelCount; lumel++)
+00671                         {
+00672                                 float factor=0;
+00673                                 rayTrace (lumels[lumel].Position, lumels[lumel].Normal, lumels[lumel].S, lumels[lumel].T, patch, factor, *shapeArray, *shapeArrayTmp, process);
+00674                                 patchInfo.Lumels[lumel]=(uint)(factor*255);
+00675                         }
+00676                         delete shapeArray;
+00677                         delete shapeArrayTmp;
+00678                 }
+00679                 else
+00680                 {
+00681                         // Lumels
+00682                         std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
+00683                 
+00684                         // Lumel count
+00685                         uint lumelCount=lumels.size();
+00686                         CPatchInfo &patchInfo=_PatchInfo[patch];
+00687                         nlassert (patchInfo.Lumels.size()==lumelCount);
+00688 
+00689                         // For each lumel
+00690                         for (uint lumel=0; lumel<lumelCount; lumel++)
+00691                         {
+00692                                 // Not shadowed
+00693                                 patchInfo.Lumels[lumel]=255;
+00694                         }
+00695                 }
+00696 
+00697                 // *** Antialising
+00698                 
+00699                 // Id of this zone in the array
+00700                 uint zoneNumber=_ZoneId[_ZoneToLight];
+00701 
+00702                 // Enabled ?
+00703                 if ((description.Shadow)&&(description.Oversampling!=CLightDesc::NoOverSampling))
+00704                 {
+00705                         // Get a patch pointer
+00706                         const CPatch *pPatch=(const_cast<const CZone*>(pZone))->getPatch (patch);
+00707 
+00708                         // Get the patch info
+00709                         CPatchInfo &patchInfo=_PatchInfo[patch];
+00710 
+00711                         // Get order of the patch
+00712                         uint orderLumelS=pPatch->getOrderS()<<2;
+00713                         uint orderLumelT=pPatch->getOrderT()<<2;
+00714 
+00715                         // ** Pointer on arries
+00716                         vector<bool> &binded=_Binded[zoneNumber][patch];
+00717                         vector<bool> &oversampleEdges=_OversampleEdges[patch];
+00718                         vector<CPatchUVLocator> &locator=_Locator[zoneNumber][patch];
+00719                         std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
+00720 
+00721                         // Shadow array
+00722                         vector<uint8> &shadowPatch=_ShadowArray[patch];
+00723 
+00724                         // Go for each lumel
+00725                         for (uint t=0; t<orderLumelT; t++)
+00726                         for (uint s=0; s<orderLumelS; s++)
+00727                         {
+00728                                 // Over sample this lumel
+00729                                 bool oversample=false;
+00730                                 uint8 shadowed=shadowPatch[s+t*orderLumelS];
+00731 
+00732                                 // Left..
+00733                                 if (s==0)
+00734                                 {
+00735                                         // Edge test
+00736                                         oversample=isLumelOnEdgeMustBeOversample (patch, 0, s, t, binded, oversampleEdges, locator, shadowed, _ShadowArray);
+00737                                 }
+00738                                 else
+00739                                 {
+00740                                         // Internal test
+00741                                         oversample=(shadowed!=shadowPatch[(s-1)+t*orderLumelS]);
+00742                                 }
+00743 
+00744                                 // Bottom..
+00745                                 if (!oversample)
+00746                                 {
+00747                                         if (t==(orderLumelT-1))
+00748                                         {
+00749                                                 // Edge test
+00750                                                 oversample=isLumelOnEdgeMustBeOversample (patch, 1, s, t, binded, oversampleEdges, locator, shadowed, _ShadowArray);
+00751                                         }
+00752                                         else
+00753                                         {
+00754                                                 // Internal test
+00755                                                 oversample=(shadowed!=shadowPatch[s+(t+1)*orderLumelS]);
+00756                                         }
+00757 
+00758                                         // Right..
+00759                                         if (!oversample)
+00760                                         {
+00761                                                 if (s==(orderLumelS-1))
+00762                                                 {
+00763                                                         // Edge test
+00764                                                         oversample=isLumelOnEdgeMustBeOversample (patch, 2, s, t, binded, oversampleEdges, locator, shadowed, _ShadowArray);
+00765                                                 }
+00766                                                 else
+00767                                                 {
+00768                                                         // Internal test
+00769                                                         oversample=(shadowed!=shadowPatch[(s+1)+t*orderLumelS]);
+00770                                                 }
+00771 
+00772                                                 // Top..
+00773                                                 if (!oversample)
+00774                                                 {
+00775                                                         if (t==0)
+00776                                                         {
+00777                                                                 // Edge test
+00778                                                                 oversample=isLumelOnEdgeMustBeOversample (patch, 3, s, t, binded, oversampleEdges, locator, shadowed, _ShadowArray);
+00779                                                         }
+00780                                                         else
+00781                                                         {
+00782                                                                 // Internal test
+00783                                                                 oversample=(shadowed!=shadowPatch[s+(t-1)*orderLumelS]);
+00784                                                         }
+00785                                                 }
+00786                                         }
+00787                                 }
+00788 
+00789                                 // Must oversample ?
+00790                                 if (oversample)
+00791                                 {
+00792                                         // LumelId
+00793                                         uint lumel=s+t*orderLumelS;
+00794 
+00795                                         // Lighting
+00796                                         float factor=0;
+00797 
+00798                                         // Number of ray clipped
+00799                                         uint tested=0;
+00800 
+00801                                         // For each triangle
+00802                                         CTriangleList *list=lumels[lumel].TriangleList;
+00803                                         while (list!=NULL)
+00804                                         {
+00805                                                 // Raytrace this triangle                                                       
+00806                                                 rayTraceTriangle (list->Triangle, lumels[lumel].Normal, description.Oversampling, lumels[lumel].S, lumels[lumel].T, factor, tested, patch);
+00807 
+00808                                                 // Next triangle
+00809                                                 list=list->Next;
+00810                                         }
+00811 
+00812                                         // Set new shadow value
+00813                                         nlassert (tested!=0);
+00814                                         if (tested!=0)
+00815                                                 patchInfo.Lumels[lumel]=(uint)(255.f*factor/(float)tested);
+00816                                 }
+00817                         }
+00818                 }
+00819 
+00820                 // *** Lighting
+00821                 
+00822                 // Get the patch info
+00823                 CPatchInfo &patchInfo=_PatchInfo[patch];
+00824 
+00825                 // ** Pointer on arries
+00826                 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
+00827 
+00828                 // Go for light each lumel
+00829                 for (uint lumel=0; lumel<lumels.size(); lumel++)
+00830                 {
+00831                         // Sky contribution
+00832                         float skyContribution;
+00833                                 
+00834                         if (description.SkyContribution)
+00835                         {                                                               
+00836                                 skyContribution = getSkyContribution(lumels[lumel].Position, lumels[lumel].Normal, description.SkyIntensity);
+00837                         }
+00838                         else
+00839                         {
+00840                                 skyContribution = 0.f;
+00841                         }
+00842 
+00843                         // Sun contribution
+00844                         float sunContribution;
+00845                         if (description.SunContribution)
+00846                         {
+00847                                 sunContribution=(-lumels[lumel].Normal*_LightDirection)-skyContribution;
+00848                                 clamp (sunContribution, 0.f, 1.f);
+00849                         }
+00850                         else
+00851                                 sunContribution=0;
+00852 
+00853                         // Final lighting
+00854                         sint finalLighting=(sint)(255.f*(((float)patchInfo.Lumels[lumel])*sunContribution/255.f+skyContribution));
+00855                         clamp (finalLighting, 0, 255);
+00856                         patchInfo.Lumels[lumel]=finalLighting;
+00857                 }
+00858 
+00859                 // Next patch
+00860                 patch = getAPatch (process);
+00861         }
+00862 }
+00863 
+00864 // ***************************************************************************
+00865 
+00866 uint8 CZoneLighter::getMaxPhi (sint s, sint t, sint deltaS, sint deltaT, float heightPos) const
+00867 {
+00868         // Start position
+00869         s+=deltaS;
+00870         t+=deltaT;
+00871 
+00872         // Distance increment
+00873         float stepDistance=CVector (deltaS*_HeightfieldCellSize, deltaT*_HeightfieldCellSize,0).norm ();
+00874 
+00875         // Current distance
+00876         float distance=stepDistance;
+00877 
+00878         // Max height
+00879         float maxHeight=0;
+00880         float maxTanTeta=0;
+00881 
+00882         // For all the line
+00883         while ((s<_HeightFieldCellCount)&&(t<_HeightFieldCellCount)&&(s>=0)&&(t>=0))
+00884         {
+00885                 // Get height
+00886                 float height=_HeightField[s+t*_HeightFieldCellCount];
+00887                 height-=heightPos;
+00888 
+00889                 // Better ?
+00890                 if (height>maxHeight)
+00891                 {
+00892                         // Calc sin teta
+00893                         float tanTeta=height/distance;
+00894                         nlassert (tanTeta>=0);
+00895 
+00896                         // Better ?
+00897                         if (tanTeta>maxTanTeta)
+00898                         {
+00899                                 // New max height
+00900                                 maxHeight=height;
+00901                                 maxTanTeta=tanTeta;
+00902                         }
+00903                 }
+00904                 s+=deltaS;
+00905                 t+=deltaT;
+00906                 distance+=stepDistance;
+00907         }
+00908 
+00909         // return phi
+00910         float teta=(float)atan (maxTanTeta);
+00911         nlassert (teta>=0);
+00912         nlassert (teta<=Pi/2);
+00913         clamp (teta, 0.f, (float)Pi/2);
+00914         sint res=(sint)((Pi/2-teta)*256/(Pi/2));
+00915         clamp (res, 0, 255);
+00916         return (uint8)res;
+00917 }
+00918 
+00919 // ***************************************************************************
+00920 
+00921 #define AllFront 0
+00922 #define AllBack 1
+00923 #define Clipped 2
+00924 
+00925 // ***************************************************************************
+00926 
+00927 void CZoneLighter::testRaytrace (const CVector& position, const CVector& normal, const CPlane &plane, float s, float t, uint patchId, CMultiShape &shape, CMultiShape &shapeTmp, uint cpu)
+00928 {
+00929          // Clear the selection of the quad tree
+00930         _QuadGrid[cpu].clearSelection ();
+00931 
+00932         // Light position
+00933         CVector lightPos=position-(_LightDirection*1000.f);
+00934 
+00935         // Select an element with the X axis as a 3d ray
+00936         _QuadGrid[cpu].select (lightPos-_RayAdd, lightPos+_RayAdd);
+00937 
+00938         // Tmp
+00939         CShape back;
+00940         CShape front;
+00941         CShape copy;
+00942 
+00943 #ifdef HARDWARE_SOFT_SHADOWS
+00944 
+00945         // Vector unit
+00946         float unit=2*_ShapeRadius;
+00947 
+00948         // Make a scale matrix
+00949         CMatrix lumelScale;
+00950         lumelScale.identity ();
+00951         lumelScale.scale (unit);
+00952 
+00953         // Get the ray basis
+00954         CMatrix lumelBasis=_RayBasis*lumelScale;
+00955 
+00956         // Change origine in the top left corner
+00957         lumelBasis.setPos (position-lumelBasis.getI()/2-lumelBasis.getJ()/2);
+00958 
+00959         // Inverse this matrix
+00960         lumelBasis.invert ();
+00961 
+00962 #endif // HARDWARE_SOFT_SHADOWS
+00963 
+00964         // For each triangle selected
+00965         CQuadGrid<const CTriangle*>::CIterator it=_QuadGrid[cpu].begin();
+00966         while (it!=_QuadGrid[cpu].end())
+00967         {
+00968                 // Source vector
+00969                 CVector source=position;
+00970 
+00971                 // Same triangle ?
+00972                 if (
+00973                         ((*it)->PatchId==patchId)&&
+00974                         ((*it)->ZoneId==_ZoneToLight)&&
+00975                         ((*it)->StartS<=s)&&
+00976                         ((*it)->StartT<=t)&&
+00977                         ((*it)->EndS>=s)&&
+00978                         ((*it)->EndT>=t)
+00979                         )
+00980                         source+=(normal*_ShadowBias);
+00981 
+00982                 // Blur ?
+00983                 if (!_Softshadow)
+00984                 {
+00985                         // Hit position
+00986                         CVector hit;
+00987 
+00988                         // Intersect
+00989                         if ((*it)->Triangle.intersect (source, lightPos, hit, (*it)->Plane))
+00990                         {
+00991                                 // Clear the shape list
+00992                                 shape.Shapes.resize (0);
+00993                                 break;
+00994                         }
+00995                 }
+00996                 else
+00997                 {
+00998                         // Triangle clippable ?
+00999                         const NLMISC::CTriangle &triangle=(*it)->Triangle;
+01000 
+01001                         // Clip the ray over the triangle
+01002                         float edgeFactor[3]=
+01003                         {
+01004                                 ((((triangle.V0+triangle.V1)/2) - source)*-_LightDirection)/_FallofDistance,
+01005                                 ((((triangle.V1+triangle.V2)/2) - source)*-_LightDirection)/_FallofDistance,
+01006                                 ((((triangle.V2+triangle.V0)/2) - source)*-_LightDirection)/_FallofDistance,
+01007                         };
+01008                         float oOEdgeFactor[3];
+01009                         bool scaleEdge[3];
+01010                         uint edgeFlags[3];
+01011                         bool oneNotBack=false;
+01012                         uint i;
+01013                         for (i=0; i<3; i++)
+01014                         {
+01015                                 // Edge factor
+01016                                 if (edgeFactor[i]<0)
+01017                                         // Polygon behing
+01018                                         break;
+01019                                 if (edgeFactor[i]>1)
+01020                                 {
+01021                                         scaleEdge[i]=false;
+01022                                         edgeFactor[i]=1;
+01023                                 }
+01024                                 else
+01025                                 {
+01026                                         scaleEdge[i]=true;
+01027                                         oOEdgeFactor[i]=1/edgeFactor[i];
+01028                                 }
+01029 
+01030                                 // Distance from clipping plane
+01031                                 float distance=(*it)->ClippingPlanes[i]*source;
+01032 
+01033                                 // Clipping distance
+01034                                 float clipDist=edgeFactor[i]*_ShapeRadius;
+01035 
+01036                                 // Clip this distance
+01037                                 if (distance<-clipDist)
+01038                                 {
+01039                                         // Back
+01040                                         edgeFlags[i]=AllBack;
+01041                                 }
+01042                                 else if (distance>clipDist)
+01043                                         // Front
+01044                                         break;
+01045                                 else
+01046                                 {
+01047                                         // Clipped
+01048                                         edgeFlags[i]=Clipped;
+01049                                         oneNotBack=true;
+01050                                 }
+01051                         }
+01052 
+01053                         // Not front clipped
+01054                         if (i==3)
+01055                         {
+01056 #ifdef HARDWARE_SOFT_SHADOWS
+01057                                 // Transform this triangle in lumel basis
+01058                                 CVector v[3] = { lumelBasis*triangle.V0, lumelBasis*triangle.V1, lumelBasis*triangle.V2 };
+01059 
+01060                                 // Draw the triangle
+01061                                 drv->drawTriangle (v[0].x, v[0].y, v[1].x, v[1].y, v[2].x, v[2].y, CRGBA(0, 0, 0, 2));
+01062                                 drv->drawTriangle (v[0].x, v[0].y, v[2].x, v[2].y, v[1].x, v[1].y, CRGBA(0, 0, 0, 2));
+01063 
+01064 #else // HARDWARE_SOFT_SHADOWS
+01065                                 // All back ?
+01066                                 if (oneNotBack)
+01067                                 {
+01068                                         uint backupSize=shape.Shapes.size();
+01069                                         for (uint s=0; s<backupSize; s++)
+01070                                         {
+01071                                                 // Reset out list
+01072                                                 shapeTmp.Shapes.resize (0);
+01073                                                 back = shape.Shapes[s];
+01074 
+01075                                                 // Clip this shape with the triangle (3 planes)
+01076                                                 for (i=0; i<3; i++)
+01077                                                 {
+01078                                                         // All back ?
+01079                                                         if (edgeFlags[i]==AllBack)
+01080                                                                 // Yes, next
+01081                                                                 continue;
+01082 
+01083                                                         // Security
+01084                                                         if (back.NumVertex > (SHAPE_VERTICES_MAX-10) )
+01085                                                                 break;
+01086 
+01087                                                         // Scale down this shape
+01088                                                         if (scaleEdge[i])
+01089                                                                 back.scale (source, edgeFactor[i]);
+01090 
+01091                                                         // Copy the back buffer
+01092                                                         copy=back;
+01093 
+01094                                                         // Clipping plane
+01095                                                         const CPlane &clippingPlane=(*it)->ClippingPlanes[i];
+01096 
+01097                                                         // Reset back and front
+01098                                                         back.NumVertex=0;
+01099                                                         front.NumVertex=0;
+01100 
+01101                                                         // Clip
+01102                                                         if(copy.NumVertex>2)
+01103                                                         {
+01104                                                                 // Previous vertex
+01105                                                                 uint prev=copy.NumVertex-1;
+01106 
+01107                                                                 // Previous front ?
+01108                                                                 bool previousFront=(clippingPlane*copy.Vertices[prev] >= 0);
+01109 
+01110                                                                 // For each vertex
+01111                                                                 for (uint cur=0;cur<copy.NumVertex;cur++)
+01112                                                                 {
+01113                                                                         // Current vertex front ?
+01114                                                                         bool currentFront=(clippingPlane*copy.Vertices[cur] >= 0);
+01115                                                                         if ( currentFront )
+01116                                                                         {
+01117                                                                                 // Previous vertex back ?
+01118                                                                                 if ( !previousFront )
+01119                                                                                 {
+01120                                                                                         // Ok, intersect
+01121                                                                                         front.Vertices[front.NumVertex]= clippingPlane.intersect(copy.Vertices[prev],copy.Vertices[cur]);
+01122                                                                                         back.Vertices[back.NumVertex++]= front.Vertices[front.NumVertex];
+01123                                                                                         front.NumVertex++;
+01124                                                                                 }
+01125                                                                                 // Store new vertex front
+01126                                                                                 front.Vertices[front.NumVertex++]=copy.Vertices[cur];
+01127                                                                         }
+01128                                                                         else
+01129                                                                         {
+01130                                                                                 // Previous vertex front ?
+01131                                                                                 if ( previousFront )
+01132                                                                                 {
+01133                                                                                         front.Vertices[front.NumVertex]= clippingPlane.intersect(copy.Vertices[prev],copy.Vertices[cur]);
+01134                                                                                         back.Vertices[back.NumVertex++]= front.Vertices[front.NumVertex];
+01135                                                                                         front.NumVertex++;
+01136                                                                                 }
+01137                                                                                 back.Vertices[back.NumVertex++]=copy.Vertices[cur];
+01138                                                                         }
+01139                                                                         prev=cur;
+01140                                                                         previousFront=currentFront;
+01141                                                                 }
+01142                                                         }
+01143 
+01144                                                         // Scale up this shape
+01145                                                         if (scaleEdge[i])
+01146                                                         {
+01147                                                                 back.scale (source, oOEdgeFactor[i]);
+01148                                                                 front.scale (source, oOEdgeFactor[i]);
+01149                                                         }
+01150 
+01151                                                         // Some vertices front ?
+01152                                                         if (front.NumVertex!=0)
+01153                                                         {
+01154                                                                 // Front vertices ?
+01155                                                                 if (back.NumVertex==0)
+01156                                                                         // Nothing else to clip
+01157                                                                         break;
+01158                                                         }
+01159                                                         else
+01160                                                         {
+01161                                                                 // All vertices are back
+01162                                                                 // Pass entire triangle to next plane
+01163                                                                 continue;
+01164                                                         }
+01165 
+01166                                                         // Code is clipped
+01167                                                         // res is the front shape, so it is out
+01168                                                         // Last plane ?
+01169                                                         shapeTmp.Shapes.push_back (front);
+01170                                                 }
+01171                                                 if (i==3)
+01172                                                 {
+01173                                                         // Merge list..
+01174                                                         if (shapeTmp.Shapes.empty())
+01175                                                         {
+01176                                                                 // Erase this entry
+01177                                                                 shape.Shapes[s].NumVertex=0;
+01178                                                         }
+01179                                                         else
+01180                                                         {
+01181                                                                 // Copy first element
+01182                                                                 shape.Shapes[s]=shapeTmp.Shapes[0];
+01183 
+01184                                                                 // Insert others
+01185                                                                 uint size=shapeTmp.Shapes.size();
+01186                                                                 for (uint t=1; t<size; t++)
+01187                                                                 {
+01188                                                                         // Append new shapes
+01189                                                                         shape.Shapes.push_back (shapeTmp.Shapes[t]);
+01190                                                                 }
+01191                                                         }
+01192                                                 }
+01193                                         }
+01194                                 }
+01195                                 else
+01196                                 {
+01197                                         // Clear all the ray
+01198                                         shape.Shapes.resize (0);
+01199                                 }
+01200 #endif // HARDWARE_SOFT_SHADOWS
+01201                         }
+01202                 }
+01203 
+01204                 // Next
+01205                 it++;
+01206         }
+01207 }
+01208 
+01209 // ***************************************************************************
+01210 
+01211 void CZoneLighter::rayTrace (const CVector& position, const CVector& normal, float s, float t, uint patchId, float &factor, CMultiShape &shape, CMultiShape &shapeTmp, uint cpu)
+01212 {
+01213         // Resize the shape list
+01214         shape.Shapes.resize (1);
+01215 
+01216         // Ref on the cshape
+01217         CShape &shp=shape.Shapes[0];
+01218 
+01219         // Copy the shape
+01220         shp=_Shape;
+01221 
+01222         // Translate the shape
+01223         sint j;
+01224         for (j=0; j<(sint)shp.NumVertex; j++)
+01225         {
+01226                 shp.Vertices[j]+=position;
+01227         }
+01228 
+01229         // Build a clipping plane
+01230         CPlane plane;
+01231         plane.make (-_LightDirection, position);
+01232 
+01233 #ifdef HARDWARE_SOFT_SHADOWS
+01234 
+01235         // Clear all pixels in green
+01236         drv->clearRGBABuffer (CRGBA (0, 255, 0, 0));
+01237 
+01238 #endif // HARDWARE_SOFT_SHADOWS
+01239 
+01240         // Go!
+01241         testRaytrace (position, normal, plane, s, t, patchId, shape, shapeTmp, cpu);
+01242 
+01243 #ifdef HARDWARE_SOFT_SHADOWS
+01244         
+01245         // Download frame buffer
+01246         static CBitmap bitmap;
+01247         drv->getBufferPart (bitmap, CRect (0, 0, LIGHT_BUFFER_SIZE, LIGHT_BUFFER_SIZE));
+01248         nlassert (bitmap.getWidth()==LIGHT_BUFFER_SIZE);
+01249         nlassert (bitmap.getHeight()==LIGHT_BUFFER_SIZE);
+01250 
+01251         // Pixels
+01252         bitmap.convertToType (CBitmap::RGBA);
+01253 
+01254         // RGBA pointer
+01255         CRGBA *pixels=(CRGBA*)&bitmap.getPixels ()[0];
+01256 
+01257         // Average pixel
+01258         factor=0;
+01259         for (uint p=0; p<LIGHT_BUFFER_SIZE*LIGHT_BUFFER_SIZE; p++)
+01260         {
+01261                 factor+=pixels[p].G;
+01262         }
+01263         factor/=(float)(255*LIGHT_BUFFER_SIZE*LIGHT_BUFFER_SIZE);
+01264 
+01265 #else // HARDWARE_SOFT_SHADOWS
+01266         // Calc the surface ratio
+01267         uint size=shape.Shapes.size();
+01268         for (uint i=0; i<size; i++)
+01269         {
+01270                 // For each shape
+01271                 CShape &vect=shape.Shapes[i];
+01272 
+01273                 for (j=1; j<(sint)vect.NumVertex-1; j++)
+01274                 {
+01275                         // Sum the area
+01276                         factor+=((vect.Vertices[j]-vect.Vertices[0])^(vect.Vertices[j+1]-vect.Vertices[0])).norm();
+01277                 }
+01278         }
+01279 
+01280         factor/=_ShapeArea;
+01281 #endif // HARDWARE_SOFT_SHADOWS
+01282 }
+01283 
+01284 // ***************************************************************************
+01285 
+01286 void CZoneLighter::rayTraceTriangle (const NLMISC::CTriangle& toOverSample, CVector& normal, uint order, float s, float t, float &factor, uint &tested, uint patch)
+01287 {
+01288         // Ok ?
+01289         if (order==0)
+01290         {
+01291                 // Ray !
+01292                 tested++;
+01293                 //rayTrace (-_LightDirection+(toOverSample.V0+toOverSample.V1+toOverSample.V2)/3, normal, s, t, patch, factor);
+01294         }
+01295         else
+01296         {
+01297                 // Subdivide the triangle
+01298                 CVector v0V1=toOverSample.V0;
+01299                 v0V1+=toOverSample.V1;
+01300                 v0V1/=2;
+01301                 CVector v0V2=toOverSample.V0;
+01302                 v0V2+=toOverSample.V2;
+01303                 v0V2/=2;
+01304                 CVector v1V2=toOverSample.V1;
+01305                 v1V2+=toOverSample.V2;
+01306                 v1V2/=2;
+01307                 rayTraceTriangle (NLMISC::CTriangle (toOverSample.V0, v0V1, v0V2), normal, order-1, s, t, factor, tested, patch);
+01308                 rayTraceTriangle (NLMISC::CTriangle (toOverSample.V1, v1V2, v0V1), normal, order-1, s, t, factor, tested, patch);
+01309                 rayTraceTriangle (NLMISC::CTriangle (toOverSample.V2, v0V2, v1V2), normal, order-1, s, t, factor, tested, patch);
+01310                 rayTraceTriangle (NLMISC::CTriangle (v0V1, v1V2, v0V2), normal, order-1, s, t, factor, tested, patch);
+01311         }
+01312 }
+01313 
+01314 // ***************************************************************************
+01315 
+01316 bool CZoneLighter::isLumelOnEdgeMustBeOversample (uint patch, uint edge, sint s, sint t, const vector<bool> &binded, 
+01317                                                                                                   const vector<bool> &oversampleEdges, vector<CPatchUVLocator> &locator, 
+01318                                                                                                   uint8 shadowed, vector<vector<uint8> >& shadowBuffer)
+01319 {
+01320         // Must force oversampling of this edge ?
+01321         if (oversampleEdges[edge])
+01322                 return true;
+01323         else
+01324         {
+01325                 // binded ?
+01326                 if (binded[edge])
+01327                 {
+01328                         // Lumel coord
+01329                         CVector2f lumelCoord (((float)(s+_GetNormalDeltaS[edge])+0.5f)/4.f, ((float)(t+_GetNormalDeltaT[edge])+0.5f)/4.f);
+01330                         uint otherPatch=locator[edge].selectPatch(lumelCoord);
+01331 
+01332                         // Get uv
+01333                         CVector2f neighborUV;
+01334                         CPatch *patchOut;
+01335                         locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
+01336                         
+01337                         // Is the same shadowed flag ?
+01338                         sint ss=(sint)(neighborUV.x*4.f);
+01339                         sint tt=(sint)(neighborUV.y*4.f);
+01340                         return (shadowBuffer[patchOut->getPatchId()][ss+(patchOut->getOrderS()<<2)*tt]!=shadowed);
+01341                 }
+01342                 else
+01343                 {
+01344                         // Not oversample if not binded
+01345                         return false;
+01346                 }
+01347         }
+01348 }
+01349 
+01350 // ***************************************************************************
+01351 
+01352 float easineasout(float x)
+01353 {
+01354  float y;
+01355  // cubic tq f(0)=0, f'(0)=0, f(1)=1, f'(1)=0.
+01356  float x2=x*x;
+01357  float x3=x2*x;
+01358  y= -2*x3 + 3*x2;
+01359  return y;
+01360 }
+01361 
+01362 // ***************************************************************************
+01363 
+01364 float easineasoutC2(float x)
+01365 {
+01366  float y;
+01367  // 5-nome tq f(0)=0, f'(0)=0, f''(0)=0, f(1)=1, f'(1)=0, f''(1)=0.
+01368  float x3=x*x*x;
+01369  float x4=x3*x;
+01370  float x5=x4*x;
+01371  y= 6*x5 -15*x4 +10*x3;
+01372  return y;
+01373 }
+01374 
+01375 // ***************************************************************************
+01376 
+01377 
+01378 sint16 CZoneLighter::_GetNormalDeltaS[4]={ -1, 0, 1, 0 };
+01379 sint16 CZoneLighter::_GetNormalDeltaT[4]={ 0, 1, 0, -1 };
+01380 
+01381 // ***************************************************************************
+01382 
+01383 void CZoneLighter::getNormal (const CPatch *pPatch, sint16 lumelS, sint16 lumelT, vector<CPatchUVLocator> &locator, 
+01384                                                                  const vector<CPatch::CBindInfo> &bindInfo, const vector<bool> &binded, set<uint64>& visited, 
+01385                                                                  float deltaS, float deltaT, uint rotation, const CBezierPatch &bezierPatch, uint lastEdge)
+01386 {
+01387         // Build a desc srructure
+01388         uint64 id=(uint64)lumelS|(((uint64)lumelT)<<16)|(((uint64)pPatch->getPatchId())<<32)|(((uint64)pPatch->getZone()->getZoneId())<<48);
+01389 
+01390         // Insert it
+01391         if (visited.insert (id).second)
+01392         {
+01393                 // Clip
+01394                 float sqDist=deltaS*deltaS+deltaT*deltaT;
+01395                 if ( sqDist < 1 )
+01396                 {
+01397                         // Continue...
+01398 
+01399                         sint orderSx4=pPatch->getOrderS()<<2;
+01400                         sint orderTx4=pPatch->getOrderT()<<2;
+01401 
+01402                         sint16 _GetNormalBorderS[4]={ 0, -10, 1, -10 };
+01403                         sint16 _GetNormalBorderT[4]={ -10, 1, -10, 0 };
+01404                         _GetNormalBorderS[2]=orderSx4-1;
+01405                         _GetNormalBorderT[1]=orderTx4-1;
+01406 
+01407                         // Add normal
+01408                         _GetNormalNormal+=bezierPatch.evalNormal ( ((float)lumelS+0.5f)/(float)orderSx4, ((float)lumelT+0.5f)/(float)orderTx4 );
+01409 
+01410                         // For the four neighbors
+01411                         for (uint edge=0; edge<4; edge++)
+01412                         {
+01413                                 // Not last edge ?
+01414                                 if (edge!=lastEdge)
+01415                                 {
+01416                                         // Direction
+01417                                         uint globalDirection=(edge+(4-rotation))&0x3;
+01418 
+01419                                         // Neighbor
+01420                                         if ( (lumelS==_GetNormalBorderS[edge]) || (lumelT==_GetNormalBorderT[edge]) )
+01421                                         {
+01422                                                 // Binded ?
+01423                                                 bool bind=binded[edge];
+01424                                                 bool smooth=pPatch->getSmoothFlag (edge);
+01425                                                 if (bind&&smooth)
+01426                                                 {
+01427                                                         // Lumel coord
+01428                                                         CVector2f lumelCoord ( ((float)(lumelS+_GetNormalDeltaS[edge])+0.5f)/4, 
+01429                                                                 ((float)(lumelT+_GetNormalDeltaT[edge])+0.5f)/4 );
+01430 
+01431                                                         // Get neighbor pixel
+01432                                                         uint otherPatch=locator[edge].selectPatch(lumelCoord);
+01433 
+01434                                                         // Get uv
+01435                                                         CVector2f neighborUV;
+01436                                                         CPatch *patchOut;
+01437                                                         locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
+01438 
+01439                                                         // New coordinates
+01440                                                         sint16 newLumelS=(sint16)(4.f*neighborUV.x);
+01441                                                         sint16 newLumelT=(sint16)(4.f*neighborUV.y);
+01442 
+01443                                                         // Zone id
+01444                                                         uint16 patchId=patchOut->getPatchId();
+01445                                                         uint16 zoneId=_ZoneId[patchOut->getZone()->getZoneId ()];
+01446 
+01447                                                         // Get edge
+01448                                                         uint newEdge=0;
+01449                                                         uint i;
+01450                                                         for (i=0; i<=(uint)bindInfo[edge].NPatchs; i++)
+01451                                                         {
+01452                                                                 // Good patch ?
+01453                                                                 if (bindInfo[edge].Next[i]==patchOut)
+01454                                                                 {
+01455                                                                         // Get its edge
+01456                                                                         newEdge=bindInfo[edge].Edge[i];
+01457                                                                         break;
+01458                                                                 }
+01459                                                         }
+01460                                                         
+01461                                                         // Rotation 
+01462                                                         uint newRotation=(2-edge+rotation+newEdge)&0x3;
+01463 
+01464                                                         // Must found it
+01465                                                         nlassert (i!=(uint)bindInfo[edge].NPatchs);
+01466 
+01467                                                         // Get the bezier patch
+01468                                                         CBezierPatch &NewBezierPatch=_BezierPatch[zoneId][patchId];
+01469 
+01470                                                         // Next lumel
+01471                                                         getNormal (patchOut, newLumelS, newLumelT, _Locator[zoneId][patchId], _BindInfo[zoneId][patchId], 
+01472                                                                 _Binded[zoneId][patchId], visited, deltaS+_GetNormalDeltaS[globalDirection], 
+01473                                                                 deltaT+_GetNormalDeltaT[globalDirection], newRotation, NewBezierPatch, newEdge);
+01474                                                 }
+01475                                         }
+01476                                         else
+01477                                         {
+01478                                                 // Left internal
+01479                                                 getNormal (pPatch, lumelS+_GetNormalDeltaS[edge], lumelT+_GetNormalDeltaT[edge], locator, bindInfo, binded, visited, 
+01480                                                         deltaS+_GetNormalDeltaS[globalDirection], deltaT+_GetNormalDeltaT[globalDirection], rotation, bezierPatch, (edge+2)&0x3);
+01481                                         }
+01482                                 }
+01483                         }
+01484                 }
+01485         }
+01486 }
+01487 
+01488 // ***************************************************************************
+01489 
+01490 void CZoneLighter::addTriangles (CLandscape &landscape, vector<uint> &listZone, uint order, std::vector<CTriangle>& triangleArray)
+01491 {
+01492         // Set all to refine
+01493         excludeAllPatchFromRefineAll (landscape, listZone, false);
+01494 
+01495         // Setup the landscape
+01496         landscape.setThreshold (0);
+01497         landscape.setTileMaxSubdivision (order);
+01498 
+01499         // Refine it
+01500         landscape.refineAll (CVector (0, 0, 0));
+01501 
+01502         // Dump tesselated triangles
+01503         std::vector<const CTessFace*> leaves;
+01504         landscape.getTessellationLeaves(leaves);
+01505 
+01506         // Number of leaves
+01507         uint leavesCount=leaves.size();
+01508 
+01509         // Reserve the array
+01510         triangleArray.reserve (triangleArray.size()+leavesCount);
+01511 
+01512         // Scan each leaves
+01513         for (uint leave=0; leave<leavesCount; leave++)
+01514         {
+01515                 // Leave
+01516                 const CTessFace *face=leaves[leave];
+01517 
+01518                 // Start and end coordinate
+01519                 float startS=min (min (face->PVBase.getS(), face->PVLeft.getS()), face->PVRight.getS());
+01520                 float endS=max (max (face->PVBase.getS(), face->PVLeft.getS()), face->PVRight.getS());
+01521                 float startT=min (min (face->PVBase.getT(), face->PVLeft.getT()), face->PVRight.getT());
+01522                 float endT=max (max (face->PVBase.getT(), face->PVLeft.getT()), face->PVRight.getT());
+01523 
+01524                 // Add a triangle
+01525                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos), 
+01526                         face->Patch->getZone()->getZoneId(), face->Patch->getPatchId(), startS ,endS, startT, endT));
+01527         }
+01528 
+01529         // Setup the landscape
+01530         landscape.setThreshold (1000);
+01531         landscape.setTileMaxSubdivision (0);
+01532 
+01533         // Remove all triangles
+01534         landscape.refineAll (CVector (0, 0, 0));
+01535         landscape.refineAll (CVector (0, 0, 0));
+01536         landscape.refineAll (CVector (0, 0, 0));
+01537         landscape.refineAll (CVector (0, 0, 0));
+01538         landscape.refineAll (CVector (0, 0, 0));
+01539         landscape.refineAll (CVector (0, 0, 0));
+01540         landscape.refineAll (CVector (0, 0, 0));
+01541         landscape.refineAll (CVector (0, 0, 0));
+01542         landscape.refineAll (CVector (0, 0, 0));
+01543         landscape.refineAll (CVector (0, 0, 0));
+01544 }
+01545 
+01546 // ***************************************************************************
+01547 
+01548 void CZoneLighter::addTriangles (const IShape &shape, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
+01549 {
+01550         // Cast to CMesh
+01551         const CMesh *mesh=dynamic_cast<const CMesh*>(&shape);
+01552 
+01553         // Cast to CMeshMultiLod
+01554         const CMeshMultiLod *meshMulti=dynamic_cast<const CMeshMultiLod*>(&shape);
+01555 
+01556         // Cast to CMeshMultiLod
+01557         const CMeshMRM *meshMRM=dynamic_cast<const CMeshMRM*>(&shape);
+01558 
+01559         // It is a mesh ?
+01560         if (mesh)
+01561         {
+01562                 // Add its triangles
+01563                 addTriangles (mesh->getMeshGeom (), modelMT, triangleArray);
+01564         }
+01565         // It is a CMeshMultiLod ?
+01566         else if (meshMulti)
+01567         {
+01568                 // Get the first geommesh
+01569                 const IMeshGeom *meshGeom=&meshMulti->getMeshGeom (0);
+01570 
+01571                 // Dynamic cast
+01572                 const CMeshGeom *geomMesh=dynamic_cast<const CMeshGeom*>(meshGeom);
+01573                 if (geomMesh)
+01574                 {
+01575                         addTriangles (*geomMesh, modelMT, triangleArray);
+01576                 }
+01577 
+01578                 // Dynamic cast
+01579                 const CMeshMRMGeom *mrmGeomMesh=dynamic_cast<const CMeshMRMGeom*>(meshGeom);
+01580                 if (mrmGeomMesh)
+01581                 {
+01582                         addTriangles (*mrmGeomMesh, modelMT, triangleArray);
+01583                 }
+01584         }
+01585         // It is a CMeshMultiLod ?
+01586         else if (meshMRM)
+01587         {
+01588                 // Get the first lod mesh geom
+01589                 addTriangles (meshMRM->getMeshGeom (), modelMT, triangleArray);
+01590         }
+01591 }
+01592 
+01593 // ***************************************************************************
+01594 
+01595 void CZoneLighter::addTriangles (const CMeshGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
+01596 {
+01597         // Get the vertex buffer
+01598         const CVertexBuffer &vb=meshGeom.getVertexBuffer();
+01599 
+01600         // For each matrix block
+01601         uint numBlock=meshGeom.getNbMatrixBlock();
+01602         for (uint block=0; block<numBlock; block++)
+01603         {
+01604                 // For each render pass
+01605                 uint numRenderPass=meshGeom.getNbRdrPass(block);
+01606                 for (uint pass=0; pass<numRenderPass; pass++)
+01607                 {
+01608                         // Get the primitive block
+01609                         const CPrimitiveBlock &primitive=meshGeom.getRdrPassPrimitiveBlock ( block, pass);
+01610 
+01611                         // Dump triangles
+01612                         const uint32* triIndex=primitive.getTriPointer ();
+01613                         uint numTri=primitive.getNumTri ();
+01614                         uint tri;
+01615                         for (tri=0; tri<numTri; tri++)
+01616                         {
+01617                                 // Vertex
+01618                                 CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3]));
+01619                                 CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+1]));
+01620                                 CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+2]));
+01621 
+01622                                 // Make a triangle
+01623                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2)));
+01624                         }
+01625 
+01626                         // Dump quad
+01627                         triIndex=primitive.getQuadPointer ();
+01628                         numTri=primitive.getNumQuad ();
+01629                         for (tri=0; tri<numTri; tri++)
+01630                         {
+01631                                 // Vertex
+01632                                 CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4]));
+01633                                 CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+1]));
+01634                                 CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+2]));
+01635                                 CVector v3=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+3]));
+01636 
+01637                                 // Make 2 triangles
+01638                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2)));
+01639                                 triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v2, v3)));
+01640                         }
+01641                 }
+01642         }
+01643 }
+01644 
+01645 // ***************************************************************************
+01646 
+01647 void CZoneLighter::addTriangles (const CMeshMRMGeom &meshGeom, const CMatrix& modelMT, std::vector<CTriangle>& triangleArray)
+01648 {
+01649         // Get the vertex buffer
+01650         const CVertexBuffer &vb=meshGeom.getVertexBuffer();
+01651 
+01652         // For each render pass
+01653         uint numRenderPass=meshGeom.getNbRdrPass(0);
+01654         for (uint pass=0; pass<numRenderPass; pass++)
+01655         {
+01656                 // Get the primitive block
+01657                 const CPrimitiveBlock &primitive=meshGeom.getRdrPassPrimitiveBlock ( 0, pass);
+01658 
+01659                 // Dump triangles
+01660                 const uint32* triIndex=primitive.getTriPointer ();
+01661                 uint numTri=primitive.getNumTri ();
+01662                 uint tri;
+01663                 for (tri=0; tri<numTri; tri++)
+01664                 {
+01665                         // Vertex
+01666                         CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3]));
+01667                         CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+1]));
+01668                         CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*3+2]));
+01669 
+01670                         // Make a triangle
+01671                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2)));
+01672                 }
+01673 
+01674                 // Dump quad
+01675                 triIndex=primitive.getQuadPointer ();
+01676                 numTri=primitive.getNumQuad ();
+01677                 for (tri=0; tri<numTri; tri++)
+01678                 {
+01679                         // Vertex
+01680                         CVector v0=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4]));
+01681                         CVector v1=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+1]));
+01682                         CVector v2=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+2]));
+01683                         CVector v3=modelMT*(*(CVector*)vb.getVertexCoordPointer (triIndex[tri*4+3]));
+01684 
+01685                         // Make 2 triangles
+01686                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v1, v2)));
+01687                         triangleArray.push_back (CTriangle (NLMISC::CTriangle (v0, v2, v3)));
+01688                 }
+01689         }
+01690 }
+01691 
+01692 // ***************************************************************************
+01693 
+01694 void CZoneLighter::excludeAllPatchFromRefineAll (CLandscape &landscape, vector<uint> &listZone, bool exclude)
+01695 {
+01696         // For each zone
+01697         for (uint zone=0; zone<listZone.size(); zone++)
+01698         {
+01699                 // Get num patches
+01700                 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
+01701 
+01702                 // For each patches
+01703                 for (uint patch=0; patch<patchCount; patch++)
+01704                 {
+01705                         // Exclude all the patches from refine all
+01706                         landscape.excludePatchFromRefineAll (listZone[zone], patch, exclude);
+01707                 }
+01708         }
+01709 }
+01710 
+01711 // ***************************************************************************
+01712 
+01713 void CZoneLighter::buildZoneInformation (CLandscape &landscape, const vector<uint> &listZone, bool oversampling, const CLightDesc &lightDesc)
+01714 {
+01715         // Bool visit
+01716         vector<vector<uint> > visited;
+01717 
+01718         // Zone count
+01719         uint zoneCount=listZone.size();
+01720 
+01721         // Resize arries
+01722         _Locator.resize (zoneCount);
+01723         _Binded.resize (zoneCount);
+01724         _BindInfo.resize (zoneCount);
+01725         _BezierPatch.resize (zoneCount);
+01726 
+01727         // For each zone
+01728         for (uint zone=0; zone<zoneCount; zone++)
+01729         {
+01730                 // Get num patches
+01731                 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
+01732 
+01733                 // Insert zone id
+01734                 _ZoneId.insert (map<uint, uint>::value_type (listZone[zone], zone));
+01735 
+01736                 // This is the zone to light ?
+01737                 if (listZone[zone]==_ZoneToLight)
+01738                 {
+01739                         // Resize the arraies
+01740                         _Lumels.resize(patchCount);
+01741 //                      _BezierPatch.resize(patchCount);
+01742                         _OversampleEdges.resize(patchCount);
+01743                         visited.resize(patchCount);
+01744                 }
+01745 
+01746                 // Common arries
+01747                 _Locator[zone].resize(patchCount);
+01748                 _Binded[zone].resize(patchCount);
+01749                 _BindInfo[zone].resize(patchCount);
+01750                 _BezierPatch[zone].resize(patchCount);
+01751 
+01752                 // For each patch
+01753                 uint patch;
+01754                 for (patch=0; patch<patchCount; patch++)
+01755                 {
+01756                         // Get a patch pointer
+01757                         const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(listZone[zone])))->getPatch (patch);
+01758 
+01759                         // Progress bar
+01760                         progress ("Scan all patches", (float)patch/(float)patchCount);
+01761 
+01762                         // Get pointer on arries
+01763                         vector<bool> &binded=_Binded[zone][patch];
+01764                         vector<CPatch::CBindInfo> &bindInfo=_BindInfo[zone][patch];
+01765                         vector<CPatchUVLocator> &locator=_Locator[zone][patch];
+01766                         CBezierPatch &bezierPatch=_BezierPatch[zone][patch];
+01767                         binded.resize (4, false);
+01768                         bindInfo.resize (4);
+01769                         locator.resize (4);
+01770 
+01771                         // Contruct the patch
+01772                         bezierPatch=*pPatch->unpackIntoCache();
+01773 
+01774                         // Same zone ?
+01775                         if (listZone[zone]==_ZoneToLight)
+01776                         {
+01777                                 // oversample this edge
+01778                                 _OversampleEdges[patch].resize (4, false);
+01779                         }
+01780 
+01781                         // *** Build bind info
+01782 
+01783                         // *** Build neighboorhood information
+01784                         uint edge;
+01785                         for (edge=0; edge<4; edge++)
+01786                         {
+01787                                 // Bond neighbor
+01788                                 pPatch->getBindNeighbor (edge, bindInfo[edge]);
+01789 
+01790                                 // Patch binded
+01791                                 if (bindInfo[edge].NPatchs>0)
+01792                                 {
+01793                                         // This edeg is binded
+01794                                         binded[edge]=true;
+01795 
+01796                                         // Same zone ?
+01797                                         if ((listZone[zone]==_ZoneToLight)&&(bindInfo[edge].Zone->getZoneId()!=_ZoneToLight))
+01798                                         {
+01799                                                 // oversample this edge
+01800                                                 _OversampleEdges[patch][edge]=true;
+01801                                         }
+01802                                         locator[edge].build (pPatch, edge, bindInfo[edge]);
+01803                                 }
+01804                                 else
+01805                                 {
+01806                                         if (listZone[zone]==_ZoneToLight)
+01807                                         {
+01808                                                 // oversample this edge
+01809                                                 _OversampleEdges[patch][edge]=true;
+01810                                         }
+01811                                 }
+01812                         }
+01813 
+01814                         // This is the zone to light ?
+01815                         if (listZone[zone]==_ZoneToLight)
+01816                         {
+01817                                 // *** Resize lumel array for this patch
+01818 
+01819                                 // Get patch order
+01820                                 uint orderS=pPatch->getOrderS();
+01821                                 uint orderT=pPatch->getOrderT();
+01822 
+01823                                 // Number of lumels
+01824                                 uint lumelCount=orderS*orderT*16;
+01825 
+01826                                 // Resize the lumel descriptor
+01827                                 CLumelDescriptor descriptor;
+01828                                 descriptor.Normal.set (0,0,0);
+01829                                 descriptor.Position.set (0,0,0);
+01830                                 descriptor.S=0;
+01831                                 descriptor.T=0;
+01832                                 _Lumels[patch].resize (lumelCount, descriptor);
+01833                                 visited[patch].resize (lumelCount, 0);
+01834 
+01835                                 // *** Unexclude this patch
+01836 
+01837                                 // Exclude all the patches from refine all
+01838                                 landscape.excludePatchFromRefineAll (listZone[zone], patch, false);
+01839                         }
+01840                         else
+01841                         {
+01842                                 // Exclude all the patches from refine all
+01843                                 landscape.excludePatchFromRefineAll (listZone[zone], patch, true);
+01844                         }
+01845                 }
+01846         }
+01847 
+01848         // *** Now tesselate this zone to shadow accuracy
+01849 
+01850         // Setup the landscape
+01851         landscape.setThreshold (0);
+01852         landscape.setTileMaxSubdivision (0);
+01853 
+01854         // Refine all
+01855         progress ("Refine landscape to shadow accuracy", 0.5f);
+01856         landscape.refineAll (CVector (0, 0, 0));
+01857 
+01858         // Get tesselated faces
+01859         std::vector<const CTessFace*> leaves;
+01860         landscape.getTessellationLeaves(leaves);
+01861         
+01862 
+01863         
+01864         
+01865         if (_WaterShapes.size() != 0) // any water shape in this zone ?
+01866         {
+01868                 makeQuadGridFromWaterShapes(landscape.getZone(_ZoneToLight)->getZoneBB().getAABBox());
+01869 
+01871                 computeTileFlagsForPositionTowardWater(lightDesc, leaves);
+01872         }
+01873         else
+01874         {
+01875                 setTileFlagsToDefault(leaves);
+01876         }
+01877         
+01878 
+01879         // Id of this zone in the array
+01880         uint zoneNumber=_ZoneId[_ZoneToLight];
+01881 
+01882         // Scan each leaves
+01883         uint leavesCount=leaves.size();
+01884         uint leave;
+01885         for (leave=0; leave<leavesCount; leave++)
+01886         {
+01887                 // Progress bar
+01888                 if ( (leave&0xff) == 0)
+01889                         progress ("Precompute lumel position", (float)leave/(float)leavesCount);
+01890 
+01891                 // Leave
+01892                 const CTessFace *face=leaves[leave];
+01893 
+01894                 // Get zone id
+01895                 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
+01896                 {
+01897                         // Get a patch pointer
+01898                         const CPatch* pPatch=face->Patch;
+01899 
+01900                         // Get order
+01901                         uint orderS=pPatch->getOrderS();
+01902                         uint orderT=pPatch->getOrderT();
+01903 
+01904                         // *** Base Coordinates
+01905                         CVector pos[14];
+01906                         pos[0]=face->VBase->EndPos;             // p0
+01907                         pos[1]=face->VRight->EndPos;
+01908                         pos[2]=face->VLeft->EndPos;             // p2
+01909                         pos[3]=(pos[1]+pos[2])/2;
+01910                         pos[4]=(pos[0]+pos[1])/2;                               // p4
+01911                         pos[5]=(pos[0]+pos[2])/2;
+01912                         pos[6]=(pos[0]+pos[3])/2;                               // p6
+01913                         pos[7]=(pos[2]+pos[3])/2;
+01914                         pos[8]=(pos[1]+pos[3])/2;                               // p8
+01915                         pos[9]=(pos[0]+pos[4])/2;
+01916                         pos[10]=(pos[1]+pos[4])/2;                              // p10
+01917                         pos[11]=(pos[0]+pos[5])/2;
+01918                         pos[12]=(pos[2]+pos[5])/2;                              // p12
+01919                         pos[13]=(pos[3]+pos[5])/2;
+01920                         pos[14]=(pos[3]+pos[4])/2;                              // p14
+01921 
+01922                         float s0=face->PVBase.getS();
+01923                         float s1=face->PVRight.getS();
+01924                         float s2=face->PVLeft.getS();
+01925                         float s3=(s1+s2)/2;
+01926                         float s4=(s0+s1)/2;
+01927                         float s5=(s0+s2)/2;
+01928                         float s6=(s4+s5)/2;
+01929                         float s7=(s2+s3)/2;
+01930                         float s8=(s1+s3)/2;
+01931 
+01932                         float t0=face->PVBase.getT();
+01933                         float t1=face->PVRight.getT();
+01934                         float t2=face->PVLeft.getT();
+01935                         float t3=(t1+t2)/2;
+01936                         float t4=(t0+t1)/2;
+01937                         float t5=(t0+t2)/2;
+01938                         float t6=(t4+t5)/2;
+01939                         float t7=(t2+t3)/2;
+01940                         float t8=(t1+t3)/2;
+01941 
+01942                         // *** Interpolated value
+01943                         CVector interpolatedP[10]=
+01944                         {
+01945                                 (pos[0]+pos[6])/2,
+01946                                 (pos[4]+pos[6])/2,
+01947                                 (pos[4]+pos[8])/2,
+01948                                 (pos[1]+pos[8])/2,
+01949                                 (pos[5]+pos[6])/2,
+01950                                 (pos[3]+pos[6])/2,
+01951                                 (pos[3]+pos[8])/2,
+01952                                 (pos[5]+pos[7])/2,
+01953                                 (pos[3]+pos[7])/2,
+01954                                 (pos[2]+pos[7])/2,
+01955                         };
+01956                         
+01957                         float interpolatedS[10]=
+01958                         {
+01959                                 (s0+s6)/2,
+01960                                 (s4+s6)/2,
+01961                                 (s4+s8)/2,
+01962                                 (s1+s8)/2,
+01963                                 (s5+s6)/2,
+01964                                 (s3+s6)/2,
+01965                                 (s3+s8)/2,
+01966                                 (s5+s7)/2,
+01967                                 (s3+s7)/2,
+01968                                 (s2+s7)/2,
+01969                         };
+01970                         
+01971                         float interpolatedT[10]=
+01972                         {
+01973                                 (t0+t6)/2,
+01974                                 (t4+t6)/2,
+01975                                 (t4+t8)/2,
+01976                                 (t1+t8)/2,
+01977                                 (t5+t6)/2,
+01978                                 (t3+t6)/2,
+01979                                 (t3+t8)/2,
+01980                                 (t5+t7)/2,
+01981                                 (t3+t7)/2,
+01982                                 (t2+t7)/2,
+01983                         };
+01984 
+01985                         static sint8 triangle[10][2][3]=
+01986                         {
+01987                                 {{0, 11, 6}, {0, 6, 9}},
+01988                                 {{9, 6, 4}, {4, 6, 14}},
+01989                                 {{4, 14, 8}, {4, 8, 10}},
+01990                                 {{10, 8, 1}, {-1, -1, -1}},
+01991                                 {{11, 5, 6}, {5, 13, 6}},
+01992                                 {{6, 13, 3}, {6, 3, 14}},
+01993                                 {{3, 8, 14}, {-1, -1, -1}},
+01994                                 {{5, 12, 7}, {5, 7, 13}},
+01995                                 {{7, 3, 13}, {-1, -1, -1}},
+01996                                 {{12, 2, 7}, {-1, -1, -1}}
+01997                         };
+01998 
+01999                         for (uint i=0; i<10; i++)
+02000                         {
+02001                                 uint s=(uint)((float)orderS*4*interpolatedS[i]);
+02002                                 uint t=(uint)((float)orderT*4*interpolatedT[i]);
+02003 
+02004                                 /*nlassert (s>=0);
+02005                                 nlassert (s<orderS*4);
+02006                                 nlassert (t>=0);
+02007                                 nlassert (t<orderT*4);*/
+02008 
+02009                                 if ((s>=0)&&(s<orderS*4)&&(t>=0)&&(t<orderT*4))
+02010                                 {
+02011                                         // Triangle index
+02012                                         uint index=s+t*orderS*4;
+02013 
+02014                                         // Ge tthe patch id
+02015                                         uint patchId=pPatch->getPatchId();
+02016 
+02017                                         // Get lumel array
+02018                                         vector<CLumelDescriptor> &lumels=_Lumels[patchId];
+02019 
+02020                                         // Visited
+02021                                         visited[patchId][index]++;
+02022 
+02023                                         // Position
+02024                                         lumels[index].Position+=interpolatedP[i];
+02025 
+02026                                         // Triangle
+02027                                         if (oversampling)
+02028                                         {
+02029                                                 // Triangle list
+02030                                                 CTriangleList *next=lumels[index].TriangleList;
+02031 
+02032                                                 // What triangle ?
+02033                                                 uint numTriangle;
+02034                                                 switch (i)
+02035                                                 {
+02036                                                 case 3:
+02037                                                 case 6:
+02038                                                 case 8:
+02039                                                 case 9:
+02040                                                         // Single triangle
+02041                                                         numTriangle=1;
+02042                                                         break;
+02043                                                 default:
+02044                                                         // Two triangles
+02045                                                         numTriangle=2;
+02046                                                         break;
+02047                                                 }
+02048 
+02049                                                 // Add triangles
+02050                                                 for (uint tri=0; tri<numTriangle; tri++)
+02051                                                 {
+02052                                                         // one triangle
+02053                                                         lumels[index].TriangleList=_TriangleListAllocateur.allocate ();
+02054                                                         lumels[index].TriangleList->Triangle=NLMISC::CTriangle (pos[triangle[i][tri][0]], pos[triangle[i][tri][1]], pos[triangle[i][tri][2]]);
+02055                                                         lumels[index].TriangleList->Next=next;
+02056                                                 }
+02057                                         }
+02058                                 }
+02059                         }
+02060                 }
+02061         }
+02062 
+02063         // *** Now, finalise patch informations for shadow source positions
+02064 
+02065         // For each patches
+02066         uint patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
+02067         uint patch;
+02068         for (patch=0; patch<patchCount; patch++)
+02069         {
+02070                 // Info
+02071                 progress ("Finalize lumel positions", (float)patch/(float)patchCount);
+02072 
+02073                 // *** Resize lumel array for this patch
+02074 
+02075                 // Get a patch pointer
+02076                 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(_ZoneToLight)))->getPatch (patch);
+02077                 uint orderS=pPatch->getOrderS();
+02078                 uint orderT=pPatch->getOrderT();
+02079 
+02080                 // Get lumel array
+02081                 vector<CLumelDescriptor> &lumels=_Lumels[patch];
+02082 
+02083                 // *** Compute an interpolated normal
+02084 
+02085                 // Renormalize
+02086                 nlassert (isPowerOf2 (orderS));
+02087                 nlassert (isPowerOf2 (orderT));
+02088                 uint powerS=getPowerOf2 (orderS);
+02089                 uint powerT=getPowerOf2 (orderT);
+02090                 uint lumelS=4<<powerS;
+02091                 uint lumelT=4<<powerT;
+02092 
+02093                 for (uint t=0; t<lumelT; t++)
+02094                 for (uint s=0; s<lumelS; s++)
+02095                 {
+02096                         // Lumel index
+02097                         uint lumelIndex=s+t*lumelS;
+02098 
+02099                         // *** Number of visit
+02100                         uint visitedCount=visited[patch][lumelIndex];
+02101                         
+02102                         // Some lumel have not been found in tesselation
+02103                         //nlassert ((visitedCount==1)||(visitedCount==2));
+02104 
+02105                         // If visited, renormalise other values
+02106                         if (visitedCount)
+02107                         {
+02108                                 // Normalise position
+02109                                 lumels[lumelIndex].Position/=(float)visitedCount;
+02110                         }
+02111 
+02112                         // Not visited for next pass
+02113                         visited[patch][lumelIndex]=false;
+02114                 }
+02115         }
+02116 
+02117         // *** Now tesselate this zone to shadow accuracy
+02118 
+02119         // Setup the landscape
+02120         landscape.setThreshold (0);
+02121         landscape.setTileMaxSubdivision (4);
+02122 
+02123         // Refine all
+02124         progress ("Refine landscape to lumels", 0.5f);
+02125         landscape.refineAll (CVector (0, 0, 0));
+02126 
+02127         // Get tesselated faces
+02128         leaves.clear ();
+02129         landscape.getTessellationLeaves(leaves);
+02130 
+02131         // Scan each leaves
+02132         leavesCount=leaves.size();
+02133         for (leave=0; leave<leavesCount; leave++)
+02134         {
+02135                 // Progress bar
+02136                 if ( (leave&0xff) == 0)
+02137                         progress ("Precompute tesselation", (float)leave/(float)leavesCount);
+02138 
+02139                 // Leave
+02140                 const CTessFace *face=leaves[leave];
+02141 
+02142                 // Get zone id
+02143                 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
+02144                 {
+02145                         // Get a patch pointer
+02146                         const CPatch* pPatch=face->Patch;
+02147 
+02148                         // Get order
+02149                         uint orderS=pPatch->getOrderS();
+02150                         uint orderT=pPatch->getOrderT();
+02151 
+02152                         // Coordinates
+02153                         float fS=(face->PVBase.getS()+face->PVLeft.getS()+face->PVRight.getS())/3.f;
+02154                         float fT=(face->PVBase.getT()+face->PVLeft.getT()+face->PVRight.getT())/3.f;
+02155                         uint s=(uint)((float)orderS*4*fS);
+02156                         uint t=(uint)((float)orderT*4*fT);
+02157                         nlassert (s>=0);
+02158                         nlassert (s<orderS*4);
+02159                         nlassert (t>=0);
+02160                         nlassert (t<orderT*4);
+02161 
+02162                         // Triangle index
+02163                         uint index=s+t*orderS*4;
+02164 
+02165                         // Ge tthe patch id
+02166                         uint patchId=pPatch->getPatchId();
+02167 
+02168                         // Get lumel array
+02169                         vector<CLumelDescriptor> &lumels=_Lumels[patchId];
+02170 
+02171                         // Visited
+02172                         visited[patchId][index]++;
+02173 
+02174                         // Lumel s and t
+02175                         lumels[index].S+=fS;
+02176                         lumels[index].T+=fT;
+02177 
+02178                         // Normal
+02179                         CPlane plane;
+02180                         plane.make (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos);
+02181                         lumels[index].Normal+=plane.getNormal();
+02182                 }
+02183         }
+02184 
+02185         // *** Now, finalise patch informations
+02186 
+02187         // For each patches
+02188         patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
+02189         for (patch=0; patch<patchCount; patch++)
+02190         {
+02191                 // Info
+02192                 progress ("Finalize patches", (float)patch/(float)patchCount);
+02193 
+02194                 // *** Resize lumel array for this patch
+02195 
+02196                 // Get a patch pointer
+02197                 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(_ZoneToLight)))->getPatch (patch);
+02198                 uint orderS=pPatch->getOrderS();
+02199                 uint orderT=pPatch->getOrderT();
+02200 
+02201                 // Get lumel array
+02202                 vector<CLumelDescriptor> &lumels=_Lumels[patch];
+02203 
+02204                 // *** Compute an interpolated normal
+02205 
+02206                 // Get pointer on arries
+02207                 vector<bool> &binded=_Binded[zoneNumber][patch];
+02208                 vector<CPatchUVLocator> &locator=_Locator[zoneNumber][patch];
+02209                 vector<CPatch::CBindInfo> &bindInfo=_BindInfo[zoneNumber][patch];
+02210                 CBezierPatch &bezierPatch=_BezierPatch[zoneNumber][patch];
+02211 
+02212                 // Renormalize
+02213                 nlassert (isPowerOf2 (orderS));
+02214                 nlassert (isPowerOf2 (orderT));
+02215                 uint powerS=getPowerOf2 (orderS);
+02216                 uint powerT=getPowerOf2 (orderT);
+02217                 uint lumelS=4<<powerS;
+02218                 uint lumelT=4<<powerT;
+02219 
+02220                 // Sample edge normal
+02221                 CVector normals[NL_MAX_TILES_BY_PATCH_EDGE*NL_LUMEL_BY_TILE+1][4];
+02222                 uint sFixed[4] = { 0, 0xffffffff, lumelS-1, 0xffffffff };
+02223                 uint tFixed[4] = { 0xffffffff, lumelT-1, 0xffffffff, 0 };
+02224                 float sOri[4] = { 0, -1, (float)lumelS, -1 };
+02225                 float tOri[4] = { -1, (float)lumelT, -1, 0 };
+02226                 for (uint edge=0; edge<4; edge++)
+02227                 {
+02228                         // s and t
+02229                         uint count=(edge&1)?lumelS:lumelT;
+02230                         for (uint lumel=0; lumel<=count; lumel++)
+02231                         {
+02232                                 // Start coordinates
+02233                                 float origineS;
+02234                                 float origineT;
+02235                                 uint startS;
+02236                                 uint startT;
+02237                                 if (edge&1)
+02238                                 {
+02239                                         if (lumel==count)
+02240                                                 startS=count-1;
+02241                                         else
+02242                                                 startS=lumel;
+02243                                         startT=tFixed[edge];
+02244                                         origineS=(float)lumel;
+02245                                         origineT=tOri[edge];
+02246                                 }
+02247                                 else
+02248                                 {
+02249                                         if (lumel==count)
+02250                                                 startT=count-1;
+02251                                         else
+02252                                                 startT=lumel;
+02253                                         startS=sFixed[edge];
+02254                                         origineT=(float)lumel;
+02255                                         origineS=sOri[edge];
+02256                                 }
+02257                                 _GetNormalNormal=CVector::Null;
+02258                                 set<uint64> visitedLumels;
+02259                                 getNormal (pPatch, startS, startT, locator, bindInfo, binded, visitedLumels, 
+02260                                         startS+0.5f-origineS, startT+0.5f-origineT, 0, bezierPatch);
+02261                                 _GetNormalNormal.normalize ();
+02262                                 normals[lumel][edge]=_GetNormalNormal;
+02263                         }
+02264 
+02265                         // Smooth the corners
+02266 #define BLUR_SIZE 4
+02267                         for (uint i=1; i<BLUR_SIZE; i++)
+02268                         {
+02269                                 float value=(float)i/BLUR_SIZE;
+02270                                 value=easineasout(value);
+02271                                 normals[i][edge]=normals[0][edge]*(1-value)+normals[i][edge]*value;
+02272                                 normals[i][edge].normalize();
+02273                                 normals[count-i][edge]=normals[count][edge]*(1-value)+normals[count-i][edge]*value;
+02274                                 normals[count-i][edge].normalize();
+02275                         }
+02276                 }
+02277                 
+02278                 for (uint t=0; t<lumelT; t++)
+02279                 for (uint s=0; s<lumelS; s++)
+02280                 {
+02281                         // Lumel index
+02282                         uint lumelIndex=s+t*lumelS;
+02283 
+02284                         // *** Calc the smoothed normal
+02285                         
+02286                         // For each edge
+02287                         CVector normalS=bezierPatch.evalNormal (((float)s+0.5f)/(float)lumelS, ((float)t+0.5f)/(float)lumelT);
+02288                         float sFactor=0;
+02289                         CVector normalT=normalS;
+02290                         float tFactor=0;
+02291                         bool sGood=false, tGood=false;
+02292                         if (s<BLUR_SIZE)
+02293                         {
+02294                                 sGood=true;
+02295                                 // Average the two normals
+02296                                 CVector average=normals[t][0];
+02297                                 average+=normals[t+1][0];
+02298                                 average/=2;
+02299 
+02300                                 // Blend
+02301                                 float value=s+0.5f;
+02302                                 sFactor=BLUR_SIZE-value;
+02303                                 value/=BLUR_SIZE;
+02304                                 value=easineasout(value);
+02305                                 normalS=(normalS*value+average*(1-value));
+02306                                 normalS.normalize();
+02307                         }
+02308                         if (s>=lumelS-BLUR_SIZE)
+02309                         {
+02310                                 sGood=true;
+02311                                 // Average the two normals
+02312                                 CVector average=normals[t][2];
+02313                                 average+=normals[t+1][2];
+02314                                 average/=2;
+02315 
+02316                                 // Blend
+02317                                 float value=s+0.5f;
+02318                                 sFactor=BLUR_SIZE-(lumelS-value);
+02319                                 value=(lumelS-value)/BLUR_SIZE;
+02320                                 value=easineasout(value);
+02321                                 normalS=(normalS*value+average*(1-value));
+02322                                 normalS.normalize();
+02323                         }
+02324                         if (t<BLUR_SIZE)
+02325                         {
+02326                                 tGood=true;
+02327                                 // Average the two normals
+02328                                 CVector average=normals[s][3];
+02329                                 average+=normals[s+1][3];
+02330                                 average/=2;
+02331 
+02332                                 // Blend
+02333                                 float value=t+0.5f;
+02334                                 tFactor=BLUR_SIZE-value;
+02335                                 value/=BLUR_SIZE;
+02336                                 value=easineasout(value);
+02337                                 normalT=(normalT*value+average*(1-value));
+02338                                 normalT.normalize();
+02339                         }
+02340                         if (t>=lumelT-BLUR_SIZE)
+02341                         {
+02342                                 tGood=true;
+02343                                 // Average the two normals
+02344                                 CVector average=normals[s][1];
+02345                                 average+=normals[s+1][1];
+02346                                 average/=2;
+02347 
+02348                                 // Blend
+02349                                 float value=t+0.5f;
+02350                                 tFactor=BLUR_SIZE-(lumelT-value);
+02351                                 value=((lumelT)-value)/BLUR_SIZE;
+02352                                 value=easineasout(value);
+02353                                 normalT=(normalT*value+average*(1-value));
+02354                                 normalT.normalize();
+02355                         }
+02356 
+02357                         // The smooth normal
+02358                         CVector smoothNormal;
+02359 
+02360                         if ((sGood)&&(tGood))
+02361                         {
+02362                                 if ((sFactor!=BLUR_SIZE)||(tFactor!=BLUR_SIZE))
+02363                                         smoothNormal=normalS*(BLUR_SIZE-tFactor)+normalT*(BLUR_SIZE-sFactor);
+02364                                 else
+02365                                         smoothNormal=normalS+normalT;
+02366                         }
+02367                         else if (sGood)
+02368                                 smoothNormal=normalS;
+02369                         else
+02370                                 smoothNormal=normalT;
+02371 
+02372                         // Normalize it
+02373                         smoothNormal.normalize();
+02374 
+02375                         // The pure normal
+02376                         CVector purNormal=bezierPatch.evalNormal (((float)s+0.5f)/(float)lumelS, ((float)t+0.5f)/(float)lumelT);
+02377 
+02378                         // Normalize the noisy normal
+02379                         lumels[lumelIndex].Normal.normalize();
+02380 
+02381                         // Final normal
+02382                         lumels[lumelIndex].Normal=lumels[lumelIndex].Normal-purNormal+smoothNormal;
+02383                         lumels[lumelIndex].Normal.normalize ();
+02384 
+02385                         // *** Number of visit
+02386                         uint visitedCount=visited[patch][lumelIndex];
+02387                         
+02388                         // Some lumel have not been found in tesselation
+02389                         //nlassert (visitedCount==2);
+02390 
+02391                         // If visited, renormalise other values
+02392                         if (visitedCount)
+02393                         {
+02394                                 // Normalise position
+02395                                 lumels[lumelIndex].S/=(float)visitedCount;
+02396                                 lumels[lumelIndex].T/=(float)visitedCount;
+02397                         }
+02398                 }
+02399         }
+02400 }
+02401 
+02402 // ***************************************************************************
+02403 
+02404 CZoneLighter::CLightDesc::CLightDesc ()
+02405 {
+02406         LightDirection.set (1, 1, -1);
+02407         GridSize=512;
+02408         GridCellSize=4;
+02409         HeightfieldSize=200;
+02410         HeightfieldCellSize=20;
+02411         SkyContribution=true;
+02412         SkyIntensity=0.25;
+02413         ShadowBias=0.5f;
+02414         SoftshadowBlurSize=1.f;
+02415         SoftshadowFallof=10.f;
+02416         SoftshadowShapeVertexCount=4;
+02417         Oversampling=OverSamplingx32;
+02418 }
+02419 
+02420 // ***************************************************************************
+02421 void CZoneLighter::addLightableShape(IShape *shape, const NLMISC::CMatrix& MT)
+02422 {
+02423         CShapeInfo lsi;
+02424         lsi.MT = MT;
+02425         lsi.Shape = shape;
+02426         _LightableShapes.push_back(lsi);
+02427 }
+02428 
+02429 
+02430 // ***************************************************************************
+02431 bool CZoneLighter::isLightableShape(IShape &shape)
+02432 {
+02434         if (dynamic_cast<CWaterShape *>(&shape) != NULL)
+02435         {
+02436                 // check that this water surface has a diffuse map that is a CTextureFile (we must be able to save it !)
+02437                 CWaterShape *ws = static_cast<CWaterShape *>(&shape);
+02438                 const ITexture *tex = ws->getColorMap();
+02439                 if (dynamic_cast<const CTextureFile *>(tex) != NULL)
+02440                 {
+02441                         return ws->isLightMappingEnabled();
+02442                 }
+02443         }
+02444         return false;
+02445 }
+02446 
+02447 // ***************************************************************************
+02448 void CZoneLighter::lightShapes(uint zoneID, const CLightDesc& description)
+02449 {
+02451         if (_LightableShapes.size() == 0) return;       
+02452 
+02453         uint numShapePerThread = 1 + (_LightableShapes.size() / _ProcessCount);
+02454         uint currShapeIndex = 0;
+02455         uint process = 0;
+02456         _ProcessExited = 0;
+02457 
+02458         _NumLightableShapesProcessed = 0;
+02459 
+02460 
+02461         progress("Processing lightable shapes", 0);
+02462         
+02463         for (uint k = 0; k < _LightableShapes.size(); ++k, ++process)
+02464         {
+02465                 uint lastShapeIndex = currShapeIndex + numShapePerThread;
+02466                 lastShapeIndex = std::min(_LightableShapes.size(), lastShapeIndex);             
+02467                 IThread *pThread = IThread::create (new CCalcLightableShapeRunnable(process, this, &description, &_LightableShapes, currShapeIndex, lastShapeIndex));
+02468                 pThread->start();
+02469                 currShapeIndex = lastShapeIndex;
+02470         }
+02471 
+02473         while (_ProcessExited != _ProcessCount)
+02474         {
+02475                 nlSleep (10);
+02476         }
+02477 
+02478 }
+02479 
+02480 
+02481 
+02482 // ***************************************************************************
+02483 
+02484 void CZoneLighter::processLightableShapeCalc (uint process,
+02485                                                                                           TShapeVect *shapesToLit,
+02486                                                                                           uint firstShape,
+02487                                                                                           uint lastShape,
+02488                                                                                           const CLightDesc& description)
+02489 {
+02490         CMultiShape *shapeArray=new CMultiShape;
+02491         CMultiShape *shapeArrayTmp=new CMultiShape;
+02492         shapeArray->Shapes.reserve (SHAPE_MAX);
+02493         shapeArrayTmp->Shapes.reserve (SHAPE_MAX);
+02494 
+02495         // for each lightable shape
+02496         for (uint k = firstShape; k < lastShape; ++k)
+02497         {               
+02498                 nlassert(isLightableShape(* (*shapesToLit)[k].Shape)); // make sure it is a lightable shape             
+02499                 lightSingleShape((*shapesToLit)[k], *shapeArray, *shapeArrayTmp, description, process); 
+02500         }
+02501 
+02502         delete shapeArray;
+02503         delete shapeArrayTmp;   
+02504 }
+02505 
+02506 
+02507 // ***************************************************************************
+02508 void CZoneLighter::lightSingleShape(CShapeInfo &si, CMultiShape &shape, CMultiShape &shapeTmp, const CLightDesc& description, uint cpu)
+02509 {
+02511         if (dynamic_cast<CWaterShape *>(si.Shape))
+02512         {
+02513                 lightWater(* static_cast<CWaterShape *>(si.Shape), si.MT, shape, shapeTmp, description, cpu);
+02514                 
+02515         }
+02516         ++_NumLightableShapesProcessed;
+02517         progress("Processing lightable shapes", (float) _NumLightableShapesProcessed / _LightableShapes.size());
+02518         return; 
+02519 }
+02520 
+02521 
+02522 
+02523 // ***************************************************************************
+02524 // utility function to get the directory of a fileName
+02525 static std::string getDir (const std::string& path)
+02526 {
+02527         char tmpPath[512];
+02528         strcpy (tmpPath, path.c_str());
+02529         char* slash=strrchr (tmpPath, '/');
+02530         if (!slash)
+02531         {
+02532                 slash=strrchr (tmpPath, '\\');
+02533         }
+02534 
+02535         if (!slash)
+02536                 return "";
+02537 
+02538         slash++;
+02539         *slash=0;
+02540         return tmpPath;
+02541 }
+02542 
+02543 
+02544 // ***************************************************************************
+02545 // utility function to get a file name fdrom a path
+02546 static std::string getName (const std::string& path)
+02547 {
+02548         std::string dir=getDir (path);
+02549 
+02550         char tmpPath[512];
+02551         strcpy (tmpPath, path.c_str());
+02552 
+02553         char *name=tmpPath;
+02554         nlassert (dir.length()<=strlen(tmpPath));
+02555         name+=dir.length();
+02556 
+02557         char* point=strrchr (name, '.');
+02558         if (point)
+02559                 *point=0;
+02560 
+02561         return name;
+02562 }
+02563 
+02564 
+02565 // ***************************************************************************
+02566 // utility function to get the extension of a fileName
+02567 static std::string getExt (const std::string& path)
+02568 {
+02569         std::string dir = getDir (path);
+02570         std::string name = getName (path);
+02571 
+02572         char tmpPath[512];
+02573         strcpy (tmpPath, path.c_str());
+02574 
+02575         char *ext=tmpPath;
+02576         nlassert (dir.length()+name.length()<=strlen(tmpPath));
+02577         ext+=dir.length()+name.length();
+02578 
+02579         return ext;
+02580 }
+02581 
+02582 
+02583 // ***************************************************************************
+02584 void CZoneLighter::lightWater(CWaterShape &ws, const CMatrix &MT, CMultiShape &shape, CMultiShape &shapeTmp, const CLightDesc& description, uint cpu)
+02585 {       
+02586         try
+02587         {       
+02589                 CTextureFile *diffuseTex = NLMISC::safe_cast<CTextureFile *>(ws.getColorMap());
+02590                 std::string texFileName = CPath::lookup(diffuseTex->getFileName());
+02591                 diffuseTex->generate();
+02592                 const uint width = diffuseTex->getWidth();
+02593                 const uint height = diffuseTex->getHeight();    
+02594                 
+02596                 NLMISC::CMatrix worldSpaceToUVs;
+02597                 NLMISC::CVector2f col0, col1, pos;
+02598                 ws.getColorMapMat(col0, col1, pos);
+02599                 worldSpaceToUVs.setRot(NLMISC::CVector(col0.x * width, col0.y * height, 0),
+02600                                                            NLMISC::CVector(col1.x * width, col1.y * height, 0),
+02601                                                            NLMISC::CVector::K);
+02602                 worldSpaceToUVs.setPos(NLMISC::CVector(pos.x * width, pos.y * height, 0));              
+02603 
+02605                 NLMISC::CPolygon p;
+02606                 ws.getShapeInWorldSpace(p);
+02607 
+02608                 float minU, maxU;
+02609                 float minV, maxV;
+02610 
+02611                 NLMISC::CVector uvs = worldSpaceToUVs * p.Vertices[0];
+02612                 minU = maxU = uvs.x;
+02613                 minV = maxV = uvs.y;
+02614 
+02615 
+02616                 for (uint k = 1; k < (uint) p.getNumVertices(); ++k)
+02617                 {
+02618                         uvs = worldSpaceToUVs * p.Vertices[k];
+02619                         minU = std::min(uvs.x, minU);
+02620                         minV = std::min(uvs.y, minV);
+02621                         maxU = std::max(uvs.x, maxU);
+02622                         maxV = std::max(uvs.y, maxV);   
+02623                 }
+02624                 
+02625                 
+02626         
+02627 
+02628                 sint iMinU = (sint) minU;
+02629                 sint iMaxU = (sint) maxU;
+02630                 sint iMinV = (sint) minV;
+02631                 sint iMaxV = (sint) maxV;
+02632 
+02633                 NLMISC::clamp(iMinU, 0, (sint) width);
+02634                 NLMISC::clamp(iMaxU, 0, (sint) width);
+02635                 NLMISC::clamp(iMinV, 0, (sint) height);
+02636                 NLMISC::clamp(iMaxV, 0, (sint) height);
+02637 
+02638                 // matrix to go from uv space to worldspace
+02639                 NLMISC::CMatrix UVSpaceToWorldSpace = worldSpaceToUVs.inverted();
+02640 
+02641                 std::vector<uint8> &pixs8 = diffuseTex->getPixels();
+02642                 NLMISC::CRGBA *rgbPixs = (NLMISC::CRGBA *) &pixs8[0];
+02643 
+02644         
+02646                 for (sint x = iMinU; x < iMaxU; ++x)
+02647                 {
+02648                         for (sint y = iMinV; y < iMaxV; ++y)
+02649                         {
+02650                                 float factor;
+02651                                 NLMISC::CVector pos = UVSpaceToWorldSpace * NLMISC::CVector( x + 0.5f, y + 0.5f, 0 ) 
+02652                                         + description.WaterShadowBias * NLMISC::CVector::K;
+02653                                 if (description.Shadow)
+02654                                 {
+02655                                         rayTrace(pos, NLMISC::CVector::K, 0, 0, -1, factor, shape, shapeTmp, cpu);
+02656                                 }
+02657                                 else
+02658                                 {
+02659                                         factor = - NLMISC::CVector::K * description.LightDirection;
+02660                                 }
+02661                                 clamp(factor, 0.f, 1.f);
+02662                                 factor = factor * description.WaterDiffuse + description.WaterAmbient;
+02663                                 if (description.SkyContributionForWater)
+02664                                 {
+02665                                         factor += getSkyContribution(pos, NLMISC::CVector::K, description.SkyIntensity);
+02666                                 }
+02667                                 clamp(factor, 0.f, 1.f);
+02668                                 uint intensity = (uint8) (255 * factor);
+02669                                 NLMISC::CRGBA srcCol(intensity,
+02670                                                                          intensity,
+02671                                                                          intensity,
+02672                                                                           255);
+02673 
+02674                                 if (!description.ModulateWaterColor)
+02675                                 {
+02676                                         rgbPixs[x + y * width] = srcCol;
+02677                                 }
+02678                                 else
+02679                                 {
+02680                                         NLMISC::CRGBA &col = rgbPixs[x + y * width];
+02681                                         col.modulateFromColor(col, srcCol);
+02682                                 }
+02683                         }
+02684                 }
+02685         
+02687                 if (getExt(texFileName) != ".tga")
+02688                 {
+02689                         nlwarning("Zone lighter : error when lighting a water surface : input bitmap is not a tga file");
+02690                 }
+02691                 else
+02692                 {
+02693                         try
+02694                         {
+02695                                 COFile of;
+02696                                 of.open(texFileName);
+02697                                 diffuseTex->writeTGA(of, 24);
+02698                                 of.close();
+02699                         }
+02700                         catch (NLMISC::Exception &)
+02701                         {
+02702                                 nlwarning("Zone lighter : while lighting a water shape, writing %s failed! ", texFileName.c_str());
+02703                         }
+02704                 }
+02705         }
+02706         catch(NLMISC::Exception &e)
+02707         {
+02708                 nlwarning("Water shape lighting failed !");
+02709                 nlwarning(e.what());
+02710         }
+02711 }
+02712 
+02714 void CZoneLighter::addWaterShape(CWaterShape *shape, const NLMISC::CMatrix &MT)
+02715 {
+02717         CShapeInfo ci;
+02718         ci.Shape = shape;
+02719         ci.MT = MT;
+02720         _WaterShapes.push_back(ci);
+02721 }
+02722 
+02724 void CZoneLighter::makeQuadGridFromWaterShapes(NLMISC::CAABBox zoneBBox)
+02725 {
+02726         if (!_WaterShapes.size()) return;
+02727 
+02728         NLMISC::CAABBox tmpBox;
+02729 
+02731         const uint numCells = 16;
+02732 
+02734         float width  = zoneBBox.getMax().x - zoneBBox.getMin().x;
+02735         float height = zoneBBox.getMax().y - zoneBBox.getMin().y;
+02736 
+02737         float dim = std::max(width, height);
+02738 
+02739 
+02741         _WaterShapeQuadGrid.create(numCells, dim / numCells);
+02742         
+02743 
+02744         uint count = 0, totalCount = _WaterShapes.size();
+02745 
+02747         for (TShapeVect::iterator it = _WaterShapes.begin(); it != _WaterShapes.end(); ++it, ++count)
+02748         {
+02750                 it->Shape->getAABBox(tmpBox);
+02751                 NLMISC::CAABBox currBB = NLMISC::CAABBox::transformAABBox(it->MT, tmpBox);
+02752 
+02754                 if (zoneBBox.intersect(currBB))
+02755                 {
+02756                         _WaterShapeQuadGrid.insert(currBB.getMin(), currBB.getMax(), NLMISC::safe_cast<CWaterShape *>(it->Shape));
+02757                 }
+02758                 progress("Building quadtree from water surfaces", (float) count / totalCount);
+02759         }
+02760 
+02762         NLMISC::contReset(_WaterShapes);
+02763 }
+02764 
+02765 
+02766 //==================================================================
+02767 
+02769 struct CTileOfPatch
+02770 {
+02771         uint8           TileId;
+02772         CPatch          *Patch;
+02773         CTileOfPatch();
+02774         CTileOfPatch(uint8 tileId, CPatch *patch) : TileId(tileId), Patch(patch)
+02775         {               
+02776         }       
+02777 };
+02778 
+02779 
+02780 
+02781 // ***************************************************************************
+02782 // ***************************************************************************
+02783 // Static point lights.
+02784 // ***************************************************************************
+02785 // ***************************************************************************
+02786 
+02787 
+02788 // ***************************************************************************
+02789 CZoneLighter::CPointLightRT::CPointLightRT()
+02790 {
+02791         RefCount= 0;
+02792 }
+02793 
+02794 
+02795 // ***************************************************************************
+02796 bool    CZoneLighter::CPointLightRT::testRaytrace(const CVector &v)
+02797 {
+02798         CVector dummy;
+02799 
+02800         if(!BSphere.include(v))
+02801                 return false;
+02802 
+02803         // If Ambient light, just skip
+02804         if(PointLight.getType()== CPointLight::AmbientLight)
+02805                 return false;
+02806 
+02807         // If SpotLight verify in angle radius.
+02808         if(PointLight.getType()== CPointLight::SpotLight)
+02809         {
+02810                 float   att= PointLight.computeLinearAttenuation(v);
+02811                 if (att==0)
+02812                         return false;
+02813         }
+02814 
+02815         // Select in the cubeGrid
+02816         FaceCubeGrid.select(v);
+02817         // For all faces selected
+02818         while(!FaceCubeGrid.isEndSel())
+02819         {
+02820                 const CTriangle *tri= FaceCubeGrid.getSel();
+02821 
+02822                 // If intersect, the point is occluded.
+02823                 if( tri->Triangle.intersect(BSphere.Center, v, dummy, tri->getPlane()) )
+02824                         return false;
+02825 
+02826                 // next
+02827                 FaceCubeGrid.nextSel();
+02828         }
+02829 
+02830         // Ok the point is visilbe from the light
+02831         return true;
+02832 }
+02833 
+02834 
+02835 // ***************************************************************************
+02836 void                    CZoneLighter::addStaticPointLight(const CPointLightNamed &pln)
+02837 {
+02838         // build the plRT.
+02839         CPointLightRT   plRT;
+02840         plRT.PointLight= pln;
+02841         // compute plRT.OODeltaAttenuation
+02842         plRT.OODeltaAttenuation= pln.getAttenuationEnd() - pln.getAttenuationBegin();
+02843         if(plRT.OODeltaAttenuation <=0 )
+02844                 plRT.OODeltaAttenuation= 0;
+02845         else
+02846                 plRT.OODeltaAttenuation= 1.0f / plRT.OODeltaAttenuation;
+02847         // compute plRT.BSphere
+02848         plRT.BSphere.Center= pln.getPosition();
+02849         plRT.BSphere.Radius= pln.getAttenuationEnd();
+02850         // NB: FaceCubeGrid will be computed during light()
+02851 
+02852         // add the plRT
+02853         _StaticPointLights.push_back(plRT);
+02854 
+02855 }
+02856 
+02857 
+02858 // ***************************************************************************
+02859 void                    CZoneLighter::compilePointLightRT(uint gridSize, float gridCellSize, std::vector<CTriangle>& obstacles, bool doShadow)
+02860 {
+02861         uint    i;
+02862 
+02863         // Fill the quadGrid of Lights.
+02864         // ===========
+02865         _StaticPointLightQuadGrid.create(gridSize, gridCellSize);
+02866         for(i=0; i<_StaticPointLights.size();i++)
+02867         {
+02868                 CPointLightRT   &plRT= _StaticPointLights[i];
+02869 
+02870                 // Compute the bbox of the light
+02871                 CAABBox         bbox;
+02872                 bbox.setCenter(plRT.BSphere.Center);
+02873                 float   hl= plRT.BSphere.Radius;
+02874                 bbox.setHalfSize(CVector(hl,hl,hl));
+02875 
+02876                 // Insert the pointLight in the quadGrid.
+02877                 _StaticPointLightQuadGrid.insert(bbox.getMin(), bbox.getMax(), &plRT);
+02878         }
+02879 
+02880 
+02881         // Append triangles to cubeGrid ??
+02882         if(doShadow)
+02883         {
+02884                 // For all obstacles, Fill a quadGrid.
+02885                 // ===========
+02886                 CQuadGrid<CTriangle*>   obstacleGrid;
+02887                 obstacleGrid.create(gridSize, gridCellSize);
+02888                 uint    size= obstacles.size();
+02889                 for(i=0; i<size; i++)
+02890                 {
+02891                         // bbox of triangle
+02892                         CAABBox bbox;
+02893                         bbox.setCenter(obstacles[i].Triangle.V0);
+02894                         bbox.extend(obstacles[i].Triangle.V1);
+02895                         bbox.extend(obstacles[i].Triangle.V2);
+02896                         // insert triangle in quadGrid.
+02897                         obstacleGrid.insert(bbox.getMin(), bbox.getMax(), &obstacles[i]);
+02898                 }
+02899 
+02900 
+02901                 // For all PointLights, fill his CubeGrid
+02902                 // ===========
+02903                 for(i=0; i<_StaticPointLights.size();i++)
+02904                 {
+02905                         // progress
+02906                         progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
+02907 
+02908                         CPointLightRT   &plRT= _StaticPointLights[i];
+02909                         // Create the cubeGrid
+02910                         plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE);
+02911 
+02912                         // AmbiantLIghts: do nothing.
+02913                         if(plRT.PointLight.getType()!=CPointLight::AmbientLight)
+02914                         {
+02915                                 // Select only obstacle Faces around the light. Other are not usefull
+02916                                 CAABBox bbox;
+02917                                 bbox.setCenter(plRT.PointLight.getPosition());
+02918                                 float   hl= plRT.PointLight.getAttenuationEnd();
+02919                                 bbox.setHalfSize(CVector(hl,hl,hl));
+02920                                 obstacleGrid.select(bbox.getMin(), bbox.getMax());
+02921 
+02922                                 // For all faces, fill the cubeGrid.
+02923                                 CQuadGrid<CTriangle*>::CIterator        itObstacle;
+02924                                 itObstacle= obstacleGrid.begin();
+02925                                 while( itObstacle!=obstacleGrid.end() )
+02926                                 {
+02927                                         CTriangle       &tri= *(*itObstacle);
+02928                                         // Test BackFace culling. Only faces which are BackFace the point light are inserted.
+02929                                         // This is to avoid AutoOccluding problems
+02930                                         if( tri.getPlane() * plRT.BSphere.Center < 0)
+02931                                         {
+02932                                                 // Insert the triangle in the CubeGrid
+02933                                                 plRT.FaceCubeGrid.insert( tri.Triangle, &tri);
+02934                                         }
+02935 
+02936                                         itObstacle++;
+02937                                 }
+02938                         }
+02939 
+02940                         // Compile the CubeGrid.
+02941                         plRT.FaceCubeGrid.compile();
+02942 
+02943                         // And Reset RefCount.
+02944                         plRT.RefCount= 0;
+02945                 }
+02946         }
+02947         // else, just build empty grid
+02948         else
+02949         {
+02950                 for(i=0; i<_StaticPointLights.size();i++)
+02951                 {
+02952                         // progress
+02953                         progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
+02954 
+02955                         CPointLightRT   &plRT= _StaticPointLights[i];
+02956                         // Create a dummy empty cubeGrid => no rayTrace :)
+02957                         plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), 4);
+02958 
+02959                         // Compile the CubeGrid.
+02960                         plRT.FaceCubeGrid.compile();
+02961 
+02962                         // And Reset RefCount.
+02963                         plRT.RefCount= 0;
+02964                 }
+02965         }
+02966 
+02967 }
+02968 
+02969 
+02970 // ***************************************************************************
+02971 bool    CZoneLighter::CPredPointLightToPoint::operator() (CPointLightRT *pla, CPointLightRT *plb) const
+02972 {
+02973         float   ra= (pla->BSphere.Center - Point).norm();
+02974         float   rb= (plb->BSphere.Center - Point).norm();
+02975         float   infA= (pla->PointLight.getAttenuationEnd() - ra) * pla->OODeltaAttenuation;
+02976         float   infB= (plb->PointLight.getAttenuationEnd() - rb) * plb->OODeltaAttenuation;
+02977         // return which light impact the most.
+02978         // If same impact
+02979         if(infA==infB)
+02980                 // return nearest
+02981                 return ra < rb;
+02982         else
+02983                 // return better impact
+02984                 return  infA > infB;
+02985 }
+02986 
+02987 // ***************************************************************************
+02988 void                    CZoneLighter::processZonePointLightRT(vector<CPointLightNamed> &listPointLight)
+02989 {
+02990         uint    i;
+02991         vector<CPointLightRT*>          lightInfs;
+02992         lightInfs.reserve(1024);
+02993 
+02994         // clear result list
+02995         listPointLight.clear();
+02996 
+02997         // zoneToLight
+02998         CZone   *zoneToLight= _Landscape->getZone(_ZoneToLight);
+02999         if(!zoneToLight)
+03000                 return;
+03001 
+03002         // Build patchForPLs
+03003         //===========
+03004         vector<CPatchForPL>             patchForPLs;
+03005         patchForPLs.resize(_PatchInfo.size());
+03006         for(i=0; i<patchForPLs.size(); i++)
+03007         {
+03008                 // Get OrderS/OrderT
+03009                 patchForPLs[i].OrderS= _PatchInfo[i].OrderS;
+03010                 patchForPLs[i].OrderT= _PatchInfo[i].OrderT;
+03011                 // resize TileLightInfluences
+03012                 uint    w= patchForPLs[i].WidthTLI= patchForPLs[i].OrderS/2 +1 ;
+03013                 uint    h= patchForPLs[i].HeightTLI= patchForPLs[i].OrderT/2 +1;
+03014                 patchForPLs[i].TileLightInfluences.resize(w*h);
+03015         }
+03016 
+03017 
+03018         // compute each TileLightInfluence
+03019         //===========
+03020         for(i=0; i<patchForPLs.size(); i++)
+03021         {
+03022                 // progress
+03023                 progress ("Compute Influences of PointLights", 0.5f + 0.5f*i / (float)patchForPLs.size());
+03024 
+03025                 CPatchForPL             &pfpl= patchForPLs[i];
+03026                 const CPatch    *patch= const_cast<const CZone*>(zoneToLight)->getPatch(i);
+03027 
+03028                 uint    x, y;
+03029                 for(y= 0; y<pfpl.HeightTLI; y++)
+03030                 {
+03031                         for(x= 0; x<pfpl.WidthTLI; x++)
+03032                         {
+03033                                 // compute the point and normal (normalized) where the TLI lies.
+03034                                 //---------
+03035                                 CVector         pos, normal;
+03036                                 float           s, t;
+03037                                 s= (float)x / (pfpl.WidthTLI-1);
+03038                                 t= (float)y / (pfpl.HeightTLI-1);
+03039                                 // Compute the Vertex, with Noise information (important for accurate raytracing).
+03040                                 pos= patch->computeVertex(s, t);
+03041                                 // Use UnNoised normal from BezierPatch, because the lighting does not need to be so precise.
+03042                                 CBezierPatch    *bp= patch->unpackIntoCache();
+03043                                 normal= bp->evalNormal(s, t);
+03044                                 
+03045 
+03046                                 // Compute Which light influences him.
+03047                                 //---------
+03048                                 lightInfs.clear();
+03049                                 // Search possible lights around the position.
+03050                                 _StaticPointLightQuadGrid.select(pos, pos);
+03051                                 // For all of them, get the ones which touch this point.
+03052                                 CQuadGrid<CPointLightRT*>::CIterator    it= _StaticPointLightQuadGrid.begin();
+03053                                 while(it != _StaticPointLightQuadGrid.end())
+03054                                 {
+03055                                         CPointLightRT   *pl= *it;
+03056 
+03057                                         // a light influence a TLI only if this one is FrontFaced to the light !!
+03058                                         if( ( pl->BSphere.Center - pos ) * normal > 0)
+03059                                         {
+03060                                                 // Add 5cm else it fails in some case where ( pl->BSphere.Center - pos ) * normal is 
+03061                                                 // nearly 0 and the point should be occluded.
+03062                                                 const float     deltaY= 0.05f;
+03063                                                 CVector posToRT= pos + normal * deltaY;
+03064                                                 // Test if really in the radius of the light, if no occlusion, and if in SpotAngle
+03065                                                 if( pl->testRaytrace(posToRT) )
+03066                                                 {
+03067                                                         // Ok, add the light to the lights which influence the TLI 
+03068                                                         lightInfs.push_back(pl);
+03069                                                 }
+03070                                         }
+03071 
+03072                                         // next
+03073                                         it++;
+03074                                 }
+03075 
+03076                                 // Choose the Best ones.
+03077                                 //---------
+03078                                 CPredPointLightToPoint  predPLTP;
+03079                                 predPLTP.Point= pos;
+03080                                 // sort.
+03081                                 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
+03082                                 // truncate.
+03083                                 lightInfs.resize( min(lightInfs.size(), (uint)CTileLightInfluence::NumLightPerCorner) );
+03084 
+03085 
+03086                                 // For each of them, fill TLI
+03087                                 //---------
+03088                                 CTileLightInfUnpack             tli;
+03089                                 uint                                    lightInfId;
+03090                                 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
+03091                                 {
+03092                                         CPointLightRT   *pl= lightInfs[lightInfId];
+03093 
+03094                                         // copy light.
+03095                                         tli.Light[lightInfId]= pl;
+03096                                         // Compute light Diffuse factor.
+03097                                         CVector         dir= pl->BSphere.Center - pos;
+03098                                         dir.normalize();
+03099                                         tli.LightFactor[lightInfId]= dir * normal;
+03100                                         clamp(tli.LightFactor[lightInfId], 0.f, 1.f);
+03101                                         // modulate by light attenuation.
+03102                                         tli.LightFactor[lightInfId]*= pl->PointLight.computeLinearAttenuation(pos);
+03103 
+03104                                         // Inc RefCount of the light.
+03105                                         pl->RefCount++;
+03106                                 }
+03107                                 // Reset any empty slot to NULL.
+03108                                 for(; lightInfId<CTileLightInfluence::NumLightPerCorner; lightInfId++)
+03109                                 {
+03110                                         tli.Light[lightInfId]= NULL;
+03111                                 }
+03112 
+03113 
+03114                                 // Set TLI in patch.
+03115                                 //---------
+03116                                 pfpl.TileLightInfluences[y*pfpl.WidthTLI + x]= tli;
+03117                         }
+03118                 }
+03119         }
+03120 
+03121 
+03122         // compress and setup _PatchInfo with compressed data.
+03123         //===========
+03124         uint    plId= 0;
+03125         // Process each pointLights
+03126         for(i=0; i<_StaticPointLights.size(); i++)
+03127         {
+03128                 CPointLightRT   &plRT= _StaticPointLights[i];
+03129                 // If this light is used.
+03130                 if(plRT.RefCount > 0)
+03131                 {
+03132                         // Must Copy it into Zone.
+03133                         listPointLight.push_back(plRT.PointLight);
+03134                         plRT.DstId= plId++;
+03135                         // If index >= 255, too many lights (NB: => because 255 is a NULL code).
+03136                         if(plId>=0xFF)
+03137                         {
+03138                                 throw Exception("Too many Static Point Lights influence the zone!!");
+03139                         }
+03140                 }
+03141         }
+03142 
+03143         // For each patch, compress TLI in PatchInfo.
+03144         for(i=0; i<patchForPLs.size(); i++)
+03145         {
+03146                 CPatchForPL             &pfpl= patchForPLs[i];
+03147                 CPatchInfo              &pInfo= _PatchInfo[i];
+03148 
+03149                 uint    w= pfpl.WidthTLI;
+03150                 uint    h= pfpl.HeightTLI;
+03151 
+03152                 // Fill  pInfo.TileLightInfluences
+03153                 pInfo.TileLightInfluences.resize(w*h);
+03154                 uint    x, y;
+03155                 for(y= 0; y<h; y++)
+03156                 {
+03157                         for(x= 0; x<w; x++)
+03158                         {
+03159                                 uint    tliId= y*w + x;
+03160                                 // For all light slot
+03161                                 for(uint lightId= 0; lightId<CTileLightInfluence::NumLightPerCorner; lightId++)
+03162                                 {
+03163                                         CTileLightInfUnpack             &tliSrc= pfpl.TileLightInfluences[tliId];
+03164                                         CTileLightInfluence             &tliDst= pInfo.TileLightInfluences[tliId];
+03165                                         if(tliSrc.Light[lightId] == NULL)
+03166                                         {
+03167                                                 // Mark as unused.
+03168                                                 tliDst.Light[lightId]= 0xFF;
+03169                                         }
+03170                                         else
+03171                                         {
+03172                                                 // Get index.
+03173                                                 tliDst.Light[lightId]= tliSrc.Light[lightId]->DstId;
+03174                                                 // Get Diffuse Factor.
+03175                                                 tliDst.setDiffuseLightFactor(lightId, (uint8)(tliSrc.LightFactor[lightId]*255));
+03176                                         }
+03177                                 }
+03178                         }
+03179                 }
+03180 
+03181         }
+03182 
+03183 }
+03184 
+03187 // TileFlagsForPositionTowardWater
+03190 
+03191 
+03192 //==================================================================
+03194 static inline bool operator < (const CTileOfPatch &lhs, const CTileOfPatch &rhs)
+03195 {
+03196         return lhs.Patch == rhs.Patch  ?
+03197                    lhs.TileId < rhs.TileId :
+03198                    lhs.Patch  < rhs.Patch;      
+03199 };
+03200 
+03202 typedef std::map<CTileOfPatch, NLMISC::CAABBox> TTileOfPatchMap;
+03203 
+03205 void CZoneLighter::computeTileFlagsForPositionTowardWater(const CLightDesc &lightDesc,
+03206                                                                                                                   std::vector<const CTessFace*> &tessFaces                                                                                                                
+03207                                                                                                                   )
+03208 {       
+03209         uint numTileAbove     = 0;
+03210         uint numTileBelow     = 0;
+03211         uint numTileIntersect = 0;
+03212         
+03214         TTileOfPatchMap tiles;
+03215 
+03217         //  First, build the bbox for all tiles  //
+03219 
+03220         uint triCount = 0, totalTriCount = tessFaces.size();    
+03221 
+03222         nlinfo("Dealing with %d tessFaces", tessFaces.size());
+03223         for (std::vector<const CTessFace*>::iterator it = tessFaces.begin(); it != tessFaces.end(); ++it, ++triCount)
+03224         {
+03226                 if ((*it)->Patch->getZone()->getZoneId() != _ZoneToLight) continue;
+03228                 if ((*it)->Patch->Tiles[(*it)->TileId].getVegetableState() == CTileElement::VegetableDisabled)
+03229                         continue;
+03230 
+03231                 CTileOfPatch top((*it)->TileId, (*it)->Patch);
+03232                 TTileOfPatchMap::iterator tileIt = tiles.find(top);
+03233 
+03235                 if (tileIt == tiles.end()) // first time ?
+03236                 {
+03238                         NLMISC::CAABBox b;
+03239                         b.setMinMax((*it)->VBase->EndPos, (*it)->VLeft->EndPos);
+03240                         b.extend((*it)->VRight->EndPos);
+03241                         b.extend(b.getMax() + lightDesc.VegetableHeight * NLMISC::CVector::K); // adds vegetable height                 
+03242                         tiles[top] = b;
+03243                 }
+03244                 else // extends the bbox with the given face
+03245                 {
+03246                         NLMISC::CAABBox &b = tileIt->second;                    
+03247                         b.extend((*it)->VBase->EndPos);
+03248                         b.extend((*it)->VRight->EndPos);
+03249                         b.extend((*it)->VLeft->EndPos);
+03250                 }
+03251 
+03252                 if ((triCount % 100) == 0)
+03253                 {
+03254                         progress("Building bbox from tiles", (float) triCount / totalTriCount);
+03255                 }
+03256         }
+03257 
+03258         progress("Building bbox from tiles", 1.f);
+03259 
+03260 
+03261 
+03263         // Now, check each tile bbox against water shapes //
+03265         NLMISC::CPolygon   waterPoly;
+03266         NLMISC::CPolygon2D tilePoly;
+03267         tilePoly.Vertices.resize(4);
+03268 
+03269         uint tileCount = 0, totalTileCount = tiles.size();      
+03270 
+03271         for (TTileOfPatchMap::iterator tileIt = tiles.begin(); tileIt != tiles.end(); ++tileIt, ++tileCount)
+03272         {
+03273                 const NLMISC::CVector v0 = tileIt->second.getMin();
+03274                 const NLMISC::CVector v1 = tileIt->second.getMax();
+03275 
+03277                 tilePoly.Vertices[0].set(v0.x, v0.y); 
+03278                 tilePoly.Vertices[1].set(v1.x, v0.y); 
+03279                 tilePoly.Vertices[2].set(v1.x, v1.y); 
+03280                 tilePoly.Vertices[3].set(v0.x, v1.y); 
+03281 
+03283                 _WaterShapeQuadGrid.clearSelection();
+03284                 _WaterShapeQuadGrid.select(tileIt->second.getMin(), tileIt->second.getMax());
+03285 
+03286                 CTileElement &te = tileIt->first.Patch->Tiles[tileIt->first.TileId]; // alias to the current tile element
+03287 
+03289                 TWaterShapeQuadGrid::CIterator qgIt;
+03290                 for (qgIt = _WaterShapeQuadGrid.begin(); qgIt != _WaterShapeQuadGrid.end(); ++qgIt)
+03291                 {
+03292                         
+03293                         (*qgIt)->getShapeInWorldSpace(waterPoly);
+03294                         NLMISC::CPolygon2D poly(waterPoly);
+03295                         if (poly.intersect(tilePoly)) // above or below a water surface ?               
+03296                         {
+03298                                 float waterHeight = waterPoly.Vertices[0].z;
+03299 
+03300                                 if (v1.z < waterHeight)
+03301                                 {
+03302                                         // below
+03303                                         te.setVegetableState(CTileElement::UnderWater);
+03304                                         //nlassert(te.getVegetableState() == CTileElement::UnderWater);
+03305                                         ++ numTileBelow;
+03306                                 }
+03307                                 else if (v0. z > waterHeight)
+03308                                 {
+03309                                         // above
+03310                                         te.setVegetableState(CTileElement::AboveWater);
+03311                                         //nlassert(te.getVegetableState() == CTileElement::AboveWater);
+03312                                         ++ numTileAbove;
+03313                                 }
+03314                                 else
+03315                                 {
+03316                                         // intersect water
+03317                                         te.setVegetableState(CTileElement::IntersectWater);
+03318                                         //nlassert(te.getVegetableState() == CTileElement::IntersectWater);
+03319                                         ++ numTileIntersect;
+03320                                 }
+03321                                 break;
+03322                         }
+03323                 }
+03324 
+03325                 if (qgIt == _WaterShapeQuadGrid.end()) // no intersection found ? if yes it's above water
+03326                 {
+03327                         te.setVegetableState(CTileElement::AboveWater); 
+03328                         //nlassert(te.getVegetableState() == CTileElement::AboveWater);
+03329                         ++ numTileAbove;
+03330                 }
+03331 
+03332                 if ((tileCount % 50) == 0)
+03333                 {
+03334                         progress("Computing tile position towards water", (float) tileCount / totalTileCount);
+03335                 }
+03336         }
+03337 
+03338         progress("Computing tile position towards water", 1.f);
+03339 
+03340         nlinfo(" %d tiles are above water.", numTileAbove);
+03341         nlinfo(" %d tiles are below water.", numTileBelow);
+03342         nlinfo(" %d tiles intersect water.", numTileIntersect);
+03343 
+03344 
+03345 
+03347         NLMISC::contReset(_WaterShapeQuadGrid);
+03348 }
+03349 
+03351 void CZoneLighter::setTileFlagsToDefault(std::vector<const CTessFace*> &tessFaces)
+03352 {
+03354         for (std::vector<const CTessFace*>::iterator it = tessFaces.begin(); it != tessFaces.end(); ++it)
+03355         {
+03356                 if ((*it)->Patch->getZone()->getZoneId() != _ZoneToLight) continue;
+03357                 CTileElement &te = (*it)->Patch->Tiles[(*it)->TileId];
+03358                 if (te.getVegetableState() != CTileElement::VegetableDisabled)
+03359                 {
+03360                         te.setVegetableState(CTileElement::AboveWater);
+03361                 }
+03362         }
+03363 }
+03364 
+03365 
+03367 uint CZoneLighter::getAPatch (uint process)
+03368 {
+03369         // Accessor
+03370         CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
+03371 
+03372         // Current index
+03373         uint index = _LastPatchComputed[process];
+03374         uint firstIndex = index;
+03375 
+03376         if (access.value().size() == 0)
+03377                 // no more patches
+03378                 return 0xffffffff;
+03379 
+03380         while (access.value()[index])
+03381         {
+03382                 // Next patch
+03383                 index++;
+03384 
+03385                 // First ?
+03386                 if (firstIndex == index)
+03387                         // no more patches
+03388                         return 0xffffffff;
+03389 
+03390                 // Last patch ?
+03391                 if (index == _PatchInfo.size())
+03392                         index = 0;
+03393         }
+03394 
+03395         // Visited
+03396         access.value()[index] = true;
+03397 
+03398         // Last index
+03399         _LastPatchComputed[process] = index;
+03400         _NumberOfPatchComputed++;
+03401 
+03402         // Print
+03403         progress ("Lighting patches", (float)_NumberOfPatchComputed/(float)_PatchInfo.size());
+03404 
+03405         // Return the index
+03406         return index;
+03407 }
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1