00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026
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
00066
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
00078 #define NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE 16
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 inline float easineasout(float x)
00155 {
00156 float y;
00157
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
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
00200
00201
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
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
00250 for (uint i=0; i<8; i++)
00251 {
00252
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
00259 float fPhi=(float)((Pi/2)*phi/256.0);
00260
00261
00262 float tmp0=(float)(fPhi-sin(2*fPhi)/2);
00263 float tmp1=(float)sin(fPhi);
00264
00265
00266 _K[phi][i].set (tmp0*sinP, tmp0*cosP, (float)((Pi/4)*tmp1*tmp1));
00267 }
00268 }
00269
00270
00271 _ZBufferOverflow = false;
00272 _Bitmaps.clear ();
00273 }
00274
00275
00276
00277
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
00295 float skyContribution;
00296
00297
00298 CVector k (0, 0, 0);
00299
00300
00301 for (uint i=0; i<8; i++)
00302 {
00303
00304 uint8 phi=getMaxPhi (s, t, deltaDirection[i][0], deltaDirection[i][1], height);
00305
00306
00307 k+=_K[phi][i];
00308 }
00309
00310
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
00337 uint64 mask = IProcess::getCurrentProcess()->getCPUMask ();
00338
00339
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
00360 thread->setCPUMask (1<<i);
00361 }
00362 }
00363
00364
00365
00366 class NL3D::CLightRunnable : public IRunnable
00367 {
00368
00369 uint _Process;
00370 CZoneLighter *_ZoneLighter;
00371 const CZoneLighter::CLightDesc *_Description;
00372
00373 public:
00374 IThread *Thread;
00375
00376 public:
00377
00378 CLightRunnable (uint process, CZoneLighter *zoneLighter, const CZoneLighter::CLightDesc *description)
00379 {
00380 _ZoneLighter = zoneLighter;
00381 _Process = process;
00382 _Description = description;
00383 }
00384
00385
00386 void run()
00387 {
00388
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
00402 uint _Process;
00403 CZoneLighter *_ZoneLighter;
00404
00405
00406 const CZoneLighter::CLightDesc *_Description;
00407
00408
00409 uint _FirstTriangle;
00410 uint _NumTriangle;
00411 const vector<CZoneLighter::CTriangle> *_Triangles;
00412
00413 public:
00414 IThread *Thread;
00415
00416 public:
00417
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
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
00444
00445
00446 CPolygon2D zBasis;
00447 zBasis.Vertices.resize (3);
00448
00449
00450 NLMISC::CTriangle gradientTriangle;
00451
00452
00453 float ooz[3];
00454
00455
00456 uint8 in = 0;
00457
00458
00459 for (uint j=0; j<3; j++)
00460 {
00461
00462 const CVector *pt = (&triangle.Triangle.V0)+j;
00463 CVector *ptDest = (&gradientTriangle.V0)+j;
00464
00465
00466 transformVectorToZBuffer (zbuffer, *pt, *ptDest);
00467
00468
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
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
00484 ptDest->z = 0;
00485 }
00486
00487
00488 if (in == CLIPPED_ALL)
00489 {
00490
00491 sint minimumY;
00492 borders.clear ();
00493 zBasis.computeBorders (borders, minimumY);
00494
00495
00496 CVector ozzGradient;
00497 gradientTriangle.computeGradient (ooz[0], ooz[1], ooz[2], ozzGradient);
00498
00499
00500 bool needUV = triangle.Texture != NULL;
00501
00502
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
00512 uint width=0;
00513 uint height=0;
00514 const CObjectVector<uint8> *pixels = 0;
00515 if (needUV)
00516 {
00517
00518 pixels = &triangle.Texture->getPixels ();
00519
00520
00521 width = triangle.Texture->getWidth ();
00522 height = triangle.Texture->getHeight ();
00523 }
00524
00525
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
00531 const CPolygon2D::TRaster &raster = borders[y-minimumY];
00532
00533
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
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
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
00561 float z = - 1.f / (ooz[0] + oozGradientX + oozGradientY);
00562
00563
00564 float u;
00565 float v;
00566 bool alphaTest = true;
00567 if (needUV)
00568 {
00569
00570 u = triangle.U[0] + uGradientX + uGradientY;
00571 v = triangle.V[0] + vGradientX + vGradientY;
00572
00573
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
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
00591 alphaTest = alpha >= triangle.AlphaTestThreshold;
00592 }
00593
00594
00595 if (alphaTest)
00596 {
00597
00598 mutex.enter ();
00599
00600
00601 uint d;
00602 for (d=0; d<radius; d++)
00603 {
00604
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
00612 if (z < zValue)
00613 {
00614
00615 zValue = z;
00616 }
00617 }
00618 }
00619
00620
00621 mutex.leave ();
00622 }
00623 }
00624 }
00625 }
00626 }
00627
00628
00629 void NL3D::CRenderZBuffer::run()
00630 {
00631
00632 setCPUMask (Thread, _Process);
00633
00634
00635 CPolygon2D::TRasterVect borders;
00636
00637
00638 uint i;
00639 for (i=_FirstTriangle; i<_FirstTriangle+_NumTriangle; i++)
00640 {
00641
00642 const CZoneLighter::CTriangle &triangle = (*_Triangles)[i];
00643
00644
00645 if ((triangle.Flags & CZoneLighter::CTriangle::DoubleSided) || ((triangle.getPlane ().getNormal() * _ZoneLighter->_SunDirection) > 0))
00646 {
00647
00648 if (triangle.Flags & CZoneLighter::CTriangle::Landscape)
00649 {
00650
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
00661 RenderTriangle (triangle, *_Description, borders, _ZoneLighter->_Mutex, _ZoneLighter->_ZBufferObject, 1);
00662 }
00663 }
00664 _ZoneLighter->_NumberOfPatchComputed++;
00665 }
00666
00667
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
00714 CRGBA *pixels = (CRGBA*)&(bitmap.getPixels ()[0]);
00715
00716
00717 sint width = (sint)bitmap.getWidth ();
00718 sint height = (sint)bitmap.getHeight ();
00719
00720
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
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
00740 const float zBufferWorldSize = (float)(tan (description.SunFOV/2)*description.SunDistance*2);
00741
00742
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
00751 zbuffer.ZBufferPixelSize = zBufferPixelSize;
00752
00753
00754
00755
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
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
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
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
00815 CBitmap bitmap;
00816 bitmap.resize (zbuffer.LocalZBufferWidth, zbuffer.LocalZBufferHeight, CBitmap::Luminance);
00817
00818
00819 CObjectVector<uint8> &pixels = bitmap.getPixels ();
00820
00821
00822 uint samples = zbuffer.LocalZBufferWidth*zbuffer.LocalZBufferHeight;
00823 for (uint i=0; i<samples; i++)
00824 {
00825
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
00832 bitmap.convertToType (CBitmap::RGBA);
00833
00834
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
00849 COFile outputZFile;
00850
00851
00852 if (outputZFile.open (filename))
00853 {
00854
00855 try
00856 {
00857
00858 bitmap.convertToType (CBitmap::RGBA);
00859
00860
00861 bitmap.writeJPG (outputZFile, 128);
00862 }
00863 catch (Exception& except)
00864 {
00865
00866 nlwarning ("ERROR writing %s: %s\n", filename, except.what());
00867 }
00868 }
00869 else
00870 {
00871
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
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
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
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
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
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929 IThread *currentThread = IThread::getCurrentThread ();
00930 uint64 threadMask = currentThread->getCPUMask();
00931 currentThread->setCPUMask (1);
00932
00933
00934 _SunDirection=description.SunDirection;
00935 NEL3DCalcBase (_SunDirection, _RayBasis);
00936
00937
00938 _ZoneToLight=zoneToLight;
00939
00940
00941 _Landscape=&landscape;
00942
00943
00944 _ProcessCount=description.NumCPU;
00945 if (_ProcessCount==0)
00946 {
00947
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
00962 printf ("Obstacle polygones : %d\n", obstacles.size ());
00963
00964
00965 printf ("Number of CPU used: %d\n", _ProcessCount);
00966
00967
00968 CZone *pZone=landscape.getZone (_ZoneToLight);
00969 if (pZone)
00970 {
00971
00972
00973
00974 const CAABBoxExt &zoneBB=pZone->getZoneBB();
00975
00976
00977 CVector center = zoneBB.getCenter ();
00978
00979
00980 const uint size=obstacles.size();
00981 uint triangleId;
00982 for (triangleId=0; triangleId<size; triangleId++)
00983 {
00984
00985 CZoneLighter::CTriangle& triangle=obstacles[triangleId];
00986
00987
00988 triangle._Plane.make (triangle.Triangle.V0, triangle.Triangle.V1, triangle.Triangle.V2);
00989 }
00990
00991
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
01000 CZBuffer &zbuffer = _ZBufferLandscape[sampleX + sampleY*description.SoftShadowSamplesSqrt];
01001
01002
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
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
01020 _ProcessExited = 0;
01021
01022
01023 uint numTriangle = (obstacles.size () / _ProcessCount) + 1;
01024
01025
01026 uint firstTriangle = 0;
01027
01028
01029 _NumberOfPatchComputed = 0;
01030
01031 for (uint process=0; process<_ProcessCount; process++)
01032 {
01033
01034 uint lastTriangle=firstTriangle+numTriangle;
01035 if (lastTriangle>obstacles.size ())
01036 lastTriangle=obstacles.size ();
01037
01038
01039 CRenderZBuffer *runnable = new CRenderZBuffer (process, this, &description, firstTriangle, lastTriangle - firstTriangle, &obstacles);
01040 IThread *pThread=IThread::create (runnable);
01041 runnable->Thread = pThread;
01042
01043
01044 firstTriangle = lastTriangle;
01045
01046
01047 pThread->start();
01048 }
01049
01050
01051 while (_ProcessExited!=_ProcessCount)
01052 {
01053 nlSleep (1000);
01054
01055
01056 progress ("Render triangles", (float)_NumberOfPatchComputed/(float)obstacles.size());
01057 }
01058
01059
01060 uint sample;
01061 const uint samples = description.SoftShadowSamplesSqrt*description.SoftShadowSamplesSqrt;
01062 #ifdef SAVE_ZBUFFER
01063 for (sample=0; sample<samples; sample++)
01064 {
01065
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
01074 SaveZBuffer (_ZBufferObject, SAVE_ZBUFFER"/zbuffer_object.jpg");
01075 #endif // SAVE_ZBUFFER
01076
01077
01078 for (sample=0; sample<samples; sample++)
01079 {
01080
01081 FilterZBuffer (_ZBufferLandscape[sample], 5);
01082 }
01083
01084
01085 CMatrix invRayBasis=_RayBasis;
01086 invRayBasis.invert ();
01087
01088
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
01096 for (triangleId=0; triangleId<size; triangleId++)
01097 {
01098
01099 if ( (triangleId&0xff) == 0)
01100 progress ("Build quadtree and heightfield", (float)triangleId/(float)size);
01101
01102
01103 CZoneLighter::CTriangle& triangle=obstacles[triangleId];
01104
01105
01106 CVector minv;
01107 minv.minof (triangle.Triangle.V0, triangle.Triangle.V1);
01108 minv.minof (minv, triangle.Triangle.V2);
01109
01110
01111 CVector maxv;
01112 maxv.maxof (triangle.Triangle.V0, triangle.Triangle.V1);
01113 maxv.maxof (maxv, triangle.Triangle.V2);
01114
01115
01116 if (triangle.Flags & CTriangle::Landscape)
01117 {
01118
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
01125 for (sint y=minY; y<maxY; y++)
01126 for (sint x=minX; x<maxX; x++)
01127 {
01128
01129 if (maxv.z>_HeightField[x+y*_HeightFieldCellCount])
01130 {
01131
01132 _HeightField[x+y*_HeightFieldCellCount]=maxv.z;
01133 }
01134 }
01135 }
01136 }
01137
01138
01139 pZone->retrieve (_PatchInfo, _BorderVertices);
01140
01141
01142 uint patchCount=_PatchInfo.size();
01143
01144
01145 if (description.Shadow)
01146 _ShadowArray.resize (patchCount);
01147
01148
01149 vector<vector<CLumelDescriptor> > lumels;
01150 lumels.resize (patchCount);
01151
01152
01153 buildZoneInformation (landscape,
01154 listZone,
01155 description);
01156
01157 }
01158
01159
01160 uint patchCount=_PatchInfo.size();
01161
01162
01163 {
01164 CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
01165 access.value().resize (0);
01166 access.value().resize (patchCount, false);
01167 }
01168
01169
01170 uint patchCountByThread = patchCount/_ProcessCount;
01171 patchCountByThread++;
01172
01173
01174 uint firstPatch=0;
01175 _NumberOfPatchComputed = 0;
01176
01177
01178 _ProcessExited=0;
01179
01180
01181 _LastPatchComputed.resize (_ProcessCount);
01182
01183
01184 uint process;
01185 for (process=0; process<_ProcessCount; process++)
01186 {
01187
01188 uint lastPatch=firstPatch+patchCountByThread;
01189 if (lastPatch>patchCount)
01190 lastPatch=patchCount;
01191
01192
01193 _LastPatchComputed[process] = firstPatch;
01194
01195
01196 CLightRunnable *runnable = new CLightRunnable (process, this, &description);
01197 IThread *pThread=IThread::create (runnable);
01198 runnable->Thread = pThread;
01199
01200
01201 firstPatch=lastPatch;
01202
01203
01204 pThread->start();
01205 }
01206
01207
01208 while (_ProcessExited!=_ProcessCount)
01209 {
01210 nlSleep (1000);
01211
01212
01213 progress ("Lighting patches", (float)_NumberOfPatchComputed/(float)_PatchInfo.size());
01214 }
01215
01216
01217 currentThread->setCPUMask (threadMask);
01218
01219
01220 if (_ZBufferOverflow)
01221 nlwarning ("Error : zbuffer overflow");
01222
01223
01224 progress ("Compute Influences of PointLights", 0.f);
01225
01226
01227
01228 compilePointLightRT(description.GridSize, description.GridCellSize, obstacles, description.Shadow);
01229
01230 std::vector<CPointLightNamed> listPointLight;
01231 processZonePointLightRT(listPointLight);
01232
01233
01234
01235
01236
01237 progress ("Compress the lightmap", 0.6f);
01238
01239
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
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
01292
01293
01294 uint patch = getAPatch (process);
01295 while (patch != 0xffffffff)
01296 {
01297
01298 if (description.Shadow)
01299 {
01300
01301 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
01302
01303
01304 uint lumelCount=lumels.size();
01305 CPatchInfo &patchInfo=_PatchInfo[patch];
01306 nlassert (patchInfo.Lumels.size()==lumelCount);
01307
01308
01309 _ShadowArray[patch].resize (lumelCount);
01310
01311
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
01322 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
01323
01324
01325 uint lumelCount=lumels.size();
01326 CPatchInfo &patchInfo=_PatchInfo[patch];
01327 nlassert (patchInfo.Lumels.size()==lumelCount);
01328
01329
01330 for (uint lumel=0; lumel<lumelCount; lumel++)
01331 {
01332
01333 patchInfo.Lumels[lumel]=255;
01334 }
01335 }
01336
01337
01338
01339
01340 CPatchInfo &patchInfo=_PatchInfo[patch];
01341
01342
01343 std::vector<CLumelDescriptor> &lumels=_Lumels[patch];
01344
01345
01346 for (uint lumel=0; lumel<lumels.size(); lumel++)
01347 {
01348
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
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
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
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
01386 s+=deltaS;
01387 t+=deltaT;
01388
01389
01390 float stepDistance=CVector (deltaS*_HeightfieldCellSize, deltaT*_HeightfieldCellSize,0).norm ();
01391
01392
01393 float distance=stepDistance;
01394
01395
01396 float maxHeight=0;
01397 float maxTanTeta=0;
01398
01399
01400 while ((s<_HeightFieldCellCount)&&(t<_HeightFieldCellCount)&&(s>=0)&&(t>=0))
01401 {
01402
01403 float height=_HeightField[s+t*_HeightFieldCellCount];
01404 height-=heightPos;
01405
01406
01407 if (height>maxHeight)
01408 {
01409
01410 float tanTeta=height/distance;
01411 nlassert (tanTeta>=0);
01412
01413
01414 if (tanTeta>maxTanTeta)
01415 {
01416
01417 maxHeight=height;
01418 maxTanTeta=tanTeta;
01419 }
01420 }
01421 s+=deltaS;
01422 t+=deltaT;
01423 distance+=stepDistance;
01424 }
01425
01426
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
01449 if (oversampleEdges[edge])
01450 return true;
01451 else
01452 {
01453
01454 if (binded[edge])
01455 {
01456
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
01461 CVector2f neighborUV;
01462 CPatch *patchOut;
01463 locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
01464
01465
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
01473 return false;
01474 }
01475 }
01476 }
01477
01478
01479
01480 float easineasoutC2(float x)
01481 {
01482 float y;
01483
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
01504 uint64 id=(uint64)lumelS|(((uint64)lumelT)<<16)|(((uint64)pPatch->getPatchId())<<32)|(((uint64)pPatch->getZone()->getZoneId())<<48);
01505
01506
01507 if (visited.insert (id).second)
01508 {
01509
01510 float sqDist=deltaS*deltaS+deltaT*deltaT;
01511 if ( sqDist < 1 )
01512 {
01513
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
01524 _GetNormalNormal+=bezierPatch.evalNormal ( ((float)lumelS+0.5f)/(float)orderSx4, ((float)lumelT+0.5f)/(float)orderTx4 );
01525
01526
01527 for (uint edge=0; edge<4; edge++)
01528 {
01529
01530 if (edge!=lastEdge)
01531 {
01532
01533 uint globalDirection=(edge+(4-rotation))&0x3;
01534
01535
01536 if ( (lumelS==_GetNormalBorderS[edge]) || (lumelT==_GetNormalBorderT[edge]) )
01537 {
01538
01539 bool bind=binded[edge];
01540 bool smooth=pPatch->getSmoothFlag (edge);
01541 if (bind&&smooth)
01542 {
01543
01544 CVector2f lumelCoord ( ((float)(lumelS+_GetNormalDeltaS[edge])+0.5f)/4,
01545 ((float)(lumelT+_GetNormalDeltaT[edge])+0.5f)/4 );
01546
01547
01548 uint otherPatch=locator[edge].selectPatch(lumelCoord);
01549
01550
01551 CVector2f neighborUV;
01552 CPatch *patchOut;
01553 locator[edge].locateUV (lumelCoord, otherPatch, patchOut, neighborUV);
01554
01555
01556 sint16 newLumelS=(sint16)(4.f*neighborUV.x);
01557 sint16 newLumelT=(sint16)(4.f*neighborUV.y);
01558
01559
01560 uint16 patchId=patchOut->getPatchId();
01561 uint16 zoneId=_ZoneId[patchOut->getZone()->getZoneId ()];
01562
01563
01564 uint newEdge=0;
01565 uint i;
01566 for (i=0; i<=(uint)bindInfo[edge].NPatchs; i++)
01567 {
01568
01569 if (bindInfo[edge].Next[i]==patchOut)
01570 {
01571
01572 newEdge=bindInfo[edge].Edge[i];
01573 break;
01574 }
01575 }
01576
01577
01578 uint newRotation=(2-edge+rotation+newEdge)&0x3;
01579
01580
01581 nlassert (i!=(uint)bindInfo[edge].NPatchs);
01582
01583
01584 CBezierPatch &NewBezierPatch=_BezierPatch[zoneId][patchId];
01585
01586
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
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
01609 excludeAllPatchFromRefineAll (landscape, listZone, false);
01610
01611
01612 landscape.setThreshold (0);
01613 landscape.setTileMaxSubdivision (order);
01614
01615
01616 landscape.refineAll (CVector (0, 0, 0));
01617
01618
01619 std::vector<const CTessFace*> leaves;
01620 landscape.getTessellationLeaves(leaves);
01621
01622
01623 uint leavesCount=leaves.size();
01624
01625
01626 triangleArray.reserve (triangleArray.size()+leavesCount);
01627
01628
01629 for (uint leave=0; leave<leavesCount; leave++)
01630 {
01631
01632 const CTessFace *face=leaves[leave];
01633
01634
01635 triangleArray.push_back (CTriangle (NLMISC::CTriangle (face->VBase->EndPos, face->VLeft->EndPos, face->VRight->EndPos)));
01636 }
01637
01638
01639 landscape.setThreshold (1000);
01640 landscape.setTileMaxSubdivision (0);
01641
01642
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
01660 const CMesh *mesh=dynamic_cast<const CMesh*>(&shape);
01661
01662
01663 const CMeshMultiLod *meshMulti=dynamic_cast<const CMeshMultiLod*>(&shape);
01664
01665
01666 const CMeshMRM *meshMRM=dynamic_cast<const CMeshMRM*>(&shape);
01667
01668
01669 if (mesh)
01670 {
01671
01672 addTriangles (*mesh, mesh->getMeshGeom (), modelMT, triangleArray);
01673 }
01674
01675 else if (meshMulti)
01676 {
01677
01678 const IMeshGeom *meshGeom=&meshMulti->getMeshGeom (0);
01679
01680
01681 const CMeshGeom *geomMesh=dynamic_cast<const CMeshGeom*>(meshGeom);
01682 if (geomMesh)
01683 {
01684 addTriangles (*meshMulti, *geomMesh, modelMT, triangleArray);
01685 }
01686
01687
01688 const CMeshMRMGeom *mrmGeomMesh=dynamic_cast<const CMeshMRMGeom*>(meshGeom);
01689 if (mrmGeomMesh)
01690 {
01691 addTriangles (*meshMulti, *mrmGeomMesh, modelMT, triangleArray);
01692 }
01693 }
01694
01695 else if (meshMRM)
01696 {
01697
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
01707 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
01708 CVertexBufferRead vba;
01709 vb.lock (vba);
01710
01711
01712 uint numBlock=meshGeom.getNbMatrixBlock();
01713 for (uint block=0; block<numBlock; block++)
01714 {
01715
01716 uint numRenderPass=meshGeom.getNbRdrPass(block);
01717 for (uint pass=0; pass<numRenderPass; pass++)
01718 {
01719
01720 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( block, pass);
01721
01722
01723 const CMaterial &material = meshBase.getMaterial (meshGeom.getRdrPassMaterial ( block, pass));
01724
01725
01726
01727
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
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
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
01751 float u[3];
01752 float v[3];
01753 for (uint i=0; i<3; i++)
01754 {
01755
01756 const float *uv = (const float*)vba.getTexCoordPointer (triIndex[tri*3+i], 0);
01757 if (uv)
01758 {
01759
01760 u[i] = uv[0];
01761 v[i] = uv[1];
01762 }
01763 }
01764
01765
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
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
01783 float u[3];
01784 float v[3];
01785 for (uint i=0; i<3; i++)
01786 {
01787
01788 const float *uv = (const float*)vba.getTexCoordPointer (triIndex[tri*3+i], 0);
01789 if (uv)
01790 {
01791
01792 u[i] = uv[0];
01793 v[i] = uv[1];
01794 }
01795 }
01796
01797
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
01812 result = NULL;
01813 clampU = false;
01814 clampV = false;
01815
01816
01817 float alphaTestThresholdF = material.getAlphaTestThreshold () * 255;
01818 clamp (alphaTestThresholdF, 0.f, 255.f);
01819 alphaTestThreshold = (uint8)alphaTestThresholdF;
01820
01821
01822 if (material.getBlend ())
01823 return false;
01824
01825
01826 if (material.getAlphaTest ())
01827 {
01828
01829 ITexture *texture = material.getTexture (0);
01830
01831
01832 if (texture && texture->supportSharing ())
01833 {
01834
01835 string name = texture->getShareName();
01836
01837
01838 std::map<string, NLMISC::CBitmap>::iterator ite = _Bitmaps.find (name);
01839 if (ite != _Bitmaps.end ())
01840 {
01841
01842 result = &(ite->second);
01843 }
01844 else
01845 {
01846
01847 ite = _Bitmaps.insert (std::map<string, NLMISC::CBitmap>::value_type (name, CBitmap())).first;
01848 result = &(ite->second);
01849
01850
01851 texture->generate ();
01852
01853
01854 texture->convertToType (CBitmap::RGBA);
01855
01856
01857 *result = *texture;
01858
01859
01860 texture->release ();
01861 }
01862
01863
01864 clampU = texture->getWrapS () == ITexture::Clamp;
01865 clampV = texture->getWrapT () == ITexture::Clamp;
01866 }
01867 }
01868
01869
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
01879 const CVertexBuffer &vb=meshGeom.getVertexBuffer();
01880 CVertexBufferRead vba;
01881 vb.lock (vba);
01882
01883
01884 uint numRenderPass=meshGeom.getNbRdrPass(0);
01885 for (uint pass=0; pass<numRenderPass; pass++)
01886 {
01887
01888 const CIndexBuffer &primitive=meshGeom.getRdrPassPrimitiveBlock ( 0, pass);
01889
01890
01891 const CMaterial &material = meshBase.getMaterial (meshGeom.getRdrPassMaterial (0, pass));
01892
01893
01894
01895
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
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
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
01917 float u[3];
01918 float v[3];
01919 for (uint i=0; i<3; i++)
01920 {
01921
01922 float *uv = (float*)vba.getTexCoordPointer (triIndex[tri*3+i], 0);
01923 if (uv)
01924 {
01925
01926 u[i] = uv[0];
01927 v[i] = uv[1];
01928 }
01929 }
01930
01931
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
01944 for (uint zone=0; zone<listZone.size(); zone++)
01945 {
01946
01947 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
01948
01949
01950 for (uint patch=0; patch<patchCount; patch++)
01951 {
01952
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
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
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
02004 vector<vector<uint> > visited;
02005
02006
02007 uint zoneCount=listZone.size();
02008
02009
02010 _Locator.resize (zoneCount);
02011 _Binded.resize (zoneCount);
02012 _BindInfo.resize (zoneCount);
02013 _BezierPatch.resize (zoneCount);
02014
02015
02016 for (uint zone=0; zone<zoneCount; zone++)
02017 {
02018
02019 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
02020
02021
02022 _ZoneId.insert (map<uint, uint>::value_type (listZone[zone], zone));
02023
02024
02025 if (listZone[zone]==_ZoneToLight)
02026 {
02027
02028 _Lumels.resize(patchCount);
02029
02030
02031 _OversampleEdges.resize(patchCount);
02032 visited.resize(patchCount);
02033 }
02034
02035
02036 _Locator[zone].resize(patchCount);
02037 _Binded[zone].resize(patchCount);
02038 _BindInfo[zone].resize(patchCount);
02039 _BezierPatch[zone].resize(patchCount);
02040
02041
02042 uint patch;
02043 for (patch=0; patch<patchCount; patch++)
02044 {
02045
02046 const CPatch* pPatch=(const_cast<const CZone*>(landscape.getZone(listZone[zone])))->getPatch (patch);
02047
02048
02049 progress ("Scan all patches", (float)patch/(float)patchCount);
02050
02051
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
02061 bezierPatch=*pPatch->unpackIntoCache();
02062
02063
02064 if (listZone[zone]==_ZoneToLight)
02065 {
02066
02067 _OversampleEdges[patch].resize (4, false);
02068 }
02069
02070
02071
02072
02073 uint edge;
02074 for (edge=0; edge<4; edge++)
02075 {
02076
02077 pPatch->getBindNeighbor (edge, bindInfo[edge]);
02078
02079
02080 if (bindInfo[edge].NPatchs>0)
02081 {
02082
02083 binded[edge]=true;
02084
02085
02086 if ((listZone[zone]==_ZoneToLight)&&(bindInfo[edge].Zone->getZoneId()!=_ZoneToLight))
02087 {
02088
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
02098 _OversampleEdges[patch][edge]=true;
02099 }
02100 }
02101 }
02102
02103
02104 if (listZone[zone]==_ZoneToLight)
02105 {
02106
02107
02108
02109 uint orderS=pPatch->getOrderS();
02110 uint orderT=pPatch->getOrderT();
02111
02112
02113 uint lumelCount = orderS*orderT*16;
02114
02115
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
02124
02125
02126
02127
02128
02129 landscape.excludePatchFromRefineAll (listZone[zone], patch, false);
02130 }
02131 else
02132 {
02133
02134 landscape.excludePatchFromRefineAll (listZone[zone], patch, true);
02135 }
02136 }
02137 }
02138
02139
02140
02141
02142 landscape.setThreshold (0);
02143 landscape.setTileMaxSubdivision (0);
02144
02145
02146 progress ("Refine landscape to shadow accuracy", 0.5f);
02147 landscape.refineAll (CVector (0, 0, 0));
02148
02149
02150 std::vector<const CTessFace*> leaves;
02151 landscape.getTessellationLeaves(leaves);
02152
02153
02154
02155
02156 if (_WaterShapes.size() != 0)
02157 {
02159 makeQuadGridFromWaterShapes(landscape.getZone(_ZoneToLight)->getZoneBB().getAABBox());
02160
02162 computeTileFlagsForPositionTowardWater(lightDesc, leaves);
02163 }
02164 else
02165 {
02166 setTileFlagsToDefault(leaves);
02167 }
02168
02169
02170
02171 uint zoneNumber=_ZoneId[_ZoneToLight];
02172
02173
02174 uint leavesCount=leaves.size();
02175 uint leave;
02176 for (leave=0; leave<leavesCount; leave++)
02177 {
02178
02179 if ( (leave&0xff) == 0)
02180 progress ("Precompute lumel position", (float)leave/(float)leavesCount);
02181
02182
02183 const CTessFace *face=leaves[leave];
02184
02185
02186 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
02187 {
02188
02189 const CPatch* pPatch=face->Patch;
02190
02191
02192 uint orderS=pPatch->getOrderS();
02193 uint orderT=pPatch->getOrderT();
02194
02195
02196
02197 CVector pos[15];
02198 pos[0]=face->VBase->EndPos;
02199 pos[1]=face->VRight->EndPos;
02200 pos[2]=face->VLeft->EndPos;
02201 pos[3]=(pos[1]+pos[2])/2;
02202 pos[4]=(pos[0]+pos[1])/2;
02203 pos[5]=(pos[0]+pos[2])/2;
02204 pos[6]=(pos[0]+pos[3])/2;
02205 pos[7]=(pos[2]+pos[3])/2;
02206 pos[8]=(pos[1]+pos[3])/2;
02207 pos[9]=(pos[0]+pos[4])/2;
02208 pos[10]=(pos[1]+pos[4])/2;
02209 pos[11]=(pos[0]+pos[5])/2;
02210 pos[12]=(pos[2]+pos[5])/2;
02211 pos[13]=(pos[3]+pos[5])/2;
02212 pos[14]=(pos[3]+pos[4])/2;
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
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
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
02293 uint i;
02294 for (i=0; i<8; i++)
02295 {
02296
02297 if (snapedBorder[VertexThanCanBeSnappedOnABorder[i][1]])
02298 {
02299
02300 interpolatedP[VertexThanCanBeSnappedOnABorder[i][0]] = (pos[VertexThanCanBeSnappedOnABorder[i][2]]
02301 + pos[VertexThanCanBeSnappedOnABorder[i][3]])/2;
02302 }
02303 }
02304
02305
02306 for (i=0; i<3; i++)
02307 {
02308
02309 uint tesselCornerIndex = VertexThanCanBeSnappedOnACorner[i][1];
02310 if ( snapedCorner[tesselCornerIndex] )
02311 {
02312
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
02353 uint index=s+t*orderS*4;
02354
02355
02356 uint patchId=pPatch->getPatchId();
02357
02358
02359 vector<CLumelDescriptor> &lumels=_Lumels[patchId];
02360
02361
02362 visited[patchId][index]++;
02363
02364
02365 lumels[index].Position+=interpolatedP[i];
02366 }
02367 }
02368 }
02369 }
02370
02371
02372
02373
02374 uint patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
02375 uint patch;
02376 for (patch=0; patch<patchCount; patch++)
02377 {
02378
02379 progress ("Finalize lumel positions", (float)patch/(float)patchCount);
02380
02381
02382
02383
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
02389 vector<CLumelDescriptor> &lumels=_Lumels[patch];
02390
02391
02392
02393
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
02403 uint lumelIndex=s+t*lumelS;
02404
02405
02406 uint visitedCount=visited[patch][lumelIndex];
02407
02408
02409 if (visitedCount)
02410 {
02411
02412 lumels[lumelIndex].Position/=(float)visitedCount;
02413 }
02414
02415
02416 visited[patch][lumelIndex]=false;
02417 }
02418 }
02419
02420
02421
02422
02423 landscape.setThreshold (0);
02424 landscape.setTileMaxSubdivision (4);
02425
02426
02427 progress ("Refine landscape to lumels", 0.5f);
02428 landscape.refineAll (CVector (0, 0, 0));
02429
02430
02431 leaves.clear ();
02432 landscape.getTessellationLeaves(leaves);
02433
02434
02435 leavesCount=leaves.size();
02436 for (leave=0; leave<leavesCount; leave++)
02437 {
02438
02439 if ( (leave&0xff) == 0)
02440 progress ("Precompute tesselation", (float)leave/(float)leavesCount);
02441
02442
02443 const CTessFace *face=leaves[leave];
02444
02445
02446 if (face->Patch->getZone()->getZoneId()==_ZoneToLight)
02447 {
02448
02449 const CPatch* pPatch=face->Patch;
02450
02451
02452 uint orderS=pPatch->getOrderS();
02453 uint orderT=pPatch->getOrderT();
02454
02455
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
02461 nlassert (s<orderS*4);
02462
02463 nlassert (t<orderT*4);
02464
02465
02466 uint index=s+t*orderS*4;
02467
02468
02469 uint patchId=pPatch->getPatchId();
02470
02471
02472 vector<CLumelDescriptor> &lumels=_Lumels[patchId];
02473
02474
02475 visited[patchId][index]++;
02476
02477
02478 lumels[index].S+=fS;
02479 lumels[index].T+=fT;
02480
02481
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
02489
02490
02491 patchCount=landscape.getZone(_ZoneToLight)->getNumPatchs();
02492 for (patch=0; patch<patchCount; patch++)
02493 {
02494
02495 progress ("Finalize patches", (float)patch/(float)patchCount);
02496
02497
02498
02499
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
02505 vector<CLumelDescriptor> &lumels=_Lumels[patch];
02506
02507
02508
02509
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
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
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
02532 uint count=(edge&1)?lumelS:lumelT;
02533 for (uint lumel=0; lumel<=count; lumel++)
02534 {
02535
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
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
02585 uint lumelIndex=s+t*lumelS;
02586
02587
02588
02589
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
02599 CVector average=normals[t][0];
02600 average+=normals[t+1][0];
02601 average/=2;
02602
02603
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
02615 CVector average=normals[t][2];
02616 average+=normals[t+1][2];
02617 average/=2;
02618
02619
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
02631 CVector average=normals[s][3];
02632 average+=normals[s+1][3];
02633 average/=2;
02634
02635
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
02647 CVector average=normals[s][1];
02648 average+=normals[s+1][1];
02649 average/=2;
02650
02651
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
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
02676 smoothNormal.normalize();
02677
02678
02679 CVector purNormal=bezierPatch.evalNormal (((float)s+0.5f)/(float)lumelS, ((float)t+0.5f)/(float)lumelT);
02680
02681
02682 lumels[lumelIndex].Normal.normalize();
02683
02684
02685 lumels[lumelIndex].Normal=lumels[lumelIndex].Normal-purNormal+smoothNormal;
02686 lumels[lumelIndex].Normal.normalize ();
02687
02688
02689 uint visitedCount=visited[patch][lumelIndex];
02690
02691
02692
02693
02694
02695 if (visitedCount)
02696 {
02697
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
02710 _ZoneToLight=zoneToLight;
02711
02712
02713 _Landscape=&landscape;
02714
02715
02716
02717 uint zoneCount=listZone.size();
02718
02719
02720 for (uint zone=0; zone<zoneCount; zone++)
02721 {
02722
02723 uint patchCount=landscape.getZone(listZone[zone])->getNumPatchs();
02724
02725
02726 _ZoneId.insert (map<uint, uint>::value_type (listZone[zone], zone));
02727
02728
02729 uint patch;
02730 for (patch=0; patch<patchCount; patch++)
02731 {
02732
02733 progress ("Scan all patches", (float)patch/(float)patchCount);
02734
02735
02736 if (listZone[zone]==_ZoneToLight)
02737 {
02738
02739 landscape.excludePatchFromRefineAll (listZone[zone], patch, false);
02740 }
02741 else
02742 {
02743
02744 landscape.excludePatchFromRefineAll (listZone[zone], patch, true);
02745 }
02746 }
02747 }
02748
02749
02750
02751
02752 landscape.setThreshold (0);
02753 landscape.setTileMaxSubdivision (0);
02754
02755
02756 progress ("Refine landscape to maximum", 0.5f);
02757 landscape.refineAll (CVector (0, 0, 0));
02758
02759
02760 std::vector<const CTessFace*> leaves;
02761 landscape.getTessellationLeaves(leaves);
02762
02763
02764
02765 if (_WaterShapes.size() != 0)
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
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
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
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
02899 for (uint k = firstShape; k < lastShape; ++k)
02900 {
02901 nlassert(isLightableShape(* (*shapesToLit)[k].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
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
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
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
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
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
03203 if(PointLight.getType()== CPointLight::AmbientLight)
03204 return false;
03205
03206
03207 if(PointLight.getType()== CPointLight::SpotLight)
03208 {
03209 float att= PointLight.computeLinearAttenuation(v);
03210 if (att==0)
03211 return false;
03212 }
03213
03214
03215 FaceCubeGrid.select(v);
03216
03217 while(!FaceCubeGrid.isEndSel())
03218 {
03219 const CTriangle *tri= FaceCubeGrid.getSel();
03220
03221
03222 if( tri->Triangle.intersect(BSphere.Center, v, dummy, tri->getPlane()) )
03223 return false;
03224
03225
03226 FaceCubeGrid.nextSel();
03227 }
03228
03229
03230 return true;
03231 }
03232
03233
03234
03235 void CZoneLighter::addStaticPointLight(const CPointLightNamed &pln)
03236 {
03237
03238 CPointLightRT plRT;
03239 plRT.PointLight= pln;
03240
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
03247 plRT.BSphere.Center= pln.getPosition();
03248 plRT.BSphere.Radius= pln.getAttenuationEnd();
03249
03250
03251
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
03263
03264 _StaticPointLightQuadGrid.create(gridSize, gridCellSize);
03265 for(i=0; i<_StaticPointLights.size();i++)
03266 {
03267 CPointLightRT &plRT= _StaticPointLights[i];
03268
03269
03270 CAABBox bbox;
03271 bbox.setCenter(plRT.BSphere.Center);
03272 float hl= plRT.BSphere.Radius;
03273 bbox.setHalfSize(CVector(hl,hl,hl));
03274
03275
03276 _StaticPointLightQuadGrid.insert(bbox.getMin(), bbox.getMax(), &plRT);
03277 }
03278
03279
03280
03281 if(doShadow)
03282 {
03283
03284 if (!_StaticPointLights.empty ())
03285 {
03286
03287
03288 CQuadGrid<CTriangle*> obstacleGrid;
03289 obstacleGrid.create(gridSize, gridCellSize);
03290 uint size= obstacles.size();
03291 for(i=0; i<size; i++)
03292 {
03293
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
03299 obstacleGrid.insert(bbox.getMin(), bbox.getMax(), &obstacles[i]);
03300 }
03301
03302
03303
03304
03305 for(i=0; i<_StaticPointLights.size();i++)
03306 {
03307
03308 progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
03309
03310 CPointLightRT &plRT= _StaticPointLights[i];
03311
03312 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), NL3D_ZONE_LIGHTER_CUBE_GRID_SIZE);
03313
03314
03315 if(plRT.PointLight.getType()!=CPointLight::AmbientLight)
03316 {
03317
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
03325 CQuadGrid<CTriangle*>::CIterator itObstacle;
03326 itObstacle= obstacleGrid.begin();
03327 while( itObstacle!=obstacleGrid.end() )
03328 {
03329 CTriangle &tri= *(*itObstacle);
03330
03331
03332 CAABBox triBbox;
03333 triBbox.setCenter (tri.Triangle.V0);
03334 triBbox.extend (tri.Triangle.V1);
03335 triBbox.extend (tri.Triangle.V2);
03336
03337
03338 if (triBbox.intersect (bbox))
03339 {
03340
03341
03342 if( tri.getPlane() * plRT.BSphere.Center < 0)
03343 {
03344
03345 plRT.FaceCubeGrid.insert( tri.Triangle, &tri);
03346 }
03347 }
03348
03349 itObstacle++;
03350 }
03351 }
03352
03353
03354 plRT.FaceCubeGrid.compile();
03355
03356
03357 plRT.RefCount= 0;
03358 }
03359 }
03360 }
03361
03362 else
03363 {
03364 for(i=0; i<_StaticPointLights.size();i++)
03365 {
03366
03367 progress ("Compute Influences of PointLights", 0.5f*i / (float)(_StaticPointLights.size()-1));
03368
03369 CPointLightRT &plRT= _StaticPointLights[i];
03370
03371 plRT.FaceCubeGrid.create(plRT.PointLight.getPosition(), 4);
03372
03373
03374 plRT.FaceCubeGrid.compile();
03375
03376
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
03392
03393 if(infA==infB)
03394
03395 return ra < rb;
03396 else
03397
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
03409 listPointLight.clear();
03410
03411
03412 CZone *zoneToLight= _Landscape->getZone(_ZoneToLight);
03413 if(!zoneToLight)
03414 return;
03415
03416
03417
03418 vector<CPatchForPL> patchForPLs;
03419 patchForPLs.resize(_PatchInfo.size());
03420 for(i=0; i<patchForPLs.size(); i++)
03421 {
03422
03423 patchForPLs[i].OrderS= _PatchInfo[i].OrderS;
03424 patchForPLs[i].OrderT= _PatchInfo[i].OrderT;
03425
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
03433
03434 for(i=0; i<patchForPLs.size(); i++)
03435 {
03436
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
03448
03449 CVector pos, normal;
03450 float s, t;
03451 s= (float)x / (pfpl.WidthTLI-1);
03452 t= (float)y / (pfpl.HeightTLI-1);
03453
03454 pos= patch->computeVertex(s, t);
03455
03456 CBezierPatch *bp= patch->unpackIntoCache();
03457 normal= bp->evalNormal(s, t);
03458
03459
03460
03461
03462 lightInfs.clear();
03463
03464 _StaticPointLightQuadGrid.select(pos, pos);
03465
03466 CQuadGrid<CPointLightRT*>::CIterator it= _StaticPointLightQuadGrid.begin();
03467 while(it != _StaticPointLightQuadGrid.end())
03468 {
03469 CPointLightRT *pl= *it;
03470
03471
03472 if( ( pl->BSphere.Center - pos ) * normal > 0)
03473 {
03474
03475
03476 const float deltaY= 0.05f;
03477 CVector posToRT= pos + normal * deltaY;
03478
03479 if( pl->testRaytrace(posToRT) )
03480 {
03481
03482 lightInfs.push_back(pl);
03483 }
03484 }
03485
03486
03487 it++;
03488 }
03489
03490
03491
03492 CPredPointLightToPoint predPLTP;
03493 predPLTP.Point= pos;
03494
03495 sort(lightInfs.begin(), lightInfs.end(), predPLTP);
03496
03497 lightInfs.resize( min((uint)lightInfs.size(), (uint)CTileLightInfluence::NumLightPerCorner) );
03498
03499
03500
03501
03502 CTileLightInfUnpack tli;
03503 uint lightInfId;
03504 for(lightInfId=0; lightInfId<lightInfs.size(); lightInfId++)
03505 {
03506 CPointLightRT *pl= lightInfs[lightInfId];
03507
03508
03509 tli.Light[lightInfId]= pl;
03510
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
03516 tli.LightFactor[lightInfId]*= pl->PointLight.computeLinearAttenuation(pos);
03517
03518
03519 pl->RefCount++;
03520 }
03521
03522 for(; lightInfId<CTileLightInfluence::NumLightPerCorner; lightInfId++)
03523 {
03524 tli.Light[lightInfId]= NULL;
03525 }
03526
03527
03528
03529
03530 pfpl.TileLightInfluences[y*pfpl.WidthTLI + x]= tli;
03531 }
03532 }
03533 }
03534
03535
03536
03537
03538 uint plId= 0;
03539
03540 for(i=0; i<_StaticPointLights.size(); i++)
03541 {
03542 CPointLightRT &plRT= _StaticPointLights[i];
03543
03544 if(plRT.RefCount > 0)
03545 {
03546
03547 listPointLight.push_back(plRT.PointLight);
03548 plRT.DstId= plId++;
03549
03550 if(plId>=0xFF)
03551 {
03552 throw Exception("Too many Static Point Lights influence the zone!!");
03553 }
03554 }
03555 }
03556
03557
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
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
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
03582 tliDst.Light[lightId]= 0xFF;
03583 }
03584 else
03585 {
03586
03587 tliDst.Light[lightId]= tliSrc.Light[lightId]->DstId;
03588
03589 tliDst.setDiffuseLightFactor(lightId, (uint8)(tliSrc.LightFactor[lightId]*255));
03590 }
03591 }
03592 }
03593 }
03594
03595 }
03596
03597 }
03598
03599
03600
03601
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
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())
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);
03656 tiles[top] = b;
03657 }
03658 else
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
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];
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))
03710 {
03712 float waterHeight = waterPoly.Vertices[0].z;
03713
03714 if (v1.z < waterHeight)
03715 {
03716
03717 te.setVegetableState(CTileElement::UnderWater);
03718
03719 ++ numTileBelow;
03720 }
03721 else if (v0. z > waterHeight)
03722 {
03723
03724 te.setVegetableState(CTileElement::AboveWater);
03725
03726 ++ numTileAbove;
03727 }
03728 else
03729 {
03730
03731 te.setVegetableState(CTileElement::IntersectWater);
03732
03733 ++ numTileIntersect;
03734 }
03735 break;
03736 }
03737 }
03738
03739 if (qgIt == _WaterShapeQuadGrid.end())
03740 {
03741 te.setVegetableState(CTileElement::AboveWater);
03742
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
03785 CSynchronized<std::vector<bool> >::CAccessor access (&_PatchComputed);
03786
03787
03788 uint index = _LastPatchComputed[process];
03789 uint firstIndex = index;
03790
03791 if (access.value().size() == 0)
03792
03793 return 0xffffffff;
03794
03795 while (access.value()[index])
03796 {
03797
03798 index++;
03799
03800
03801 if (index == _PatchInfo.size())
03802 index = 0;
03803
03804
03805 if (firstIndex == index)
03806
03807 return 0xffffffff;
03808 }
03809
03810
03811 access.value()[index] = true;
03812
03813
03814 _LastPatchComputed[process] = index;
03815 _NumberOfPatchComputed++;
03816
03817
03818 return index;
03819 }
03820
03821
03822
03823 float CZoneLighter::attenuation (const CVector &pos, const CZoneLighter::CLightDesc &description)
03824 {
03825
03826
03827
03828
03829
03830 float averageAttenuation = 0;
03831 float randomSum = 0;
03832
03833
03834 uint sample;
03835 const uint samples = description.SoftShadowSamplesSqrt*description.SoftShadowSamplesSqrt;
03836 for (sample=0; sample<samples; sample++)
03837 {
03838
03839 CZBuffer &zbuffer = _ZBufferLandscape[sample];
03840
03841
03842 CVector zPos;
03843 transformVectorToZBuffer (zbuffer, pos, zPos);
03844
03845
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
03852 averageAttenuation /= randomSum;
03853
03854
03855
03856
03857
03858
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
03866 return std::min (objectAttenuation, averageAttenuation);
03867 }
03868
03869
03870
03871