# 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  

patch_vegetable.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/patch.h"
00030 #include "3d/vegetable.h"
00031 #include "3d/vegetable_manager.h"
00032 #include "3d/landscape_vegetable_block.h"
00033 #include "3d/landscape.h"
00034 #include "nel/misc/vector.h"
00035 #include "nel/misc/common.h"
00036 #include "3d/fast_floor.h"
00037 #include "3d/tile_vegetable_desc.h"
00038 #include "3d/vegetable_light_ex.h"
00039 #include "3d/patchdlm_context.h"
00040 
00041 
00042 using namespace std;
00043 using namespace NLMISC;
00044 
00045 namespace NL3D 
00046 {
00047 
00048 
00049 // ***************************************************************************
00050 void            CPatch::generateTileVegetable(CVegetableInstanceGroup *vegetIg, uint distType, uint ts, uint tt,
00051         CLandscapeVegetableBlockCreateContext &vbCreateCtx)
00052 {
00053         uint    i;
00054 
00055         // Get tile infos for vegetable
00056         // =========================
00057 
00058         // Get the state for this vegetable tile
00059         CTileElement::TVegetableInfo    vegetWaterState= Tiles[tt * OrderS + ts].getVegetableState();
00060         // If vegetable disabled, skip!
00061         if(vegetWaterState == CTileElement::VegetableDisabled)
00062                 return;
00063 
00064         // get the tileId under this tile (<=> the tile material)
00065         uint    tileId= Tiles[tt * OrderS + ts].Tile[0];
00066 
00067         // get list of vegetable for this tile, and for hist distanceType category.
00068         const CTileVegetableDesc                &tileVegetDesc= getLandscape()->getTileVegetableDesc(tileId);
00069         const std::vector<CVegetable>   &vegetableList= tileVegetDesc.getVegetableList(distType);
00070         uint                                                    distAddSeed= tileVegetDesc.getVegetableSeed(distType);
00071         uint                                                    numVegetable= vegetableList.size();
00072         
00073         // If no vegetables at all, skip.
00074         if(numVegetable==0)
00075                 return;
00076 
00077         // compute approximate tile position and normal: get the middle
00078         float   tileU= (ts + 0.5f) / (float)OrderS;
00079         float   tileV= (tt + 0.5f) / (float)OrderT;
00080         CBezierPatch    *bpatch= unpackIntoCache();
00081         // Get approximate position for the tile (usefull for noise). NB: eval() is faster than computeVertex().
00082         CVector         tilePos= bpatch->eval(tileU, tileV);
00083         // Get also the normal used for all instances on this tile (not precise, 
00084         // don't take noise into account, but faster).
00085         CVector         tileNormal= bpatch->evalNormal(tileU, tileV);
00086 
00087         // Compute also position on middle of 4 edges of this tile, for generateGroupBiLinear().
00088         CVector         tilePosBiLinear[4];
00089         float           OOos= 1.0f / OrderS;
00090         float           OOot= 1.0f / OrderT;
00091         tilePosBiLinear[0]= bpatch->eval( (ts + 0.0f) * OOos, (tt + 0.5f) * OOot);
00092         tilePosBiLinear[1]= bpatch->eval( (ts + 1.0f) * OOos, (tt + 0.5f) * OOot);
00093         tilePosBiLinear[2]= bpatch->eval( (ts + 0.5f) * OOos, (tt + 0.0f) * OOot);
00094         tilePosBiLinear[3]= bpatch->eval( (ts + 0.5f) * OOos, (tt + 1.0f) * OOot);
00095 
00096 
00097         // compute a rotation matrix with the normal
00098         CMatrix         matInstance;
00099         matInstance.setRot(CVector::I, CVector::J, tileNormal);
00100         // must normalize the matrix. use the vector which is the most orthogonal to tileNormal
00101         // If tileNormal is much more a J vector, then use plane (I,tileNormal), and vice-versa
00102         if(fabs(tileNormal.y) > fabs(tileNormal.x))
00103                 matInstance.normalize(CMatrix::ZXY);
00104         else
00105                 matInstance.normalize(CMatrix::ZYX);
00106 
00107 
00108         // prepare color / lighting
00109         // =========================
00110 
00111         // say that ambient never change. VegetableManager handle the ambient and diffuse itself (for precomputeLighting)
00112         CRGBAF  ambientF= CRGBAF(1,1,1,1);
00113 
00114         // Compute the tileLightmap (not modified by tileColor).
00115         static  uint8   tileLumelmap[NL_LUMEL_BY_TILE * NL_LUMEL_BY_TILE];
00116         getTileLumelmapPrecomputed(ts, tt, tileLumelmap, NL_LUMEL_BY_TILE);
00117         // compute diffuse color by substracting from ambient.
00118         CRGBAF  diffuseColorF[NL_LUMEL_BY_TILE * NL_LUMEL_BY_TILE];
00119         // TODO_VEGET_OPTIM: optimize this.
00120         // For all lumel of this tile.
00121         for(i= 0; i<NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE; i++)
00122         {
00123                 // mul by 2, because shade is done twice here: by vertex, and by landscape.
00124                 sint    tileLumel= 2*tileLumelmap[i];
00125                 tileLumel= min(tileLumel, 255);
00126                 float   tlf= tileLumel / 255.f;
00127                 diffuseColorF[i].R= tlf;
00128                 diffuseColorF[i].G= tlf;
00129                 diffuseColorF[i].B= tlf;
00130                 diffuseColorF[i].A= 1;
00131         }
00132 
00133         // Compute The CVegetableLightEx, adding pointLight effect to vegetation
00134         // First get pointLight at this tiles.
00135         static  vector<CPointLightInfluence>    lightList;
00136         lightList.clear();
00137         appendTileLightInfluences( CUV(tileU, tileV), lightList);
00138         // for each light, modulate the factor of influence
00139         for(i=0; i<lightList.size();i++)
00140         {
00141                 CPointLight     *pl= lightList[i].PointLight;
00142                 // compute the attenuation to the pos of the tile
00143                 float   att= pl->computeLinearAttenuation(tilePos);
00144                 // modulate the influence with this factor
00145                 lightList[i].BkupInfluence= lightList[i].Influence;
00146                 lightList[i].Influence*= att;
00147         }
00148         // sort the light by influence
00149         sort(lightList.begin(), lightList.end());
00150         // Setup the vegetLex directly in the ig. 
00151         CVegetableLightEx       &vegetLex= vegetIg->VegetableLightEx;
00152         // take only 2 first, computing direction to tilePos and computing attenuation.
00153         vegetLex.NumLights= min((uint)CVegetableLightEx::MaxNumLight, lightList.size());
00154         for(i=0;i<vegetLex.NumLights;i++)
00155         {
00156                 CPointLight     *pl= lightList[i].PointLight;
00157                 // copy to vegetLex.
00158                 vegetLex.PointLight[i]= pl;
00159                 // get the attenuation
00160                 vegetLex.PointLightFactor[i]= (uint)(256* lightList[i].Influence);
00161                 // Setup the direction from pointLight.
00162                 vegetLex.Direction[i]= tilePos - pl->getPosition();
00163                 vegetLex.Direction[i].normalize();
00164         }
00165         // compute now the current colors of the vegetLex.
00166         vegetLex.computeCurrentColors();
00167 
00168 
00169         // Compute Dynamic Lightmap UV for this tile.
00170         nlassert(_DLMContext);
00171         CUV             dlmUV;
00172         // get coordinate in 0..1 in texture.
00173         dlmUV.U= _DLMContext->DLMUBias + _DLMContext->DLMUScale * tileU;
00174         dlmUV.V= _DLMContext->DLMVBias + _DLMContext->DLMVScale * tileV;
00175         // get coordinate in 0..255.
00176         CVegetableUV8   dlmUV8;
00177         dlmUV8.U= (uint8)OptFastFloor(dlmUV.U * 255 + 0.5f);
00178         dlmUV8.V= (uint8)OptFastFloor(dlmUV.V * 255 + 0.5f);
00179         // bound them, ensuring 8Bits UV "uncompressed" by driver are in the lightmap area.
00180         clamp(dlmUV8.U, _DLMContext->MinU8, _DLMContext->MaxU8);
00181         clamp(dlmUV8.V, _DLMContext->MinV8, _DLMContext->MaxV8);
00182 
00183 
00184         // for all vegetable of this list, generate instances.
00185         // =========================
00186 
00187         // Get an array for each vegetable (static for speed).
00188         typedef         std::vector<NLMISC::CVector2f>  TPositionVector;
00189         static  std::vector<TPositionVector>    instanceUVArray;
00190         // realloc if necessary.
00191         if(instanceUVArray.size() < numVegetable)
00192         {
00193                 // clean.
00194                 contReset(instanceUVArray);
00195                 // realloc.
00196                 instanceUVArray.resize(numVegetable);
00197         }
00198 
00199         // First, for each vegetable, generate the number of instance to create, and their relative position.
00200         for(i= 0; i<numVegetable; i++)
00201         {
00202                 // get the vegetable
00203                 const CVegetable        &veget= vegetableList[i];
00204 
00205                 // generate instance for this vegetable.
00206                 veget.generateGroupBiLinear(tilePos, tilePosBiLinear, tileNormal, NL3D_PATCH_TILE_AREA, i + distAddSeed, instanceUVArray[i]);
00207         }
00208 
00209         // Then, now that we kno how many instance to generate for each vegetable, reserve space.
00210         CVegetableInstanceGroupReserve  vegetIgReserve;
00211         for(i= 0; i<numVegetable; i++)
00212         {
00213                 // get the vegetable
00214                 const CVegetable        &veget= vegetableList[i];
00215 
00216                 // reseve instance space for this vegetable.
00217                 // instanceUVArray[i].size() is the number of instances to create.
00218                 veget.reserveIgAddInstances(vegetIgReserve, (CVegetable::TVegetableWater)vegetWaterState, instanceUVArray[i].size());
00219         }
00220         // actual reseve memory of the ig.
00221         getLandscape()->_VegetableManager->reserveIgCompile(vegetIg, vegetIgReserve);
00222 
00223 
00224         // generate the instances for all the vegetables.
00225         for(i= 0; i<numVegetable; i++)
00226         {
00227                 // get the vegetable
00228                 const CVegetable        &veget= vegetableList[i];
00229 
00230                 // get the relatives position of the instances
00231                 std::vector<CVector2f>  &instanceUV= instanceUVArray[i];
00232 
00233                 // For all instance, generate the real instances.
00234                 for(uint j=0; j<instanceUV.size(); j++)
00235                 {
00236                         // generate the position in world Space.
00237                         // instanceUV is in [0..1] interval, which maps to a tile, so explode to the patch
00238                         CVector         instancePos;
00239                         vbCreateCtx.eval(ts, tt, instanceUV[j].x, instanceUV[j].y, instancePos);
00240                         // NB: use same normal for rotation for all instances in a same tile.
00241                         matInstance.setPos( instancePos );
00242 
00243                         // peek color into the lightmap.
00244                         sint    lumelS= OptFastFloor(instanceUV[j].x * NL_LUMEL_BY_TILE);
00245                         sint    lumelT= OptFastFloor(instanceUV[j].y * NL_LUMEL_BY_TILE);
00246                         clamp(lumelS, 0, NL_LUMEL_BY_TILE-1);
00247                         clamp(lumelT, 0, NL_LUMEL_BY_TILE-1);
00248 
00249                         // generate the instance of the vegetable
00250                         veget.generateInstance(vegetIg, matInstance, ambientF, 
00251                                 diffuseColorF[ (lumelT<<NL_LUMEL_BY_TILE_SHIFT) + lumelS ],
00252                                 (distType+1) * NL3D_VEGETABLE_BLOCK_ELTDIST, (CVegetable::TVegetableWater)vegetWaterState, dlmUV8);
00253                 }
00254         }
00255 }
00256 
00257 
00258 // ***************************************************************************
00259 void    CPatch::recreateAllVegetableIgs()
00260 {
00261         // For all TessBlocks, try to release their VegetableBlock
00262         for(uint numtb=0; numtb<TessBlocks.size(); numtb++)
00263         {
00264                 // if the vegetableBlock is deleted, and if there is at least one Material in the tessBlock, and if possible
00265                 if( TessBlocks[numtb].VegetableBlock==NULL && TessBlocks[numtb].TileMaterialRefCount>0
00266                         && getLandscape()->isVegetableActive())
00267                 {
00268                         // compute tessBlock coordinate
00269                         uint tbWidth= OrderS>>1;
00270                         uint ts= numtb&(tbWidth-1);
00271                         uint tt= numtb/tbWidth;
00272                         // crate the vegetable with tilecooridante (ie tessBlock coord *2);
00273                         createVegetableBlock(numtb, ts*2, tt*2);
00274                 }
00275         }
00276 
00277 }
00278 
00279 
00280 // ***************************************************************************
00281 void    CPatch::deleteAllVegetableIgs()
00282 {
00283         // For all TessBlocks, try to release their VegetableBlock
00284         for(uint i=0; i<TessBlocks.size(); i++)
00285         {
00286                 releaseVegetableBlock(i);
00287         }
00288 
00289 }
00290 
00291 
00292 // ***************************************************************************
00293 void            CPatch::createVegetableBlock(uint numTb, uint ts, uint tt)
00294 {
00295         // TessBlock width
00296         uint    tbWidth= OrderS >> 1;
00297         // clipBlock width
00298         uint    nTbPerCb= NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK;
00299         uint    cbWidth= (tbWidth + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
00300 
00301         // compute tessBlock coordinate.
00302         uint    tbs ,tbt;
00303         tbs= ts >> 1;
00304         tbt= tt >> 1;
00305         // compute clipBlock coordinate.
00306         uint    cbs,cbt;
00307         cbs= tbs >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
00308         cbt= tbt >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
00309 
00310         // create the vegetable block.
00311         CLandscapeVegetableBlock                *vegetBlock= new CLandscapeVegetableBlock;
00312         // Init / append to list.
00313         // compute center of the vegetableBlock (approx).
00314         CBezierPatch    *bpatch= unpackIntoCache();
00315         CVector         center= bpatch->eval( (float)(tbs*2+1)/OrderS, (float)(tbt*2+1)/OrderT );
00316         // Lower-Left tile is (tbs*2, tbt*2)
00317         vegetBlock->init(center, getLandscape()->_VegetableManager, VegetableClipBlocks[cbt *cbWidth + cbs], this, tbs*2, tbt*2, getLandscape()->_VegetableBlockList);
00318 
00319         // set in the tessBlock
00320         TessBlocks[numTb].VegetableBlock= vegetBlock;
00321 }
00322 
00323 
00324 // ***************************************************************************
00325 void            CPatch::releaseVegetableBlock(uint numTb)
00326 {
00327         // if exist, must delete the VegetableBlock.
00328         if(TessBlocks[numTb].VegetableBlock)
00329         {
00330                 // delete Igs, and remove from list.
00331                 TessBlocks[numTb].VegetableBlock->release(getLandscape()->_VegetableManager, getLandscape()->_VegetableBlockList);
00332                 // delete.
00333                 delete TessBlocks[numTb].VegetableBlock;
00334                 TessBlocks[numTb].VegetableBlock= NULL;
00335         }
00336 }
00337 
00338 
00339 
00340 
00341 
00342 } // NL3D