From 0ea5fc66924303d1bf73ba283a383e2aadee02f2 Mon Sep 17 00:00:00 2001 From: neodarz Date: Sat, 11 Aug 2018 20:21:34 +0200 Subject: Initial commit --- .../nel/vegetable__manager_8cpp-source.html | 2671 ++++++++++++++++++++ 1 file changed, 2671 insertions(+) create mode 100644 docs/doxygen/nel/vegetable__manager_8cpp-source.html (limited to 'docs/doxygen/nel/vegetable__manager_8cpp-source.html') diff --git a/docs/doxygen/nel/vegetable__manager_8cpp-source.html b/docs/doxygen/nel/vegetable__manager_8cpp-source.html new file mode 100644 index 00000000..b1320d98 --- /dev/null +++ b/docs/doxygen/nel/vegetable__manager_8cpp-source.html @@ -0,0 +1,2671 @@ + + + + nevrax.org : docs + + + + + + + + + + + + + + +
# Home   # nevrax.com   
+ + + + +
Nevrax
+ + + + + + + + + + +
+ + +
+ Nevrax.org
+ + + + + + + +
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
+
+ + +
+ + +
+Docs + +
+  + + + + + +
Documentation 
+ +
+Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  
+

vegetable_manager.cpp

Go to the documentation of this file.
00001 
+00007 /* Copyright, 2001 Nevrax Ltd.
+00008  *
+00009  * This file is part of NEVRAX NEL.
+00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
+00011  * it under the terms of the GNU General Public License as published by
+00012  * the Free Software Foundation; either version 2, or (at your option)
+00013  * any later version.
+00014 
+00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
+00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
+00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+00018  * General Public License for more details.
+00019 
+00020  * You should have received a copy of the GNU General Public License
+00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
+00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+00023  * MA 02111-1307, USA.
+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         // Init all the allocators
+00069         nlassert((uint)(CVegetableVBAllocator::VBTypeCount) == 2);
+00070         _VBHardAllocator[CVegetableVBAllocator::VBTypeLighted].init( CVegetableVBAllocator::VBTypeLighted, maxVertexVbHardLighted );
+00071         _VBHardAllocator[CVegetableVBAllocator::VBTypeUnlit].init( CVegetableVBAllocator::VBTypeUnlit, maxVertexVbHardUnlit );
+00072         // Init soft one, with no vbHard vertices.
+00073         _VBSoftAllocator[CVegetableVBAllocator::VBTypeLighted].init( CVegetableVBAllocator::VBTypeLighted, 0 );
+00074         _VBSoftAllocator[CVegetableVBAllocator::VBTypeUnlit].init( CVegetableVBAllocator::VBTypeUnlit, 0 );
+00075 
+00076         // NB Vertex programs are initilized during the first call to update driver.
+00077 
+00078         // setup the material. Unlit (doesn't matter, lighting in VP) Alpha Test.
+00079         _VegetableMaterial.initUnlit();
+00080         _VegetableMaterial.setAlphaTest(true);
+00081         _VegetableMaterial.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
+00082 
+00083         // default light.
+00084         _DirectionalLight= (CVector(0,1, -1)).normed();
+00085         _GlobalAmbient.set(64, 64, 64, 255);
+00086         _GlobalDiffuse.set(150, 150, 150, 255);
+00087 
+00088         // Wind.
+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         // Init CosTable.
+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         // init to NULL _ZSortModelLayers.
+00104         _NumZSortBlendLayers= max(1U, _NumZSortBlendLayers);
+00105         _ZSortModelLayers.resize(_NumZSortBlendLayers, NULL);
+00106         _ZSortModelLayersUW.resize(_NumZSortBlendLayers, NULL);
+00107 
+00108 
+00109         // UL
+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         // Misc.
+00121         _NumVegetableFaceRendered= 0;
+00122 
+00123         std::fill(_VertexProgram, _VertexProgram + NL3D_VEGETABLE_NRDRPASS, (CVertexProgram *) NULL);
+00124 
+00125 }
+00126 
+00127 
+00128 // ***************************************************************************
+00129 CVegetableManager::~CVegetableManager()
+00130 {
+00131         // delete All VP
+00132         for(sint i=0; i <NL3D_VEGETABLE_NRDRPASS; i++)
+00133         {
+00134                 delete  _VertexProgram[i];
+00135                 _VertexProgram[i]= NULL;
+00136         }
+00137 
+00138         // delete ZSort models.
+00139         if(_ZSortScene)
+00140         {
+00141                 // remove models from scene.
+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         // setup scene
+00159         nlassert(scene);
+00160         _ZSortScene= scene;
+00161 
+00162         // create the layers models.
+00163         for(uint i=0;i<_NumZSortBlendLayers; i++)
+00164         {
+00165                 // assert not already done.
+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                 // init owner.
+00172                 _ZSortModelLayers[i]->VegetableManager= this;
+00173                 _ZSortModelLayersUW[i]->VegetableManager= this;
+00174 
+00175                 // Set UnderWater layer for _ZSortModelLayersUW
+00176                 _ZSortModelLayersUW[i]->setOrderingLayer(2);
+00177         }
+00178 }
+00179 
+00180 
+00181 // ***************************************************************************
+00182 CVegetableVBAllocator   &CVegetableManager::getVBAllocatorForRdrPassAndVBHardMode(uint rdrPass, uint vbHardMode)
+00183 {
+00184         // If software VB
+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         // If hard VB
+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         // abnormal case
+00214         nlstop;
+00215         // To avoid warning;
+00216         return _VBSoftAllocator[0];
+00217 }
+00218 
+00219 
+00220 
+00221 // ***************************************************************************
+00222 // ***************************************************************************
+00223 // Vertex Program.
+00224 // ***************************************************************************
+00225 // ***************************************************************************
+00226 
+00227 
+00228 // ***************************************************************************
+00229 /*
+00230         Vegetable, without bend for now.
+00231 
+00232         Inputs
+00233         --------
+00234         v[0]  == Pos to Center of the vegetable in world space.
+00235         v[10] == Center of the vegetable in world space.
+00236         v[2]  == Normal (present if lighted only)
+00237         v[3]  == Color (if unlit) or DiffuseColor (if lighted)
+00238         v[4]  == SecondaryColor (==ambient if Lighted or backFace color if Unlit)
+00239         v[8]  == Tex0 (xy) 
+00240         v[9]  == BendInfo (xyz) = {BendWeight/2, BendPhase, BendFrequencyFactor}
+00241                 NB: /2 because compute a quaternion
+00242 
+00243         Changes: If unlit, then small changes:
+00244         v[0]  == Pos to center, with v[0].w == BendWeight * v[0].norm()
+00245         v[9]  == BendInfo/BlendInfo (xyzw) = {v[0].norm(), BendPhase, BendFrequencyFactor, BlendDist}
+00246 
+00247         NB: v[9].w. is used only in Unlit+2Sided+AlphaBlend. But prefer do this for gestion purpose:
+00248                 to have only one VBAllocator for all modes.
+00249 
+00250         NB: Color and Secondary color Alpha Part contains Dynamic LightMap UV, (in 8 bits).
+00251 
+00252         Constant:
+00253         --------
+00254         Setuped at beginning of CVegetableManager::render()
+00255         c[0..3]= ModelViewProjection Matrix.
+00256         c[4..7]= ModelView Matrix (for Fog).
+00257         c[8]= {0, 1, 0.5, 2}
+00258         c[9]= unit world space Directionnal light.
+00259         c[10]= camera pos in world space.
+00260         c[11]= {1/DistBlendTransition}
+00261         NB: DiffuseColor and AmbientColor of vertex must have been pre-multiplied by lightColor
+00262 
+00263         // Bend:
+00264         c[16]= quaternion axis. w==1, and z must be 0
+00265         c[17]=  { timeAnim , WindPower, WindPower*(1-WindBendMin)/2, 0 }
+00266         c[18]=  High order Taylor cos coefficient: { -1/2, 1/24, -1/720, 1/40320 }
+00267         c[19]=  Low order Taylor cos coefficient: { 1, -1/2, 1/24, -1/720 }
+00268         c[20]=  Low order Taylor sin coefficient: { 1, -1/6, 1/120, -1/5040 }
+00269         c[21]=  Special constant vector for quatToMatrix: { 0, 1, -1, 0 }
+00270         c[22]=  {0.5, Pi, 2*Pi, 1/(2*Pi)}
+00271         c[23]=  {64, 0, 0, 0}  (size of the LUT)
+00272 
+00273         // Bend Lut:
+00274         c[32..95] 64 Lut entries for cos-like animation
+00275 
+00276 
+00277         Fog Note:
+00278         -----------
+00279         Fog should be disabled, because not computed (for speed consideration and becasue micro-vegetation should never
+00280         be in Fog).
+00281 
+00282 
+00283         Speed Note:
+00284         -----------
+00285         Max program length (lighted/2Sided) is:
+00286                 29 (bend-quaternion) + 
+00287                 16 (rotNormal + bend + lit 2Sided) + 
+00288                 5  (proj + tex)
+00289                 2  (Dynamic lightmap copy)
+00290                 51
+00291 
+00292         Normal program length (unlit/2Sided/No Alpha Blend) is:
+00293                 12 (bend-delta) + 
+00294                 2  (unlit 2Sided) + 
+00295                 5  (proj + tex)
+00296                 2  (Dynamic lightmap copy)
+00297                 21
+00298 
+00299         AlphaBlend program length (unlit/2Sided/Alpha Blend) is:
+00300                 12 (bend-delta) + 
+00301                 2  (unlit 2Sided) + 
+00302                 5  (Alpha Blend)
+00303                 5  (proj + tex)
+00304                 2  (Dynamic lightmap copy)
+00305                 26
+00306 
+00307 */
+00308 
+00309 
+00310 // ***********************
+00311 /*
+00312         Fast (but less accurate) Bend program:
+00313                 Result: bend pos into R5, 
+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 // Test
+00345 /*const char* NL3D_FastBendProgram=
+00346 "!!VP1.0                                                                                                                                                                \n\
+00347         # compute time of animation: time + phase.                                                                                      \n\
+00348         ADD     R0.x, c[17].x, v[9].y;          # R0.x= time of animation                                                       \n\
+00349                                                                                                                                                                                 \n\
+00350         # animation: f(x)= cos(x). compute a high precision cosinus                                                     \n\
+00351         EXP     R0.y, R0.x;                                             # fract part=> R0.y= [0,1] <=> [-Pi, Pi]                \n\
+00352         MAD     R0.x, R0.y, c[22].z, -c[22].y;  # R0.x= a= [-Pi, Pi]                                                    \n\
+00353         # R0 must get a2, a4, a6, a8                                                                                                            \n\
+00354         MUL     R0.x, R0.x, R0.x;                               # R0.x= a2                                                                              \n\
+00355         MUL     R0.y, R0.x, R0.x;                               # R0= a2, a4                                                                    \n\
+00356         MUL     R0.zw, R0.y, R0.xxxy;                   # R0= a2, a4, a6, a8                                                    \n\
+00357         # Taylor serie: cos(x)= 1 - (1/2) a2 + (1/24) a4 - (1/720) a6 + (1/40320) a8.           \n\
+00358         DP4     R0.x, R0, c[18];                                # R0.x= cos(x) - 1.                                                             \n\
+00359                                                                                                                                                                                 \n\
+00360                                                                                                                                                                                 \n\
+00361         # original      norm                                                                                                                                    \n\
+00362         DP3     R2.x, v[0], v[0];                                                                                                                               \n\
+00363         RSQ     R2.y, R2.x;                                                                                                                                             \n\
+00364         MUL     R2.x, R2.x, R2.y;                                                                                                                               \n\
+00365         # norm, mul by factor, and add to relpos                                                                                        \n\
+00366         ADD     R1.x, R0.x, c[8].w;                                                                                                                                     \n\
+00367         MUL     R0.x, v[9].x, R2.x;                                                                                                                     \n\
+00368         MUL     R1, R1, R0.x;                                                                                                                                   \n\
+00369         ADD     R5.xyz, R1, v[0];                                                                                                                               \n\
+00370         # mod norm                                                                                                                                                      \n\
+00371         DP3     R0.x, R5, R5;                                                                                                                                   \n\
+00372         RSQ     R0.x, R0.x;                                                                                                                                             \n\
+00373         MUL     R0.x, R0.x, R2.x;                                                                                                                               \n\
+00374         MAD     R5, R0.x, R5, v[10];                                                                                                                    \n\
+00375 ";*/
+00376 
+00377 
+00378 
+00379 // ***********************
+00380 /*
+00381         Bend start program:
+00382                 Result: bend pos into R5, and R7,R8,R9 is the rotation matrix for possible normal lighting.
+00383 */
+00384 // ***********************
+00385 // Splitted in 2 parts because of the 2048 char limit
+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 // Concat the 2 strings
+00460 const string NL3D_BendProgram= string(NL3D_BendProgramP0) + string(NL3D_BendProgramP1);
+00461 
+00462 
+00463 
+00464 // ***********************
+00465 /*
+00466         Lighted start program:
+00467                 bend pos and normal, normalize and lit
+00468 */
+00469 // ***********************
+00470 // Common start program.
+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 //      1Sided lighting.
+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 //      2Sided lighting.
+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         Unlit start program:
+00516                 bend pos into R5, and copy color(s)
+00517 */
+00518 // ***********************
+00519 
+00520 
+00521 // Common start program.
+00522 // nothing to add.
+00523 const char* NL3D_UnlitStartVegetableProgram= 
+00524 "";
+00525 
+00526 
+00527 //      1Sided "lighting".
+00528 const char* NL3D_UnlitMiddle1SidedVegetableProgram=
+00529 "       MOV o[COL0].xyz, v[3];                  # col.RGBA= vertex color                                                        \n\
+00530                                                                                                                                                                                 \n\
+00531 ";
+00532 
+00533 
+00534 //      2Sided "lighting".
+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 //      2Sided "lighting" + AlphaBlend.
+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 //      1Sided "lighting" + AlphaBlend.
+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         Common end of program: project, texture. Take pos from R5
+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         Speed test VP, No bend,no lighting.
+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); // update driver should have been called at least once !
+00614         // Init the Vertex Program.
+00615         string  vpgram;
+00616         // start always with Bend.
+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         // If double sided V.P are not supported, switch to 1-sided version
+00623         bool doubleSided = _LastDriver->supportVertexProgramDoubleSidedColor();
+00624 
+00625         // combine the VP according to Type
+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         // common end of VP
+00656         vpgram+= string(NL3D_CommonEndVegetableProgram);
+00657 
+00658         // create VP.
+00659         _VertexProgram[vpType]= new CVertexProgram(vpgram.c_str());
+00660 
+00661 }
+00662 
+00663 
+00664 // ***************************************************************************
+00665 // ***************************************************************************
+00666 // Instanciation
+00667 // ***************************************************************************
+00668 // ***************************************************************************
+00669 
+00670 
+00671 // ***************************************************************************
+00672 CVegetableClipBlock                     *CVegetableManager::createClipBlock()
+00673 {
+00674         // create a clipblock
+00675         CVegetableClipBlock     *ret;
+00676         ret= _ClipBlockMemory.allocate();
+00677 
+00678         // append to list.
+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         // verify no more sortBlocks in this clipblock
+00691         nlassert(clipBlock->_SortBlockList.size() == 0);
+00692 
+00693         // unlink from _EmptyClipBlockList, because _InstanceGroupList.size() == 0 ...
+00694         _EmptyClipBlockList.remove(clipBlock);
+00695 
+00696         // delete
+00697         _ClipBlockMemory.free(clipBlock);
+00698 }
+00699 
+00700 
+00701 // ***************************************************************************
+00702 CVegetableSortBlock                     *CVegetableManager::createSortBlock(CVegetableClipBlock *clipBlock, const CVector &center, float radius)
+00703 {
+00704         nlassert(clipBlock);
+00705 
+00706         // create a clipblock
+00707         CVegetableSortBlock     *ret;
+00708         ret= _SortBlockMemory.allocate();
+00709         ret->_Owner= clipBlock;
+00710         ret->_Center= center;
+00711         ret->_Radius= radius;
+00712 
+00713         // append to list.
+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         // verify no more IGs in this sortblock
+00726         nlassert(sortBlock->_InstanceGroupList.size() == 0);
+00727 
+00728         // unlink from clipBlock
+00729         sortBlock->_Owner->_SortBlockList.remove(sortBlock);
+00730 
+00731         // delete
+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         // create an IG
+00744         CVegetableInstanceGroup *ret;
+00745         ret= _InstanceGroupMemory.allocate();
+00746         ret->_SortOwner= sortBlock;
+00747         ret->_ClipOwner= clipBlock;
+00748 
+00749         // if the clipBlock is empty, change list, because won't be no more.
+00750         if(clipBlock->_NumIgs==0)
+00751         {
+00752                 // remove from empty list
+00753                 _EmptyClipBlockList.remove(clipBlock);
+00754                 // and append to not empty one.
+00755                 _ClipBlockList.append(clipBlock);
+00756         }
+00757 
+00758         // inc the number of igs appended to the clipBlock.
+00759         clipBlock->_NumIgs++;
+00760 
+00761         // link ig to sortBlock.
+00762         sortBlock->_InstanceGroupList.append(ret);
+00763 
+00764         // Special Init: The ZSort rdrPass must start with the same HardMode than SortBlock.
+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         // update lighting mgt: no more vertices.
+00777         // -----------
+00778         // If I delete the ig which is the current root
+00779         if(_ULRootIg == ig)
+00780         {
+00781                 // switch to next
+00782                 _ULRootIg= ig->_ULNext;
+00783                 // if still the same, it means that the circular list is now empty
+00784                 if(_ULRootIg == ig)
+00785                         _ULRootIg= NULL;
+00786                 // Reset UL instance info.
+00787                 _ULCurrentIgRdrPass= 0;
+00788                 _ULCurrentIgInstance= 0;
+00789         }
+00790         // remove UL vertex count of the deleted ig
+00791         _ULNTotalVertices-= ig->_ULNumVertices;
+00792         // unlink the ig for lighting update.
+00793         ig->unlinkUL();
+00794 
+00795 
+00796         // For all render pass of this instance, delete his vertices
+00797         // -----------
+00798         for(sint rdrPass=0; rdrPass < NL3D_VEGETABLE_NRDRPASS; rdrPass++)
+00799         {
+00800                 // rdrPass
+00801                 CVegetableInstanceGroup::CVegetableRdrPass      &vegetRdrPass= ig->_RdrPass[rdrPass];
+00802                 // which allocator?
+00803                 CVegetableVBAllocator   &vbAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vegetRdrPass.HardMode);
+00804 
+00805                 // For all vertices of this rdrPass, delete it
+00806                 sint    numVertices;
+00807                 numVertices= vegetRdrPass.Vertices.size();
+00808                 // all vertices must have been setuped.
+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         // If I have got some faces in ZSort rdrPass
+00821         if(ig->_HasZSortPassInstances)
+00822                 // after my deletion, the sortBlock must be updated.
+00823                 sortBlock->_Dirty= true;
+00824 
+00825 
+00826         // unlink from sortBlock, and delete.
+00827         sortBlock->_InstanceGroupList.remove(ig);
+00828         _InstanceGroupMemory.free(ig);
+00829 
+00830 
+00831         // decRef the clipBlock
+00832         clipBlock->_NumIgs--;
+00833         // if the clipBlock is now empty, change list
+00834         if(clipBlock->_NumIgs==0)
+00835         {
+00836                 // remove from normal list
+00837                 _ClipBlockList.remove(clipBlock);
+00838                 // and append to empty list.
+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         // if found
+00850         if(it != _ShapeMap.end())
+00851                 return &it->second;
+00852         // else insert
+00853         {
+00854                 // insert.
+00855                 CVegetableShape         *ret;
+00856                 it= ( _ShapeMap.insert(make_pair(shape, CVegetableShape()) ) ).first;
+00857                 ret= &it->second;
+00858 
+00859                 // fill.
+00860                 try
+00861                 {
+00862                         ret->loadShape(shape);
+00863                 }
+00864                 catch (Exception &e)
+00865                 {
+00866                         // Warning
+00867                         nlwarning ("CVegetableManager::getVegetableShape error while loading shape file '%s' : '%s'", shape.c_str (), e.what ());
+00868 
+00869                         // Remove from map
+00870                         _ShapeMap.erase (shape);
+00871 
+00872                         // Return NULL
+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         // Disable ZSorting when we intersect water.
+00889         instanceZSort= shape->AlphaBlend && vegetWaterState!=IntersectWater;
+00890         destLighted= instanceLighted && !shape->PreComputeLighting;
+00891         precomputeLighting= instanceLighted && shape->PreComputeLighting;
+00892 
+00893         // get correct rdrPass
+00894         uint    rdrPass;
+00895         // get according to lighted / doubleSided state
+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         // get correct rdrPass / info
+00930         uint    rdrPass;
+00931         rdrPass= getRdrPassInfoForShape(shape, vegetWaterState, instanceLighted, instanceDoubleSided, 
+00932                 instanceZSort, destLighted, precomputeLighting);
+00933 
+00934         // veget rdrPass
+00935         CVegetableInstanceGroupReserve::CVegetableRdrPass       &vegetRdrPass= vegetIgReserve._RdrPass[rdrPass];
+00936 
+00937         // Reserve space in the rdrPass.
+00938         vegetRdrPass.NVertices+= numInstances * shape->VB.getNumVertices();
+00939         vegetRdrPass.NTriangles+= numInstances * shape->TriangleIndices.size()/3;
+00940         // if the instances are lighted, reserve space for lighting updates
+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         // Check.
+00953         //===========
+00954         // For all rdrPass of the ig, check empty
+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         // Do the same for all quadrants of the zsort rdrPass.
+00964         nlassert(ig->_TriangleQuadrantOrderArray.size()==0);
+00965         nlassert(ig->_TriangleQuadrantOrderNumTriangles==0);
+00966 
+00967 
+00968         // Reserve.
+00969         //===========
+00970         // For all rdrPass of the ig, reserve.
+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                 // reserve triangles indices and vertices for this rdrPass.
+00978                 vegetRdrPass.TriangleIndices.resize(numTris*3);
+00979                 vegetRdrPass.TriangleLocalIndices.resize(numTris*3);
+00980                 vegetRdrPass.Vertices.resize(numVertices);
+00981                 // reserve ligthedinstances space.
+00982                 vegetRdrPass.LightedInstances.resize(numLightedInstances);
+00983         }
+00984 
+00985         // Reserve space for the zsort rdrPass sorting.
+00986         uint    numZSortTris= vegetIgReserve._RdrPass[NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT].NTriangles;
+00987         // allocate sufficient space for all quadrants (1 alloc for all quadrants).
+00988         ig->_TriangleQuadrantOrderArray.resize(numZSortTris * NL3D_VEGETABLE_NUM_QUADRANT);
+00989 
+00990         // And init ptrs.
+00991         if(numZSortTris>0)
+00992         {
+00993                 float   *start= ig->_TriangleQuadrantOrderArray.getPtr();
+00994                 // init ptr to each qaudrant
+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         // compute front-facing coloring.
+01016         {
+01017                 // Compute Sun Light.
+01018                 dpSun= rotNormal*sunDir;
+01019                 float   f= max(0.f, -dpSun);
+01020                 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
+01021                 // Add it with ambient
+01022                 resColor.addRGBOnly(col, secondaryRGBA);
+01023 
+01024                 // Add influence of 2 lights only. (unrolled for better BTB use)
+01025                 // Compute Light 0 ?
+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                         // Compute Light 1 ?
+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                 // Keep correct U of Dynamic Lightmap UV encoded in primaryRGBA Alpha part.
+01043                 resColor.A= primaryRGBA.A;
+01044 
+01045                 // copy to dest
+01046                 *dstFront= resColor;
+01047         }
+01048 
+01049         // If 2Sided
+01050         if(instanceDoubleSided)
+01051         {
+01052                 // reuse dotproduct of front-facing computing.
+01053 
+01054                 // Compute Sun Light.
+01055                 float   f= max(0.f, dpSun);
+01056                 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
+01057                 // Add it with ambient
+01058                 resColor.addRGBOnly(col, secondaryRGBA);
+01059 
+01060                 // Add influence of 2 lights only. (unrolled for better BTB use)
+01061                 // Compute Light 0 ?
+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                         // Compute Light 1 ?
+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                 // Keep correct V of Dynamic Lightmap UV encoded in secondaryRGBA Alpha part.
+01077                 resColor.A= secondaryRGBA.A;
+01078 
+01079                 // copy to dest
+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         // compute front-facing coloring.
+01098         {
+01099                 // Compute Sun Light.
+01100                 dpSun= rotNormal*sunDir;
+01101                 // ForceBestSided: take the absolute value (max of -val,val)
+01102                 float   f= (float)fabs(dpSun);
+01103                 col.modulateFromuiRGBOnly(primaryRGBA, OptFastFloor(f*256));
+01104                 // Add it with ambient
+01105                 resColor.addRGBOnly(col, secondaryRGBA);
+01106 
+01107                 // Add influence of 2 lights only. (unrolled for better BTB use)
+01108                 // Compute Light 0 ?
+01109                 if(vegetLex.NumLights>=1)
+01110                 {
+01111                         dpPL[0]= rotNormal*vegetLex.Direction[0];
+01112                         // ForceBestSided: take the absolute value (max of -val,val)
+01113                         f= (float)fabs(dpPL[0]);
+01114                         col.modulateFromuiRGBOnly(diffusePL[0], OptFastFloor(f*256));
+01115                         resColor.addRGBOnly(col, resColor);
+01116                         // Compute Light 1 ?
+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                 // Keep correct U of Dynamic Lightmap UV encoded in primaryRGBA Alpha part.
+01127                 resColor.A= primaryRGBA.A;
+01128 
+01129                 // copy to dest
+01130                 *dstFront= resColor;
+01131         }
+01132 
+01133         // If 2Sided
+01134         if(instanceDoubleSided)
+01135         {
+01136                 // Since forceBestSided, same color as front_facing
+01137 
+01138                 // Keep correct V of Dynamic Lightmap UV encoded in secondaryRGBA Alpha part.
+01139                 resColor.A= secondaryRGBA.A;
+01140 
+01141                 // copy to dest
+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         // Some setup.
+01158         //--------------------
+01159         bool    instanceLighted;
+01160         bool    instanceDoubleSided;
+01161         bool    instanceZSort;
+01162         bool    destLighted;
+01163         bool    precomputeLighting;
+01164 
+01165         // get correct rdrPass / info
+01166         uint    rdrPass;
+01167         rdrPass= getRdrPassInfoForShape(shape, vegetWaterState, instanceLighted, instanceDoubleSided, 
+01168                 instanceZSort, destLighted, precomputeLighting);
+01169         // bestSided Precompute lighting or not??
+01170         bool    bestSidedPrecomputeLighting= precomputeLighting && shape->BestSidedPreComputeLighting;
+01171 
+01172 
+01173         // veget rdrPass
+01174         CVegetableInstanceGroup::CVegetableRdrPass      &vegetRdrPass= ig->_RdrPass[rdrPass];
+01175 
+01176         // color.
+01177         // setup using OptFastFloor.
+01178         CRGBA           ambientRGBA, diffuseRGBA;
+01179         CRGBA           primaryRGBA, secondaryRGBA;
+01180         // diffuseColor
+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         // ambientColor
+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         // For Unlit and Lighted, modulate with global light.
+01192         primaryRGBA.modulateFromColorRGBOnly(diffuseRGBA, _GlobalDiffuse);
+01193         secondaryRGBA.modulateFromColorRGBOnly(ambientRGBA, _GlobalAmbient);
+01194 
+01195         // if the instance is not lighted, then suppose full lighting => add ambient and diffuse
+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                 // useFull if 2Sided
+01202                 secondaryRGBA= primaryRGBA;
+01203         }
+01204 
+01205         // Copy Dynamic Lightmap UV in Alpha part (save memory for an extra cost of 1 VP instruction)
+01206         primaryRGBA.A= dlmUV.U;
+01207         secondaryRGBA.A= dlmUV.V;
+01208 
+01209         // get ref on the vegetLex.
+01210         CVegetableLightEx       &vegetLex= ig->VegetableLightEx;
+01211         // Color of pointLights modulated by diffuse.
+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         // normalize bendFreqFactor
+01223         bendFreqFactor*= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC;
+01224         bendFreqFactor= (float)floor(bendFreqFactor + 0.5f);
+01225         bendFreqFactor/= NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC;
+01226 
+01227 
+01228         // Get allocator, and manage VBhard overriding.
+01229         //--------------------
+01230         CVegetableVBAllocator   *allocator;
+01231         // if still in Sfot mode, keep it.
+01232         if(!vegetRdrPass.HardMode)
+01233         {
+01234                 // get the soft allocator.
+01235                 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 0);
+01236         }
+01237         else
+01238         {
+01239                 // Get VB allocator Hard for this rdrPass
+01240                 allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 1);
+01241                 // Test if the instance don't add too many vertices for this VBHard
+01242                 if(allocator->exceedMaxVertexInBufferHard(shape->VB.getNumVertices()))
+01243                 {
+01244                         // if exceed, then must pass ALL the IG in software mode. vertices/faces are correclty updated.
+01245                         // special: if rdrPass is the ZSort one, 
+01246                         if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01247                         {
+01248                                 nlassert(ig->_SortOwner->ZSortHardMode);
+01249 
+01250                                 // must do it on ALL igs of the sortBlock, for less VBuffer mode switching.
+01251                                 CVegetableInstanceGroup         *pIg= ig->_SortOwner->_InstanceGroupList.begin();
+01252                                 while(pIg)
+01253                                 {
+01254                                         // let's pass them in software mode.
+01255                                         swapIgRdrPassHardMode(pIg, rdrPass);
+01256                                         // next
+01257                                         pIg= (CVegetableInstanceGroup*)pIg->Next;
+01258                                 }
+01259 
+01260                                 // Then all The sortBlock is in SoftMode.
+01261                                 ig->_SortOwner->ZSortHardMode= false;
+01262                         }
+01263                         else
+01264                         {
+01265                                 // just do it on this Ig (can mix hardMode in a SortBlock for normal rdrPass)
+01266                                 swapIgRdrPassHardMode(ig, rdrPass);
+01267                         }
+01268 
+01269                         // now, we can use the software only Allocator to append our instance
+01270                         allocator= &getVBAllocatorForRdrPassAndVBHardMode(rdrPass, 0);
+01271                 }
+01272         }
+01273 
+01274 
+01275         // get correct dstVB
+01276         const CVertexBuffer     &dstVBInfo= allocator->getSoftwareVertexBuffer();
+01277 
+01278 
+01279         // Transform vertices to a vegetable instance, and enlarge clipBlock
+01280         //--------------------
+01281         // compute matrix to multiply normals, ie (M-1)t
+01282         CMatrix         normalMat;
+01283         // need just rotation scale matrix.
+01284         normalMat.setRot(mat);
+01285         normalMat.invert();
+01286         normalMat.transpose();
+01287         // compute Instance position
+01288         CVector         instancePos;
+01289         mat.getPos(instancePos);
+01290 
+01291 
+01292         // At least, the bbox of the clipBlock must include the center of the shape.
+01293         ig->_ClipOwner->extendSphere(instancePos);
+01294 
+01295 
+01296         // Vertex/triangle Info.
+01297         uint    numNewVertices= shape->VB.getNumVertices();
+01298         uint    numNewTris= shape->TriangleIndices.size()/3;
+01299         uint    numNewIndices= shape->TriangleIndices.size();
+01300 
+01301         // src info.
+01302         uint    srcNormalOff= (instanceLighted? shape->VB.getNormalOff() : 0);
+01303         uint    srcTex0Off= shape->VB.getTexCoordOff(0);
+01304         uint    srcTex1Off= shape->VB.getTexCoordOff(1);
+01305 
+01306         // dst info
+01307         uint    dstNormalOff= (destLighted? dstVBInfo.getValueOffEx(NL3D_VEGETABLE_VPPOS_NORMAL) : 0);
+01308         // got 2nd color if really lighted (for ambient) or if 2Sided.
+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         // Usefull For !destLighted only.
+01318         CVector         deltaPos;
+01319         float           deltaPosNorm=0.0;
+01320 
+01321 
+01322         // UseFull for ZSORT rdrPass, the worldVertices.
+01323         static  vector<CVector>         worldVertices;
+01324         if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01325         {
+01326                 worldVertices.resize(numNewVertices);
+01327         }
+01328 
+01329 
+01330         // For all vertices of shape, transform and store manager indices in temp shape.
+01331         for(i=0; i<(sint)numNewVertices;i++)
+01332         {
+01333                 // allocate a Vertex
+01334                 uint    vid= allocator->allocateVertex();
+01335                 // store in tmp shape.
+01336                 shape->InstanceVertices[i]= vid;
+01337 
+01338                 // Fill this vertex.
+01339                 uint8   *srcPtr= (uint8*)shape->VB.getVertexCoordPointer(i);
+01340                 uint8   *dstPtr= (uint8*)allocator->getVertexPointer(vid);
+01341 
+01342                 // Get bendWeight for this vertex.
+01343                 float   vertexBendWeight= ((CUV*)(srcPtr + srcTex1Off))->U * bendFactor;
+01344 
+01345                 // Pos.
+01346                 //-------
+01347                 // Separate Center and relative pos.
+01348                 CVector relPos= mat.mulVector(*(CVector*)srcPtr);       // mulVector, because translation in v[center]
+01349                 // compute bendCenterPos
+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);                                // mulVector, because translation in v[center]
+01358                 }
+01359                 // copy
+01360                 deltaPos= relPos-bendCenterPos;
+01361                 *(CVector*)dstPtr= deltaPos;
+01362                 *(CVector*)(dstPtr + dstCenterOff)= instancePos + bendCenterPos;
+01363                 // if !destLighted, then VP is different
+01364                 if(!destLighted)
+01365                 {
+01366                         deltaPosNorm= deltaPos.norm();
+01367                         // copy bendWeight in v.w
+01368                         CVectorH        *vh= (CVectorH*)dstPtr;
+01369                         // Mul by deltaPosNorm, to draw an arc circle.
+01370                         vh->w= vertexBendWeight * deltaPosNorm;
+01371                 }
+01372 
+01373                 // Enlarge the clipBlock of the IG.
+01374                 // Since small shape, enlarge with each vertices. simpler and maybe faster.
+01375                 // TODO_VEGET: bend and clipping ...
+01376                 ig->_ClipOwner->extendBBoxOnly(instancePos + relPos);
+01377 
+01378                 // prepare for ZSort
+01379                 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01380                 {
+01381                         worldVertices[i]= instancePos + relPos;
+01382                 }
+01383 
+01384 
+01385                 // Color-ligthing.
+01386                 //-------
+01387                 if(!precomputeLighting)
+01388                 {
+01389                         // just copy the primary color (means diffuse part if lighted)
+01390                         *(CRGBA*)(dstPtr + dstColor0Off)= primaryRGBA;
+01391                         // normal and secondary color
+01392                         if(destLighted)
+01393                         {
+01394                                 // normal
+01395                                 *(CVector*)(dstPtr + dstNormalOff)= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
+01396                         }
+01397                         // If destLighted, secondaryRGBA is the ambient
+01398                         // else if(instanceDoubleSided), secondaryRGBA is backface color.
+01399                         // else, still important to copy secondaryRGBA, because alpha part contains Dynamic LightMap V.
+01400                         *(CRGBA*)(dstPtr + dstColor1Off)= secondaryRGBA;
+01401                 }
+01402                 else
+01403                 {
+01404                         nlassert(!destLighted);
+01405 
+01406                         // compute normal.
+01407                         CVector         rotNormal= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
+01408                         // must normalize() because scale is possible.
+01409                         rotNormal.normalize();
+01410 
+01411                         // Do the compute.
+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                 // Texture.
+01431                 //-------
+01432                 *(CUV*)(dstPtr + dstTex0Off)= *(CUV*)(srcPtr + srcTex0Off);
+01433 
+01434                 // Bend.
+01435                 //-------
+01436                 CVector         *dstBendPtr= (CVector*)(dstPtr + dstBendOff);
+01437                 // setup bend Phase.
+01438                 dstBendPtr->y= bendPhase;
+01439                 // setup bend Weight.
+01440                 // if !destLighted, then VP is different, vertexBendWeight is stored in v[0].w
+01441                 if(destLighted)
+01442                         dstBendPtr->x= vertexBendWeight;
+01443                 else
+01444                         // the VP need the norm of relPos in v[9].x
+01445                         dstBendPtr->x= deltaPosNorm;
+01446                 // setup bendFreqFactor
+01447                 dstBendPtr->z= bendFreqFactor;
+01449                 if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01450                 {
+01451                         // get ptr on v[9].w NB: in Unlit mode, it has 4 components.
+01452                         CVectorH                *dstBendPtr= (CVectorH*)(dstPtr + dstBendOff);
+01453                         // setup the constant of linear formula:
+01454                         // Alpha= -1/blendTransDist * dist + blendDistMax/blendTransDist
+01455                         dstBendPtr->w= blendDistMax/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST;
+01456                 }
+01457 
+01458 
+01459                 // fill the vertex in AGP.
+01460                 //-------
+01461                 allocator->flushVertex(vid);
+01462         }
+01463 
+01464 
+01465         // must recompute the sphere according to the bbox.
+01466         ig->_ClipOwner->updateSphere();
+01467 
+01468 
+01469         // If ZSort, compute Triangle Centers and Orders for quadrant
+01470         //--------------------
+01471         if(rdrPass==NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01472         {
+01473                 // inform the SB that it must be updated.
+01474                 ig->_SortOwner->_Dirty= true;
+01475                 // For deletion, inform the ig that it has instances which impact the SB.
+01476                 ig->_HasZSortPassInstances= true;
+01477 
+01478                 // change UnderWater falg of the SB
+01479                 if(vegetWaterState == AboveWater)
+01480                         ig->_SortOwner->_UnderWater= false;
+01481                 else if(vegetWaterState == UnderWater)
+01482                         ig->_SortOwner->_UnderWater= true;
+01483 
+01484                 // static to avoid reallocation
+01485                 static  vector<CVector>         triangleCenters;
+01486                 triangleCenters.resize(numNewTris);
+01487 
+01488                 // compute triangle centers
+01489                 for(uint i=0; i<numNewTris; i++)
+01490                 {
+01491                         // get index in shape.
+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                         // get world coord.
+01497                         const CVector   &vert0= worldVertices[v0];
+01498                         const CVector   &vert1= worldVertices[v1];
+01499                         const CVector   &vert2= worldVertices[v2];
+01500 
+01501                         // compute center
+01502                         triangleCenters[i]= (vert0 + vert1 + vert2) / 3;
+01503                         // relative to center of the sortBlock (for more precision, especially for radixSort)
+01504                         triangleCenters[i]-= ig->_SortOwner->_Center;
+01505                 }
+01506 
+01507 
+01508                 // resize the array. Actually only modify the number of triangles really setuped.
+01509                 uint    offTri= ig->_TriangleQuadrantOrderNumTriangles;
+01510                 ig->_TriangleQuadrantOrderNumTriangles+= numNewTris;
+01511                 // verify user has correclty used reserveIg system.
+01512                 nlassert(ig->_TriangleQuadrantOrderNumTriangles * NL3D_VEGETABLE_NUM_QUADRANT <= ig->_TriangleQuadrantOrderArray.size());
+01513 
+01514 
+01515                 // compute distance for each quadrant.
+01516                 for(uint quadId=0; quadId<NL3D_VEGETABLE_NUM_QUADRANT; quadId++)
+01517                 {
+01518                         const CVector           &quadDir= CVegetableQuadrant::Dirs[quadId];
+01519 
+01520                         // For all tris.
+01521                         for(uint i=0; i<numNewTris; i++)
+01522                         {
+01523                                 // compute the distance with orientation of the quadrant. (DotProduct)
+01524                                 ig->_TriangleQuadrantOrders[quadId][offTri + i]= triangleCenters[i] * quadDir;
+01525                         }
+01526                 }
+01527         }
+01528 
+01529 
+01530         // Append list of indices and list of triangles to the IG
+01531         //--------------------
+01532 
+01533         // TODO_VEGET_OPTIM: system reallocation of array is very bad...
+01534 
+01535 
+01536         // compute dest start idx.
+01537         uint    offVertex= vegetRdrPass.NVertices;
+01538         uint    offTri= vegetRdrPass.NTriangles;
+01539         uint    offTriIdx= offTri*3;
+01540 
+01541         // verify user has correclty used reserveIg system.
+01542         nlassert(offVertex + numNewVertices <= vegetRdrPass.Vertices.size());
+01543         nlassert(offTriIdx + numNewIndices <= vegetRdrPass.TriangleIndices.size());
+01544         nlassert(offTriIdx + numNewIndices <= vegetRdrPass.TriangleLocalIndices.size());
+01545 
+01546 
+01547         // insert list of vertices to delete in ig vertices.
+01548         vegetRdrPass.Vertices.copy(offVertex, offVertex+numNewVertices, &shape->InstanceVertices[0]);
+01549 
+01550         // insert array of triangles in ig.
+01551         // for all indices, fill IG
+01552         for(i=0; i<(sint)numNewIndices; i++)
+01553         {
+01554                 // get the index of the vertex in the shape
+01555                 uint    vid= shape->TriangleIndices[i];
+01556                 // re-direction, using InstanceVertices;
+01557                 vegetRdrPass.TriangleIndices[offTriIdx + i]= shape->InstanceVertices[vid];
+01558                 // local re-direction: adding vertexOffset.
+01559                 vegetRdrPass.TriangleLocalIndices[offTriIdx + i]= offVertex + vid;
+01560         }
+01561 
+01562         // new triangle and vertex size.
+01563         vegetRdrPass.NTriangles+= numNewTris;
+01564         vegetRdrPass.NVertices+= numNewVertices;
+01565 
+01566 
+01567         // if lighted, must add a lightedInstance for lighting update.
+01568         //--------------------
+01569         if(instanceLighted)
+01570         {
+01571                 // first, update Ig.
+01572                 ig->_ULNumVertices+= numNewVertices;
+01573                 // and update the vegetable manager.
+01574                 _ULNTotalVertices+= numNewVertices;
+01575                 // link at the end of the circular list: link before the current root.
+01576                 if(_ULRootIg==NULL)
+01577                         _ULRootIg= ig;
+01578                 else
+01579                         ig->linkBeforeUL(_ULRootIg);
+01580 
+01581                 // check good use of reserveIg.
+01582                 nlassert(vegetRdrPass.NLightedInstances < vegetRdrPass.LightedInstances.size());
+01583 
+01584                 // Fill instance info
+01585                 CVegetableInstanceGroup::CVegetableLightedInstance      &vli= 
+01586                         vegetRdrPass.LightedInstances[vegetRdrPass.NLightedInstances];
+01587                 vli.Shape= shape;
+01588                 vli.NormalMat= normalMat;
+01589                 // copy colors unmodulated by global light.
+01590                 vli.MatAmbient= ambientRGBA;
+01591                 vli.MatDiffuse= diffuseRGBA;
+01592                 // store dynamic lightmap UV
+01593                 vli.DlmUV= dlmUV;
+01594                 // where vertices of this instances are wrote in the VegetRdrPass
+01595                 vli.StartIdInRdrPass= offVertex;
+01596 
+01597                 // Inc size setuped.
+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         // the allocator where vertices come from
+01610         CVegetableVBAllocator   &srcAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vegetRdrPass.HardMode);
+01611         // the allocator where vertices will go
+01612         CVegetableVBAllocator   &dstAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, !vegetRdrPass.HardMode);
+01613 
+01614         // vertex size
+01615         uint    vbSize= srcAllocator.getSoftwareVertexBuffer().getVertexSize();
+01616         nlassert(vbSize == dstAllocator.getSoftwareVertexBuffer().getVertexSize());
+01617 
+01618         // for all vertices of the IG, change of VBAllocator
+01619         uint i;
+01620         // Do it only for current Vertices setuped!!! because a swapIgRdrPassHardMode awlays arise when the ig is 
+01621         // in construcion.
+01622         // Hence here, we may have vegetRdrPass.NVertices < vegetRdrPass.Vertices.size() !!!
+01623         for(i=0;i<vegetRdrPass.NVertices;i++)
+01624         {
+01625                 // get idx in src allocator.
+01626                 uint    srcId= vegetRdrPass.Vertices[i];
+01627                 // allocate a verex in the dst allocator.
+01628                 uint    dstId= dstAllocator.allocateVertex();
+01629 
+01630                 // copy from VBsoft of src to dst.
+01631                 void    *vbSrc= srcAllocator.getVertexPointer(srcId);
+01632                 void    *vbDst= dstAllocator.getVertexPointer(dstId);
+01633                 memcpy(vbDst, vbSrc, vbSize);
+01634                 // release src vertex.
+01635                 srcAllocator.deleteVertex(srcId);
+01636 
+01637                 // and copy new dest id in Vertices array.
+01638                 vegetRdrPass.Vertices[i]= dstId;
+01639 
+01640                 // and flush this vertex into VBHard (if dst is aVBHard).
+01641                 dstAllocator.flushVertex(dstId);
+01642         }
+01643 
+01644         // For all triangles, bind correct triangles.
+01645         nlassert(vegetRdrPass.TriangleIndices.size() == vegetRdrPass.TriangleLocalIndices.size());
+01646         // Do it only for current Triangles setuped!!! same reason as vertices
+01647         // For all setuped triangles indices
+01648         for(i=0;i<vegetRdrPass.NTriangles*3;i++)
+01649         {
+01650                 // get the index in Vertices.
+01651                 uint    localVid= vegetRdrPass.TriangleLocalIndices[i];
+01652                 // get the index in new VBufffer (dstAllocator), and copy to TriangleIndices
+01653                 vegetRdrPass.TriangleIndices[i]= vegetRdrPass.Vertices[localVid];
+01654         }
+01655 
+01656         // Since change is made, flag the IG rdrpass
+01657         vegetRdrPass.HardMode= !vegetRdrPass.HardMode;
+01658 }
+01659 
+01660 
+01661 // ***************************************************************************
+01662 // ***************************************************************************
+01663 // Render
+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         // update all driver
+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         // if driver changed, recreate vertex programs
+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         // setup a CTextureFile (smartPtr-ized).
+01704         ITexture        *tex= new CTextureFile(texName);
+01705         loadTexture(tex);
+01706         // setup good params.
+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         // setup a ITexture (smartPtr-ized).
+01716         // Store in stage1, for dynamicLightmaping
+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         // Setup ambient/Diffuse.
+01726         _GlobalAmbient= ambient;
+01727         _GlobalDiffuse= diffuse;
+01728 }
+01729 
+01730 // ***************************************************************************
+01731 void                    CVegetableManager::lockBuffers()
+01732 {
+01733         // lock all buffers
+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         // unlock all buffers
+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         // for sort()
+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         // Standard
+01776         // setup VertexProgram constants.
+01777         // c[0..3] take the ModelViewProjection Matrix. After setupModelMatrix();
+01778         driver->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
+01779         // c[4..7] take the ModelView Matrix. After setupModelMatrix();
+01780         driver->setConstantMatrix(4, IDriver::ModelView, IDriver::Identity);
+01781         // c[8] take usefull constants.
+01782         driver->setConstant(8, 0, 1, 0.5f, 2);
+01783         // c[9] take normalized directional light
+01784         driver->setConstant(9, _DirectionalLight);
+01785         // c[10] take pos of camera
+01786         driver->setConstant(10, _ViewCenter);
+01787         // c[11] take factor for Blend formula
+01788         driver->setConstant(11, -1.f/NL3D_VEGETABLE_BLOCK_BLEND_TRANSITION_DIST, 0, 0, 0);
+01789 
+01790 
+01791 
+01792         // Bend.
+01793         // c[16]= quaternion axis. w==1, and z must be 0
+01794         driver->setConstant( 16, _AngleAxis.x, _AngleAxis.y, _AngleAxis.z, 1);
+01795         // c[17]=       {timeAnim, WindPower, WindPower*(1-WindBendMin)/2, 0)}
+01796         driver->setConstant( 17, (float)_WindAnimTime, _WindPower, _WindPower*(1-_WindBendMin)/2, 0 );
+01797         // c[18]=       High order Taylor cos coefficient: { -1/2, 1/24, -1/720, 1/40320 }
+01798         driver->setConstant( 18, -1/2.f, 1/24.f, -1/720.f, 1/40320.f );
+01799         // c[19]=       Low order Taylor cos coefficient: { 1, -1/2, 1/24, -1/720 }
+01800         driver->setConstant( 19, 1, -1/2.f, 1/24.f, -1/720.f );
+01801         // c[20]=       Low order Taylor sin coefficient: { 1, -1/6, 1/120, -1/5040 }
+01802         driver->setConstant( 20, 1, -1/6.f, 1/120.f, -1/5040.f );
+01803         // c[21]=       Special constant vector for quatToMatrix: { 0, 1, -1, 0 }
+01804         driver->setConstant( 21, 0.f, 1.f, -1.f, 0.f);
+01805         // c[22]=       {0.5f, Pi, 2*Pi, 1/(2*Pi)}
+01806         driver->setConstant( 22, 0.5f, (float)Pi, (float)(2*Pi), (float)(1/(2*Pi)) );
+01807         // c[23]=       {NL3D_VEGETABLE_VP_LUT_SIZE, 0, 0, 0}. NL3D_VEGETABLE_VP_LUT_SIZE==64.
+01808         driver->setConstant( 23, NL3D_VEGETABLE_VP_LUT_SIZE, 0.f, 0.f, 0.f );
+01809 
+01810 
+01811         // Fill constant. Start at 32.
+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         // get normalized front vector.
+01830         CVector         frontVectorNormed= frontVector.normed();
+01831 
+01832         // For Speed debug only.
+01833         /*extern        bool    YOYO_ATTest;
+01834         if(YOYO_ATTest)
+01835                 return;
+01836         */
+01837 
+01838         // Clip.
+01839         //--------------------
+01840         // For all current not empty clipBlocks, clip against pyramid, and insert visibles in list.
+01841         CVegetableClipBlock             *ptrClipBlock= _ClipBlockList.begin();
+01842         while(ptrClipBlock)
+01843         {
+01844                 // if the clipBlock is visible and not empty
+01845                 if(ptrClipBlock->clip(pyramid))
+01846                 {
+01847                         // insert into visible list.
+01848                         ptrClipBlock->_RenderNext= rootToRender;
+01849                         rootToRender= ptrClipBlock;
+01850                 }
+01851 
+01852                 // next
+01853                 ptrClipBlock= (CVegetableClipBlock*)ptrClipBlock->Next;
+01854         }
+01855 
+01856 
+01857         // If no clip block visible, just skip!!
+01858         if(rootToRender==NULL)
+01859                 return;
+01860 
+01861 
+01862         // Prepare Render
+01863         //--------------------
+01864 
+01865         // profile.
+01866         CPrimitiveProfile       ppIn, ppOut;
+01867         driver->profileRenderedPrimitives(ppIn, ppOut);
+01868         uint    precNTriRdr= ppOut.NTriangles;
+01869 
+01870 
+01871         // Disable Fog.
+01872         bool    bkupFog;
+01873         bkupFog= driver->fogEnabled();
+01874         driver->enableFog(false);
+01875 
+01876 
+01877         // Used by setupVertexProgramConstants(). The center of camera.
+01878         // Used for AlphaBlending, and for ZBuffer precision problems.
+01879         _ViewCenter= viewCenter;
+01880 
+01881 
+01882         // The manager is identity in essence. But for ZBuffer improvements, must set it as close
+01883         // to the camera. In the VertexProgram, _ViewCenter is substracted from bent vertex pos. So take it as position.
+01884         _ManagerMatrix.identity();
+01885         _ManagerMatrix.setPos(_ViewCenter);
+01886 
+01887 
+01888         // set model matrix to the manager matrix.
+01889         driver->setupModelMatrix(_ManagerMatrix);
+01890 
+01891 
+01892         // set the driver for all allocators
+01893         updateDriver(driver);
+01894 
+01895 
+01896         // Compute Bend Anim.
+01897 
+01898         // AnimFrequency factor.
+01899         // Doing it incrementaly allow change of of frequency each frame with good results.
+01900         _WindAnimTime+= (_Time - _WindPrecRenderTime)*_WindFrequency;
+01901         _WindAnimTime= fmod(_WindAnimTime, (float)NL3D_VEGETABLE_FREQUENCY_FACTOR_PREC);
+01902         // NB: Leave timeBend (_WindAnimTime) as a time (ie [0..1]), because VP do a "EXP time".
+01903         // For incremental computing.
+01904         _WindPrecRenderTime= _Time;
+01905 
+01906 
+01907         // compute the angleAxis corresponding to direction
+01908         // perform a 90° rotation to get correct angleAxis
+01909         _AngleAxis.set(-_WindDirection.y,_WindDirection.x,0);
+01910 
+01911 
+01912         // Fill LUT WindTable.
+01913         uint    i;
+01914         for(i=0; i<NL3D_VEGETABLE_VP_LUT_SIZE; i++)
+01915         {
+01916                 /* NB: this formula works quite well, because vertex BendFactor is expressed in Radian/2.
+01917                         And since animFactor==(_CosTable[i] + 1) E [0..2], we have here an arc-cirle computing:
+01918                         dmove= Radius * AngleRadian/2 *  animFactor. So at max of animFactor (ie 2), we have:
+01919                         dmove= Radius * AngleRadian, which is by definition an arc-cirle computing...
+01920                         And so this approximate the Bend-quaternion Vertex Program.
+01921                 */
+01922                 float   windForce= (_CosTable[(i+32)%64] + 1);
+01923                 // Modify with _WindPower / _WindBendMin.
+01924                 windForce= _WindBendMin*2 + windForce * (1-_WindBendMin);
+01925                 windForce*= _WindPower;
+01926                 // Compute direction of the wind, and multiply by windForce.
+01927                 _WindTable[i]= CVector2f(_WindDirection.x, _WindDirection.y) * windForce;
+01928         }
+01929         // compute delta
+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         // setup VP constants.
+01939         setupVertexProgramConstants(driver);
+01940 
+01941 
+01942         // Setup TexEnvs for Dynamic lightmapping
+01943         //--------------------
+01944         // if the dynamic lightmap is provided
+01945         if(textureDLM)
+01946         {
+01947                 // stage0 RGB is Diffuse + DLM.
+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                 // stage1 RGB is Previous * Texture
+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                 // reset stage0 (to skip it)
+01960                 _VegetableMaterial.setTexture(0, NULL);
+01961                 // stage1 RGB is Diffuse * Texture
+01962                 _VegetableMaterial.texEnvOpRGB(1, CMaterial::Modulate);
+01963                 _VegetableMaterial.texEnvArg0RGB(1, CMaterial::Texture, CMaterial::SrcColor);
+01964                 _VegetableMaterial.texEnvArg1RGB(1, CMaterial::Diffuse, CMaterial::SrcColor);
+01965         }
+01966         // stage1 Alpha is always "Modulate texture with diffuse Alpha"
+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         // Render !ZSORT pass
+01974         //--------------------
+01975 
+01976         // setup material (may have change because of ZSORT / alphaBlend pass)
+01977         _VegetableMaterial.setBlend(false);
+01978         _VegetableMaterial.setZWrite(true);
+01979         _VegetableMaterial.setAlphaTestThreshold(0.5f);
+01980 
+01981 
+01982         /*
+01983                 Prefer sort with Soft / Hard first.
+01984                 Also, Prefer do VBsoft last, for better GPU //ism with Landscape.
+01985         */
+01986         // For both allocators: Hard(1) then Soft(0)
+01987         for(sint vbHardMode= 1; vbHardMode>=0; vbHardMode--)
+01988         {
+01989                 // For all renderPass.
+01990                 for(sint rdrPass=0; rdrPass < NL3D_VEGETABLE_NRDRPASS; rdrPass++)
+01991                 {
+01992                         // skip ZSORT rdrPass, done after.
+01993                         if(rdrPass == NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT)
+01994                                 continue;
+01995 
+01996                         // which allocator?
+01997                         CVegetableVBAllocator   &vbAllocator= getVBAllocatorForRdrPassAndVBHardMode(rdrPass, vbHardMode);
+01998 
+01999                         // Do the pass only if there is some vertices to draw.
+02000                         if(vbAllocator.getNumUserVerticesAllocated()>0)
+02001                         {
+02002                                 // additional setup to the material
+02003                                 bool    doubleSided= doubleSidedRdrPass(rdrPass);
+02004                                 // set the 2Sided flag in the material
+02005                                 _VegetableMaterial.setDoubleSided( doubleSided );
+02006                                 // must enable VP DoubleSided coloring
+02007                                 driver->enableVertexProgramDoubleSidedColor(doubleSided);
+02008 
+02009 
+02010                                 // Activate the unique material.
+02011                                 driver->setupMaterial(_VegetableMaterial);
+02012 
+02013                                 // activate Vertex program first.
+02014                                 //nlinfo("\nSTARTVP\n%s\nENDVP\n", _VertexProgram[rdrPass]->getProgram().c_str());
+02015                                 nlverify(driver->activeVertexProgram(_VertexProgram[rdrPass]));
+02016 
+02017                                 // Activate the good VBuffer
+02018                                 vbAllocator.activate();
+02019 
+02020                                 // For all visibles clipBlock, render their instance groups.
+02021                                 ptrClipBlock= rootToRender;
+02022                                 while(ptrClipBlock)
+02023                                 {
+02024                                         // For all sortBlock of the clipBlock
+02025                                         CVegetableSortBlock     *ptrSortBlock= ptrClipBlock->_SortBlockList.begin();
+02026                                         while(ptrSortBlock)
+02027                                         {
+02028                                                 // For all igs of the sortBlock
+02029                                                 CVegetableInstanceGroup         *ptrIg= ptrSortBlock->_InstanceGroupList.begin();
+02030                                                 while(ptrIg)
+02031                                                 {
+02032                                                         // rdrPass
+02033                                                         CVegetableInstanceGroup::CVegetableRdrPass      &vegetRdrPass= ptrIg->_RdrPass[rdrPass];
+02034 
+02035                                                         // if this rdrPass is in same HardMode as we process now.
+02036                                                         if( (vegetRdrPass.HardMode && vbHardMode==1) || (!vegetRdrPass.HardMode && vbHardMode==0) )
+02037                                                         {
+02038                                                                 // Ok, Render the faces.
+02039                                                                 if(vegetRdrPass.NTriangles)
+02040                                                                 {
+02041                                                                         driver->renderSimpleTriangles(&vegetRdrPass.TriangleIndices[0], 
+02042                                                                                 vegetRdrPass.NTriangles);
+02043                                                                 }
+02044                                                         }
+02045 
+02046                                                         // next ig.
+02047                                                         ptrIg= (CVegetableInstanceGroup*)ptrIg->Next;
+02048                                                 }
+02049 
+02050                                                 // next sortBlock
+02051                                                 ptrSortBlock= (CVegetableSortBlock      *)(ptrSortBlock->Next);
+02052                                         }
+02053 
+02054                                         // next clipBlock to render 
+02055                                         ptrClipBlock= ptrClipBlock->_RenderNext;
+02056                                 }
+02057                         }
+02058 
+02059                 }
+02060 
+02061         }
+02062 
+02063         // Render ZSort pass.
+02064         //--------------------
+02065 
+02066         // Debug Quadrants.
+02067         /*static vector<CVector>                p0DebugLines;
+02068         static vector<CVector>          p1DebugLines;
+02069         p0DebugLines.clear();
+02070         p1DebugLines.clear();*/
+02071 
+02072         // For all Blend model Layers, clear Sort Block list and setup.
+02073         for(i=0; i<_NumZSortBlendLayers;i++)
+02074         {
+02075                 // must have been created.
+02076                 nlassert(_ZSortModelLayers[i]);
+02077                 nlassert(_ZSortModelLayersUW[i]);
+02078                 // NB: don't refresh list, it is done in CVegetableBlendLayerModel.
+02079                 // We must do it here, because if vegetableManger::render() is no more called (eg: disabled),
+02080                 // then the models must do nothing.
+02081 
+02082                 // To get layers correclty sorted from fornt to back, must init their pos
+02083                 // because it is the renderTraversal which sort them.
+02084                 // compute distance to camera of this layer.
+02085                 float   layerZ= i * _ZSortLayerDistMax / _NumZSortBlendLayers;
+02086                 // compute position of this layer.
+02087                 CVector         pos= viewCenter + frontVector * layerZ;
+02088                 // special setup in the layer.
+02089                 _ZSortModelLayers[i]->setWorldPos(pos);
+02090                 _ZSortModelLayersUW[i]->setWorldPos(pos);
+02091         }
+02092 
+02093         // If some vertices in arrays for ZSort rdrPass
+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                 // sort
+02100                 //-------------
+02101                 // Array for sorting. (static to avoid reallocation)
+02102                 static  vector<CSortVSB>                sortVegetSbs;
+02103                 sortVegetSbs.clear();
+02104 
+02105                 // For all visibles clipBlock
+02106                 ptrClipBlock= rootToRender;
+02107                 while(ptrClipBlock)
+02108                 {
+02109                         // For all sortBlock, prepare to sort them
+02110                         CVegetableSortBlock     *ptrSortBlock= ptrClipBlock->_SortBlockList.begin();
+02111                         while(ptrSortBlock)
+02112                         {
+02113                                 // if the sortBlock has some sorted faces to render
+02114                                 if(ptrSortBlock->_NTriangles != 0)
+02115                                 {
+02116                                         // Compute Distance to Viewer.
+02117                                         /* NB: compute radial distance (with norm()) instead of linear distance 
+02118                                                 (DotProduct with front vector) get less "ZSort poping".
+02119                                         */
+02120                                         CVector         dirToSb= ptrSortBlock->_Center - viewCenter;
+02121                                         float           distToViewer= dirToSb.norm();
+02122                                         // SortKey change if the center is behind the camera.
+02123                                         if(dirToSb * frontVectorNormed<0)
+02124                                         {
+02125                                                 ptrSortBlock->_SortKey= - distToViewer;
+02126                                         }
+02127                                         else
+02128                                         {
+02129                                                 ptrSortBlock->_SortKey= distToViewer;
+02130                                         }
+02131 
+02132                                         // Choose the quadrant for this sortBlock
+02133                                         sint            bestDirIdx= 0;
+02134                                         float           bestDirVal= -FLT_MAX;
+02135                                         // If too near, must take the frontVector as key, to get better sort.
+02136                                         // use ptrSortBlock->_SortKey to get correct negative values.
+02137                                         if(ptrSortBlock->_SortKey < ptrSortBlock->_Radius)
+02138                                         {
+02139                                                 dirToSb= frontVectorNormed;
+02140                                         }
+02141 
+02142                                         // NB: no need to normalize dirToSb, because need only to sort with DP
+02143                                         // choose the good list of triangles according to quadrant.
+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                                         // set the result.
+02155                                         ptrSortBlock->_QuadrantId= bestDirIdx;
+02156 
+02157                                         // insert in list to sort.
+02158                                         sortVegetSbs.push_back(CSortVSB(ptrSortBlock));
+02159 
+02160                                         // Debug Quadrants
+02161                                         /*p0DebugLines.push_back(ptrSortBlock->_Center);
+02162                                         p1DebugLines.push_back(ptrSortBlock->_Center + CVegetableQuadrant::Dirs[bestDirIdx]);*/
+02163                                 }
+02164 
+02165                                 // next sortBlock
+02166                                 ptrSortBlock= (CVegetableSortBlock      *)(ptrSortBlock->Next);
+02167                         }
+02168 
+02169                         // next clipBlock to render 
+02170                         ptrClipBlock= ptrClipBlock->_RenderNext;
+02171                 }
+02172 
+02173                 // sort!
+02174                 // QSort. (I tried, better than radix sort, guckk!!)
+02175                 sort(sortVegetSbs.begin(), sortVegetSbs.end());
+02176 
+02177 
+02178                 // setup material for this rdrPass. NB: rendered after (in LayerModels).
+02179                 //-------------
+02180                 bool    doubleSided= doubleSidedRdrPass(rdrPass);
+02181                 // set the 2Sided flag in the material
+02182                 _VegetableMaterial.setDoubleSided( doubleSided );
+02183 
+02184                 // setup the unique material.
+02185                 _VegetableMaterial.setBlend(true);
+02186                 _VegetableMaterial.setZWrite(false);
+02187                 // leave AlphaTest but still kick low alpha values (for fillRate performance)
+02188                 _VegetableMaterial.setAlphaTestThreshold(0.1f);
+02189 
+02190 
+02191 
+02192                 // order them in Layers.
+02193                 //-------------
+02194 
+02195                 // render from back to front, to keep correct Z order in a single layer.
+02196                 for(uint i=0; i<sortVegetSbs.size();i++)
+02197                 {
+02198                         CVegetableSortBlock     *ptrSortBlock= sortVegetSbs[i].Sb;
+02199 
+02200                         float   z= ptrSortBlock->_SortKey;
+02201                         // compute in which layer must store this SB.
+02202                         z= z*_NumZSortBlendLayers / _ZSortLayerDistMax;
+02203                         // Avoid a floor(), using an OptFastFloor, but without the OptFastFloorBegin() End() group.
+02204                         // => avoid the imprecision with such a trick; *256, then divide the integer by 256.
+02205                         sint    layer= OptFastFloor(z*256) >> 8;
+02206                         clamp(layer, 0, (sint)_NumZSortBlendLayers-1);
+02207 
+02208                         // Range in correct layer, according to water ordering
+02209                         if(ptrSortBlock->_UnderWater)
+02210                                 // range in the correct layermodel (NB: keep the same layer internal order).
+02211                                 _ZSortModelLayersUW[layer]->SortBlocks.push_back(ptrSortBlock);
+02212                         else
+02213                                 _ZSortModelLayers[layer]->SortBlocks.push_back(ptrSortBlock);
+02214                 }
+02215                 
+02216         }
+02217 
+02218 
+02219         // Quit
+02220         //--------------------
+02221 
+02222         // disable VertexProgram.
+02223         driver->activeVertexProgram(NULL);
+02224 
+02225         // reset state to default.
+02226         driver->enableVertexProgramDoubleSidedColor(false);
+02227 
+02228 
+02229         // restore Fog.
+02230         driver->enableFog(bkupFog);
+02231 
+02232 
+02233         // Debug Quadrants
+02234         /*for(uint l=0; l<p0DebugLines.size();l++)
+02235         {
+02236                 CVector dv= CVector::K;
+02237                 CDRU::drawLine(p0DebugLines[l]+dv, p1DebugLines[l]+dv, CRGBA(255,0,0), *driver);
+02238         }*/
+02239 
+02240         // profile: compute number of triangles rendered with vegetable manager.
+02241         driver->profileRenderedPrimitives(ppIn, ppOut);
+02242         _NumVegetableFaceRendered= ppOut.NTriangles-precNTriRdr;
+02243 
+02244 }
+02245 
+02246 
+02247 // ***************************************************************************
+02248 void            CVegetableManager::setupRenderStateForBlendLayerModel(IDriver *driver)
+02249 {
+02250         // Setup Global.
+02251         //=============
+02252         // disable fog, for faster VP.
+02253         _BkupFog= driver->fogEnabled();
+02254         driver->enableFog(false);
+02255 
+02256         // set model matrix to the manager matrix.
+02257         driver->setupModelMatrix(_ManagerMatrix);
+02258 
+02259         // setup VP constants.
+02260         setupVertexProgramConstants(driver);
+02261 
+02262         // Setup RdrPass.
+02263         //=============
+02264         uint    rdrPass= NL3D_VEGETABLE_RDRPASS_UNLIT_2SIDED_ZSORT;
+02265 
+02266         // setup doubleSidedmaterial for this rdrPass.
+02267         bool    doubleSided= doubleSidedRdrPass(rdrPass);
+02268         // must enable VP DoubleSided coloring
+02269         driver->enableVertexProgramDoubleSidedColor(doubleSided);
+02270 
+02271         // Activate the unique material (correclty setuped for AlphaBlend in render()).
+02272         driver->setupMaterial(_VegetableMaterial);
+02273 
+02274         // activate Vertex program first.
+02275         //nlinfo("\nSTARTVP\n%s\nENDVP\n", _VertexProgram[rdrPass]->getProgram().c_str());
+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         // disable VertexProgram.
+02299         driver->activeVertexProgram(NULL);
+02300 
+02301         // reset state to default.
+02302         driver->enableVertexProgramDoubleSidedColor(false);
+02303 
+02304         // restore Fog.
+02305         driver->enableFog(_BkupFog);
+02306 }
+02307 
+02308 
+02309 
+02310 // ***************************************************************************
+02311 void            CVegetableManager::setWind(const CVector &windDir, float windFreq, float windPower, float windBendMin)
+02312 {
+02313         // Keep only XY component of the Wind direction (because VP only support z==0 quaternions).
+02314         _WindDirection= windDir;
+02315         _WindDirection.z= 0;
+02316         _WindDirection.normalize();
+02317         // copy setup
+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         // copy time
+02328         _Time= time;
+02329 }
+02330 
+02331 
+02332 // ***************************************************************************
+02333 // ***************************************************************************
+02334 // Lighting part.
+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         // first time in this method??
+02350         if(!_ULPrecTimeInit)
+02351         {
+02352                 _ULPrecTimeInit= true;
+02353                 _ULPrecTime= _ULTime;
+02354         }
+02355         // compute delta time from last update.
+02356         float dt= float(_ULTime - _ULPrecTime);
+02357         _ULPrecTime= _ULTime;
+02358 
+02359         // compute number of vertices to update.
+02360         _ULNVerticesToUpdate+= dt*_ULFrequency * _ULNTotalVertices;
+02361         // maximize, so at max, it computes all Igs, just one time.
+02362         _ULNVerticesToUpdate= min(_ULNVerticesToUpdate, (float)_ULNTotalVertices);
+02363 
+02364         // go.
+02365         doUpdateLighting();
+02366 }
+02367 
+02368 
+02369 // ***************************************************************************
+02370 void            CVegetableManager::updateLightingAll()
+02371 {
+02372         // maximize, so at max, it computes all Igs
+02373         _ULNVerticesToUpdate= (float)_ULNTotalVertices;
+02374 
+02375         // go.
+02376         doUpdateLighting();
+02377 }
+02378 
+02379 
+02380 // ***************************************************************************
+02381 void            CVegetableManager::doUpdateLighting()
+02382 {
+02383         // while there is still some vertices to update.
+02384         while(_ULNVerticesToUpdate > 0 && _ULRootIg)
+02385         {
+02386                 // update the current ig. if all updated, skip to next one.
+02387                 if(updateLightingIGPart())
+02388                 {
+02389                         // next
+02390                         _ULRootIg= _ULRootIg->_ULNext;
+02391                 }
+02392         }
+02393 
+02394         // Now, _ULNVerticesToUpdate should be <=0. (most of the time < 0)
+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         // First, update lighting info global to the ig, ie update current 
+02413         // colros of the PointLights which influence the ig.
+02414         _ULRootIg->VegetableLightEx.computeCurrentColors();
+02415 
+02416         // while there is some vertices to update
+02417         while(_ULNVerticesToUpdate>0)
+02418         {
+02419                 // if all rdrPass of the ig are processed.
+02420                 if(_ULCurrentIgRdrPass>= NL3D_VEGETABLE_NRDRPASS)
+02421                 {
+02422                         // All this Ig is updated.
+02423                         _ULCurrentIgRdrPass= 0;
+02424                         _ULCurrentIgInstance= 0;
+02425                         // skip to next Ig.
+02426                         return true;
+02427                 }
+02428                 CVegetableInstanceGroup::CVegetableRdrPass      &vegetRdrPass= _ULRootIg->_RdrPass[_ULCurrentIgRdrPass];
+02429 
+02430                 // if all instances are processed for this pass (especially if size()==0 !!)
+02431                 if(_ULCurrentIgInstance>= vegetRdrPass.LightedInstances.size())
+02432                 {
+02433                         // skip to the next rdrPass.
+02434                         _ULCurrentIgRdrPass++;
+02435                         _ULCurrentIgInstance= 0;
+02436                         continue;
+02437                 }
+02438 
+02439                 // Process this instance.
+02440                 _ULNVerticesToUpdate-= updateInstanceLighting(_ULRootIg, _ULCurrentIgRdrPass, _ULCurrentIgInstance);
+02441 
+02442                 // next instance.
+02443                 _ULCurrentIgInstance++;
+02444 
+02445                 // if all instances are processed for this pass
+02446                 if(_ULCurrentIgInstance>= vegetRdrPass.LightedInstances.size())
+02447                 {
+02448                         // skip to the next rdrPass.
+02449                         _ULCurrentIgRdrPass++;
+02450                         _ULCurrentIgInstance= 0;
+02451                 }
+02452         }
+02453 
+02454         // If all rdrPass of the ig are processed.
+02455         if(_ULCurrentIgRdrPass>= NL3D_VEGETABLE_NRDRPASS)
+02456         {
+02457                 // All this Ig is updated.
+02458                 _ULCurrentIgRdrPass= 0;
+02459                 _ULCurrentIgInstance= 0;
+02460                 // skip to next Ig.
+02461                 return true;
+02462         }
+02463         else
+02464         {
+02465                 // The Ig is not entirely updated.
+02466                 return false;
+02467         }
+02468 
+02469 }
+02470 
+02471 
+02472 // ***************************************************************************
+02473 uint            CVegetableManager::updateInstanceLighting(CVegetableInstanceGroup *ig, uint rdrPassId, uint instanceId)
+02474 {
+02475         nlassert(ig);
+02476         // get the rdrPass.
+02477         nlassert(rdrPassId<NL3D_VEGETABLE_NRDRPASS);
+02478         CVegetableInstanceGroup::CVegetableRdrPass      &vegetRdrPass= ig->_RdrPass[rdrPassId];
+02479         // get the lighted instance.
+02480         nlassert(instanceId<vegetRdrPass.LightedInstances.size());
+02481         CVegetableInstanceGroup::CVegetableLightedInstance      &vegetLI= vegetRdrPass.LightedInstances[instanceId];
+02482 
+02483         // get the shape
+02484         CVegetableShape         *shape= vegetLI.Shape;
+02485         // it must be lighted.
+02486         nlassert(shape->Lighted);
+02487         bool    instanceLighted= true;
+02488 
+02489 
+02490         // get ref on the vegetLex.
+02491         CVegetableLightEx       &vegetLex= ig->VegetableLightEx;
+02492         // Color of pointLights modulated by diffuse.
+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         // Recompute lighting
+02504         //===========
+02505         
+02506         // setup for this instance.
+02507         //---------
+02508         // 2Sided
+02509         bool    instanceDoubleSided= shape->DoubleSided;
+02510         // Precompute lighting or not??
+02511         bool    precomputeLighting= instanceLighted && shape->PreComputeLighting;
+02512         // bestSided Precompute lighting or not??
+02513         bool    bestSidedPrecomputeLighting= precomputeLighting && shape->BestSidedPreComputeLighting;
+02514         // destLighted?
+02515         bool    destLighted= instanceLighted && !shape->PreComputeLighting;
+02516         // Diffuse and ambient, modulated by current GlobalAmbient and GlobalDiffuse.
+02517         CRGBA   primaryRGBA, secondaryRGBA;
+02518         primaryRGBA.modulateFromColorRGBOnly(vegetLI.MatDiffuse, _GlobalDiffuse);
+02519         secondaryRGBA.modulateFromColorRGBOnly(vegetLI.MatAmbient, _GlobalAmbient);
+02520         // get normal matrix
+02521         CMatrix         &normalMat= vegetLI.NormalMat;
+02522         // array of vertex id to update
+02523         uint32          *ptrVid= vegetRdrPass.Vertices.getPtr() + vegetLI.StartIdInRdrPass;
+02524         uint            numVertices= shape->InstanceVertices.size();
+02525 
+02526         // Copy Dynamic Lightmap UV in Alpha part (save memory for an extra cost of 1 VP instruction)
+02527         primaryRGBA.A= vegetLI.DlmUV.U;
+02528         secondaryRGBA.A= vegetLI.DlmUV.V;
+02529 
+02530 
+02531         // get VertexBuffer info.
+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         // got 2nd color if really lighted (for ambient) or if 2Sided.
+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         // For all vertices, recompute lighting.
+02546         //---------
+02547         for(sint i=0; i<(sint)numVertices;i++)
+02548         {
+02549                 // get the Vertex in the VB.
+02550                 uint    vid= ptrVid[i];
+02551                 // store in tmp shape.
+02552                 shape->InstanceVertices[i]= vid;
+02553 
+02554                 // Fill this vertex.
+02555                 uint8   *srcPtr= (uint8*)shape->VB.getVertexCoordPointer(i);
+02556                 uint8   *dstPtr= (uint8*)allocator->getVertexPointer(vid);
+02557 
+02558 
+02559                 // if !precomputeLighting (means destLighted...)
+02560                 if(!precomputeLighting)
+02561                 {
+02562                         // just copy the primary and secondary color
+02563                         *(CRGBA*)(dstPtr + dstColor0Off)= primaryRGBA;
+02564                         *(CRGBA*)(dstPtr + dstColor1Off)= secondaryRGBA;
+02565                 }
+02566                 else
+02567                 {
+02568                         nlassert(!destLighted);
+02569 
+02570                         // compute normal.
+02571                         CVector         rotNormal= normalMat.mulVector( *(CVector*)(srcPtr + srcNormalOff) );
+02572                         // must normalize() because scale is possible.
+02573                         rotNormal.normalize();
+02574 
+02575                         // Do the compute.
+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                 // flust the vertex in AGP.
+02594                 allocator->flushVertex(vid);
+02595         }
+02596 
+02597 
+02598         // numVertices vertices are updated
+02599         return numVertices;
+02600 }
+02601 
+02602 
+02603 } // NL3D
+
+ + +
                                                                                                                                                                    +
+ + -- cgit v1.2.1