zone_lighter.cpp

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

Generated on Thu Jan 7 08:26:32 2010 for NeL by  doxygen 1.6.1