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