1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/3d/vegetable_manager.h"
24 #include "nel/3d/driver.h"
25 #include "nel/3d/texture_file.h"
26 #include "nel/misc/fast_floor.h"
27 #include "nel/3d/vegetable_quadrant.h"
28 #include "nel/3d/dru.h"
29 #include "nel/3d/radix_sort.h"
30 #include "nel/3d/scene.h"
31 #include "nel/3d/vegetable_blend_layer_model.h"
32 #include "nel/3d/vegetable_light_ex.h"
33 #include "nel/misc/hierarchical_timer.h"
39 using namespace NLMISC
;
49 #define NL3D_VEGETABLE_CLIP_BLOCK_BLOCKSIZE 16
50 #define NL3D_VEGETABLE_SORT_BLOCK_BLOCKSIZE 64
51 #define NL3D_VEGETABLE_INSTANCE_GROUP_BLOCKSIZE 128
54 // ***************************************************************************
55 CVegetableManager::CVegetableManager(uint maxVertexVbHardUnlit
, uint maxVertexVbHardLighted
,
56 uint nbBlendLayers
, float blendLayerDistMax
) :
57 _ClipBlockMemory(NL3D_VEGETABLE_CLIP_BLOCK_BLOCKSIZE
),
58 _SortBlockMemory(NL3D_VEGETABLE_SORT_BLOCK_BLOCKSIZE
),
59 _InstanceGroupMemory(NL3D_VEGETABLE_INSTANCE_GROUP_BLOCKSIZE
),
61 _NumZSortBlendLayers(nbBlendLayers
), _ZSortLayerDistMax(blendLayerDistMax
),
66 // Init all the allocators
67 nlassert((uint
)(CVegetableVBAllocator::VBTypeCount
) == 2);
68 _VBHardAllocator
[CVegetableVBAllocator::VBTypeLighted
].init( CVegetableVBAllocator::VBTypeLighted
, maxVertexVbHardLighted
);
69 _VBHardAllocator
[CVegetableVBAllocator::VBTypeUnlit
].init( CVegetableVBAllocator::VBTypeUnlit
, maxVertexVbHardUnlit
);
70 // Init soft one, with no vbHard vertices.
71 _VBSoftAllocator
[CVegetableVBAllocator::VBTypeLighted
].init( CVegetableVBAllocator::VBTypeLighted
, 0 );
72 _VBSoftAllocator
[CVegetableVBAllocator::VBTypeUnlit
].init( CVegetableVBAllocator::VBTypeUnlit
, 0 );
74 // NB Vertex programs are initilized during the first call to update driver.
76 // setup the material. Unlit (doesn't matter, lighting in VP) Alpha Test.
77 _VegetableMaterial
.initUnlit();
78 _VegetableMaterial
.setAlphaTest(true);
79 _VegetableMaterial
.setBlendFunc(CMaterial::srcalpha
, CMaterial::invsrcalpha
);
82 _DirectionalLight
= (CVector(0,1, -1)).normed();
83 _GlobalAmbient
.set(64, 64, 64, 255);
84 _GlobalDiffuse
.set(150, 150, 150, 255);
87 _WindDirection
.set(1,0,0);
92 _WindPrecRenderTime
= 0;
96 for(i
=0; i
<NL3D_VEGETABLE_VP_LUT_SIZE
; i
++)
98 _CosTable
[i
]= (float)cos( i
*2*Pi
/ NL3D_VEGETABLE_VP_LUT_SIZE
);
101 // init to NULL _ZSortModelLayers.
102 _NumZSortBlendLayers
= max(1U, _NumZSortBlendLayers
);
103 _ZSortModelLayers
.resize(_NumZSortBlendLayers
, NULL
);
104 _ZSortModelLayersUW
.resize(_NumZSortBlendLayers
, NULL
);
109 _ULNVerticesToUpdate
=0;
110 _ULNTotalVertices
= 0;
112 _ULCurrentIgRdrPass
= 0;
113 _ULCurrentIgInstance
= 0;
115 _ULPrecTimeInit
= false;
119 _NumVegetableFaceRendered
= 0;
121 for (uint k
= 0; k
< NL3D_VEGETABLE_NRDRPASS
; ++k
)
123 _VertexProgram
[k
][0] = NULL
;
124 _VertexProgram
[k
][1] = NULL
;
129 // ***************************************************************************
130 CVegetableManager::~CVegetableManager()
133 for(sint i
=0; i
<NL3D_VEGETABLE_NRDRPASS
; i
++)
135 _VertexProgram
[i
][0] = NULL
; // smart ptr
136 _VertexProgram
[i
][1] = NULL
;
139 // delete ZSort models.
142 // remove models from scene.
143 for(uint i
= 0; i
<_NumZSortBlendLayers
; i
++)
145 _ZSortScene
->deleteModel(_ZSortModelLayers
[i
]);
146 _ZSortModelLayers
[i
]= NULL
;
147 _ZSortScene
->deleteModel(_ZSortModelLayersUW
[i
]);
148 _ZSortModelLayersUW
[i
]= NULL
;
156 // ***************************************************************************
157 void CVegetableManager::createVegetableBlendLayersModels(CScene
*scene
)
163 // create the layers models.
164 for(uint i
=0;i
<_NumZSortBlendLayers
; i
++)
166 // assert not already done.
167 nlassert(_ZSortModelLayers
[i
]==NULL
);
168 nlassert(_ZSortModelLayersUW
[i
]==NULL
);
170 _ZSortModelLayers
[i
]= (CVegetableBlendLayerModel
*)scene
->createModel(VegetableBlendLayerModelId
);
171 _ZSortModelLayersUW
[i
]= (CVegetableBlendLayerModel
*)scene
->createModel(VegetableBlendLayerModelId
);
173 _ZSortModelLayers
[i
]->VegetableManager
= this;
174 _ZSortModelLayersUW
[i
]->VegetableManager
= this;
176 // Set UnderWater layer for _ZSortModelLayersUW
177 _ZSortModelLayersUW
[i
]->setOrderingLayer(2);
182 // ***************************************************************************
183 CVegetableVBAllocator
&CVegetableManager::getVBAllocatorForRdrPassAndVBHardMode(uint rdrPass
, uint vbHardMode
)
188 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_LIGHTED
)
189 return _VBSoftAllocator
[CVegetableVBAllocator::VBTypeLighted
];
190 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
)
191 return _VBSoftAllocator
[CVegetableVBAllocator::VBTypeLighted
];
192 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT
)
193 return _VBSoftAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
194 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED
)
195 return _VBSoftAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
196 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
197 return _VBSoftAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
202 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_LIGHTED
)
203 return _VBHardAllocator
[CVegetableVBAllocator::VBTypeLighted
];
204 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
)
205 return _VBHardAllocator
[CVegetableVBAllocator::VBTypeLighted
];
206 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT
)
207 return _VBHardAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
208 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED
)
209 return _VBHardAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
210 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
211 return _VBHardAllocator
[CVegetableVBAllocator::VBTypeUnlit
];
217 return _VBSoftAllocator
[0];
222 // ***************************************************************************
223 // ***************************************************************************
225 // ***************************************************************************
226 // ***************************************************************************
229 // ***************************************************************************
231 Vegetable, without bend for now.
235 v[0] == Pos to Center of the vegetable in world space.
236 v[10] == Center of the vegetable in world space.
237 v[2] == Normal (present if lighted only)
238 v[3] == Color (if unlit) or DiffuseColor (if lighted)
239 v[4] == SecondaryColor (==ambient if Lighted, and use only Alpha part for DLM if Unlit)
241 v[9] == BendInfo (xyz) = {BendWeight/2, BendPhase, BendFrequencyFactor}
242 NB: /2 because compute a quaternion
244 Changes: If unlit, then small changes:
245 v[0] == Pos to center, with v[0].w == BendWeight * v[0].norm()
246 v[9] == BendInfo/BlendInfo (xyzw) = {v[0].norm(), BendPhase, BendFrequencyFactor, BlendDist}
248 NB: v[9].w. is used only in Unlit+2Sided+AlphaBlend. But prefer do this for gestion purpose:
249 to have only one VBAllocator for all modes.
251 NB: Color and Secondary color Alpha Part contains Dynamic LightMap UV, (in 8 bits).
255 Setuped at beginning of CVegetableManager::render()
256 c[0..3]= ModelViewProjection Matrix.
259 c[9]= unit world space Directionnal light.
260 c[10]= camera pos in world space.
261 c[11]= {1/DistBlendTransition}
262 NB: DiffuseColor and AmbientColor of vertex must have been pre-multiplied by lightColor
265 c[16]= quaternion axis. w==1, and z must be 0
266 c[17]= { timeAnim , WindPower, WindPower*(1-WindBendMin)/2, 0 }
267 c[18]= High order Taylor cos coefficient: { -1/2, 1/24, -1/720, 1/40320 }
268 c[19]= Low order Taylor cos coefficient: { 1, -1/2, 1/24, -1/720 }
269 c[20]= Low order Taylor sin coefficient: { 1, -1/6, 1/120, -1/5040 }
270 c[21]= Special constant vector for quatToMatrix: { 0, 1, -1, 0 }
271 c[22]= {0.5, Pi, 2*Pi, 1/(2*Pi)}
272 c[23]= {64, 0, 0, 0} (size of the LUT)
275 c[32..95] 64 Lut entries for cos-like animation
280 Fog should be disabled, because not computed (for speed consideration and becasue micro-vegetation should never
286 Max program length (lighted/2Sided) is:
287 29 (bend-quaternion) +
288 16 (rotNormal + bend + lit 2Sided) +
290 2 (Dynamic lightmap copy)
293 Normal program length (unlit/2Sided/No Alpha Blend) is:
297 2 (Dynamic lightmap copy)
300 AlphaBlend program length (unlit/2Sided/Alpha Blend) is:
305 2 (Dynamic lightmap copy)
311 // ***********************
313 Fast (but less accurate) Bend program:
314 Result: bend pos into R5,
316 // ***********************
317 const char* NL3D_FastBendProgram
=
319 # compute time of animation: time*freqfactor + phase. \n\
320 MAD R0.x, c[17].x, v[9].z, v[9].y; # R0.x= time of animation \n\
322 # animation: use the 64 LUT entries \n\
323 EXP R0.y, R0.x; # fract part=> R0.y= [0,1[ \n\
324 MUL R0, R0.y, c[23].xyyy; # R0.x= [0,64[ \n\
325 ARL A0.x, R0.x; # A0.x= index in the LUT \n\
326 EXP R0.y, R0.x; # R0.y= R0.x-A0.x= fp (fract part) \n\
327 # lookup and lerp in one it: R0= value + fp * dv. \n\
328 MAD R0.xy, R0.y, c[A0.x+32].zwww, c[A0.x+32].xyww; \n\
330 # The direction and power of the wind is encoded in the LUT. \n\
331 # Scale now by vertex BendFactor (stored in v[0].w) \n\
332 MAD R5, R0, v[0].w, v[0].xyzw; \n\
333 # compute 1/norm, and multiply by original norm stored in v[9].x \n\
334 DP3 R0.x, R5, R5; \n\
336 MUL R0.x, R0.x, v[9].x; \n\
337 # mul by this factor, and add to center \n\
338 MAD R5, R0.xxxw, R5, v[10]; \n\
340 # make local to camera pos. Important for ZBuffer precision \n\
341 ADD R5, R5, -c[10]; \n\
346 /*const char* NL3D_FastBendProgram=
348 # compute time of animation: time + phase. \n\
349 ADD R0.x, c[17].x, v[9].y; # R0.x= time of animation \n\
351 # animation: f(x)= cos(x). compute a high precision cosinus \n\
352 EXP R0.y, R0.x; # fract part=> R0.y= [0,1] <=> [-Pi, Pi] \n\
353 MAD R0.x, R0.y, c[22].z, -c[22].y; # R0.x= a= [-Pi, Pi] \n\
354 # R0 must get a2, a4, a6, a8 \n\
355 MUL R0.x, R0.x, R0.x; # R0.x= a2 \n\
356 MUL R0.y, R0.x, R0.x; # R0= a2, a4 \n\
357 MUL R0.zw, R0.y, R0.xxxy; # R0= a2, a4, a6, a8 \n\
358 # Taylor serie: cos(x)= 1 - (1/2) a2 + (1/24) a4 - (1/720) a6 + (1/40320) a8. \n\
359 DP4 R0.x, R0, c[18]; # R0.x= cos(x) - 1. \n\
363 DP3 R2.x, v[0], v[0]; \n\
365 MUL R2.x, R2.x, R2.y; \n\
366 # norm, mul by factor, and add to relpos \n\
367 ADD R1.x, R0.x, c[8].w; \n\
368 MUL R0.x, v[9].x, R2.x; \n\
369 MUL R1, R1, R0.x; \n\
370 ADD R5.xyz, R1, v[0]; \n\
372 DP3 R0.x, R5, R5; \n\
374 MUL R0.x, R0.x, R2.x; \n\
375 MAD R5, R0.x, R5, v[10]; \n\
380 // ***********************
383 Result: bend pos into R5, and R7,R8,R9 is the rotation matrix for possible normal lighting.
385 // ***********************
386 // Splitted in 2 parts because of the 2048 char limit
387 const char* NL3D_BendProgramP0
=
389 # compute time of animation: time*freqfactor + phase. \n\
390 MAD R0.x, c[17].x, v[9].z, v[9].y; # R0.x= time of animation \n\
392 # animation: f(x)= cos(x). compute a high precision cosinus \n\
393 EXP R0.y, R0.x; # fract part=> R0.y= [0,1] <=> [-Pi, Pi] \n\
394 MAD R0.x, R0.y, c[22].z, -c[22].y; # R0.x= a= [-Pi, Pi] \n\
395 # R0 must get a2, a4, a6, a8 \n\
396 MUL R0.x, R0.x, R0.x; # R0.x= a2 \n\
397 MUL R0.y, R0.x, R0.x; # R0= a2, a4 \n\
398 MUL R0.zw, R0.y, R0.xxxy; # R0= a2, a4, a6, a8 \n\
399 # Taylor serie: cos(x)= 1 - (1/2) a2 + (1/24) a4 - (1/720) a6 + (1/40320) a8. \n\
400 DP4 R0.x, R0, c[18]; # R0.x= cos(x) - 1. \n\
402 # R0.x= [-2, 0]. And we want a result in BendWeight/2*WindPower*[WindBendMin, 1] \n\
403 MAD R0.x, R0.x, c[17].z, c[17].y; # R0.x= WindPower*[WindBendMin, 1] \n\
404 MUL R0.x, R0.x, v[9].x; # R0.x= angle= BendWeight/2*WindPower*[WindBendMin, 1] \n\
406 # compute good precision sinus and cosinus, in R0.xy. \n\
407 # suppose that BendWeightMax/2== 2Pi/3 => do not need to fmod() nor \n\
408 # to have high order taylor serie \n\
409 DST R1.xy, R0.x, R0.x; # R1= 1, a2 \n\
410 MUL R1.z, R1.y, R1.y; # R1= 1, a2, a4 \n\
411 MUL R1.w, R1.y, R1.z; # R1= 1, a2, a4, a6 (cos serie) \n\
412 MUL R2, R1, R0.x; # R2= a, a3, a5, a7 (sin serie) \n\
413 DP4 R0.x, R1, c[19]; # R0.x= cos(a) \n\
414 DP4 R0.y, R2, c[20]; # R0.y= sin(a) \n\
416 const char* NL3D_BendProgramP1
=
418 # build our quaternion \n\
419 # multiply the angleAxis by sin(a) / cos(a), where a is actually a/2 \n\
420 # remind: c[16].z== angleAxis.z== 0 \n\
421 MUL R0, c[16], R0.yyyx; # R0= quaternion.xyzw \n\
423 # build our matrix from this quaternion, into R7,R8,R9 \n\
424 # Quaternion TO matrix 3x3 in 7 ope, with quat.z==0 \n\
425 MUL R1, R0, c[8].w; # R1= quat2= 2*quat == 2*x, 2*y, 0, 2*w \n\
426 MUL R2, R1, R0.x; # R2= quatX= xx, xy, 0, wx \n\
427 MUL R3, R1, R0.y; # R3= quatY= xy, yy, 0, wy \n\
428 # NB: c[21]= {0, 1, -1, 0} \n\
429 # Write to w, then w = 0, this avoid an unitialized component \n\
430 MAD R7.xyzw, c[21].zyyw, R3.yxww, c[21].yxxw; \n\
431 # R7.x= a11 = 1.0f - (yy) \n\
434 # NB: c[21]= {0, 1, -1, 0} \n\
435 # Write to w, then w = 0, this avoid an unitialized component \n\
436 MAD R8.xyzw, c[21].yzzw, R2.yxww, c[21].xyxw; \n\
438 # R8.y= a22 = 1.0f - (xx) \n\
439 # R8.z= a23 = - wx \n\
440 # NB: c[21]= {0, 1, -1, 0} \n\
441 # Write to w, then w = 0, this avoid an unitialized component \n\
442 ADD R9.xyzw, R2.zwxw, R3.wzyw; # a31= 0+wy, a32= wx+0, a33= xx + yy, because z==0 \n\
443 MAD R9.xyzw, R9.xyzw, c[21].zyzw, c[21].xxyw; \n\
444 # R9.x= a31 = - wy \n\
446 # R9.z= a33 = 1.0f - (xx + yy) \n\
448 DP3 R5.x, R7, v[0]; \n\
449 DP3 R5.y, R8, v[0]; \n\
450 DP3 R5.z, R9, v[0]; # R5= bended relative pos to center. \n\
451 #temp, to optimize \n\
452 MOV R5.w, c[21].w; \n\
453 # add pos to center pos. \n\
454 ADD R5, R5, v[10]; # R5= world pos. R5.w= R5.w+v[10].w= 0+1= 1 \n\
455 # make local to camera pos. Important for ZBuffer precision \n\
456 ADD R5, R5, -c[10]; \n\
460 // Concat the 2 strings
461 const string NL3D_BendProgram
= string(NL3D_BendProgramP0
) + string(NL3D_BendProgramP1
);
465 // ***********************
467 Lighted start program:
468 bend pos and normal, normalize and lit
470 // ***********************
471 // Common start program.
472 const char* NL3D_LightedStartVegetableProgram
=
474 # bend Pos into R5. Now do it for normal \n\
475 DP3 R0.x, R7, v[2]; \n\
476 DP3 R0.y, R8, v[2]; \n\
477 DP3 R0.z, R9, v[2]; # R0= matRot * normal. \n\
478 # Do the rot 2 times for normal (works fine) \n\
479 DP3 R6.x, R7, R0; \n\
480 DP3 R6.y, R8, R0; \n\
481 DP3 R6.z, R9, R0; # R6= bended normal. \n\
483 # Normalize normal, and dot product, into R0.x \n\
484 # w hasn't been written \n\
485 DP3 R0.x, R6.xyzz, R6.xyzz; # R0.x= R6.sqrnorm() \n\
486 RSQ R0.x, R0.x; # R0.x= 1/norm() \n\
487 MUL R6, R6.xyzz, R0.x; # R6= R6.normed() \n\
488 DP3 R0.x, R6, c[9]; \n\
491 MAX R0.y, -R0.x, c[8].x; # R0.y= diffFactor= max(0, -R6*LightDir) \n\
492 MUL R1.xyz, R0.y, v[3]; # R7= diffFactor*DiffuseColor \n\
493 ADD o[COL0].xyz, R1, v[4]; # col0.RGB= AmbientColor + diffFactor*DiffuseColor \n\
494 MOV o[COL0].w, c[8].y; \n\
498 // ***********************
501 bend pos into R5, and copy color(s)
503 // ***********************
506 // Unlit no alpha blend.
507 const char* NL3D_UnlitVegetableProgram
=
508 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
510 MOV o[COL0].w, c[8].y; \n\
514 // Unlit with AlphaBlend.
515 const char* NL3D_UnlitAlphaBlendVegetableProgram
=
516 " MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
518 #Blend transition. NB: in R5, we already have the position relative to the camera \n\
519 DP3 R0.x, R5, R5; # R0.x= sqr(dist to viewer). \n\
521 MUL R0.x, R0.x, R0.y; # R0.x= dist to viewer \n\
522 # setup alpha Blending. Distance of appartition is encoded in the vertex. \n\
523 MAD o[COL0].w, R0.x, c[11].x, v[9].w; \n\
528 // ***********************
530 Common end of program: project, texture. Take pos from R5
532 // ***********************
533 const char* NL3D_CommonEndVegetableProgram
=
534 " # compute in Projection space \n\
535 DP4 o[HPOS].x, c[0], R5; \n\
536 DP4 o[HPOS].y, c[1], R5; \n\
537 DP4 o[HPOS].z, c[2], R5; \n\
538 DP4 o[HPOS].w, c[3], R5; \n\
539 # copy Dynamic lightmap UV in stage0, from colors Alpha part. \n\
540 MAD o[TEX0].xzw, v[3].w, c[8].yxxx, c[8].xxxy; \n\
541 MOV o[TEX0].y, v[4].w; \n\
542 # copy diffuse texture uv to stage 1. \n\
543 MOV o[TEX1], v[8]; \n\
547 const char* NL3D_VegetableProgramFog
=
548 " DP4 o[FOGC].x, c[6], R5; \n\
552 // ***********************
554 Speed test VP, No bend,no lighting.
556 // ***********************
557 const char* NL3D_SimpleStartVegetableProgram
=
559 # compute in Projection space \n\
560 MAD R5, v[0], c[8].yyyx, c[8].xxxy; \n\
561 ADD R5.xyz, R5, v[10]; \n\
562 # make local to camera pos \n\
563 ADD R5, R5, -c[10]; \n\
564 MOV o[COL0].xyz, v[3]; # col.RGBA= vertex color \n\
567 class CVertexProgramVeget
: public CVertexProgram
572 // 0-3 modelViewProjection
577 uint ProgramConstants0
; // 8
578 uint DirectionalLight
; // 9
579 uint ViewCenter
; // 10
580 uint NegInvTransDist
; // 11
585 uint AngleAxis
; // 16
587 uint CosCoeff0
; // 18
588 uint CosCoeff1
; // 19
589 uint CosCoeff2
; // 20
590 uint QuatConstants
; // 21
591 uint PiConstants
; // 22
592 uint LUTSize
; // 23 (value = 64)
593 uint LUT
[NL3D_VEGETABLE_VP_LUT_SIZE
]; // 32+
595 CVertexProgramVeget(uint vpType
, bool fogEnabled
)
599 CSource
*source
= new CSource();
600 source
->Profile
= nelvp
;
601 source
->DisplayName
= "nelvp/Veget";
603 // Init the Vertex Program.
605 // start always with Bend.
606 if( vpType
==NL3D_VEGETABLE_RDRPASS_LIGHTED
|| vpType
==NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
)
608 source
->DisplayName
+= "/Bend";
609 vpgram
= NL3D_BendProgram
;
613 source
->DisplayName
+= "/FastBend";
614 vpgram
= NL3D_FastBendProgram
;
617 // combine the VP according to Type
620 case NL3D_VEGETABLE_RDRPASS_LIGHTED
:
621 case NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
:
622 source
->DisplayName
+= "/Lighted";
623 vpgram
+= string(NL3D_LightedStartVegetableProgram
);
625 case NL3D_VEGETABLE_RDRPASS_UNLIT
:
626 case NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED
:
627 source
->DisplayName
+= "/Unlit";
628 vpgram
+= string(NL3D_UnlitVegetableProgram
);
630 case NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
:
631 source
->DisplayName
+= "/UnlitAlphaBlend";
632 vpgram
+= string(NL3D_UnlitAlphaBlendVegetableProgram
);
637 vpgram
+= string(NL3D_CommonEndVegetableProgram
);
641 source
->DisplayName
+= "/Fog";
642 vpgram
+= string(NL3D_VegetableProgramFog
);
647 source
->setSource(vpgram
);
649 source
->ParamIndices
["modelViewProjection"] = 0;
650 source
->ParamIndices
["fog"] = 6;
651 source
->ParamIndices
["programConstants0"] = 8;
652 source
->ParamIndices
["directionalLight"] = 9;
653 source
->ParamIndices
["viewCenter"] = 10;
654 source
->ParamIndices
["negInvTransDist"] = 11;
655 source
->ParamIndices
["angleAxis"] = 16;
656 source
->ParamIndices
["wind"] = 17;
657 source
->ParamIndices
["cosCoeff0"] = 18;
658 source
->ParamIndices
["cosCoeff1"] = 19;
659 source
->ParamIndices
["cosCoeff2"] = 20;
660 source
->ParamIndices
["quatConstants"] = 21;
661 source
->ParamIndices
["piConstants"] = 22;
662 source
->ParamIndices
["lutSize"] = 23;
663 for (uint i
= 0; i
< NL3D_VEGETABLE_VP_LUT_SIZE
; ++i
)
665 source
->ParamIndices
[NLMISC::toString("lut[%i]", i
)] = 32 + i
;
672 virtual ~CVertexProgramVeget()
676 virtual void buildInfo()
678 m_Idx
.ProgramConstants0
= getUniformIndex("programConstants0");
679 nlassert(m_Idx
.ProgramConstants0
!= std::numeric_limits
<uint
>::max());
680 m_Idx
.DirectionalLight
= getUniformIndex("directionalLight");
681 nlassert(m_Idx
.DirectionalLight
!= std::numeric_limits
<uint
>::max());
682 m_Idx
.ViewCenter
= getUniformIndex("viewCenter");
683 nlassert(m_Idx
.ViewCenter
!= std::numeric_limits
<uint
>::max());
684 m_Idx
.NegInvTransDist
= getUniformIndex("negInvTransDist");
685 nlassert(m_Idx
.NegInvTransDist
!= std::numeric_limits
<uint
>::max());
686 m_Idx
.AngleAxis
= getUniformIndex("angleAxis");
687 nlassert(m_Idx
.AngleAxis
!= std::numeric_limits
<uint
>::max());
688 m_Idx
.Wind
= getUniformIndex("wind");
689 nlassert(m_Idx
.Wind
!= std::numeric_limits
<uint
>::max());
690 m_Idx
.CosCoeff0
= getUniformIndex("cosCoeff0");
691 nlassert(m_Idx
.CosCoeff0
!= std::numeric_limits
<uint
>::max());
692 m_Idx
.CosCoeff1
= getUniformIndex("cosCoeff1");
693 nlassert(m_Idx
.CosCoeff1
!= std::numeric_limits
<uint
>::max());
694 m_Idx
.CosCoeff2
= getUniformIndex("cosCoeff2");
695 nlassert(m_Idx
.CosCoeff2
!= std::numeric_limits
<uint
>::max());
696 m_Idx
.QuatConstants
= getUniformIndex("quatConstants");
697 nlassert(m_Idx
.QuatConstants
!= std::numeric_limits
<uint
>::max());
698 m_Idx
.PiConstants
= getUniformIndex("piConstants");
699 nlassert(m_Idx
.PiConstants
!= std::numeric_limits
<uint
>::max());
700 m_Idx
.LUTSize
= getUniformIndex("lutSize");
701 nlassert(m_Idx
.LUTSize
!= std::numeric_limits
<uint
>::max());
702 for (uint i
= 0; i
< NL3D_VEGETABLE_VP_LUT_SIZE
; ++i
)
704 m_Idx
.LUT
[i
] = getUniformIndex(NLMISC::toString("lut[%i]", i
));
705 nlassert(m_Idx
.LUT
[i
] != std::numeric_limits
<uint
>::max());
708 const CIdx
&idx() const { return m_Idx
; }
713 // ***************************************************************************
714 void CVegetableManager::initVertexProgram(uint vpType
, bool fogEnabled
)
716 nlassert(_LastDriver
); // update driver should have been called at least once !
719 _VertexProgram
[vpType
][fogEnabled
? 1 : 0] = new CVertexProgramVeget(vpType
, fogEnabled
);
723 // ***************************************************************************
724 // ***************************************************************************
726 // ***************************************************************************
727 // ***************************************************************************
730 // ***************************************************************************
731 CVegetableClipBlock
*CVegetableManager::createClipBlock()
733 // create a clipblock
734 CVegetableClipBlock
*ret
;
735 ret
= _ClipBlockMemory
.allocate();
738 _EmptyClipBlockList
.append(ret
);
743 // ***************************************************************************
744 void CVegetableManager::deleteClipBlock(CVegetableClipBlock
*clipBlock
)
749 // verify no more sortBlocks in this clipblock
750 nlassert(clipBlock
->_SortBlockList
.size() == 0);
752 // unlink from _EmptyClipBlockList, because _InstanceGroupList.size() == 0 ...
753 _EmptyClipBlockList
.remove(clipBlock
);
756 _ClipBlockMemory
.freeBlock(clipBlock
);
760 // ***************************************************************************
761 CVegetableSortBlock
*CVegetableManager::createSortBlock(CVegetableClipBlock
*clipBlock
, const CVector
¢er
, float radius
)
765 // create a clipblock
766 CVegetableSortBlock
*ret
;
767 ret
= _SortBlockMemory
.allocate();
768 ret
->_Owner
= clipBlock
;
769 ret
->_Center
= center
;
770 ret
->_Radius
= radius
;
773 clipBlock
->_SortBlockList
.append(ret
);
778 // ***************************************************************************
779 void CVegetableManager::deleteSortBlock(CVegetableSortBlock
*sortBlock
)
784 // verify no more IGs in this sortblock
785 nlassert(sortBlock
->_InstanceGroupList
.size() == 0);
787 // unlink from clipBlock
788 sortBlock
->_Owner
->_SortBlockList
.remove(sortBlock
);
791 _SortBlockMemory
.freeBlock(sortBlock
);
795 // ***************************************************************************
796 CVegetableInstanceGroup
*CVegetableManager::createIg(CVegetableSortBlock
*sortBlock
)
799 CVegetableClipBlock
*clipBlock
= sortBlock
->_Owner
;
803 CVegetableInstanceGroup
*ret
;
804 ret
= _InstanceGroupMemory
.allocate();
805 ret
->_SortOwner
= sortBlock
;
806 ret
->_ClipOwner
= clipBlock
;
808 // if the clipBlock is empty, change list, because won't be no more.
809 if(clipBlock
->_NumIgs
==0)
811 // remove from empty list
812 _EmptyClipBlockList
.remove(clipBlock
);
813 // and append to not empty one.
814 _ClipBlockList
.append(clipBlock
);
817 // inc the number of igs appended to the clipBlock.
818 clipBlock
->_NumIgs
++;
820 // link ig to sortBlock.
821 sortBlock
->_InstanceGroupList
.append(ret
);
823 // Special Init: The ZSort rdrPass must start with the same HardMode than SortBlock.
824 ret
->_RdrPass
[NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
].HardMode
= sortBlock
->ZSortHardMode
;
829 // ***************************************************************************
830 void CVegetableManager::deleteIg(CVegetableInstanceGroup
*ig
)
835 // update lighting mgt: no more vertices.
837 // If I delete the ig which is the current root
841 _ULRootIg
= ig
->_ULNext
;
842 // if still the same, it means that the circular list is now empty
845 // Reset UL instance info.
846 _ULCurrentIgRdrPass
= 0;
847 _ULCurrentIgInstance
= 0;
849 // remove UL vertex count of the deleted ig
850 _ULNTotalVertices
-= ig
->_ULNumVertices
;
851 // unlink the ig for lighting update.
855 // For all render pass of this instance, delete his vertices
857 for(sint rdrPass
=0; rdrPass
< NL3D_VEGETABLE_NRDRPASS
; rdrPass
++)
860 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPass
];
862 CVegetableVBAllocator
&vbAllocator
= getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, vegetRdrPass
.HardMode
);
864 // For all vertices of this rdrPass, delete it
866 numVertices
= vegetRdrPass
.Vertices
.size();
867 // all vertices must have been setuped.
868 nlassert((uint
)numVertices
== vegetRdrPass
.NVertices
);
869 for(sint i
=0; i
<numVertices
;i
++)
871 vbAllocator
.deleteVertex(vegetRdrPass
.Vertices
[i
]);
873 vegetRdrPass
.Vertices
.clear();
876 CVegetableClipBlock
*clipBlock
= ig
->_ClipOwner
;
877 CVegetableSortBlock
*sortBlock
= ig
->_SortOwner
;
879 // If I have got some faces in ZSort rdrPass
880 if(ig
->_HasZSortPassInstances
)
881 // after my deletion, the sortBlock must be updated.
882 sortBlock
->_Dirty
= true;
885 // unlink from sortBlock, and delete.
886 sortBlock
->_InstanceGroupList
.remove(ig
);
887 _InstanceGroupMemory
.freeBlock(ig
);
890 // decRef the clipBlock
891 clipBlock
->_NumIgs
--;
892 // if the clipBlock is now empty, change list
893 if(clipBlock
->_NumIgs
==0)
895 // remove from normal list
896 _ClipBlockList
.remove(clipBlock
);
897 // and append to empty list.
898 _EmptyClipBlockList
.append(clipBlock
);
904 // ***************************************************************************
905 CVegetableShape
*CVegetableManager::getVegetableShape(const std::string
&shape
)
907 ItShapeMap it
= _ShapeMap
.find(shape
);
909 if(it
!= _ShapeMap
.end())
914 CVegetableShape
*ret
;
915 it
= ( _ShapeMap
.insert(make_pair(shape
, CVegetableShape()) ) ).first
;
921 if( !ret
->loadShape(shape
) )
924 nlwarning ("CVegetableManager::getVegetableShape could not load shape file '%s'", shape
.c_str ());
927 _ShapeMap
.erase (shape
);
933 catch (const Exception
&e
)
936 nlwarning ("CVegetableManager::getVegetableShape error while loading shape file '%s' : '%s'", shape
.c_str (), e
.what ());
939 _ShapeMap
.erase (shape
);
950 // ***************************************************************************
951 uint
CVegetableManager::getRdrPassInfoForShape(CVegetableShape
*shape
, TVegetableWater vegetWaterState
,
952 bool &instanceLighted
, bool &instanceDoubleSided
, bool &instanceZSort
,
953 bool &destLighted
, bool &precomputeLighting
)
955 instanceLighted
= shape
->Lighted
;
956 instanceDoubleSided
= shape
->DoubleSided
;
957 // Disable ZSorting when we intersect water.
958 instanceZSort
= shape
->AlphaBlend
&& vegetWaterState
!=IntersectWater
;
959 destLighted
= instanceLighted
&& !shape
->PreComputeLighting
;
960 precomputeLighting
= instanceLighted
&& shape
->PreComputeLighting
;
962 // get correct rdrPass
964 // get according to lighted / doubleSided state
967 if(instanceDoubleSided
)
968 rdrPass
= NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
;
970 rdrPass
= NL3D_VEGETABLE_RDRPASS_LIGHTED
;
974 if(instanceDoubleSided
)
977 rdrPass
= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
;
979 rdrPass
= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED
;
982 rdrPass
= NL3D_VEGETABLE_RDRPASS_UNLIT
;
989 // ***************************************************************************
990 void CVegetableManager::reserveIgAddInstances(CVegetableInstanceGroupReserve
&vegetIgReserve
, CVegetableShape
*shape
, TVegetableWater vegetWaterState
, uint numInstances
)
992 bool instanceLighted
;
993 bool instanceDoubleSided
;
996 bool precomputeLighting
;
998 // get correct rdrPass / info
1000 rdrPass
= getRdrPassInfoForShape(shape
, vegetWaterState
, instanceLighted
, instanceDoubleSided
,
1001 instanceZSort
, destLighted
, precomputeLighting
);
1004 CVegetableInstanceGroupReserve::CVegetableRdrPass
&vegetRdrPass
= vegetIgReserve
._RdrPass
[rdrPass
];
1006 // Reserve space in the rdrPass.
1007 vegetRdrPass
.NVertices
+= numInstances
* shape
->VB
.getNumVertices();
1008 vegetRdrPass
.NTriangles
+= numInstances
* (uint
)shape
->TriangleIndices
.size()/3;
1009 // if the instances are lighted, reserve space for lighting updates
1011 vegetRdrPass
.NLightedInstances
+= numInstances
;
1015 // ***************************************************************************
1016 void CVegetableManager::reserveIgCompile(CVegetableInstanceGroup
*ig
, const CVegetableInstanceGroupReserve
&vegetIgReserve
)
1023 // For all rdrPass of the ig, check empty
1024 for(rdrPass
= 0; rdrPass
<NL3D_VEGETABLE_NRDRPASS
; rdrPass
++)
1026 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPass
];
1027 nlassert(vegetRdrPass
.TriangleIndices
.getNumIndexes()==0);
1028 nlassert(vegetRdrPass
.TriangleLocalIndices
.empty());
1029 nlassert(vegetRdrPass
.Vertices
.empty());
1030 nlassert(vegetRdrPass
.LightedInstances
.empty());
1032 // Do the same for all quadrants of the zsort rdrPass.
1033 nlassert(ig
->_TriangleQuadrantOrderArray
.empty());
1034 nlassert(ig
->_TriangleQuadrantOrderNumTriangles
==0);
1039 // For all rdrPass of the ig, reserve.
1040 for(rdrPass
= 0; rdrPass
<NL3D_VEGETABLE_NRDRPASS
; rdrPass
++)
1042 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPass
];
1043 uint numVertices
= vegetIgReserve
._RdrPass
[rdrPass
].NVertices
;
1044 uint numTris
= vegetIgReserve
._RdrPass
[rdrPass
].NTriangles
;
1045 uint numLightedInstances
= vegetIgReserve
._RdrPass
[rdrPass
].NLightedInstances
;
1046 // reserve triangles indices and vertices for this rdrPass.
1047 vegetRdrPass
.TriangleIndices
.setFormat(vegetRdrPass
.HardMode
? CIndexBuffer::Indices16
: CIndexBuffer::Indices32
);
1048 vegetRdrPass
.TriangleIndices
.setNumIndexes(numTris
*3);
1049 vegetRdrPass
.TriangleLocalIndices
.resize(numTris
*3);
1050 vegetRdrPass
.Vertices
.resize(numVertices
);
1051 // reserve ligthedinstances space.
1052 vegetRdrPass
.LightedInstances
.resize(numLightedInstances
);
1055 // Reserve space for the zsort rdrPass sorting.
1056 uint numZSortTris
= vegetIgReserve
._RdrPass
[NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
].NTriangles
;
1057 // allocate sufficient space for all quadrants (1 alloc for all quadrants).
1058 ig
->_TriangleQuadrantOrderArray
.resize(numZSortTris
* NL3D_VEGETABLE_NUM_QUADRANT
);
1063 sint16
*start
= ig
->_TriangleQuadrantOrderArray
.getPtr();
1064 // init ptr to each qaudrant
1065 for(uint i
=0; i
<NL3D_VEGETABLE_NUM_QUADRANT
; i
++)
1067 ig
->_TriangleQuadrantOrders
[i
]= start
+ i
*numZSortTris
;
1073 // ***************************************************************************
1074 inline void computeVegetVertexLighting(const CVector
&rotNormal
,
1075 const CVector
&sunDir
, CRGBA primaryRGBA
, CRGBA secondaryRGBA
,
1076 CVegetableLightEx
&vegetLex
, CRGBA diffusePL
[2], CRGBA
*dst
)
1084 // compute front-facing coloring.
1086 // Compute Sun Light.
1087 dpSun
= rotNormal
*sunDir
;
1088 float f
= max(0.f
, -dpSun
);
1089 col
.modulateFromuiRGBOnly(primaryRGBA
, NLMISC::OptFastFloor(f
*256));
1090 // Add it with ambient
1091 resColor
.addRGBOnly(col
, secondaryRGBA
);
1093 // Add influence of 2 lights only. (unrolled for better BTB use)
1094 // Compute Light 0 ?
1095 if(vegetLex
.NumLights
>=1)
1097 dpPL
[0]= rotNormal
*vegetLex
.Direction
[0];
1098 f
= max(0.f
, -dpPL
[0]);
1099 col
.modulateFromuiRGBOnly(diffusePL
[0], NLMISC::OptFastFloor(f
*256));
1100 resColor
.addRGBOnly(col
, resColor
);
1101 // Compute Light 1 ?
1102 if(vegetLex
.NumLights
>=2)
1104 dpPL
[1]= rotNormal
*vegetLex
.Direction
[1];
1105 f
= max(0.f
, -dpPL
[1]);
1106 col
.modulateFromuiRGBOnly(diffusePL
[1], NLMISC::OptFastFloor(f
*256));
1107 resColor
.addRGBOnly(col
, resColor
);
1111 // Keep correct U of Dynamic Lightmap UV encoded in primaryRGBA Alpha part.
1112 resColor
.A
= primaryRGBA
.A
;
1120 // ***************************************************************************
1121 inline void computeVegetVertexLightingForceBestSided(const CVector
&rotNormal
,
1122 const CVector
&sunDir
, CRGBA primaryRGBA
, CRGBA secondaryRGBA
,
1123 CVegetableLightEx
&vegetLex
, CRGBA diffusePL
[2], CRGBA
*dst
)
1131 // compute best-facing coloring.
1133 // Compute Sun Light.
1134 dpSun
= rotNormal
*sunDir
;
1135 // ForceBestSided: take the absolute value (max of -val,val)
1136 float f
= (float)fabs(dpSun
);
1137 col
.modulateFromuiRGBOnly(primaryRGBA
, NLMISC::OptFastFloor(f
*256));
1138 // Add it with ambient
1139 resColor
.addRGBOnly(col
, secondaryRGBA
);
1141 // Add influence of 2 lights only. (unrolled for better BTB use)
1142 // Compute Light 0 ?
1143 if(vegetLex
.NumLights
>=1)
1145 dpPL
[0]= rotNormal
*vegetLex
.Direction
[0];
1146 // ForceBestSided: take the absolute value (max of -val,val)
1147 f
= (float)fabs(dpPL
[0]);
1148 col
.modulateFromuiRGBOnly(diffusePL
[0], NLMISC::OptFastFloor(f
*256));
1149 resColor
.addRGBOnly(col
, resColor
);
1150 // Compute Light 1 ?
1151 if(vegetLex
.NumLights
>=2)
1153 dpPL
[1]= rotNormal
*vegetLex
.Direction
[1];
1154 f
= (float)fabs(dpPL
[1]);
1155 col
.modulateFromuiRGBOnly(diffusePL
[1], NLMISC::OptFastFloor(f
*256));
1156 resColor
.addRGBOnly(col
, resColor
);
1160 // Keep correct U of Dynamic Lightmap UV encoded in primaryRGBA Alpha part.
1161 resColor
.A
= primaryRGBA
.A
;
1170 // ***************************************************************************
1171 void CVegetableManager::addInstance(CVegetableInstanceGroup
*ig
,
1172 CVegetableShape
*shape
, const NLMISC::CMatrix
&mat
,
1173 const NLMISC::CRGBAF
&ambientColor
, const NLMISC::CRGBAF
&diffuseColor
,
1174 float bendFactor
, float bendPhase
, float bendFreqFactor
, float blendDistMax
,
1175 TVegetableWater vegetWaterState
, CVegetableUV8 dlmUV
)
1181 //--------------------
1182 bool instanceLighted
;
1183 bool instanceDoubleSided
;
1186 bool precomputeLighting
;
1188 // get correct rdrPass / info
1190 rdrPass
= getRdrPassInfoForShape(shape
, vegetWaterState
, instanceLighted
, instanceDoubleSided
,
1191 instanceZSort
, destLighted
, precomputeLighting
);
1192 // bestSided Precompute lighting or not??
1193 bool bestSidedPrecomputeLighting
= precomputeLighting
&& shape
->BestSidedPreComputeLighting
;
1197 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPass
];
1200 // setup using OptFastFloor.
1201 CRGBA ambientRGBA
, diffuseRGBA
;
1202 CRGBA primaryRGBA
, secondaryRGBA
;
1204 diffuseRGBA
.R
= (uint8
)NLMISC::OptFastFloor(diffuseColor
.R
*255);
1205 diffuseRGBA
.G
= (uint8
)NLMISC::OptFastFloor(diffuseColor
.G
*255);
1206 diffuseRGBA
.B
= (uint8
)NLMISC::OptFastFloor(diffuseColor
.B
*255);
1209 ambientRGBA
.R
= (uint8
)NLMISC::OptFastFloor(ambientColor
.R
*255);
1210 ambientRGBA
.G
= (uint8
)NLMISC::OptFastFloor(ambientColor
.G
*255);
1211 ambientRGBA
.B
= (uint8
)NLMISC::OptFastFloor(ambientColor
.B
*255);
1214 // For Lighted, modulate with global light.
1217 primaryRGBA
.modulateFromColorRGBOnly(diffuseRGBA
, _GlobalDiffuse
);
1218 secondaryRGBA
.modulateFromColorRGBOnly(ambientRGBA
, _GlobalAmbient
);
1220 // if the instance is not lighted, then don't take care of lighting
1223 primaryRGBA
.R
= diffuseRGBA
.R
;
1224 primaryRGBA
.G
= diffuseRGBA
.G
;
1225 primaryRGBA
.B
= diffuseRGBA
.B
;
1226 // may not be useful (2Sided lighting no more supported)
1227 secondaryRGBA
= primaryRGBA
;
1230 // Copy Dynamic Lightmap UV in Alpha part (save memory for an extra cost of 1 VP instruction)
1231 primaryRGBA
.A
= dlmUV
.U
;
1232 secondaryRGBA
.A
= dlmUV
.V
;
1234 // get ref on the vegetLex.
1235 CVegetableLightEx
&vegetLex
= ig
->VegetableLightEx
;
1236 // Color of pointLights modulated by diffuse.
1238 diffusePL
[0] = CRGBA::Black
;
1239 diffusePL
[1] = CRGBA::Black
;
1240 if(vegetLex
.NumLights
>=1)
1242 diffusePL
[0].modulateFromColorRGBOnly(diffuseRGBA
, vegetLex
.Color
[0]);
1243 if(vegetLex
.NumLights
>=2)
1245 diffusePL
[1].modulateFromColorRGBOnly(diffuseRGBA
, vegetLex
.Color
[1]);
1249 // normalize bendFreqFactor
1250 bendFreqFactor
*= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC
;
1251 bendFreqFactor
= (float)floor(bendFreqFactor
+ 0.5f
);
1252 bendFreqFactor
/= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC
;
1255 // Get allocator, and manage VBhard overriding.
1256 //--------------------
1257 CVegetableVBAllocator
*allocator
;
1258 // if still in Sfot mode, keep it.
1259 if(!vegetRdrPass
.HardMode
)
1261 // get the soft allocator.
1262 allocator
= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, 0);
1266 // Get VB allocator Hard for this rdrPass
1267 allocator
= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, 1);
1268 // Test if the instance don't add too many vertices for this VBHard
1269 if(allocator
->exceedMaxVertexInBufferHard(shape
->VB
.getNumVertices()))
1271 // if exceed, then must pass ALL the IG in software mode. vertices/faces are correclty updated.
1272 // special: if rdrPass is the ZSort one,
1273 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
1275 nlassert(ig
->_SortOwner
->ZSortHardMode
);
1277 // must do it on ALL igs of the sortBlock, for less VBuffer mode switching.
1278 CVegetableInstanceGroup
*pIg
= ig
->_SortOwner
->_InstanceGroupList
.begin();
1281 // let's pass them in software mode.
1282 swapIgRdrPassHardMode(pIg
, rdrPass
);
1284 pIg
= (CVegetableInstanceGroup
*)pIg
->Next
;
1287 // Then all The sortBlock is in SoftMode.
1288 ig
->_SortOwner
->ZSortHardMode
= false;
1292 // just do it on this Ig (can mix hardMode in a SortBlock for normal rdrPass)
1293 swapIgRdrPassHardMode(ig
, rdrPass
);
1296 // now, we can use the software only Allocator to append our instance
1297 allocator
= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, 0);
1302 // get correct dstVB
1303 const CVertexBuffer
&dstVBInfo
= allocator
->getSoftwareVertexBuffer();
1306 // Transform vertices to a vegetable instance, and enlarge clipBlock
1307 //--------------------
1308 // compute matrix to multiply normals, ie (M-1)t
1310 // need just rotation scale matrix.
1311 normalMat
.setRot(mat
);
1313 normalMat
.transpose();
1314 // compute Instance position
1315 CVector instancePos
;
1316 mat
.getPos(instancePos
);
1319 // At least, the bbox of the clipBlock must include the center of the shape.
1320 ig
->_ClipOwner
->extendSphere(instancePos
);
1323 // Vertex/triangle Info.
1324 uint numNewVertices
= shape
->VB
.getNumVertices();
1325 uint numNewTris
= (uint
)shape
->TriangleIndices
.size()/3;
1326 uint numNewIndices
= (uint
)shape
->TriangleIndices
.size();
1329 uint srcNormalOff
= (instanceLighted
? shape
->VB
.getNormalOff() : 0);
1330 uint srcTex0Off
= shape
->VB
.getTexCoordOff(0);
1331 uint srcTex1Off
= shape
->VB
.getTexCoordOff(1);
1334 uint dstNormalOff
= (destLighted
? dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_NORMAL
) : 0);
1335 uint dstColor0Off
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR0
);
1336 uint dstColor1Off
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR1
);
1337 uint dstTex0Off
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_TEX0
);
1338 uint dstBendOff
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_BENDINFO
);
1339 uint dstCenterOff
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_CENTER
);
1341 // For D3D, If the VertexBuffer is in BGRA mode
1342 if(allocator
->isBGRA())
1344 // then swap only the B and R (no cpu cycle added per vertex)
1345 primaryRGBA
.swapBR();
1346 secondaryRGBA
.swapBR();
1347 diffusePL
[0].swapBR();
1348 diffusePL
[1].swapBR();
1351 // Useful for !destLighted only.
1353 float deltaPosNorm
=0.0;
1356 // Useful for ZSORT rdrPass, the worldVertices.
1357 static vector
<CVector
> worldVertices
;
1358 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
1360 worldVertices
.resize(numNewVertices
);
1363 CVertexBufferRead vba
;
1364 shape
->VB
.lock (vba
);
1366 // For all vertices of shape, transform and store manager indices in temp shape.
1367 for(i
=0; i
<(sint
)numNewVertices
;i
++)
1369 // allocate a Vertex
1370 uint vid
= allocator
->allocateVertex();
1372 CVertexBufferReadWrite vbaOut
;
1373 allocator
->getSoftwareVertexBuffer ().lock(vbaOut
);
1375 // store in tmp shape.
1376 shape
->InstanceVertices
[i
]= vid
;
1378 // Fill this vertex.
1379 const uint8
*srcPtr
= (uint8
*)vba
.getVertexCoordPointer(i
);
1380 uint8
*dstPtr
= (uint8
*)vbaOut
.getVertexCoordPointer(vid
);
1382 // Get bendWeight for this vertex.
1383 float vertexBendWeight
= ((CUV
*)(srcPtr
+ srcTex1Off
))->U
* bendFactor
;
1387 // Separate Center and relative pos.
1388 CVector relPos
= mat
.mulVector(*(CVector
*)srcPtr
); // mulVector, because translation in v[center]
1389 // compute bendCenterPos
1390 CVector bendCenterPos
;
1391 if(shape
->BendCenterMode
== CVegetableShapeBuild::BendCenterNull
)
1392 bendCenterPos
= CVector::Null
;
1395 CVector v
= *(CVector
*)srcPtr
;
1397 bendCenterPos
= mat
.mulVector(v
); // mulVector, because translation in v[center]
1400 deltaPos
= relPos
-bendCenterPos
;
1401 *(CVector
*)dstPtr
= deltaPos
;
1402 *(CVector
*)(dstPtr
+ dstCenterOff
)= instancePos
+ bendCenterPos
;
1403 // if !destLighted, then VP is different
1406 deltaPosNorm
= deltaPos
.norm();
1407 // copy bendWeight in v.w
1408 CVectorH
*vh
= (CVectorH
*)dstPtr
;
1409 // Mul by deltaPosNorm, to draw an arc circle.
1410 vh
->w
= vertexBendWeight
* deltaPosNorm
;
1413 // Enlarge the clipBlock of the IG.
1414 // Since small shape, enlarge with each vertices. simpler and maybe faster.
1415 // TODO_VEGET: bend and clipping ...
1416 ig
->_ClipOwner
->extendBBoxOnly(instancePos
+ relPos
);
1418 // prepare for ZSort
1419 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
1421 worldVertices
[i
]= instancePos
+ relPos
;
1427 if(!precomputeLighting
)
1429 // just copy the primary color (means diffuse part if lighted)
1430 *(CRGBA
*)(dstPtr
+ dstColor0Off
)= primaryRGBA
;
1431 // normal and secondary color
1435 *(CVector
*)(dstPtr
+ dstNormalOff
)= normalMat
.mulVector( *(CVector
*)(srcPtr
+ srcNormalOff
) );
1437 // If destLighted, secondaryRGBA is the ambient
1438 // else secondaryRGBA is used only for Alpha (DLM uv.v).
1439 *(CRGBA
*)(dstPtr
+ dstColor1Off
)= secondaryRGBA
;
1443 nlassert(!destLighted
);
1446 CVector rotNormal
= normalMat
.mulVector( *(CVector
*)(srcPtr
+ srcNormalOff
) );
1447 // must normalize() because scale is possible.
1448 rotNormal
.normalize();
1451 if(!bestSidedPrecomputeLighting
)
1453 computeVegetVertexLighting(rotNormal
,
1454 _DirectionalLight
, primaryRGBA
, secondaryRGBA
,
1455 vegetLex
, diffusePL
, (CRGBA
*)(dstPtr
+ dstColor0Off
) );
1459 computeVegetVertexLightingForceBestSided(rotNormal
,
1460 _DirectionalLight
, primaryRGBA
, secondaryRGBA
,
1461 vegetLex
, diffusePL
, (CRGBA
*)(dstPtr
+ dstColor0Off
) );
1464 // copy secondaryRGBA, used only for Alpha (DLM uv.v).
1465 *(CRGBA
*)(dstPtr
+ dstColor1Off
)= secondaryRGBA
;
1471 *(CUV
*)(dstPtr
+ dstTex0Off
)= *(CUV
*)(srcPtr
+ srcTex0Off
);
1475 CVector
*dstBendPtr
= (CVector
*)(dstPtr
+ dstBendOff
);
1476 // setup bend Phase.
1477 dstBendPtr
->y
= bendPhase
;
1478 // setup bend Weight.
1479 // if !destLighted, then VP is different, vertexBendWeight is stored in v[0].w
1481 dstBendPtr
->x
= vertexBendWeight
;
1483 // the VP need the norm of relPos in v[9].x
1484 dstBendPtr
->x
= deltaPosNorm
;
1485 // setup bendFreqFactor
1486 dstBendPtr
->z
= bendFreqFactor
;
1487 /// If AlphaBlend / ZSort rdrPass, then setup AlphaBlend computing.
1488 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
1490 // get ptr on v[9].w NB: in Unlit mode, it has 4 components.
1491 CVectorH
*dstBendPtr
= (CVectorH
*)(dstPtr
+ dstBendOff
);
1492 // setup the constant of linear formula:
1493 // Alpha= -1/blendTransDist * dist + blendDistMax/blendTransDist
1494 dstBendPtr
->w
= blendDistMax
/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST
;
1498 // fill the vertex in AGP.
1500 allocator
->flushVertex(vid
);
1504 // must recompute the sphere according to the bbox.
1505 ig
->_ClipOwner
->updateSphere();
1508 // If ZSort, compute Triangle Centers and Orders for quadrant
1509 //--------------------
1510 if(rdrPass
==NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
1512 // inform the SB that it must be updated.
1513 ig
->_SortOwner
->_Dirty
= true;
1514 // For deletion, inform the ig that it has instances which impact the SB.
1515 ig
->_HasZSortPassInstances
= true;
1517 // change UnderWater falg of the SB
1518 if(vegetWaterState
== AboveWater
)
1519 ig
->_SortOwner
->_UnderWater
= false;
1520 else if(vegetWaterState
== UnderWater
)
1521 ig
->_SortOwner
->_UnderWater
= true;
1523 // static to avoid reallocation
1524 static vector
<CVector
> triangleCenters
;
1525 triangleCenters
.resize(numNewTris
);
1527 // compute triangle centers
1528 for(uint i
=0; i
<numNewTris
; i
++)
1530 // get index in shape.
1531 uint v0
= shape
->TriangleIndices
[i
*3+0];
1532 uint v1
= shape
->TriangleIndices
[i
*3+1];
1533 uint v2
= shape
->TriangleIndices
[i
*3+2];
1536 const CVector
&vert0
= worldVertices
[v0
];
1537 const CVector
&vert1
= worldVertices
[v1
];
1538 const CVector
&vert2
= worldVertices
[v2
];
1541 triangleCenters
[i
]= (vert0
+ vert1
+ vert2
) / 3;
1542 // relative to center of the sortBlock (for sint16 compression)
1543 triangleCenters
[i
]-= ig
->_SortOwner
->_Center
;
1547 // resize the array. Actually only modify the number of triangles really setuped.
1548 uint offTri
= ig
->_TriangleQuadrantOrderNumTriangles
;
1549 ig
->_TriangleQuadrantOrderNumTriangles
+= numNewTris
;
1550 // verify user has correclty used reserveIg system.
1551 nlassert(ig
->_TriangleQuadrantOrderNumTriangles
* NL3D_VEGETABLE_NUM_QUADRANT
<= ig
->_TriangleQuadrantOrderArray
.size());
1554 // compute distance for each quadrant. Since we are not sure of the sortBlockSize, mul with a (big: 16) security.
1555 // NB: for landscape practical usage, this left us with more than 1mm precision.
1556 float distFactor
=32768/(16*ig
->_SortOwner
->_Radius
);
1557 for(uint quadId
=0; quadId
<NL3D_VEGETABLE_NUM_QUADRANT
; quadId
++)
1559 const CVector
&quadDir
= CVegetableQuadrant::Dirs
[quadId
];
1562 for(uint i
=0; i
<numNewTris
; i
++)
1564 // compute the distance with orientation of the quadrant. (DotProduct)
1565 float dist
= triangleCenters
[i
] * quadDir
;
1566 // compress to sint16.
1567 ig
->_TriangleQuadrantOrders
[quadId
][offTri
+ i
]= (sint16
)NLMISC::OptFastFloor(dist
*distFactor
);
1573 // Append list of indices and list of triangles to the IG
1574 //--------------------
1576 // TODO_VEGET_OPTIM: system reallocation of array is very bad...
1579 // compute dest start idx.
1580 uint offVertex
= vegetRdrPass
.NVertices
;
1581 uint offTri
= vegetRdrPass
.NTriangles
;
1582 uint offTriIdx
= offTri
*3;
1584 // verify user has correclty used reserveIg system.
1585 nlassert(offVertex
+ numNewVertices
<= vegetRdrPass
.Vertices
.size());
1586 nlassert(offTriIdx
+ numNewIndices
<= vegetRdrPass
.TriangleIndices
.getNumIndexes());
1587 nlassert(offTriIdx
+ numNewIndices
<= vegetRdrPass
.TriangleLocalIndices
.size());
1590 // insert list of vertices to delete in ig vertices.
1591 vegetRdrPass
.Vertices
.copy(offVertex
, offVertex
+numNewVertices
, &shape
->InstanceVertices
[0]);
1593 // insert array of triangles in ig.
1594 // for all indices, fill IG
1595 CIndexBufferReadWrite ibaWrite
;
1596 vegetRdrPass
.TriangleIndices
.lock (ibaWrite
);
1597 if (vegetRdrPass
.TriangleIndices
.getFormat() == CIndexBuffer::Indices16
)
1599 uint16
*ptr
= (uint16
*) ibaWrite
.getPtr();
1600 for(i
=0; i
<(sint
)numNewIndices
; i
++)
1602 // get the index of the vertex in the shape
1603 uint vid
= shape
->TriangleIndices
[i
];
1604 // re-direction, using InstanceVertices;
1606 nlassert(shape
->InstanceVertices
[vid
] <= 0xffff);
1608 ptr
[offTriIdx
+ i
]= (uint16
) shape
->InstanceVertices
[vid
];
1609 // local re-direction: adding vertexOffset.
1610 vegetRdrPass
.TriangleLocalIndices
[offTriIdx
+ i
]= offVertex
+ vid
;
1615 uint32
*ptr
= (uint32
*) ibaWrite
.getPtr();
1616 for(i
=0; i
<(sint
)numNewIndices
; i
++)
1618 // get the index of the vertex in the shape
1619 uint vid
= shape
->TriangleIndices
[i
];
1620 // re-direction, using InstanceVertices;
1621 ptr
[offTriIdx
+ i
]= shape
->InstanceVertices
[vid
];
1622 // local re-direction: adding vertexOffset.
1623 vegetRdrPass
.TriangleLocalIndices
[offTriIdx
+ i
]= offVertex
+ vid
;
1627 // new triangle and vertex size.
1628 vegetRdrPass
.NTriangles
+= numNewTris
;
1629 vegetRdrPass
.NVertices
+= numNewVertices
;
1632 // if lighted, must add a lightedInstance for lighting update.
1633 //--------------------
1636 // first, update Ig.
1637 ig
->_ULNumVertices
+= numNewVertices
;
1638 // and update the vegetable manager.
1639 _ULNTotalVertices
+= numNewVertices
;
1640 // link at the end of the circular list: link before the current root.
1644 ig
->linkBeforeUL(_ULRootIg
);
1646 // check good use of reserveIg.
1647 nlassert(vegetRdrPass
.NLightedInstances
< vegetRdrPass
.LightedInstances
.size());
1649 // Fill instance info
1650 CVegetableInstanceGroup::CVegetableLightedInstance
&vli
=
1651 vegetRdrPass
.LightedInstances
[vegetRdrPass
.NLightedInstances
];
1653 vli
.NormalMat
= normalMat
;
1654 // copy colors unmodulated by global light.
1655 vli
.MatAmbient
= ambientRGBA
;
1656 vli
.MatDiffuse
= diffuseRGBA
;
1657 // store dynamic lightmap UV
1659 // where vertices of this instances are wrote in the VegetRdrPass
1660 vli
.StartIdInRdrPass
= offVertex
;
1662 // Inc size setuped.
1663 vegetRdrPass
.NLightedInstances
++;
1669 // ***************************************************************************
1670 void CVegetableManager::swapIgRdrPassHardMode(CVegetableInstanceGroup
*ig
, uint rdrPass
)
1672 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPass
];
1674 // the allocator where vertices come from
1675 CVegetableVBAllocator
&srcAllocator
= getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, vegetRdrPass
.HardMode
);
1676 // the allocator where vertices will go
1677 CVegetableVBAllocator
&dstAllocator
= getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, !vegetRdrPass
.HardMode
);
1680 uint vbSize
= srcAllocator
.getSoftwareVertexBuffer().getVertexSize();
1681 nlassert(vbSize
== dstAllocator
.getSoftwareVertexBuffer().getVertexSize());
1683 CVertexBufferRead vbaIn
;
1684 srcAllocator
.getSoftwareVertexBuffer ().lock(vbaIn
);
1686 // for all vertices of the IG, change of VBAllocator
1688 // Do it only for current Vertices setuped!!! because a swapIgRdrPassHardMode awlays arise when the ig is
1690 // Hence here, we may have vegetRdrPass.NVertices < vegetRdrPass.Vertices.size() !!!
1691 for(i
=0;i
<vegetRdrPass
.NVertices
;i
++)
1693 // get idx in src allocator.
1694 uint srcId
= vegetRdrPass
.Vertices
[i
];
1695 // allocate a vertex in the dst allocator.
1696 uint dstId
= dstAllocator
.allocateVertex();
1698 CVertexBufferReadWrite vbaOut
;
1699 dstAllocator
.getSoftwareVertexBuffer ().lock(vbaOut
);
1701 // copy from VBsoft of src to dst.
1702 const void *vbSrc
= vbaIn
.getVertexCoordPointer(srcId
);
1703 void *vbDst
= vbaOut
.getVertexCoordPointer(dstId
);
1704 memcpy(vbDst
, vbSrc
, vbSize
);
1705 // release src vertex.
1706 srcAllocator
.deleteVertex(srcId
);
1708 // and copy new dest id in Vertices array.
1709 vegetRdrPass
.Vertices
[i
]= dstId
;
1711 // and flush this vertex into VBHard (if dst is aVBHard).
1712 dstAllocator
.flushVertex(dstId
);
1715 // For all triangles, bind correct triangles.
1716 nlassert(vegetRdrPass
.TriangleIndices
.getNumIndexes() == vegetRdrPass
.TriangleLocalIndices
.size());
1717 // Do it only for current Triangles setuped!!! same reason as vertices
1718 // For all setuped triangles indices
1719 CIndexBufferReadWrite ibaWrite
;
1720 // For hard mode, uses faster 16 bit indices because the VB is not bigger than 65K
1721 vegetRdrPass
.TriangleIndices
.setFormat(vegetRdrPass
.HardMode
? CIndexBuffer::Indices32
: CIndexBuffer::Indices16
); // NB : this is not an error here : vegetRdrPass.HardMode has not been inverted yet
1722 vegetRdrPass
.TriangleIndices
.lock (ibaWrite
);
1723 if (ibaWrite
.getFormat() == CIndexBuffer::Indices16
)
1725 uint16
*ptr
= (uint16
*) ibaWrite
.getPtr();
1726 for(i
=0;i
<vegetRdrPass
.NTriangles
*3;i
++)
1728 // get the index in Vertices.
1729 uint localVid
= vegetRdrPass
.TriangleLocalIndices
[i
];
1730 // get the index in new VBufffer (dstAllocator), and copy to TriangleIndices
1731 ptr
[i
]= (uint16
) vegetRdrPass
.Vertices
[localVid
];
1736 uint32
*ptr
= (uint32
*) ibaWrite
.getPtr();
1737 for(i
=0;i
<vegetRdrPass
.NTriangles
*3;i
++)
1739 // get the index in Vertices.
1740 uint localVid
= vegetRdrPass
.TriangleLocalIndices
[i
];
1741 // get the index in new VBufffer (dstAllocator), and copy to TriangleIndices
1742 ptr
[i
]= (uint32
) vegetRdrPass
.Vertices
[localVid
];
1746 // Since change is made, flag the IG rdrpass
1747 vegetRdrPass
.HardMode
= !vegetRdrPass
.HardMode
;
1751 // ***************************************************************************
1752 void CVegetableManager::setGlobalDensity(float density
)
1754 clamp(density
, 0.f
, 100.f
);
1755 _GlobalDensity
= density
;
1759 // ***************************************************************************
1760 // ***************************************************************************
1762 // ***************************************************************************
1763 // ***************************************************************************
1766 // ***************************************************************************
1767 bool CVegetableManager::doubleSidedRdrPass(uint rdrPass
)
1769 nlassert(rdrPass
<NL3D_VEGETABLE_NRDRPASS
);
1770 return (rdrPass
== NL3D_VEGETABLE_RDRPASS_LIGHTED_2SIDED
) ||
1771 (rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED
) ||
1772 (rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
);
1775 // ***************************************************************************
1776 void CVegetableManager::updateDriver(IDriver
*driver
)
1778 // update all driver
1780 for(i
=0; i
<CVegetableVBAllocator::VBTypeCount
; i
++)
1782 _VBHardAllocator
[i
].updateDriver(driver
);
1783 _VBSoftAllocator
[i
].updateDriver(driver
);
1786 // if driver changed, recreate vertex programs
1787 if (driver
!= _LastDriver
)
1789 _LastDriver
= driver
;
1790 for(i
=0; i
<NL3D_VEGETABLE_NRDRPASS
; i
++)
1792 // both fog & no fog
1793 initVertexProgram(i
, true);
1794 initVertexProgram(i
, false);
1800 // ***************************************************************************
1801 void CVegetableManager::loadTexture(const string
&texName
)
1803 // setup a CTextureFile (smartPtr-ized).
1804 ITexture
*tex
= new CTextureFile(texName
);
1806 // setup good params.
1807 tex
->setFilterMode(ITexture::Linear
, ITexture::LinearMipMapLinear
);
1808 tex
->setWrapS(ITexture::Clamp
);
1809 tex
->setWrapT(ITexture::Clamp
);
1812 // ***************************************************************************
1813 void CVegetableManager::loadTexture(ITexture
*itex
)
1815 // setup a ITexture (smartPtr-ized).
1816 // Store in stage1, for dynamicLightmaping
1817 _VegetableMaterial
.setTexture(1, itex
);
1820 // ***************************************************************************
1821 void CVegetableManager::setDirectionalLight(const CRGBA
&ambient
, const CRGBA
&diffuse
, const CVector
&light
)
1823 _DirectionalLight
= light
;
1824 _DirectionalLight
.normalize();
1825 // Setup ambient/Diffuse.
1826 _GlobalAmbient
= ambient
;
1827 _GlobalDiffuse
= diffuse
;
1830 // ***************************************************************************
1831 void CVegetableManager::lockBuffers()
1834 for(uint i
=0; i
<CVegetableVBAllocator::VBTypeCount
; i
++)
1836 _VBHardAllocator
[i
].lockBuffer();
1837 _VBSoftAllocator
[i
].lockBuffer();
1841 // ***************************************************************************
1842 void CVegetableManager::unlockBuffers()
1844 // unlock all buffers
1845 for(uint i
=0; i
<CVegetableVBAllocator::VBTypeCount
; i
++)
1847 _VBHardAllocator
[i
].unlockBuffer();
1848 _VBSoftAllocator
[i
].unlockBuffer();
1853 // ***************************************************************************
1857 CVegetableSortBlock
*Sb
;
1859 CSortVSB() : Sb(NULL
) {}
1860 CSortVSB(CVegetableSortBlock
*sb
) : Sb(sb
) {}
1864 bool operator<(const CSortVSB
&o
) const
1866 return Sb
->_SortKey
>o
.Sb
->_SortKey
;
1872 // ***************************************************************************
1873 void CVegetableManager::setupVertexProgramConstants(IDriver
*driver
, bool fogEnabled
)
1875 nlassert(_ActiveVertexProgram
);
1879 // setup VertexProgram constants.
1880 // c[0..3] take the ModelViewProjection Matrix. After setupModelMatrix();
1881 driver
->setUniformMatrix(IDriver::VertexProgram
, _ActiveVertexProgram
->getUniformIndex(CProgramIndex::ModelViewProjection
), IDriver::ModelViewProjection
, IDriver::Identity
);
1882 // c[6] take the Fog vector. After setupModelMatrix();
1885 driver
->setUniformFog(IDriver::VertexProgram
, _ActiveVertexProgram
->getUniformIndex(CProgramIndex::Fog
));
1887 // c[8] take useful constants.
1888 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().ProgramConstants0
, 0, 1, 0.5f
, 2);
1889 // c[9] take normalized directional light
1890 driver
->setUniform3f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().DirectionalLight
, _DirectionalLight
);
1891 // c[10] take pos of camera
1892 driver
->setUniform3f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().ViewCenter
, _ViewCenter
);
1893 // c[11] take factor for Blend formula
1894 driver
->setUniform1f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().NegInvTransDist
, -1.f
/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST
);
1899 // c[16]= quaternion axis. w==1, and z must be 0
1900 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().AngleAxis
, _AngleAxis
, 1);
1901 // c[17]= {timeAnim, WindPower, WindPower*(1-WindBendMin)/2, 0)}
1902 driver
->setUniform3f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().Wind
, (float)_WindAnimTime
, _WindPower
, _WindPower
* (1 - _WindBendMin
) / 2);
1903 // c[18]= High order Taylor cos coefficient: { -1/2, 1/24, -1/720, 1/40320 }
1904 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().CosCoeff0
, -1/2.f
, 1/24.f
, -1/720.f
, 1/40320.f
);
1905 // c[19]= Low order Taylor cos coefficient: { 1, -1/2, 1/24, -1/720 }
1906 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().CosCoeff1
, 1, -1/2.f
, 1/24.f
, -1/720.f
);
1907 // c[20]= Low order Taylor sin coefficient: { 1, -1/6, 1/120, -1/5040 }
1908 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().CosCoeff2
, 1, -1/6.f
, 1/120.f
, -1/5040.f
);
1909 // c[21]= Special constant vector for quatToMatrix: { 0, 1, -1, 0 }
1910 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().QuatConstants
, 0.f
, 1.f
, -1.f
, 0.f
);
1911 // c[22]= {0.5f, Pi, 2*Pi, 1/(2*Pi)}
1912 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().PiConstants
, 0.5f
, (float)Pi
, (float)(2*Pi
), (float)(1/(2*Pi
)));
1913 // c[23]= {NL3D_VEGETABLE_VP_LUT_SIZE, 0, 0, 0}. NL3D_VEGETABLE_VP_LUT_SIZE==64.
1914 driver
->setUniform1f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().LUTSize
, NL3D_VEGETABLE_VP_LUT_SIZE
);
1917 // Fill constant. Start at 32.
1918 for(uint i
=0; i
<NL3D_VEGETABLE_VP_LUT_SIZE
; i
++)
1920 CVector2f cur
= _WindTable
[i
];
1921 CVector2f delta
= _WindDeltaTable
[i
];
1922 driver
->setUniform4f(IDriver::VertexProgram
, _ActiveVertexProgram
->idx().LUT
[i
], cur
.x
, cur
.y
, delta
.x
, delta
.y
);
1927 // ***************************************************************************
1928 void CVegetableManager::render(const CVector
&viewCenter
, const CVector
&frontVector
, const std::vector
<CPlane
> &pyramid
,
1929 ITexture
*textureDLM
, IDriver
*driver
)
1931 H_AUTO( NL3D_Vegetable_Render
);
1933 CVegetableClipBlock
*rootToRender
= NULL
;
1935 // get normalized front vector.
1936 CVector frontVectorNormed
= frontVector
.normed();
1938 // For Speed debug only.
1939 /*extern bool YOYO_ATTest;
1945 //--------------------
1946 // For all current not empty clipBlocks, clip against pyramid, and insert visibles in list.
1947 CVegetableClipBlock
*ptrClipBlock
= _ClipBlockList
.begin();
1950 // if the clipBlock is visible and not empty
1951 if(ptrClipBlock
->clip(pyramid
))
1953 // insert into visible list.
1954 ptrClipBlock
->_RenderNext
= rootToRender
;
1955 rootToRender
= ptrClipBlock
;
1959 ptrClipBlock
= (CVegetableClipBlock
*)ptrClipBlock
->Next
;
1963 // If no clip block visible, just skip!!
1964 if(rootToRender
==NULL
)
1969 //--------------------
1972 CPrimitiveProfile ppIn
, ppOut
;
1973 driver
->profileRenderedPrimitives(ppIn
, ppOut
);
1974 uint precNTriRdr
= ppOut
.NTriangles
;
1979 bkupFog
= driver
->fogEnabled();
1981 bool fogged
= bkupFog
&& driver
->getFogStart() < _ZSortLayerDistMax
;
1984 driver
->enableFog(fogged
);
1987 // Used by setupVertexProgramConstants(). The center of camera.
1988 // Used for AlphaBlending, and for ZBuffer precision problems.
1989 _ViewCenter
= viewCenter
;
1992 // The manager is identity in essence. But for ZBuffer improvements, must set it as close
1993 // to the camera. In the VertexProgram, _ViewCenter is substracted from bent vertex pos. So take it as position.
1994 _ManagerMatrix
.identity();
1995 _ManagerMatrix
.setPos(_ViewCenter
);
1998 // set model matrix to the manager matrix.
1999 driver
->setupModelMatrix(_ManagerMatrix
);
2002 // set the driver for all allocators
2003 updateDriver(driver
);
2006 // Compute Bend Anim.
2008 // AnimFrequency factor.
2009 // Doing it incrementally allow change of of frequency each frame with good results.
2010 _WindAnimTime
+= (_Time
- _WindPrecRenderTime
)*_WindFrequency
;
2011 _WindAnimTime
= fmod((float)_WindAnimTime
, (float)NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC
);
2012 // NB: Leave timeBend (_WindAnimTime) as a time (ie [0..1]), because VP do a "EXP time".
2013 // For incremental computing.
2014 _WindPrecRenderTime
= _Time
;
2017 // compute the angleAxis corresponding to direction
2018 // perform a 90deg rotation to get correct angleAxis
2019 _AngleAxis
.set(-_WindDirection
.y
,_WindDirection
.x
,0);
2022 // Fill LUT WindTable.
2024 for(i
=0; i
<NL3D_VEGETABLE_VP_LUT_SIZE
; i
++)
2026 /* NB: this formula works quite well, because vertex BendFactor is expressed in Radian/2.
2027 And since animFactor==(_CosTable[i] + 1) E [0..2], we have here an arc-circle computing:
2028 dmove= Radius * AngleRadian/2 * animFactor. So at max of animFactor (ie 2), we have:
2029 dmove= Radius * AngleRadian, which is by definition an arc-circle computing...
2030 And so this approximate the Bend-quaternion Vertex Program.
2032 float windForce
= (_CosTable
[(i
+32)%64] + 1);
2033 // Modify with _WindPower / _WindBendMin.
2034 windForce
= _WindBendMin
*2 + windForce
* (1-_WindBendMin
);
2035 windForce
*= _WindPower
;
2036 // Compute direction of the wind, and multiply by windForce.
2037 _WindTable
[i
]= CVector2f(_WindDirection
.x
, _WindDirection
.y
) * windForce
;
2040 for(i
=0; i
<NL3D_VEGETABLE_VP_LUT_SIZE
; i
++)
2042 CVector2f cur
= _WindTable
[i
];
2043 CVector2f delta
= _WindTable
[ (i
+1)%NL3D_VEGETABLE_VP_LUT_SIZE
] - cur
;
2044 _WindDeltaTable
[i
]= delta
;
2048 // Setup TexEnvs for Dynamic lightmapping
2049 //--------------------
2050 // if the dynamic lightmap is provided
2053 // stage0 RGB is Diffuse + DLM.
2054 _VegetableMaterial
.setTexture(0, textureDLM
);
2055 _VegetableMaterial
.texEnvOpRGB(0, CMaterial::Add
);
2056 _VegetableMaterial
.texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
2057 _VegetableMaterial
.texEnvArg1RGB(0, CMaterial::Diffuse
, CMaterial::SrcColor
);
2058 // stage1 RGB is Previous * Texture
2059 _VegetableMaterial
.texEnvOpRGB(1, CMaterial::Modulate
);
2060 _VegetableMaterial
.texEnvArg0RGB(1, CMaterial::Texture
, CMaterial::SrcColor
);
2061 _VegetableMaterial
.texEnvArg1RGB(1, CMaterial::Previous
, CMaterial::SrcColor
);
2065 // reset stage0 (to skip it)
2066 _VegetableMaterial
.setTexture(0, NULL
);
2067 // stage1 RGB is Diffuse * Texture
2068 _VegetableMaterial
.texEnvOpRGB(1, CMaterial::Modulate
);
2069 _VegetableMaterial
.texEnvArg0RGB(1, CMaterial::Texture
, CMaterial::SrcColor
);
2070 _VegetableMaterial
.texEnvArg1RGB(1, CMaterial::Diffuse
, CMaterial::SrcColor
);
2072 // stage1 Alpha is always "Modulate texture with diffuse Alpha"
2073 _VegetableMaterial
.texEnvOpAlpha(1, CMaterial::Modulate
);
2074 _VegetableMaterial
.texEnvArg0Alpha(1, CMaterial::Texture
, CMaterial::SrcAlpha
);
2075 _VegetableMaterial
.texEnvArg1Alpha(1, CMaterial::Diffuse
, CMaterial::SrcAlpha
);
2079 // Render !ZSORT pass
2080 //--------------------
2082 // setup material (may have change because of ZSORT / alphaBlend pass)
2083 _VegetableMaterial
.setBlend(false);
2084 _VegetableMaterial
.setZWrite(true);
2085 _VegetableMaterial
.setAlphaTestThreshold(0.5f
);
2087 bool uprogst
= driver
->isUniformProgramState();
2088 bool progstateset
[NL3D_VEGETABLE_NRDRPASS
];
2089 for (sint rdrPass
= 0; rdrPass
< NL3D_VEGETABLE_NRDRPASS
; ++rdrPass
)
2091 progstateset
[rdrPass
] = false;
2095 Prefer sort with Soft / Hard first.
2096 Also, Prefer do VBsoft last, for better GPU //ism with Landscape.
2098 // For both allocators: Hard(1) then Soft(0)
2099 for(sint vbHardMode
= 1; vbHardMode
>=0; vbHardMode
--)
2101 // For all renderPass.
2102 for(sint rdrPass
=0; rdrPass
< NL3D_VEGETABLE_NRDRPASS
; rdrPass
++)
2104 // skip ZSORT rdrPass, done after.
2105 if(rdrPass
== NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
)
2109 CVegetableVBAllocator
&vbAllocator
= getVBAllocatorForRdrPassAndVBHardMode(rdrPass
, vbHardMode
);
2112 // Do the pass only if there is some vertices to draw.
2113 if(vbAllocator
.getNumUserVerticesAllocated()>0)
2115 // additional setup to the material
2116 bool doubleSided
= doubleSidedRdrPass(rdrPass
);
2117 // set the 2Sided flag in the material
2118 _VegetableMaterial
.setDoubleSided( doubleSided
);
2120 // activate Vertex program first.
2121 //nlinfo("\nSTARTVP\n%s\nENDVP\n", _VertexProgram[rdrPass]->getProgram().c_str());
2123 _ActiveVertexProgram
= _VertexProgram
[rdrPass
][fogged
? 1 : 0];
2124 nlverify(driver
->activeVertexProgram(_ActiveVertexProgram
));
2127 if (!progstateset
[uprogst
? rdrPass
: 0])
2129 setupVertexProgramConstants(driver
, uprogst
? fogged
: true);
2132 // Activate the unique material.
2133 driver
->setupMaterial(_VegetableMaterial
);
2135 // Activate the good VBuffer
2136 vbAllocator
.activate();
2138 // For all visibles clipBlock, render their instance groups.
2139 ptrClipBlock
= rootToRender
;
2142 // For all sortBlock of the clipBlock
2143 CVegetableSortBlock
*ptrSortBlock
= ptrClipBlock
->_SortBlockList
.begin();
2146 // For all igs of the sortBlock
2147 CVegetableInstanceGroup
*ptrIg
= ptrSortBlock
->_InstanceGroupList
.begin();
2151 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ptrIg
->_RdrPass
[rdrPass
];
2153 // if this rdrPass is in same HardMode as we process now.
2154 if( (vegetRdrPass
.HardMode
&& vbHardMode
==1) || (!vegetRdrPass
.HardMode
&& vbHardMode
==0) )
2156 // Ok, Render the faces.
2157 if(vegetRdrPass
.NTriangles
)
2159 driver
->activeIndexBuffer(vegetRdrPass
.TriangleIndices
);
2161 if (vegetRdrPass
.HardMode
)
2163 nlassert(vegetRdrPass
.TriangleIndices
.getFormat() == CIndexBuffer::Indices16
);
2167 nlassert(vegetRdrPass
.TriangleIndices
.getFormat() == CIndexBuffer::Indices32
);
2170 driver
->renderSimpleTriangles(0,
2171 vegetRdrPass
.NTriangles
);
2176 ptrIg
= (CVegetableInstanceGroup
*)ptrIg
->Next
;
2180 ptrSortBlock
= (CVegetableSortBlock
*)(ptrSortBlock
->Next
);
2183 // next clipBlock to render
2184 ptrClipBlock
= ptrClipBlock
->_RenderNext
;
2192 // Render ZSort pass.
2193 //--------------------
2196 /*static vector<CVector> p0DebugLines;
2197 static vector<CVector> p1DebugLines;
2198 p0DebugLines.clear();
2199 p1DebugLines.clear();*/
2201 // For all Blend model Layers, clear Sort Block list and setup.
2202 for(i
=0; i
<_NumZSortBlendLayers
;i
++)
2204 // must have been created.
2205 nlassert(_ZSortModelLayers
[i
]);
2206 nlassert(_ZSortModelLayersUW
[i
]);
2207 // NB: don't refresh list, it is done in CVegetableBlendLayerModel.
2208 // We must do it here, because if vegetableManger::render() is no more called (eg: disabled),
2209 // then the models must do nothing.
2211 // To get layers correclty sorted from fornt to back, must init their pos
2212 // because it is the renderTraversal which sort them.
2213 // compute distance to camera of this layer.
2214 float layerZ
= i
* _ZSortLayerDistMax
/ _NumZSortBlendLayers
;
2215 // compute position of this layer.
2216 CVector pos
= viewCenter
+ frontVector
* layerZ
;
2217 // special setup in the layer.
2218 _ZSortModelLayers
[i
]->setWorldPos(pos
);
2219 _ZSortModelLayersUW
[i
]->setWorldPos(pos
);
2222 // If some vertices in arrays for ZSort rdrPass
2223 if( getVBAllocatorForRdrPassAndVBHardMode(NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
, 0).getNumUserVerticesAllocated()>0 ||
2224 getVBAllocatorForRdrPassAndVBHardMode(NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
, 1).getNumUserVerticesAllocated()>0 )
2226 uint rdrPass
= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
;
2230 // Array for sorting. (static to avoid reallocation)
2231 static vector
<CSortVSB
> sortVegetSbs
;
2232 sortVegetSbs
.clear();
2234 // For all visibles clipBlock
2235 ptrClipBlock
= rootToRender
;
2238 // For all sortBlock, prepare to sort them
2239 CVegetableSortBlock
*ptrSortBlock
= ptrClipBlock
->_SortBlockList
.begin();
2242 // if the sortBlock has some sorted faces to render
2243 if(ptrSortBlock
->_NTriangles
!= 0)
2245 // Compute Distance to Viewer.
2246 /* NB: compute radial distance (with norm()) instead of linear distance
2247 (DotProduct with front vector) get less "ZSort poping".
2249 CVector dirToSb
= ptrSortBlock
->_Center
- viewCenter
;
2250 float distToViewer
= dirToSb
.norm();
2251 // SortKey change if the center is behind the camera.
2252 if(dirToSb
* frontVectorNormed
<0)
2254 ptrSortBlock
->_SortKey
= - distToViewer
;
2258 ptrSortBlock
->_SortKey
= distToViewer
;
2261 // Choose the quadrant for this sortBlock
2263 float bestDirVal
= -FLT_MAX
;
2264 // If too near, must take the frontVector as key, to get better sort.
2265 // use ptrSortBlock->_SortKey to get correct negative values.
2266 if(ptrSortBlock
->_SortKey
< ptrSortBlock
->_Radius
)
2268 dirToSb
= frontVectorNormed
;
2271 // NB: no need to normalize dirToSb, because need only to sort with DP
2272 // choose the good list of triangles according to quadrant.
2273 for(uint dirIdx
=0; dirIdx
<NL3D_VEGETABLE_NUM_QUADRANT
; dirIdx
++)
2275 float dirVal
= CVegetableQuadrant::Dirs
[dirIdx
] * dirToSb
;
2276 if(dirVal
>bestDirVal
)
2284 ptrSortBlock
->_QuadrantId
= bestDirIdx
;
2286 // insert in list to sort.
2287 sortVegetSbs
.push_back(CSortVSB(ptrSortBlock
));
2290 /*p0DebugLines.push_back(ptrSortBlock->_Center);
2291 p1DebugLines.push_back(ptrSortBlock->_Center + CVegetableQuadrant::Dirs[bestDirIdx]);*/
2295 ptrSortBlock
= (CVegetableSortBlock
*)(ptrSortBlock
->Next
);
2298 // next clipBlock to render
2299 ptrClipBlock
= ptrClipBlock
->_RenderNext
;
2303 // QSort. (I tried, better than radix sort, guckk!!)
2304 sort(sortVegetSbs
.begin(), sortVegetSbs
.end());
2307 // setup material for this rdrPass. NB: rendered after (in LayerModels).
2309 bool doubleSided
= doubleSidedRdrPass(rdrPass
);
2310 // set the 2Sided flag in the material
2311 _VegetableMaterial
.setDoubleSided( doubleSided
);
2313 // setup the unique material.
2314 _VegetableMaterial
.setBlend(true);
2315 _VegetableMaterial
.setZWrite(false);
2316 // leave AlphaTest but still kick low alpha values (for fillRate performance)
2317 _VegetableMaterial
.setAlphaTestThreshold(0.1f
);
2321 // order them in Layers.
2324 // render from back to front, to keep correct Z order in a single layer.
2325 for(uint i
=0; i
<sortVegetSbs
.size();i
++)
2327 CVegetableSortBlock
*ptrSortBlock
= sortVegetSbs
[i
].Sb
;
2329 float z
= ptrSortBlock
->_SortKey
;
2330 // compute in which layer must store this SB.
2331 z
= z
*_NumZSortBlendLayers
/ _ZSortLayerDistMax
;
2332 // Avoid a floor(), using an OptFastFloor, but without the OptFastFloorBegin() End() group.
2333 // => avoid the imprecision with such a trick; *256, then divide the integer by 256.
2334 sint layer
= NLMISC::OptFastFloor(z
*256) >> 8;
2335 clamp(layer
, 0, (sint
)_NumZSortBlendLayers
-1);
2337 // Range in correct layer, according to water ordering
2338 if(ptrSortBlock
->_UnderWater
)
2339 // range in the correct layermodel (NB: keep the same layer internal order).
2340 _ZSortModelLayersUW
[layer
]->SortBlocks
.push_back(ptrSortBlock
);
2342 _ZSortModelLayers
[layer
]->SortBlocks
.push_back(ptrSortBlock
);
2349 //--------------------
2351 // disable VertexProgram.
2352 driver
->activeVertexProgram(NULL
);
2353 _ActiveVertexProgram
= NULL
;
2357 driver
->enableFog(bkupFog
);
2361 /*for(uint l=0; l<p0DebugLines.size();l++)
2363 CVector dv= CVector::K;
2364 CDRU::drawLine(p0DebugLines[l]+dv, p1DebugLines[l]+dv, CRGBA(255,0,0), *driver);
2367 // profile: compute number of triangles rendered with vegetable manager.
2368 driver
->profileRenderedPrimitives(ppIn
, ppOut
);
2369 _NumVegetableFaceRendered
= ppOut
.NTriangles
-precNTriRdr
;
2378 // ***************************************************************************
2379 void CVegetableManager::setupRenderStateForBlendLayerModel(IDriver
*driver
)
2384 // disable fog, for faster VP.
2385 _BkupFog
= driver
->fogEnabled();
2386 static volatile bool testDist
= true;
2387 bool fogged
= _BkupFog
&& driver
->getFogStart() < _ZSortLayerDistMax
;
2388 driver
->enableFog(fogged
);
2390 // set model matrix to the manager matrix.
2391 driver
->setupModelMatrix(_ManagerMatrix
);
2395 uint rdrPass
= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT
;
2397 // activate Vertex program first.
2398 //nlinfo("\nSTARTVP\n%s\nENDVP\n", _VertexProgram[rdrPass]->getProgram().c_str());
2399 _ActiveVertexProgram
= _VertexProgram
[rdrPass
][fogged
? 1 : 0];
2400 nlverify(driver
->activeVertexProgram(_ActiveVertexProgram
));
2402 // setup VP constants.
2403 setupVertexProgramConstants(driver
, fogged
);
2405 /*if (fogged) // duplicate
2407 driver->setCon/stantFog(6);
2410 // Activate the unique material (correclty setuped for AlphaBlend in render()).
2411 driver
->setupMaterial(_VegetableMaterial
);
2415 // ***************************************************************************
2416 void CVegetableManager::resetNumVegetableFaceRendered()
2418 _NumVegetableFaceRendered
= 0;
2422 // ***************************************************************************
2423 uint
CVegetableManager::getNumVegetableFaceRendered() const
2425 return _NumVegetableFaceRendered
;
2429 // ***************************************************************************
2430 void CVegetableManager::exitRenderStateForBlendLayerModel(IDriver
*driver
)
2432 // disable VertexProgram.
2433 driver
->activeVertexProgram(NULL
);
2434 _ActiveVertexProgram
= NULL
;
2437 driver
->enableFog(_BkupFog
);
2442 // ***************************************************************************
2443 void CVegetableManager::setWind(const CVector
&windDir
, float windFreq
, float windPower
, float windBendMin
)
2445 // Keep only XY component of the Wind direction (because VP only support z==0 quaternions).
2446 _WindDirection
= windDir
;
2447 _WindDirection
.z
= 0;
2448 _WindDirection
.normalize();
2450 _WindFrequency
= windFreq
;
2451 _WindPower
= windPower
;
2452 _WindBendMin
= windBendMin
;
2453 clamp(_WindBendMin
, 0, 1);
2456 // ***************************************************************************
2457 void CVegetableManager::setTime(double time
)
2464 // ***************************************************************************
2465 // ***************************************************************************
2467 // ***************************************************************************
2468 // ***************************************************************************
2471 // ***************************************************************************
2472 void CVegetableManager::setUpdateLightingTime(double time
)
2478 // ***************************************************************************
2479 void CVegetableManager::updateLighting()
2481 // first time in this method??
2482 if(!_ULPrecTimeInit
)
2484 _ULPrecTimeInit
= true;
2485 _ULPrecTime
= _ULTime
;
2487 // compute delta time from last update.
2488 float dt
= float(_ULTime
- _ULPrecTime
);
2489 _ULPrecTime
= _ULTime
;
2491 // compute number of vertices to update.
2492 _ULNVerticesToUpdate
+= dt
*_ULFrequency
* _ULNTotalVertices
;
2493 // maximize, so at max, it computes all Igs, just one time.
2494 _ULNVerticesToUpdate
= min(_ULNVerticesToUpdate
, (float)_ULNTotalVertices
);
2501 // ***************************************************************************
2502 void CVegetableManager::updateLightingAll()
2504 // maximize, so at max, it computes all Igs
2505 _ULNVerticesToUpdate
= (float)_ULNTotalVertices
;
2512 // ***************************************************************************
2513 void CVegetableManager::doUpdateLighting()
2515 // while there is still some vertices to update.
2516 while(_ULNVerticesToUpdate
> 0 && _ULRootIg
)
2518 // update the current ig. if all updated, skip to next one.
2519 if(updateLightingIGPart())
2522 _ULRootIg
= _ULRootIg
->_ULNext
;
2526 // Now, _ULNVerticesToUpdate should be <=0. (most of the time < 0)
2530 // ***************************************************************************
2531 void CVegetableManager::setUpdateLightingFrequency(float freq
)
2533 freq
= max(freq
, 0.f
);
2538 // ***************************************************************************
2539 bool CVegetableManager::updateLightingIGPart()
2541 nlassert(_ULRootIg
);
2544 // First, update lighting info global to the ig, ie update current
2545 // colros of the PointLights which influence the ig.
2546 _ULRootIg
->VegetableLightEx
.computeCurrentColors();
2548 // while there is some vertices to update
2549 while(_ULNVerticesToUpdate
>0)
2551 // if all rdrPass of the ig are processed.
2552 if(_ULCurrentIgRdrPass
>= NL3D_VEGETABLE_NRDRPASS
)
2554 // All this Ig is updated.
2555 _ULCurrentIgRdrPass
= 0;
2556 _ULCurrentIgInstance
= 0;
2560 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= _ULRootIg
->_RdrPass
[_ULCurrentIgRdrPass
];
2562 // if all instances are processed for this pass (especially if empty() !!)
2563 if(_ULCurrentIgInstance
>= vegetRdrPass
.LightedInstances
.size())
2565 // skip to the next rdrPass.
2566 _ULCurrentIgRdrPass
++;
2567 _ULCurrentIgInstance
= 0;
2571 // Process this instance.
2572 _ULNVerticesToUpdate
-= updateInstanceLighting(_ULRootIg
, _ULCurrentIgRdrPass
, _ULCurrentIgInstance
);
2575 _ULCurrentIgInstance
++;
2577 // if all instances are processed for this pass
2578 if(_ULCurrentIgInstance
>= vegetRdrPass
.LightedInstances
.size())
2580 // skip to the next rdrPass.
2581 _ULCurrentIgRdrPass
++;
2582 _ULCurrentIgInstance
= 0;
2586 // If all rdrPass of the ig are processed.
2587 if(_ULCurrentIgRdrPass
>= NL3D_VEGETABLE_NRDRPASS
)
2589 // All this Ig is updated.
2590 _ULCurrentIgRdrPass
= 0;
2591 _ULCurrentIgInstance
= 0;
2597 // The Ig is not entirely updated.
2604 // ***************************************************************************
2605 uint
CVegetableManager::updateInstanceLighting(CVegetableInstanceGroup
*ig
, uint rdrPassId
, uint instanceId
)
2609 nlassert(rdrPassId
<NL3D_VEGETABLE_NRDRPASS
);
2610 CVegetableInstanceGroup::CVegetableRdrPass
&vegetRdrPass
= ig
->_RdrPass
[rdrPassId
];
2611 // get the lighted instance.
2612 nlassert(instanceId
<vegetRdrPass
.LightedInstances
.size());
2613 CVegetableInstanceGroup::CVegetableLightedInstance
&vegetLI
= vegetRdrPass
.LightedInstances
[instanceId
];
2616 CVegetableShape
*shape
= vegetLI
.Shape
;
2617 // it must be lighted.
2618 nlassert(shape
->Lighted
);
2619 bool instanceLighted
= true;
2622 // get ref on the vegetLex.
2623 CVegetableLightEx
&vegetLex
= ig
->VegetableLightEx
;
2624 // Color of pointLights modulated by diffuse.
2626 diffusePL
[0] = CRGBA::Black
;
2627 diffusePL
[1] = CRGBA::Black
;
2628 if(vegetLex
.NumLights
>=1)
2630 diffusePL
[0].modulateFromColorRGBOnly(vegetLI
.MatDiffuse
, vegetLex
.Color
[0]);
2631 if(vegetLex
.NumLights
>=2)
2633 diffusePL
[1].modulateFromColorRGBOnly(vegetLI
.MatDiffuse
, vegetLex
.Color
[1]);
2637 // Recompute lighting
2640 // setup for this instance.
2642 // Precompute lighting or not??
2643 bool precomputeLighting
= instanceLighted
&& shape
->PreComputeLighting
;
2644 // bestSided Precompute lighting or not??
2645 bool bestSidedPrecomputeLighting
= precomputeLighting
&& shape
->BestSidedPreComputeLighting
;
2647 bool destLighted
= instanceLighted
&& !shape
->PreComputeLighting
;
2648 // Diffuse and ambient, modulated by current GlobalAmbient and GlobalDiffuse.
2649 CRGBA primaryRGBA
, secondaryRGBA
;
2650 primaryRGBA
.modulateFromColorRGBOnly(vegetLI
.MatDiffuse
, _GlobalDiffuse
);
2651 secondaryRGBA
.modulateFromColorRGBOnly(vegetLI
.MatAmbient
, _GlobalAmbient
);
2652 // get normal matrix
2653 CMatrix
&normalMat
= vegetLI
.NormalMat
;
2654 // array of vertex id to update
2655 uint32
*ptrVid
= vegetRdrPass
.Vertices
.getPtr() + vegetLI
.StartIdInRdrPass
;
2656 uint numVertices
= (uint
)shape
->InstanceVertices
.size();
2658 // Copy Dynamic Lightmap UV in Alpha part (save memory for an extra cost of 1 VP instruction)
2659 primaryRGBA
.A
= vegetLI
.DlmUV
.U
;
2660 secondaryRGBA
.A
= vegetLI
.DlmUV
.V
;
2663 // get VertexBuffer info.
2664 CVegetableVBAllocator
*allocator
;
2665 allocator
= &getVBAllocatorForRdrPassAndVBHardMode(rdrPassId
, vegetRdrPass
.HardMode
);
2666 const CVertexBuffer
&dstVBInfo
= allocator
->getSoftwareVertexBuffer();
2668 uint srcNormalOff
= (instanceLighted
? shape
->VB
.getNormalOff() : 0);
2669 uint dstColor0Off
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR0
);
2670 uint dstColor1Off
= dstVBInfo
.getValueOffEx(NL3D_VEGETABLE_VPPOS_COLOR1
);
2672 // For D3D, If the VertexBuffer is in BGRA mode
2673 if(allocator
->isBGRA())
2675 // then swap only the B and R (no cpu cycle added per vertex)
2676 primaryRGBA
.swapBR();
2677 secondaryRGBA
.swapBR();
2678 diffusePL
[0].swapBR();
2679 diffusePL
[1].swapBR();
2682 CVertexBufferRead vba
;
2683 shape
->VB
.lock (vba
);
2684 CVertexBufferReadWrite vbaOut
;
2685 allocator
->getSoftwareVertexBuffer ().lock(vbaOut
);
2687 // For all vertices, recompute lighting.
2689 for(sint i
=0; i
<(sint
)numVertices
;i
++)
2691 // get the Vertex in the VB.
2692 uint vid
= ptrVid
[i
];
2693 // store in tmp shape.
2694 shape
->InstanceVertices
[i
]= vid
;
2696 // Fill this vertex.
2697 const uint8
*srcPtr
= (const uint8
*)vba
.getVertexCoordPointer(i
);
2698 uint8
*dstPtr
= (uint8
*)vbaOut
.getVertexCoordPointer(vid
);
2701 // if !precomputeLighting (means destLighted...)
2702 if(!precomputeLighting
)
2704 // just copy the primary and secondary color
2705 *(CRGBA
*)(dstPtr
+ dstColor0Off
)= primaryRGBA
;
2706 *(CRGBA
*)(dstPtr
+ dstColor1Off
)= secondaryRGBA
;
2710 nlassert(!destLighted
);
2713 CVector rotNormal
= normalMat
.mulVector( *(CVector
*)(srcPtr
+ srcNormalOff
) );
2714 // must normalize() because scale is possible.
2715 rotNormal
.normalize();
2718 if(!bestSidedPrecomputeLighting
)
2720 computeVegetVertexLighting(rotNormal
,
2721 _DirectionalLight
, primaryRGBA
, secondaryRGBA
,
2722 vegetLex
, diffusePL
, (CRGBA
*)(dstPtr
+ dstColor0Off
) );
2726 computeVegetVertexLightingForceBestSided(rotNormal
,
2727 _DirectionalLight
, primaryRGBA
, secondaryRGBA
,
2728 vegetLex
, diffusePL
, (CRGBA
*)(dstPtr
+ dstColor0Off
) );
2733 // flust the vertex in AGP.
2734 allocator
->flushVertex(vid
);
2738 // numVertices vertices are updated