# 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 }