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
00029 #include "3d/vegetable_manager.h"
00030 #include "3d/driver.h"
00031 #include "3d/texture_file.h"
00032 #include "3d/fast_floor.h"
00033 #include "3d/vegetable_quadrant.h"
00034 #include "3d/dru.h"
00035 #include "3d/radix_sort.h"
00036 #include "3d/scene.h"
00037 #include "3d/vegetable_blend_layer_model.h"
00038 #include "3d/vegetable_light_ex.h"
00039 #include "nel/misc/hierarchical_timer.h"
00040
00041 #include <algorithm>
00042
00043
00044 using namespace std;
00045 using namespace NLMISC;
00046
00047
00048 namespace NL3D
00049 {
00050
00051
00052 #define NL3D_VEGETABLE_CLIP_BLOCK_BLOCKSIZE 16
00053 #define NL3D_VEGETABLE_SORT_BLOCK_BLOCKSIZE 64
00054 #define NL3D_VEGETABLE_INSTANCE_GROUP_BLOCKSIZE 128
00055
00056
00057
00058 CVegetableManager::CVegetableManager(uint maxVertexVbHardUnlit, uint maxVertexVbHardLighted,
00059 uint nbBlendLayers, float blendLayerDistMax) :
00060 _ClipBlockMemory(NL3D_VEGETABLE_CLIP_BLOCK_BLOCKSIZE),
00061 _SortBlockMemory(NL3D_VEGETABLE_SORT_BLOCK_BLOCKSIZE),
00062 _InstanceGroupMemory(NL3D_VEGETABLE_INSTANCE_GROUP_BLOCKSIZE),
00063 _NumZSortBlendLayers(nbBlendLayers), _ZSortLayerDistMax(blendLayerDistMax),
00064 _ZSortScene(NULL)
00065 {
00066 uint i;
00067
00068
00069 nlassert((uint)(CVegetableVBAllocator::VBTypeCount) == 2);
00070 _VBHardAllocator[CVegetableVBAllocator::VBTypeLighted].init( CVegetableVBAllocator::VBTypeLighted, maxVertexVbHardLighted );
00071 _VBHardAllocator[CVegetableVBAllocator::VBTypeUnlit].init( CVegetableVBAllocator::VBTypeUnlit, maxVertexVbHardUnlit );
00072
00073 _VBSoftAllocator[CVegetableVBAllocator::VBTypeLighted].init( CVegetableVBAllocator::VBTypeLighted, 0 );
00074 _VBSoftAllocator[CVegetableVBAllocator::VBTypeUnlit].init( CVegetableVBAllocator::VBTypeUnlit, 0 );
00075
00076
00077
00078
00079 _VegetableMaterial.initUnlit();
00080 _VegetableMaterial.setAlphaTest(true);
00081 _VegetableMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
00082
00083
00084 _DirectionalLight= (CVector(0,1, -1)).normed();
00085 _GlobalAmbient.set(64, 64, 64, 255);
00086 _GlobalDiffuse.set(150, 150, 150, 255);
00087
00088
00089 _WindDirection.set(1,0,0);
00090 _WindFrequency= 1;
00091 _WindPower= 1;
00092 _WindBendMin= 0;
00093 _Time= 0;
00094 _WindPrecRenderTime= 0;
00095 _WindAnimTime= 0;
00096
00097
00098 for(i=0; i<NL3D_VEGETABLE_VP_LUT_SIZE; i++)
00099 {
00100 _CosTable[i]= (float)cos( i*2*Pi / NL3D_VEGETABLE_VP_LUT_SIZE );
00101 }
00102
00103
00104 _NumZSortBlendLayers= max(1U, _NumZSortBlendLayers);
00105 _ZSortModelLayers.resize(_NumZSortBlendLayers, NULL);
00106 _ZSortModelLayersUW.resize(_NumZSortBlendLayers, NULL);
00107
00108
00109
00110 _ULFrequency= 0;
00111 _ULNVerticesToUpdate=0;
00112 _ULNTotalVertices= 0;
00113 _ULRootIg= NULL;
00114 _ULCurrentIgRdrPass= 0;
00115 _ULCurrentIgInstance= 0;
00116 _ULPrecTime= 0;
00117 _ULPrecTimeInit= false;
00118 _ULTime= 0;
00119
00120
00121 _NumVegetableFaceRendered= 0;
00122
00123 std::fill(_VertexProgram, _VertexProgram + NL3D_VEGETABLE_NRDRPASS, (CVertexProgram *) NULL);
00124
00125 }
00126
00127
00128
00129 CVegetableManager::~CVegetableManager()
00130 {
00131
00132 for(sint i=0; i <NL3D_VEGETABLE_NRDRPASS; i++)
00133 {
00134 delete _VertexProgram[i];
00135 _VertexProgram[i]= NULL;
00136 }
00137
00138
00139 if(_ZSortScene)
00140 {
00141
00142 for(uint i= 0; i<_NumZSortBlendLayers; i++)
00143 {
00144 _ZSortScene->deleteModel(_ZSortModelLayers[i]);
00145 _ZSortModelLayers[i]= NULL;
00146 _ZSortScene->deleteModel(_ZSortModelLayersUW[i]);
00147 _ZSortModelLayersUW[i]= NULL;
00148 }
00149
00150 _ZSortScene= NULL;
00151 }
00152 }
00153
00154
00155
00156 void CVegetableManager::createVegetableBlendLayersModels(CScene *scene)
00157 {
00158
00159 nlassert(scene);
00160 _ZSortScene= scene;
00161
00162
00163 for(uint i=0;i<_NumZSortBlendLayers; i++)
00164 {
00165
00166 nlassert(_ZSortModelLayers[i]==NULL);
00167 nlassert(_ZSortModelLayersUW[i]==NULL);
00168
00169 _ZSortModelLayers[i]= (CVegetableBlendLayerModel*)scene->createModel(VegetableBlendLayerModelId);
00170 _ZSortModelLayersUW[i]= (CVegetableBlendLayerModel*)scene->createModel(VegetableBlendLayerModelId);
00171
00172 _ZSortModelLayers[i]->VegetableManager= this;
00173 _ZSortModelLayersUW[i]->VegetableManager= this;
00174
00175
00176 _ZSortModelLayersUW[i]->setOrderingLayer(2);
00177 }
00178 }
00179
00180
00181
00182 CVegetableVBAllocator &CVegetableManager::getVBAllocatorForRdrPassAndVBHardMode(uint rdrPass, uint vbHardMode)
00183 {
00184
00185 if(vbHardMode==0)
00186 {
00187 if(rdrPass == NL3D_VEGETABLE_RDRPASS_LIGHTED)
00188 return _VBSoftAllocator[CVegetableVBAllocator::VBTypeLighted];
00189 if(rdrPass == NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED)
00190 return _VBSoftAllocator[CVegetableVBAllocator::VBTypeLighted];
00191 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT)
00192 return _VBSoftAllocator[CVegetableVBAllocator::VBTypeUnlit];
00193 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED)
00194 return _VBSoftAllocator[CVegetableVBAllocator::VBTypeUnlit];
00195 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
00196 return _VBSoftAllocator[CVegetableVBAllocator::VBTypeUnlit];
00197 }
00198
00199 else
00200 {
00201 if(rdrPass == NL3D_VEGETABLE_RDRPASS_LIGHTED)
00202 return _VBHardAllocator[CVegetableVBAllocator::VBTypeLighted];
00203 if(rdrPass == NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED)
00204 return _VBHardAllocator[CVegetableVBAllocator::VBTypeLighted];
00205 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT)
00206 return _VBHardAllocator[CVegetableVBAllocator::VBTypeUnlit];
00207 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED)
00208 return _VBHardAllocator[CVegetableVBAllocator::VBTypeUnlit];
00209 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
00210 return _VBHardAllocator[CVegetableVBAllocator::VBTypeUnlit];
00211 }
00212
00213
00214 nlstop;
00215
00216 return _VBSoftAllocator[0];
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 const char* NL3D_FastBendProgram=
00317 "!!VP1.0 \n\
00318 # compute time of animation: time*freqfactor + phase. \n\
00319 MAD R0.x, c[17].x, v[9].z, v[9].y; # R0.x= time of animation \n\
00320 \n\
00321 # animation: use the 64 LUT entries \n\
00322 EXP R0.y, R0.x; # fract part=> R0.y= [0,1[ \n\
00323 MUL R0, R0.y, c[23].xyyy; # R0.x= [0,64[ \n\
00324 ARL A0.x, R0.x; # A0.x= index in the LUT \n\
00325 EXP R0.y, R0.x; # R0.y= R0.x-A0.x= fp (fract part) \n\
00326 # lookup and lerp in one it: R0= value + fp * dv. \n\
00327 MAD R0.xy, R0.y, c[A0.x+32].zwww, c[A0.x+32].xyww; \n\
00328 \n\
00329 # The direction and power of the wind is encoded in the LUT. \n\
00330 # Scale now by vertex BendFactor (stored in v[0].w) \n\
00331 MAD R5, R0, v[0].w, v[0].xyzw; \n\
00332 # compute 1/norm, and multiply by original norm stored in v[9].x \n\
00333 DP3 R0.x, R5, R5; \n\
00334 RSQ R0.x, R0.x; \n\
00335 MUL R0.x, R0.x, v[9].x; \n\
00336 # mul by this factor, and add to center \n\
00337 MAD R5, R0.xxxw, R5, v[10]; \n\
00338 \n\
00339 # make local to camera pos. Important for ZBuffer precision \n\
00340 ADD R5, R5, -c[10]; \n\
00341 ";
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 const char* NL3D_BendProgramP0=
00387 "!!VP1.0 \n\
00388 # compute time of animation: time*freqfactor + phase. \n\
00389 MAD R0.x, c[17].x, v[9].z, v[9].y; # R0.x= time of animation \n\
00390 \n\
00391 # animation: f(x)= cos(x). compute a high precision cosinus \n\
00392 EXP R0.y, R0.x; # fract part=> R0.y= [0,1] <=> [-Pi, Pi] \n\
00393 MAD R0.x, R0.y, c[22].z, -c[22].y; # R0.x= a= [-Pi, Pi] \n\
00394 # R0 must get a2, a4, a6, a8 \n\
00395 MUL R0.x, R0.x, R0.x; # R0.x= a2 \n\
00396 MUL R0.y, R0.x, R0.x; # R0= a2, a4 \n\
00397 MUL R0.zw, R0.y, R0.xxxy; # R0= a2, a4, a6, a8 \n\
00398 # Taylor serie: cos(x)= 1 - (1/2) a2 + (1/24) a4 - (1/720) a6 + (1/40320) a8. \n\
00399 DP4 R0.x, R0, c[18]; # R0.x= cos(x) - 1. \n\
00400 \n\
00401 # R0.x= [-2, 0]. And we want a result in BendWeight/2*WindPower*[WindBendMin, 1] \n\
00402 MAD R0.x, R0.x, c[17].z, c[17].y; # R0.x= WindPower*[WindBendMin, 1] \n\
00403 MUL R0.x, R0.x, v[9].x; # R0.x= angle= BendWeight/2*WindPower*[WindBendMin, 1] \n\
00404 \n\
00405 # compute good precision sinus and cosinus, in R0.xy. \n\
00406 # suppose that BendWeightMax/2== 2Pi/3 => do not need to fmod() nor \n\
00407 # to have high order taylor serie \n\
00408 DST R1.xy, R0.x, R0.x; # R1= 1, a2 \n\
00409 MUL R1.z, R1.y, R1.y; # R1= 1, a2, a4 \n\
00410 MUL R1.w, R1.y, R1.z; # R1= 1, a2, a4, a6 (cos serie) \n\
00411 MUL R2, R1, R0.x; # R2= a, a3, a5, a7 (sin serie) \n\
00412 DP4 R0.x, R1, c[19]; # R0.x= cos(a) \n\
00413 DP4 R0.y, R2, c[20]; # R0.y= sin(a) \n\
00414 ";
00415 const char* NL3D_BendProgramP1=
00416 " \n\
00417 # build our quaternion \n\
00418 # multiply the angleAxis by sin(a) / cos(a), where a is actually a/2 \n\
00419 # remind: c[16].z== angleAxis.z== 0 \n\
00420 MUL R0, c[16], R0.yyyx; # R0= quaternion.xyzw \n\
00421 \n\
00422 # build our matrix from this quaternion, into R7,R8,R9 \n\
00423 # Quaternion TO matrix 3x3 in 7 ope, with quat.z==0 \n\
00424 MUL R1, R0, c[8].w; # R1= quat2= 2*quat == 2*x, 2*y, 0, 2*w \n\
00425 MUL R2, R1, R0.x; # R2= quatX= xx, xy, 0, wx \n\
00426 MUL R3, R1, R0.y; # R3= quatY= xy, yy, 0, wy \n\
00427 # NB: c[21]= {0, 1, -1, 0} \n\
00428 # Write to w, then w = 0, this avoid an unitialized component \n\
00429 MAD R7.xyzw, c[21].zyyw, R3.yxww, c[21].yxxw; \n\
00430 # R7.x= a11 = 1.0f - (yy) \n\
00431 # R7.y= a12 = xy \n\
00432 # R7.z= a13 = wy \n\
00433 # NB: c[21]= {0, 1, -1, 0} \n\
00434 # Write to w, then w = 0, this avoid an unitialized component \n\
00435 MAD R8.xyzw, c[21].yzzw, R2.yxww, c[21].xyxw; \n\
00436 # R8.x= a21 = xy \n\
00437 # R8.y= a22 = 1.0f - (xx) \n\
00438 # R8.z= a23 = - wx \n\
00439 # NB: c[21]= {0, 1, -1, 0} \n\
00440 # Write to w, then w = 0, this avoid an unitialized component \n\
00441 ADD R9.xyzw, R2.zwxw, R3.wzyw; # a31= 0+wy, a32= wx+0, a33= xx + yy, because z==0 \n\
00442 MAD R9.xyzw, R9.xyzw, c[21].zyzw, c[21].xxyw; \n\
00443 # R9.x= a31 = - wy \n\
00444 # R9.y= a32 = wx \n\
00445 # R9.z= a33 = 1.0f - (xx + yy) \n\
00446 # transform pos \n\
00447 DP3 R5.x, R7, v[0]; \n\
00448 DP3 R5.y, R8, v[0]; \n\
00449 DP3 R5.z, R9, v[0]; # R5= bended relative pos to center. \n\
00450 #temp, to optimize \n\
00451 MOV R5.w, c[21].w; \n\
00452 # add pos to center pos. \n\
00453 ADD R5, R5, v[10]; # R5= world pos. R5.w= R5.w+v[10].w= 0+1= 1 \n\
00454 # make local to camera pos. Important for ZBuffer precision \n\
00455 ADD R5, R5, -c[10]; \n\
00456 ";
00457
00458
00459
00460 const string NL3D_BendProgram= string(NL3D_BendProgramP0) + string(NL3D_BendProgramP1);
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 const char* NL3D_LightedStartVegetableProgram=
00472 " \n\
00473 # bend Pos into R5. Now do it for normal \n\
00474 DP3 R0.x, R7, v[2]; \n\
00475 DP3 R0.y, R8, v[2]; \n\
00476 DP3 R0.z, R9, v[2]; # R0= matRot * normal. \n\
00477 # Do the rot 2 times for normal (works fine) \n\
00478 DP3 R6.x, R7, R0; \n\
00479 DP3 R6.y, R8, R0; \n\
00480 DP3 R6.z, R9, R0; # R6= bended normal. \n\
00481 \n\
00482 # Normalize normal, and dot product, into R0.x \n\
00483 # w hasn't been written \n\
00484 DP3 R0.x, R6.xyzz, R6.xyzz; # R0.x= R6.sqrnorm() \n\
00485 RSQ R0.x, R0.x; # R0.x= 1/norm() \n\
00486 MUL R6, R6.xyzz, R0.x; # R6= R6.normed() \n\
00487 DP3 R0.x, R6, c[9]; \n\
00488 ";
00489
00490
00491
00492 const char* NL3D_LightedMiddle1SidedVegetableProgram=
00493 " #FrontFacing \n\
00494 MAX R0.y, -R0.x, c[8].x; # R0.y= diffFactor= max(0, -R6*LightDir) \n\
00495 MUL R1.xyz, R0.y, v[3]; # R7= diffFactor*DiffuseColor \n\
00496 ADD o[COL0].xyz, R1, v[4]; # col0.RGB= AmbientColor + diffFactor*DiffuseColor \n\
00497 ";
00498
00499
00500
00501 const char* NL3D_LightedMiddle2SidedVegetableProgram=
00502 " #FrontFacing \n\
00503 MAX R0.y, -R0.x, c[8].x; # R0.y= diffFactor= max(0, -R6*LightDir) \n\
00504 MUL R1.xyz, R0.y, v[3]; # R7= diffFactor*DiffuseColor \n\
00505 ADD o[COL0].xyz, R1, v[4]; # col0.RGB= AmbientColor + diffFactor*DiffuseColor \n\
00506 # BackFacing. \n\
00507 MAX R0.y, R0.x, c[8].x; # R0.y= diffFactor= max(0, -(-R6)*LightDir) \n\
00508 MUL R1.xyz, R0.y, v[3]; # R7= diffFactor*DiffuseColor \n\
00509 ADD o[BFC0].xyz, R1, v[4]; # bfc0.RGB= AmbientColor + diffFactor*DiffuseColor \n\
00510 ";
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 const char* NL3D_UnlitStartVegetableProgram=
00524 "";
00525
00526
00527
00528 const char* NL3D_UnlitMiddle1SidedVegetableProgram=
00529 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
00530 \n\
00531 ";
00532
00533
00534
00535 const char* NL3D_UnlitMiddle2SidedVegetableProgram=
00536 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
00537 MOV o[BFC0].xyz, v[4]; # bfc0.RGBA= bcf color \n\
00538 \n\
00539 ";
00540
00541
00542
00543 const char* NL3D_UnlitMiddle2SidedAlphaBlendVegetableProgram=
00544 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
00545 MOV o[BFC0].xyz, v[4]; # bfc0.RGBA= bcf color \n\
00546 \n\
00547 #Blend transition. NB: in R5, we already have the position relative to the camera \n\
00548 DP3 R0.x, R5, R5; # R0.x= sqr(dist to viewer). \n\
00549 RSQ R0.y, R0.x; \n\
00550 MUL R0.x, R0.x, R0.y; # R0.x= dist to viewer \n\
00551 # setup alpha Blending. Distance of appartition is encoded in the vertex. \n\
00552 MAD o[COL0].w, R0.x, c[11].x, v[9].w; \n\
00553 MAD o[BFC0].w, R0.x, c[11].x, v[9].w; \n\
00554 ";
00555
00556
00557
00558 const char* NL3D_UnlitMiddle1SidedAlphaBlendVegetableProgram=
00559 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
00560 \n\
00561 #Blend transition. NB: in R5, we already have the position relative to the camera \n\
00562 DP3 R0.x, R5, R5; # R0.x= sqr(dist to viewer). \n\
00563 RSQ R0.y, R0.x; \n\
00564 MUL R0.x, R0.x, R0.y; # R0.x= dist to viewer \n\
00565 # setup alpha Blending. Distance of appartition is encoded in the vertex. \n\
00566 MAD o[COL0].w, R0.x, c[11].x, v[9].w; \n\
00567 ";
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 const char* NL3D_CommonEndVegetableProgram=
00578 " # compute in Projection space \n\
00579 DP4 o[HPOS].x, c[0], R5; \n\
00580 DP4 o[HPOS].y, c[1], R5; \n\
00581 DP4 o[HPOS].z, c[2], R5; \n\
00582 DP4 o[HPOS].w, c[3], R5; \n\
00583 # copy Dynamic lightmap UV in stage0, from colors Alpha part. \n\
00584 MOV o[TEX0].x, v[3].w; \n\
00585 MOV o[TEX0].y, v[4].w; \n\
00586 # copy diffuse texture uv to stage 1. \n\
00587 MOV o[TEX1].xy, v[8]; \n\
00588 END \n\
00589 ";
00590
00591
00592
00593
00594
00595
00596
00597 const char* NL3D_SimpleStartVegetableProgram=
00598 "!!VP1.0 \n\
00599 # compute in Projection space \n\
00600 MOV R5, v[0]; \n\
00601 ADD R5.xyz, R5, v[10]; \n\
00602 # make local to camera pos \n\
00603 ADD R5, R5, -c[10]; \n\
00604 MOV o[COL0], c[8].yyyy; \n\
00605 MOV o[BFC0], c[8].xxyy; \n\
00606 ";
00607
00608
00609
00610
00611 void CVegetableManager::initVertexProgram(uint vpType)
00612 {
00613 nlassert(_LastDriver);
00614
00615 string vpgram;
00616
00617 if( vpType==NL3D_VEGETABLE_RDRPASS_LIGHTED || vpType==NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED )
00618 vpgram= NL3D_BendProgram;
00619 else
00620 vpgram= NL3D_FastBendProgram;
00621
00622
00623 bool doubleSided = _LastDriver->supportVertexProgramDoubleSidedColor();
00624
00625
00626 switch(vpType)
00627 {
00628 case NL3D_VEGETABLE_RDRPASS_LIGHTED:
00629 vpgram+= string(NL3D_LightedStartVegetableProgram);
00630 vpgram+= string(NL3D_LightedMiddle1SidedVegetableProgram);
00631 break;
00632 case NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED:
00633 vpgram+= string(NL3D_LightedStartVegetableProgram);
00634 vpgram+= string(doubleSided ? NL3D_LightedMiddle2SidedVegetableProgram
00635 : NL3D_LightedMiddle1SidedVegetableProgram);
00636 break;
00637 case NL3D_VEGETABLE_RDRPASS_UNLIT:
00638 vpgram+= string(NL3D_UnlitStartVegetableProgram);
00639 vpgram+= string(NL3D_UnlitMiddle1SidedVegetableProgram);
00640 break;
00641 case NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED:
00642 vpgram+= string(NL3D_UnlitStartVegetableProgram);
00643 vpgram+= string(doubleSided ? NL3D_UnlitMiddle2SidedVegetableProgram
00644 : NL3D_UnlitMiddle1SidedVegetableProgram
00645 );
00646 break;
00647 case NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT:
00648 vpgram+= string(NL3D_UnlitStartVegetableProgram);
00649 vpgram+= string(doubleSided ? NL3D_UnlitMiddle2SidedAlphaBlendVegetableProgram
00650 : NL3D_UnlitMiddle1SidedAlphaBlendVegetableProgram
00651 );
00652 break;
00653 }
00654
00655
00656 vpgram+= string(NL3D_CommonEndVegetableProgram);
00657
00658
00659 _VertexProgram[vpType]= new CVertexProgram(vpgram.c_str());
00660
00661 }
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 CVegetableClipBlock *CVegetableManager::createClipBlock()
00673 {
00674
00675 CVegetableClipBlock *ret;
00676 ret= _ClipBlockMemory.allocate();
00677
00678
00679 _EmptyClipBlockList.append(ret);
00680
00681 return ret;
00682 }
00683
00684
00685 void CVegetableManager::deleteClipBlock(CVegetableClipBlock *clipBlock)
00686 {
00687 if(!clipBlock)
00688 return;
00689
00690
00691 nlassert(clipBlock->_SortBlockList.size() == 0);
00692
00693
00694 _EmptyClipBlockList.remove(clipBlock);
00695
00696
00697 _ClipBlockMemory.free(clipBlock);
00698 }
00699
00700
00701
00702 CVegetableSortBlock *CVegetableManager::createSortBlock(CVegetableClipBlock *clipBlock, const CVector ¢er, float radius)
00703 {
00704 nlassert(clipBlock);
00705
00706
00707 CVegetableSortBlock *ret;
00708 ret= _SortBlockMemory.allocate();
00709 ret->_Owner= clipBlock;
00710 ret->_Center= center;
00711 ret->_Radius= radius;
00712
00713
00714 clipBlock->_SortBlockList.append(ret);
00715
00716 return ret;
00717 }
00718
00719
00720 void CVegetableManager::deleteSortBlock(CVegetableSortBlock *sortBlock)
00721 {
00722 if(!sortBlock)
00723 return;
00724
00725
00726 nlassert(sortBlock->_InstanceGroupList.size() == 0);
00727
00728
00729 sortBlock->_Owner->_SortBlockList.remove(sortBlock);
00730
00731
00732 _SortBlockMemory.free(sortBlock);
00733 }
00734
00735
00736
00737 CVegetableInstanceGroup *CVegetableManager::createIg(CVegetableSortBlock *sortBlock)
00738 {
00739 nlassert(sortBlock);
00740 CVegetableClipBlock *clipBlock= sortBlock->_Owner;
00741
00742
00743
00744 CVegetableInstanceGroup *ret;
00745 ret= _InstanceGroupMemory.allocate();
00746 ret->_SortOwner= sortBlock;
00747 ret->_ClipOwner= clipBlock;
00748
00749
00750 if(clipBlock->_NumIgs==0)
00751 {
00752
00753 _EmptyClipBlockList.remove(clipBlock);
00754
00755 _ClipBlockList.append(clipBlock);
00756 }
00757
00758
00759 clipBlock->_NumIgs++;
00760
00761
00762 sortBlock->_InstanceGroupList.append(ret);
00763
00764
00765 ret->_RdrPass[NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT].HardMode= sortBlock->ZSortHardMode;
00766
00767 return ret;
00768 }
00769
00770
00771 void CVegetableManager::deleteIg(CVegetableInstanceGroup *ig)
00772 {
00773 if(!ig)
00774 return;
00775
00776
00777
00778
00779 if(_ULRootIg == ig)
00780 {
00781
00782 _ULRootIg= ig->_ULNext;
00783
00784 if(_ULRootIg == ig)
00785 _ULRootIg= NULL;
00786
00787 _ULCurrentIgRdrPass= 0;
00788 _ULCurrentIgInstance= 0;
00789 }
00790
00791 _ULNTotalVertices-= ig->_ULNumVertices;
00792
00793 ig->unlinkUL();
00794
00795
00796
00797
00798 for(sint rdrPass=0; rdrPass < NL3D_VEGETABLE_NRDRPASS; rdrPass++)
00799 {
00800
00801 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPass];
00802
00803 CVegetableVBAllocator &vbAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vegetRdrPass.HardMode);
00804
00805
00806 sint numVertices;
00807 numVertices= vegetRdrPass.Vertices.size();
00808
00809 nlassert((uint)numVertices == vegetRdrPass.NVertices);
00810 for(sint i=0; i<numVertices;i++)
00811 {
00812 vbAllocator.deleteVertex(vegetRdrPass.Vertices[i]);
00813 }
00814 vegetRdrPass.Vertices.clear();
00815 }
00816
00817 CVegetableClipBlock *clipBlock= ig->_ClipOwner;
00818 CVegetableSortBlock *sortBlock= ig->_SortOwner;
00819
00820
00821 if(ig->_HasZSortPassInstances)
00822
00823 sortBlock->_Dirty= true;
00824
00825
00826
00827 sortBlock->_InstanceGroupList.remove(ig);
00828 _InstanceGroupMemory.free(ig);
00829
00830
00831
00832 clipBlock->_NumIgs--;
00833
00834 if(clipBlock->_NumIgs==0)
00835 {
00836
00837 _ClipBlockList.remove(clipBlock);
00838
00839 _EmptyClipBlockList.append(clipBlock);
00840 }
00841
00842 }
00843
00844
00845
00846 CVegetableShape *CVegetableManager::getVegetableShape(const std::string &shape)
00847 {
00848 ItShapeMap it= _ShapeMap.find(shape);
00849
00850 if(it != _ShapeMap.end())
00851 return &it->second;
00852
00853 {
00854
00855 CVegetableShape *ret;
00856 it= ( _ShapeMap.insert(make_pair(shape, CVegetableShape()) ) ).first;
00857 ret= &it->second;
00858
00859
00860 try
00861 {
00862 ret->loadShape(shape);
00863 }
00864 catch (Exception &e)
00865 {
00866
00867 nlwarning ("CVegetableManager::getVegetableShape error while loading shape file '%s' : '%s'", shape.c_str (), e.what ());
00868
00869
00870 _ShapeMap.erase (shape);
00871
00872
00873 ret = NULL;
00874 }
00875
00876 return ret;
00877 }
00878 }
00879
00880
00881
00882 uint CVegetableManager::getRdrPassInfoForShape(CVegetableShape *shape, TVegetableWater vegetWaterState,
00883 bool &instanceLighted, bool &instanceDoubleSided, bool &instanceZSort,
00884 bool &destLighted, bool &precomputeLighting)
00885 {
00886 instanceLighted= shape->Lighted;
00887 instanceDoubleSided= shape->DoubleSided;
00888
00889 instanceZSort= shape->AlphaBlend && vegetWaterState!=IntersectWater;
00890 destLighted= instanceLighted && !shape->PreComputeLighting;
00891 precomputeLighting= instanceLighted && shape->PreComputeLighting;
00892
00893
00894 uint rdrPass;
00895
00896 if(destLighted)
00897 {
00898 if(instanceDoubleSided)
00899 rdrPass= NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED;
00900 else
00901 rdrPass= NL3D_VEGETABLE_RDRPASS_LIGHTED;
00902 }
00903 else
00904 {
00905 if(instanceDoubleSided)
00906 {
00907 if(instanceZSort)
00908 rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT;
00909 else
00910 rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED;
00911 }
00912 else
00913 rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT;
00914 }
00915
00916 return rdrPass;
00917 }
00918
00919
00920
00921 void CVegetableManager::reserveIgAddInstances(CVegetableInstanceGroupReserve &vegetIgReserve, CVegetableShape *shape, TVegetableWater vegetWaterState, uint numInstances)
00922 {
00923 bool instanceLighted;
00924 bool instanceDoubleSided;
00925 bool instanceZSort;
00926 bool destLighted;
00927 bool precomputeLighting;
00928
00929
00930 uint rdrPass;
00931 rdrPass= getRdrPassInfoForShape(shape, vegetWaterState, instanceLighted, instanceDoubleSided,
00932 instanceZSort, destLighted, precomputeLighting);
00933
00934
00935 CVegetableInstanceGroupReserve::CVegetableRdrPass &vegetRdrPass= vegetIgReserve._RdrPass[rdrPass];
00936
00937
00938 vegetRdrPass.NVertices+= numInstances * shape->VB.getNumVertices();
00939 vegetRdrPass.NTriangles+= numInstances * shape->TriangleIndices.size()/3;
00940
00941 if(instanceLighted)
00942 vegetRdrPass.NLightedInstances+= numInstances;
00943 }
00944
00945
00946
00947 void CVegetableManager::reserveIgCompile(CVegetableInstanceGroup *ig, const CVegetableInstanceGroupReserve &vegetIgReserve)
00948 {
00949 uint rdrPass;
00950
00951
00952
00953
00954
00955 for(rdrPass= 0; rdrPass<NL3D_VEGETABLE_NRDRPASS; rdrPass++)
00956 {
00957 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPass];
00958 nlassert(vegetRdrPass.TriangleIndices.size()==0);
00959 nlassert(vegetRdrPass.TriangleLocalIndices.size()==0);
00960 nlassert(vegetRdrPass.Vertices.size()==0);
00961 nlassert(vegetRdrPass.LightedInstances.size()==0);
00962 }
00963
00964 nlassert(ig->_TriangleQuadrantOrderArray.size()==0);
00965 nlassert(ig->_TriangleQuadrantOrderNumTriangles==0);
00966
00967
00968
00969
00970
00971 for(rdrPass= 0; rdrPass<NL3D_VEGETABLE_NRDRPASS; rdrPass++)
00972 {
00973 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPass];
00974 uint numVertices= vegetIgReserve._RdrPass[rdrPass].NVertices;
00975 uint numTris= vegetIgReserve._RdrPass[rdrPass].NTriangles;
00976 uint numLightedInstances= vegetIgReserve._RdrPass[rdrPass].NLightedInstances;
00977
00978 vegetRdrPass.TriangleIndices.resize(numTris*3);
00979 vegetRdrPass.TriangleLocalIndices.resize(numTris*3);
00980 vegetRdrPass.Vertices.resize(numVertices);
00981
00982 vegetRdrPass.LightedInstances.resize(numLightedInstances);
00983 }
00984
00985
00986 uint numZSortTris= vegetIgReserve._RdrPass[NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT].NTriangles;
00987
00988 ig->_TriangleQuadrantOrderArray.resize(numZSortTris * NL3D_VEGETABLE_NUM_QUADRANT);
00989
00990
00991 if(numZSortTris>0)
00992 {
00993 float *start= ig->_TriangleQuadrantOrderArray.getPtr();
00994
00995 for(uint i=0; i<NL3D_VEGETABLE_NUM_QUADRANT; i++)
00996 {
00997 ig->_TriangleQuadrantOrders[i]= start + i*numZSortTris;
00998 }
00999 }
01000 }
01001
01002
01003
01004 inline void computeVegetVertexLighting(const CVector &rotNormal, bool instanceDoubleSided,
01005 const CVector &sunDir, CRGBA primaryRGBA, CRGBA secondaryRGBA,
01006 CVegetableLightEx &vegetLex, CRGBA diffusePL[2],
01007 CRGBA *dstFront, CRGBA *dstBack)
01008 {
01009 float dpSun;
01010 float dpPL[2];
01011 CRGBA col;
01012 CRGBA resColor;
01013
01014
01015
01016 {
01017
01018 dpSun= rotNormal*sunDir;
01019 float f= max(0.f, -dpSun);
01020 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
01021
01022 resColor.addRGBOnly(col, secondaryRGBA);
01023
01024
01025
01026 if(vegetLex.NumLights>=1)
01027 {
01028 dpPL[0]= rotNormal*vegetLex.Direction[0];
01029 f= max(0.f, -dpPL[0]);
01030 col.modulateFromuiRGBOnly(diffusePL[0], OptFastFloor(f*256));
01031 resColor.addRGBOnly(col, resColor);
01032
01033 if(vegetLex.NumLights>=2)
01034 {
01035 dpPL[1]= rotNormal*vegetLex.Direction[1];
01036 f= max(0.f, -dpPL[1]);
01037 col.modulateFromuiRGBOnly(diffusePL[1], OptFastFloor(f*256));
01038 resColor.addRGBOnly(col, resColor);
01039 }
01040 }
01041
01042
01043 resColor.A= primaryRGBA.A;
01044
01045
01046 *dstFront= resColor;
01047 }
01048
01049
01050 if(instanceDoubleSided)
01051 {
01052
01053
01054
01055 float f= max(0.f, dpSun);
01056 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
01057
01058 resColor.addRGBOnly(col, secondaryRGBA);
01059
01060
01061
01062 if(vegetLex.NumLights>=1)
01063 {
01064 f= max(0.f, dpPL[0]);
01065 col.modulateFromuiRGBOnly(diffusePL[0], OptFastFloor(f*256));
01066 resColor.addRGBOnly(col, resColor);
01067
01068 if(vegetLex.NumLights>=2)
01069 {
01070 f= max(0.f, dpPL[1]);
01071 col.modulateFromuiRGBOnly(diffusePL[1], OptFastFloor(f*256));
01072 resColor.addRGBOnly(col, resColor);
01073 }
01074 }
01075
01076
01077 resColor.A= secondaryRGBA.A;
01078
01079
01080 *dstBack= resColor;
01081 }
01082 }
01083
01084
01085
01086 inline void computeVegetVertexLightingForceBestSided(const CVector &rotNormal, bool instanceDoubleSided,
01087 const CVector &sunDir, CRGBA primaryRGBA, CRGBA secondaryRGBA,
01088 CVegetableLightEx &vegetLex, CRGBA diffusePL[2],
01089 CRGBA *dstFront, CRGBA *dstBack)
01090 {
01091 float dpSun;
01092 float dpPL[2];
01093 CRGBA col;
01094 CRGBA resColor;
01095
01096
01097
01098 {
01099
01100 dpSun= rotNormal*sunDir;
01101
01102 float f= (float)fabs(dpSun);
01103 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
01104
01105 resColor.addRGBOnly(col, secondaryRGBA);
01106
01107
01108
01109 if(vegetLex.NumLights>=1)
01110 {
01111 dpPL[0]= rotNormal*vegetLex.Direction[0];
01112
01113 f= (float)fabs(dpPL[0]);
01114 col.modulateFromuiRGBOnly(diffusePL[0], OptFastFloor(f*256));
01115 resColor.addRGBOnly(col, resColor);
01116
01117 if(vegetLex.NumLights>=2)
01118 {
01119 dpPL[1]= rotNormal*vegetLex.Direction[1];
01120 f= (float)fabs(dpPL[1]);
01121 col.modulateFromuiRGBOnly(diffusePL[1], OptFastFloor(f*256));
01122 resColor.addRGBOnly(col, resColor);
01123 }
01124 }
01125
01126
01127 resColor.A= primaryRGBA.A;
01128
01129
01130 *dstFront= resColor;
01131 }
01132
01133
01134 if(instanceDoubleSided)
01135 {
01136
01137
01138
01139 resColor.A= secondaryRGBA.A;
01140
01141
01142 *dstBack= resColor;
01143 }
01144 }
01145
01146
01147
01148 void CVegetableManager::addInstance(CVegetableInstanceGroup *ig,
01149 CVegetableShape *shape, const NLMISC::CMatrix &mat,
01150 const NLMISC::CRGBAF &ambientColor, const NLMISC::CRGBAF &diffuseColor,
01151 float bendFactor, float bendPhase, float bendFreqFactor, float blendDistMax,
01152 TVegetableWater vegetWaterState, CVegetableUV8 dlmUV)
01153 {
01154 sint i;
01155
01156
01157
01158
01159 bool instanceLighted;
01160 bool instanceDoubleSided;
01161 bool instanceZSort;
01162 bool destLighted;
01163 bool precomputeLighting;
01164
01165
01166 uint rdrPass;
01167 rdrPass= getRdrPassInfoForShape(shape, vegetWaterState, instanceLighted, instanceDoubleSided,
01168 instanceZSort, destLighted, precomputeLighting);
01169
01170 bool bestSidedPrecomputeLighting= precomputeLighting && shape->BestSidedPreComputeLighting;
01171
01172
01173
01174 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPass];
01175
01176
01177
01178 CRGBA ambientRGBA, diffuseRGBA;
01179 CRGBA primaryRGBA, secondaryRGBA;
01180
01181 diffuseRGBA.R= (uint8)OptFastFloor(diffuseColor.R*255);
01182 diffuseRGBA.G= (uint8)OptFastFloor(diffuseColor.G*255);
01183 diffuseRGBA.B= (uint8)OptFastFloor(diffuseColor.B*255);
01184 diffuseRGBA.A= 255;
01185
01186 ambientRGBA.R= (uint8)OptFastFloor(ambientColor.R*255);
01187 ambientRGBA.G= (uint8)OptFastFloor(ambientColor.G*255);
01188 ambientRGBA.B= (uint8)OptFastFloor(ambientColor.B*255);
01189 ambientRGBA.A= 255;
01190
01191
01192 primaryRGBA.modulateFromColorRGBOnly(diffuseRGBA, _GlobalDiffuse);
01193 secondaryRGBA.modulateFromColorRGBOnly(ambientRGBA, _GlobalAmbient);
01194
01195
01196 if(!instanceLighted)
01197 {
01198 primaryRGBA.R= min(255, primaryRGBA.R + secondaryRGBA.R);
01199 primaryRGBA.G= min(255, primaryRGBA.G + secondaryRGBA.G);
01200 primaryRGBA.B= min(255, primaryRGBA.B + secondaryRGBA.B);
01201
01202 secondaryRGBA= primaryRGBA;
01203 }
01204
01205
01206 primaryRGBA.A= dlmUV.U;
01207 secondaryRGBA.A= dlmUV.V;
01208
01209
01210 CVegetableLightEx &vegetLex= ig->VegetableLightEx;
01211
01212 CRGBA diffusePL[2];
01213 if(vegetLex.NumLights>=1)
01214 {
01215 diffusePL[0].modulateFromColorRGBOnly(diffuseRGBA, vegetLex.Color[0]);
01216 if(vegetLex.NumLights>=2)
01217 {
01218 diffusePL[1].modulateFromColorRGBOnly(diffuseRGBA, vegetLex.Color[1]);
01219 }
01220 }
01221
01222
01223 bendFreqFactor*= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC;
01224 bendFreqFactor= (float)floor(bendFreqFactor + 0.5f);
01225 bendFreqFactor/= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC;
01226
01227
01228
01229
01230 CVegetableVBAllocator *allocator;
01231
01232 if(!vegetRdrPass.HardMode)
01233 {
01234
01235 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 0);
01236 }
01237 else
01238 {
01239
01240 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 1);
01241
01242 if(allocator->exceedMaxVertexInBufferHard(shape->VB.getNumVertices()))
01243 {
01244
01245
01246 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01247 {
01248 nlassert(ig->_SortOwner->ZSortHardMode);
01249
01250
01251 CVegetableInstanceGroup *pIg= ig->_SortOwner->_InstanceGroupList.begin();
01252 while(pIg)
01253 {
01254
01255 swapIgRdrPassHardMode(pIg, rdrPass);
01256
01257 pIg= (CVegetableInstanceGroup*)pIg->Next;
01258 }
01259
01260
01261 ig->_SortOwner->ZSortHardMode= false;
01262 }
01263 else
01264 {
01265
01266 swapIgRdrPassHardMode(ig, rdrPass);
01267 }
01268
01269
01270 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 0);
01271 }
01272 }
01273
01274
01275
01276 const CVertexBuffer &dstVBInfo= allocator->getSoftwareVertexBuffer();
01277
01278
01279
01280
01281
01282 CMatrix normalMat;
01283
01284 normalMat.setRot(mat);
01285 normalMat.invert();
01286 normalMat.transpose();
01287
01288 CVector instancePos;
01289 mat.getPos(instancePos);
01290
01291
01292
01293 ig->_ClipOwner->extendSphere(instancePos);
01294
01295
01296
01297 uint numNewVertices= shape->VB.getNumVertices();
01298 uint numNewTris= shape->TriangleIndices.size()/3;
01299 uint numNewIndices= shape->TriangleIndices.size();
01300
01301
01302 uint srcNormalOff= (instanceLighted? shape->VB.getNormalOff() : 0);
01303 uint srcTex0Off= shape->VB.getTexCoordOff(0);
01304 uint srcTex1Off= shape->VB.getTexCoordOff(1);
01305
01306
01307 uint dstNormalOff= (destLighted? dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_NORMAL) : 0);
01308
01309 uint dstColor1Off= ( (destLighted||instanceDoubleSided)?
01310 dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR1) : 0);
01311 uint dstColor0Off= dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR0);
01312 uint dstTex0Off= dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_TEX0);
01313 uint dstBendOff= dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_BENDINFO);
01314 uint dstCenterOff= dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_CENTER);
01315
01316
01317
01318 CVector deltaPos;
01319 float deltaPosNorm=0.0;
01320
01321
01322
01323 static vector<CVector> worldVertices;
01324 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01325 {
01326 worldVertices.resize(numNewVertices);
01327 }
01328
01329
01330
01331 for(i=0; i<(sint)numNewVertices;i++)
01332 {
01333
01334 uint vid= allocator->allocateVertex();
01335
01336 shape->InstanceVertices[i]= vid;
01337
01338
01339 uint8 *srcPtr= (uint8*)shape->VB.getVertexCoordPointer(i);
01340 uint8 *dstPtr= (uint8*)allocator->getVertexPointer(vid);
01341
01342
01343 float vertexBendWeight= ((CUV*)(srcPtr + srcTex1Off))->U * bendFactor;
01344
01345
01346
01347
01348 CVector relPos= mat.mulVector(*(CVector*)srcPtr);
01349
01350 CVector bendCenterPos;
01351 if(shape->BendCenterMode == CVegetableShapeBuild::BendCenterNull)
01352 bendCenterPos= CVector::Null;
01353 else
01354 {
01355 CVector v= *(CVector*)srcPtr;
01356 v.z= 0;
01357 bendCenterPos= mat.mulVector(v);
01358 }
01359
01360 deltaPos= relPos-bendCenterPos;
01361 *(CVector*)dstPtr= deltaPos;
01362 *(CVector*)(dstPtr + dstCenterOff)= instancePos + bendCenterPos;
01363
01364 if(!destLighted)
01365 {
01366 deltaPosNorm= deltaPos.norm();
01367
01368 CVectorH *vh= (CVectorH*)dstPtr;
01369
01370 vh->w= vertexBendWeight * deltaPosNorm;
01371 }
01372
01373
01374
01375
01376 ig->_ClipOwner->extendBBoxOnly(instancePos + relPos);
01377
01378
01379 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01380 {
01381 worldVertices[i]= instancePos + relPos;
01382 }
01383
01384
01385
01386
01387 if(!precomputeLighting)
01388 {
01389
01390 *(CRGBA*)(dstPtr + dstColor0Off)= primaryRGBA;
01391
01392 if(destLighted)
01393 {
01394
01395 *(CVector*)(dstPtr + dstNormalOff)= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
01396 }
01397
01398
01399
01400 *(CRGBA*)(dstPtr + dstColor1Off)= secondaryRGBA;
01401 }
01402 else
01403 {
01404 nlassert(!destLighted);
01405
01406
01407 CVector rotNormal= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
01408
01409 rotNormal.normalize();
01410
01411
01412 if(!bestSidedPrecomputeLighting)
01413 {
01414 computeVegetVertexLighting(rotNormal, instanceDoubleSided,
01415 _DirectionalLight, primaryRGBA, secondaryRGBA,
01416 vegetLex, diffusePL,
01417 (CRGBA*)(dstPtr + dstColor0Off), (CRGBA*)(dstPtr + dstColor1Off) );
01418 }
01419 else
01420 {
01421 computeVegetVertexLightingForceBestSided(rotNormal, instanceDoubleSided,
01422 _DirectionalLight, primaryRGBA, secondaryRGBA,
01423 vegetLex, diffusePL,
01424 (CRGBA*)(dstPtr + dstColor0Off), (CRGBA*)(dstPtr + dstColor1Off) );
01425 }
01426
01427 }
01428
01429
01430
01431
01432 *(CUV*)(dstPtr + dstTex0Off)= *(CUV*)(srcPtr + srcTex0Off);
01433
01434
01435
01436 CVector *dstBendPtr= (CVector*)(dstPtr + dstBendOff);
01437
01438 dstBendPtr->y= bendPhase;
01439
01440
01441 if(destLighted)
01442 dstBendPtr->x= vertexBendWeight;
01443 else
01444
01445 dstBendPtr->x= deltaPosNorm;
01446
01447 dstBendPtr->z= bendFreqFactor;
01449 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01450 {
01451
01452 CVectorH *dstBendPtr= (CVectorH*)(dstPtr + dstBendOff);
01453
01454
01455 dstBendPtr->w= blendDistMax/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST;
01456 }
01457
01458
01459
01460
01461 allocator->flushVertex(vid);
01462 }
01463
01464
01465
01466 ig->_ClipOwner->updateSphere();
01467
01468
01469
01470
01471 if(rdrPass==NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01472 {
01473
01474 ig->_SortOwner->_Dirty= true;
01475
01476 ig->_HasZSortPassInstances= true;
01477
01478
01479 if(vegetWaterState == AboveWater)
01480 ig->_SortOwner->_UnderWater= false;
01481 else if(vegetWaterState == UnderWater)
01482 ig->_SortOwner->_UnderWater= true;
01483
01484
01485 static vector<CVector> triangleCenters;
01486 triangleCenters.resize(numNewTris);
01487
01488
01489 for(uint i=0; i<numNewTris; i++)
01490 {
01491
01492 uint v0= shape->TriangleIndices[i*3+0];
01493 uint v1= shape->TriangleIndices[i*3+1];
01494 uint v2= shape->TriangleIndices[i*3+2];
01495
01496
01497 const CVector &vert0= worldVertices[v0];
01498 const CVector &vert1= worldVertices[v1];
01499 const CVector &vert2= worldVertices[v2];
01500
01501
01502 triangleCenters[i]= (vert0 + vert1 + vert2) / 3;
01503
01504 triangleCenters[i]-= ig->_SortOwner->_Center;
01505 }
01506
01507
01508
01509 uint offTri= ig->_TriangleQuadrantOrderNumTriangles;
01510 ig->_TriangleQuadrantOrderNumTriangles+= numNewTris;
01511
01512 nlassert(ig->_TriangleQuadrantOrderNumTriangles * NL3D_VEGETABLE_NUM_QUADRANT <= ig->_TriangleQuadrantOrderArray.size());
01513
01514
01515
01516 for(uint quadId=0; quadId<NL3D_VEGETABLE_NUM_QUADRANT; quadId++)
01517 {
01518 const CVector &quadDir= CVegetableQuadrant::Dirs[quadId];
01519
01520
01521 for(uint i=0; i<numNewTris; i++)
01522 {
01523
01524 ig->_TriangleQuadrantOrders[quadId][offTri + i]= triangleCenters[i] * quadDir;
01525 }
01526 }
01527 }
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537 uint offVertex= vegetRdrPass.NVertices;
01538 uint offTri= vegetRdrPass.NTriangles;
01539 uint offTriIdx= offTri*3;
01540
01541
01542 nlassert(offVertex + numNewVertices <= vegetRdrPass.Vertices.size());
01543 nlassert(offTriIdx + numNewIndices <= vegetRdrPass.TriangleIndices.size());
01544 nlassert(offTriIdx + numNewIndices <= vegetRdrPass.TriangleLocalIndices.size());
01545
01546
01547
01548 vegetRdrPass.Vertices.copy(offVertex, offVertex+numNewVertices, &shape->InstanceVertices[0]);
01549
01550
01551
01552 for(i=0; i<(sint)numNewIndices; i++)
01553 {
01554
01555 uint vid= shape->TriangleIndices[i];
01556
01557 vegetRdrPass.TriangleIndices[offTriIdx + i]= shape->InstanceVertices[vid];
01558
01559 vegetRdrPass.TriangleLocalIndices[offTriIdx + i]= offVertex + vid;
01560 }
01561
01562
01563 vegetRdrPass.NTriangles+= numNewTris;
01564 vegetRdrPass.NVertices+= numNewVertices;
01565
01566
01567
01568
01569 if(instanceLighted)
01570 {
01571
01572 ig->_ULNumVertices+= numNewVertices;
01573
01574 _ULNTotalVertices+= numNewVertices;
01575
01576 if(_ULRootIg==NULL)
01577 _ULRootIg= ig;
01578 else
01579 ig->linkBeforeUL(_ULRootIg);
01580
01581
01582 nlassert(vegetRdrPass.NLightedInstances < vegetRdrPass.LightedInstances.size());
01583
01584
01585 CVegetableInstanceGroup::CVegetableLightedInstance &vli=
01586 vegetRdrPass.LightedInstances[vegetRdrPass.NLightedInstances];
01587 vli.Shape= shape;
01588 vli.NormalMat= normalMat;
01589
01590 vli.MatAmbient= ambientRGBA;
01591 vli.MatDiffuse= diffuseRGBA;
01592
01593 vli.DlmUV= dlmUV;
01594
01595 vli.StartIdInRdrPass= offVertex;
01596
01597
01598 vegetRdrPass.NLightedInstances++;
01599 }
01600
01601 }
01602
01603
01604
01605 void CVegetableManager::swapIgRdrPassHardMode(CVegetableInstanceGroup *ig, uint rdrPass)
01606 {
01607 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPass];
01608
01609
01610 CVegetableVBAllocator &srcAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vegetRdrPass.HardMode);
01611
01612 CVegetableVBAllocator &dstAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, !vegetRdrPass.HardMode);
01613
01614
01615 uint vbSize= srcAllocator.getSoftwareVertexBuffer().getVertexSize();
01616 nlassert(vbSize == dstAllocator.getSoftwareVertexBuffer().getVertexSize());
01617
01618
01619 uint i;
01620
01621
01622
01623 for(i=0;i<vegetRdrPass.NVertices;i++)
01624 {
01625
01626 uint srcId= vegetRdrPass.Vertices[i];
01627
01628 uint dstId= dstAllocator.allocateVertex();
01629
01630
01631 void *vbSrc= srcAllocator.getVertexPointer(srcId);
01632 void *vbDst= dstAllocator.getVertexPointer(dstId);
01633 memcpy(vbDst, vbSrc, vbSize);
01634
01635 srcAllocator.deleteVertex(srcId);
01636
01637
01638 vegetRdrPass.Vertices[i]= dstId;
01639
01640
01641 dstAllocator.flushVertex(dstId);
01642 }
01643
01644
01645 nlassert(vegetRdrPass.TriangleIndices.size() == vegetRdrPass.TriangleLocalIndices.size());
01646
01647
01648 for(i=0;i<vegetRdrPass.NTriangles*3;i++)
01649 {
01650
01651 uint localVid= vegetRdrPass.TriangleLocalIndices[i];
01652
01653 vegetRdrPass.TriangleIndices[i]= vegetRdrPass.Vertices[localVid];
01654 }
01655
01656
01657 vegetRdrPass.HardMode= !vegetRdrPass.HardMode;
01658 }
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 bool CVegetableManager::doubleSidedRdrPass(uint rdrPass)
01670 {
01671 nlassert(rdrPass<NL3D_VEGETABLE_NRDRPASS);
01672 return (rdrPass == NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED) ||
01673 (rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED) ||
01674 (rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT);
01675 }
01676
01677
01678 void CVegetableManager::updateDriver(IDriver *driver)
01679 {
01680
01681 uint i;
01682 for(i=0; i <CVegetableVBAllocator::VBTypeCount; i++)
01683 {
01684 _VBHardAllocator[i].updateDriver(driver);
01685 _VBSoftAllocator[i].updateDriver(driver);
01686 }
01687
01688
01689 if (driver != _LastDriver)
01690 {
01691 _LastDriver = driver;
01692 for(i=0; i <NL3D_VEGETABLE_NRDRPASS; i++)
01693 {
01694 initVertexProgram(i);
01695 }
01696 }
01697 }
01698
01699
01700
01701 void CVegetableManager::loadTexture(const string &texName)
01702 {
01703
01704 ITexture *tex= new CTextureFile(texName);
01705 loadTexture(tex);
01706
01707 tex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapLinear);
01708 tex->setWrapS(ITexture::Clamp);
01709 tex->setWrapT(ITexture::Clamp);
01710 }
01711
01712
01713 void CVegetableManager::loadTexture(ITexture *itex)
01714 {
01715
01716
01717 _VegetableMaterial.setTexture(1, itex);
01718 }
01719
01720
01721 void CVegetableManager::setDirectionalLight(const CRGBA &ambient, const CRGBA &diffuse, const CVector &light)
01722 {
01723 _DirectionalLight= light;
01724 _DirectionalLight.normalize();
01725
01726 _GlobalAmbient= ambient;
01727 _GlobalDiffuse= diffuse;
01728 }
01729
01730
01731 void CVegetableManager::lockBuffers()
01732 {
01733
01734 for(uint i=0; i <CVegetableVBAllocator::VBTypeCount; i++)
01735 {
01736 _VBHardAllocator[i].lockBuffer();
01737 _VBSoftAllocator[i].lockBuffer();
01738 }
01739 }
01740
01741
01742 void CVegetableManager::unlockBuffers()
01743 {
01744
01745 for(uint i=0; i <CVegetableVBAllocator::VBTypeCount; i++)
01746 {
01747 _VBHardAllocator[i].unlockBuffer();
01748 _VBSoftAllocator[i].unlockBuffer();
01749 }
01750 }
01751
01752
01753
01754 class CSortVSB
01755 {
01756 public:
01757 CVegetableSortBlock *Sb;
01758
01759 CSortVSB() : Sb(NULL) {}
01760 CSortVSB(CVegetableSortBlock *sb) : Sb(sb) {}
01761
01762
01763
01764 bool operator<(const CSortVSB &o) const
01765 {
01766 return Sb->_SortKey>o.Sb->_SortKey;
01767 }
01768
01769 };
01770
01771
01772
01773 void CVegetableManager::setupVertexProgramConstants(IDriver *driver)
01774 {
01775
01776
01777
01778 driver->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
01779
01780 driver->setConstantMatrix(4, IDriver::ModelView, IDriver::Identity);
01781
01782 driver->setConstant(8, 0, 1, 0.5f, 2);
01783
01784 driver->setConstant(9, _DirectionalLight);
01785
01786 driver->setConstant(10, _ViewCenter);
01787
01788 driver->setConstant(11, -1.f/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST, 0, 0, 0);
01789
01790
01791
01792
01793
01794 driver->setConstant( 16, _AngleAxis.x, _AngleAxis.y, _AngleAxis.z, 1);
01795
01796 driver->setConstant( 17, (float)_WindAnimTime, _WindPower, _WindPower*(1-_WindBendMin)/2, 0 );
01797
01798 driver->setConstant( 18, -1/2.f, 1/24.f, -1/720.f, 1/40320.f );
01799
01800 driver->setConstant( 19, 1, -1/2.f, 1/24.f, -1/720.f );
01801
01802 driver->setConstant( 20, 1, -1/6.f, 1/120.f, -1/5040.f );
01803
01804 driver->setConstant( 21, 0.f, 1.f, -1.f, 0.f);
01805
01806 driver->setConstant( 22, 0.5f, (float)Pi, (float)(2*Pi), (float)(1/(2*Pi)) );
01807
01808 driver->setConstant( 23, NL3D_VEGETABLE_VP_LUT_SIZE, 0.f, 0.f, 0.f );
01809
01810
01811
01812 for(uint i=0; i<NL3D_VEGETABLE_VP_LUT_SIZE; i++)
01813 {
01814 CVector2f cur= _WindTable[i];
01815 CVector2f delta= _WindDeltaTable[i];
01816 driver->setConstant( 32+i, cur.x, cur.y, delta.x, delta.y );
01817 }
01818 }
01819
01820
01821
01822 void CVegetableManager::render(const CVector &viewCenter, const CVector &frontVector, const std::vector<CPlane> &pyramid,
01823 ITexture *textureDLM, IDriver *driver)
01824 {
01825 H_AUTO( NL3D_Vegetable_Render );
01826
01827 CVegetableClipBlock *rootToRender= NULL;
01828
01829
01830 CVector frontVectorNormed= frontVector.normed();
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841 CVegetableClipBlock *ptrClipBlock= _ClipBlockList.begin();
01842 while(ptrClipBlock)
01843 {
01844
01845 if(ptrClipBlock->clip(pyramid))
01846 {
01847
01848 ptrClipBlock->_RenderNext= rootToRender;
01849 rootToRender= ptrClipBlock;
01850 }
01851
01852
01853 ptrClipBlock= (CVegetableClipBlock*)ptrClipBlock->Next;
01854 }
01855
01856
01857
01858 if(rootToRender==NULL)
01859 return;
01860
01861
01862
01863
01864
01865
01866 CPrimitiveProfile ppIn, ppOut;
01867 driver->profileRenderedPrimitives(ppIn, ppOut);
01868 uint precNTriRdr= ppOut.NTriangles;
01869
01870
01871
01872 bool bkupFog;
01873 bkupFog= driver->fogEnabled();
01874 driver->enableFog(false);
01875
01876
01877
01878
01879 _ViewCenter= viewCenter;
01880
01881
01882
01883
01884 _ManagerMatrix.identity();
01885 _ManagerMatrix.setPos(_ViewCenter);
01886
01887
01888
01889 driver->setupModelMatrix(_ManagerMatrix);
01890
01891
01892
01893 updateDriver(driver);
01894
01895
01896
01897
01898
01899
01900 _WindAnimTime+= (_Time - _WindPrecRenderTime)*_WindFrequency;
01901 _WindAnimTime= fmod(_WindAnimTime, (float)NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC);
01902
01903
01904 _WindPrecRenderTime= _Time;
01905
01906
01907
01908
01909 _AngleAxis.set(-_WindDirection.y,_WindDirection.x,0);
01910
01911
01912
01913 uint i;
01914 for(i=0; i<NL3D_VEGETABLE_VP_LUT_SIZE; i++)
01915 {
01916
01917
01918
01919
01920
01921
01922 float windForce= (_CosTable[(i+32)%64] + 1);
01923
01924 windForce= _WindBendMin*2 + windForce * (1-_WindBendMin);
01925 windForce*= _WindPower;
01926
01927 _WindTable[i]= CVector2f(_WindDirection.x, _WindDirection.y) * windForce;
01928 }
01929
01930 for(i=0; i<NL3D_VEGETABLE_VP_LUT_SIZE; i++)
01931 {
01932 CVector2f cur= _WindTable[i];
01933 CVector2f delta= _WindTable[ (i+1)%NL3D_VEGETABLE_VP_LUT_SIZE ] - cur;
01934 _WindDeltaTable[i]= delta;
01935 }
01936
01937
01938
01939 setupVertexProgramConstants(driver);
01940
01941
01942
01943
01944
01945 if(textureDLM)
01946 {
01947
01948 _VegetableMaterial.setTexture(0, textureDLM);
01949 _VegetableMaterial.texEnvOpRGB(0, CMaterial::Add);
01950 _VegetableMaterial.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
01951 _VegetableMaterial.texEnvArg1RGB(0, CMaterial::Diffuse, CMaterial::SrcColor);
01952
01953 _VegetableMaterial.texEnvOpRGB(1, CMaterial::Modulate);
01954 _VegetableMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
01955 _VegetableMaterial.texEnvArg1RGB(1, CMaterial::Previous, CMaterial::SrcColor);
01956 }
01957 else
01958 {
01959
01960 _VegetableMaterial.setTexture(0, NULL);
01961
01962 _VegetableMaterial.texEnvOpRGB(1, CMaterial::Modulate);
01963 _VegetableMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
01964 _VegetableMaterial.texEnvArg1RGB(1, CMaterial::Diffuse, CMaterial::SrcColor);
01965 }
01966
01967 _VegetableMaterial.texEnvOpAlpha(1, CMaterial::Modulate);
01968 _VegetableMaterial.texEnvArg0Alpha(1, CMaterial::Texture, CMaterial::SrcAlpha);
01969 _VegetableMaterial.texEnvArg1Alpha(1, CMaterial::Diffuse, CMaterial::SrcAlpha);
01970
01971
01972
01973
01974
01975
01976
01977 _VegetableMaterial.setBlend(false);
01978 _VegetableMaterial.setZWrite(true);
01979 _VegetableMaterial.setAlphaTestThreshold(0.5f);
01980
01981
01982
01983
01984
01985
01986
01987 for(sint vbHardMode= 1; vbHardMode>=0; vbHardMode--)
01988 {
01989
01990 for(sint rdrPass=0; rdrPass < NL3D_VEGETABLE_NRDRPASS; rdrPass++)
01991 {
01992
01993 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
01994 continue;
01995
01996
01997 CVegetableVBAllocator &vbAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vbHardMode);
01998
01999
02000 if(vbAllocator.getNumUserVerticesAllocated()>0)
02001 {
02002
02003 bool doubleSided= doubleSidedRdrPass(rdrPass);
02004
02005 _VegetableMaterial.setDoubleSided( doubleSided );
02006
02007 driver->enableVertexProgramDoubleSidedColor(doubleSided);
02008
02009
02010
02011 driver->setupMaterial(_VegetableMaterial);
02012
02013
02014
02015 nlverify(driver->activeVertexProgram(_VertexProgram[rdrPass]));
02016
02017
02018 vbAllocator.activate();
02019
02020
02021 ptrClipBlock= rootToRender;
02022 while(ptrClipBlock)
02023 {
02024
02025 CVegetableSortBlock *ptrSortBlock= ptrClipBlock->_SortBlockList.begin();
02026 while(ptrSortBlock)
02027 {
02028
02029 CVegetableInstanceGroup *ptrIg= ptrSortBlock->_InstanceGroupList.begin();
02030 while(ptrIg)
02031 {
02032
02033 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ptrIg->_RdrPass[rdrPass];
02034
02035
02036 if( (vegetRdrPass.HardMode && vbHardMode==1) || (!vegetRdrPass.HardMode && vbHardMode==0) )
02037 {
02038
02039 if(vegetRdrPass.NTriangles)
02040 {
02041 driver->renderSimpleTriangles(&vegetRdrPass.TriangleIndices[0],
02042 vegetRdrPass.NTriangles);
02043 }
02044 }
02045
02046
02047 ptrIg= (CVegetableInstanceGroup*)ptrIg->Next;
02048 }
02049
02050
02051 ptrSortBlock= (CVegetableSortBlock *)(ptrSortBlock->Next);
02052 }
02053
02054
02055 ptrClipBlock= ptrClipBlock->_RenderNext;
02056 }
02057 }
02058
02059 }
02060
02061 }
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073 for(i=0; i<_NumZSortBlendLayers;i++)
02074 {
02075
02076 nlassert(_ZSortModelLayers[i]);
02077 nlassert(_ZSortModelLayersUW[i]);
02078
02079
02080
02081
02082
02083
02084
02085 float layerZ= i * _ZSortLayerDistMax / _NumZSortBlendLayers;
02086
02087 CVector pos= viewCenter + frontVector * layerZ;
02088
02089 _ZSortModelLayers[i]->setWorldPos(pos);
02090 _ZSortModelLayersUW[i]->setWorldPos(pos);
02091 }
02092
02093
02094 if( getVBAllocatorForRdrPassAndVBHardMode(NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT, 0).getNumUserVerticesAllocated()>0 ||
02095 getVBAllocatorForRdrPassAndVBHardMode(NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT, 1).getNumUserVerticesAllocated()>0 )
02096 {
02097 uint rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT;
02098
02099
02100
02101
02102 static vector<CSortVSB> sortVegetSbs;
02103 sortVegetSbs.clear();
02104
02105
02106 ptrClipBlock= rootToRender;
02107 while(ptrClipBlock)
02108 {
02109
02110 CVegetableSortBlock *ptrSortBlock= ptrClipBlock->_SortBlockList.begin();
02111 while(ptrSortBlock)
02112 {
02113
02114 if(ptrSortBlock->_NTriangles != 0)
02115 {
02116
02117
02118
02119
02120 CVector dirToSb= ptrSortBlock->_Center - viewCenter;
02121 float distToViewer= dirToSb.norm();
02122
02123 if(dirToSb * frontVectorNormed<0)
02124 {
02125 ptrSortBlock->_SortKey= - distToViewer;
02126 }
02127 else
02128 {
02129 ptrSortBlock->_SortKey= distToViewer;
02130 }
02131
02132
02133 sint bestDirIdx= 0;
02134 float bestDirVal= -FLT_MAX;
02135
02136
02137 if(ptrSortBlock->_SortKey < ptrSortBlock->_Radius)
02138 {
02139 dirToSb= frontVectorNormed;
02140 }
02141
02142
02143
02144 for(uint dirIdx=0; dirIdx<NL3D_VEGETABLE_NUM_QUADRANT; dirIdx++)
02145 {
02146 float dirVal= CVegetableQuadrant::Dirs[dirIdx] * dirToSb;
02147 if(dirVal>bestDirVal)
02148 {
02149 bestDirVal= dirVal;
02150 bestDirIdx= dirIdx;
02151 }
02152 }
02153
02154
02155 ptrSortBlock->_QuadrantId= bestDirIdx;
02156
02157
02158 sortVegetSbs.push_back(CSortVSB(ptrSortBlock));
02159
02160
02161
02162
02163 }
02164
02165
02166 ptrSortBlock= (CVegetableSortBlock *)(ptrSortBlock->Next);
02167 }
02168
02169
02170 ptrClipBlock= ptrClipBlock->_RenderNext;
02171 }
02172
02173
02174
02175 sort(sortVegetSbs.begin(), sortVegetSbs.end());
02176
02177
02178
02179
02180 bool doubleSided= doubleSidedRdrPass(rdrPass);
02181
02182 _VegetableMaterial.setDoubleSided( doubleSided );
02183
02184
02185 _VegetableMaterial.setBlend(true);
02186 _VegetableMaterial.setZWrite(false);
02187
02188 _VegetableMaterial.setAlphaTestThreshold(0.1f);
02189
02190
02191
02192
02193
02194
02195
02196 for(uint i=0; i<sortVegetSbs.size();i++)
02197 {
02198 CVegetableSortBlock *ptrSortBlock= sortVegetSbs[i].Sb;
02199
02200 float z= ptrSortBlock->_SortKey;
02201
02202 z= z*_NumZSortBlendLayers / _ZSortLayerDistMax;
02203
02204
02205 sint layer= OptFastFloor(z*256) >> 8;
02206 clamp(layer, 0, (sint)_NumZSortBlendLayers-1);
02207
02208
02209 if(ptrSortBlock->_UnderWater)
02210
02211 _ZSortModelLayersUW[layer]->SortBlocks.push_back(ptrSortBlock);
02212 else
02213 _ZSortModelLayers[layer]->SortBlocks.push_back(ptrSortBlock);
02214 }
02215
02216 }
02217
02218
02219
02220
02221
02222
02223 driver->activeVertexProgram(NULL);
02224
02225
02226 driver->enableVertexProgramDoubleSidedColor(false);
02227
02228
02229
02230 driver->enableFog(bkupFog);
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241 driver->profileRenderedPrimitives(ppIn, ppOut);
02242 _NumVegetableFaceRendered= ppOut.NTriangles-precNTriRdr;
02243
02244 }
02245
02246
02247
02248 void CVegetableManager::setupRenderStateForBlendLayerModel(IDriver *driver)
02249 {
02250
02251
02252
02253 _BkupFog= driver->fogEnabled();
02254 driver->enableFog(false);
02255
02256
02257 driver->setupModelMatrix(_ManagerMatrix);
02258
02259
02260 setupVertexProgramConstants(driver);
02261
02262
02263
02264 uint rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT;
02265
02266
02267 bool doubleSided= doubleSidedRdrPass(rdrPass);
02268
02269 driver->enableVertexProgramDoubleSidedColor(doubleSided);
02270
02271
02272 driver->setupMaterial(_VegetableMaterial);
02273
02274
02275
02276 nlverify(driver->activeVertexProgram(_VertexProgram[rdrPass]));
02277
02278 }
02279
02280
02281
02282 void CVegetableManager::resetNumVegetableFaceRendered()
02283 {
02284 _NumVegetableFaceRendered= 0;
02285 }
02286
02287
02288
02289 uint CVegetableManager::getNumVegetableFaceRendered() const
02290 {
02291 return _NumVegetableFaceRendered;
02292 }
02293
02294
02295
02296 void CVegetableManager::exitRenderStateForBlendLayerModel(IDriver *driver)
02297 {
02298
02299 driver->activeVertexProgram(NULL);
02300
02301
02302 driver->enableVertexProgramDoubleSidedColor(false);
02303
02304
02305 driver->enableFog(_BkupFog);
02306 }
02307
02308
02309
02310
02311 void CVegetableManager::setWind(const CVector &windDir, float windFreq, float windPower, float windBendMin)
02312 {
02313
02314 _WindDirection= windDir;
02315 _WindDirection.z= 0;
02316 _WindDirection.normalize();
02317
02318 _WindFrequency= windFreq;
02319 _WindPower= windPower;
02320 _WindBendMin= windBendMin;
02321 clamp(_WindBendMin, 0, 1);
02322 }
02323
02324
02325 void CVegetableManager::setTime(double time)
02326 {
02327
02328 _Time= time;
02329 }
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340 void CVegetableManager::setUpdateLightingTime(double time)
02341 {
02342 _ULTime= time;
02343 }
02344
02345
02346
02347 void CVegetableManager::updateLighting()
02348 {
02349
02350 if(!_ULPrecTimeInit)
02351 {
02352 _ULPrecTimeInit= true;
02353 _ULPrecTime= _ULTime;
02354 }
02355
02356 float dt= float(_ULTime - _ULPrecTime);
02357 _ULPrecTime= _ULTime;
02358
02359
02360 _ULNVerticesToUpdate+= dt*_ULFrequency * _ULNTotalVertices;
02361
02362 _ULNVerticesToUpdate= min(_ULNVerticesToUpdate, (float)_ULNTotalVertices);
02363
02364
02365 doUpdateLighting();
02366 }
02367
02368
02369
02370 void CVegetableManager::updateLightingAll()
02371 {
02372
02373 _ULNVerticesToUpdate= (float)_ULNTotalVertices;
02374
02375
02376 doUpdateLighting();
02377 }
02378
02379
02380
02381 void CVegetableManager::doUpdateLighting()
02382 {
02383
02384 while(_ULNVerticesToUpdate > 0 && _ULRootIg)
02385 {
02386
02387 if(updateLightingIGPart())
02388 {
02389
02390 _ULRootIg= _ULRootIg->_ULNext;
02391 }
02392 }
02393
02394
02395 }
02396
02397
02398
02399 void CVegetableManager::setUpdateLightingFrequency(float freq)
02400 {
02401 freq= max(freq, 0.f);
02402 _ULFrequency= freq;
02403 }
02404
02405
02406
02407 bool CVegetableManager::updateLightingIGPart()
02408 {
02409 nlassert(_ULRootIg);
02410
02411
02412
02413
02414 _ULRootIg->VegetableLightEx.computeCurrentColors();
02415
02416
02417 while(_ULNVerticesToUpdate>0)
02418 {
02419
02420 if(_ULCurrentIgRdrPass>= NL3D_VEGETABLE_NRDRPASS)
02421 {
02422
02423 _ULCurrentIgRdrPass= 0;
02424 _ULCurrentIgInstance= 0;
02425
02426 return true;
02427 }
02428 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= _ULRootIg->_RdrPass[_ULCurrentIgRdrPass];
02429
02430
02431 if(_ULCurrentIgInstance>= vegetRdrPass.LightedInstances.size())
02432 {
02433
02434 _ULCurrentIgRdrPass++;
02435 _ULCurrentIgInstance= 0;
02436 continue;
02437 }
02438
02439
02440 _ULNVerticesToUpdate-= updateInstanceLighting(_ULRootIg, _ULCurrentIgRdrPass, _ULCurrentIgInstance);
02441
02442
02443 _ULCurrentIgInstance++;
02444
02445
02446 if(_ULCurrentIgInstance>= vegetRdrPass.LightedInstances.size())
02447 {
02448
02449 _ULCurrentIgRdrPass++;
02450 _ULCurrentIgInstance= 0;
02451 }
02452 }
02453
02454
02455 if(_ULCurrentIgRdrPass>= NL3D_VEGETABLE_NRDRPASS)
02456 {
02457
02458 _ULCurrentIgRdrPass= 0;
02459 _ULCurrentIgInstance= 0;
02460
02461 return true;
02462 }
02463 else
02464 {
02465
02466 return false;
02467 }
02468
02469 }
02470
02471
02472
02473 uint CVegetableManager::updateInstanceLighting(CVegetableInstanceGroup *ig, uint rdrPassId, uint instanceId)
02474 {
02475 nlassert(ig);
02476
02477 nlassert(rdrPassId<NL3D_VEGETABLE_NRDRPASS);
02478 CVegetableInstanceGroup::CVegetableRdrPass &vegetRdrPass= ig->_RdrPass[rdrPassId];
02479
02480 nlassert(instanceId<vegetRdrPass.LightedInstances.size());
02481 CVegetableInstanceGroup::CVegetableLightedInstance &vegetLI= vegetRdrPass.LightedInstances[instanceId];
02482
02483
02484 CVegetableShape *shape= vegetLI.Shape;
02485
02486 nlassert(shape->Lighted);
02487 bool instanceLighted= true;
02488
02489
02490
02491 CVegetableLightEx &vegetLex= ig->VegetableLightEx;
02492
02493 CRGBA diffusePL[2];
02494 if(vegetLex.NumLights>=1)
02495 {
02496 diffusePL[0].modulateFromColorRGBOnly(vegetLI.MatDiffuse, vegetLex.Color[0]);
02497 if(vegetLex.NumLights>=2)
02498 {
02499 diffusePL[1].modulateFromColorRGBOnly(vegetLI.MatDiffuse, vegetLex.Color[1]);
02500 }
02501 }
02502
02503
02504
02505
02506
02507
02508
02509 bool instanceDoubleSided= shape->DoubleSided;
02510
02511 bool precomputeLighting= instanceLighted && shape->PreComputeLighting;
02512
02513 bool bestSidedPrecomputeLighting= precomputeLighting && shape->BestSidedPreComputeLighting;
02514
02515 bool destLighted= instanceLighted && !shape->PreComputeLighting;
02516
02517 CRGBA primaryRGBA, secondaryRGBA;
02518 primaryRGBA.modulateFromColorRGBOnly(vegetLI.MatDiffuse, _GlobalDiffuse);
02519 secondaryRGBA.modulateFromColorRGBOnly(vegetLI.MatAmbient, _GlobalAmbient);
02520
02521 CMatrix &normalMat= vegetLI.NormalMat;
02522
02523 uint32 *ptrVid= vegetRdrPass.Vertices.getPtr() + vegetLI.StartIdInRdrPass;
02524 uint numVertices= shape->InstanceVertices.size();
02525
02526
02527 primaryRGBA.A= vegetLI.DlmUV.U;
02528 secondaryRGBA.A= vegetLI.DlmUV.V;
02529
02530
02531
02532 CVegetableVBAllocator *allocator;
02533 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPassId, vegetRdrPass.HardMode);
02534 const CVertexBuffer &dstVBInfo= allocator->getSoftwareVertexBuffer();
02535
02536 uint srcNormalOff= (instanceLighted? shape->VB.getNormalOff() : 0);
02537
02538
02539 uint dstColor1Off= ( (destLighted||instanceDoubleSided)?
02540 dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR1) : 0);
02541 uint dstColor0Off= dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR0);
02542
02543
02544
02545
02546
02547 for(sint i=0; i<(sint)numVertices;i++)
02548 {
02549
02550 uint vid= ptrVid[i];
02551
02552 shape->InstanceVertices[i]= vid;
02553
02554
02555 uint8 *srcPtr= (uint8*)shape->VB.getVertexCoordPointer(i);
02556 uint8 *dstPtr= (uint8*)allocator->getVertexPointer(vid);
02557
02558
02559
02560 if(!precomputeLighting)
02561 {
02562
02563 *(CRGBA*)(dstPtr + dstColor0Off)= primaryRGBA;
02564 *(CRGBA*)(dstPtr + dstColor1Off)= secondaryRGBA;
02565 }
02566 else
02567 {
02568 nlassert(!destLighted);
02569
02570
02571 CVector rotNormal= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
02572
02573 rotNormal.normalize();
02574
02575
02576 if(!bestSidedPrecomputeLighting)
02577 {
02578 computeVegetVertexLighting(rotNormal, instanceDoubleSided,
02579 _DirectionalLight, primaryRGBA, secondaryRGBA,
02580 vegetLex, diffusePL,
02581 (CRGBA*)(dstPtr + dstColor0Off), (CRGBA*)(dstPtr + dstColor1Off) );
02582 }
02583 else
02584 {
02585 computeVegetVertexLightingForceBestSided(rotNormal, instanceDoubleSided,
02586 _DirectionalLight, primaryRGBA, secondaryRGBA,
02587 vegetLex, diffusePL,
02588 (CRGBA*)(dstPtr + dstColor0Off), (CRGBA*)(dstPtr + dstColor1Off) );
02589 }
02590
02591 }
02592
02593
02594 allocator->flushVertex(vid);
02595 }
02596
02597
02598
02599 return numVertices;
02600 }
02601
02602
02603 }