# 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