Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / patch_vegetable.cpp
blob385b6f6157328fd44b665f7484e0111f4000deea
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
20 #include "nel/3d/patch.h"
21 #include "nel/3d/vegetable.h"
22 #include "nel/3d/vegetable_manager.h"
23 #include "nel/3d/landscape_vegetable_block.h"
24 #include "nel/3d/landscape.h"
25 #include "nel/misc/vector.h"
26 #include "nel/misc/common.h"
27 #include "nel/misc/fast_floor.h"
28 #include "nel/3d/tile_vegetable_desc.h"
29 #include "nel/3d/vegetable_light_ex.h"
30 #include "nel/3d/patchdlm_context.h"
33 using namespace std;
34 using namespace NLMISC;
36 #ifdef DEBUG_NEW
37 #define new DEBUG_NEW
38 #endif
40 namespace NL3D
44 // ***************************************************************************
45 void CPatch::generateTileVegetable(CVegetableInstanceGroup *vegetIg, uint distType, uint ts, uint tt,
46 CLandscapeVegetableBlockCreateContext &vbCreateCtx)
48 uint i;
50 // Get tile infos for vegetable
51 // =========================
53 // Get the state for this vegetable tile
54 CTileElement::TVegetableInfo vegetWaterState= Tiles[tt * OrderS + ts].getVegetableState();
55 // If vegetable disabled, skip!
56 if(vegetWaterState == CTileElement::VegetableDisabled)
57 return;
59 // get the tileId under this tile (<=> the tile material)
60 uint tileId= Tiles[tt * OrderS + ts].Tile[0];
62 // get list of vegetable for this tile, and for hist distanceType category.
63 const CTileVegetableDesc &tileVegetDesc= getLandscape()->getTileVegetableDesc(tileId);
64 const std::vector<CVegetable> &vegetableList= tileVegetDesc.getVegetableList(distType);
65 uint distAddSeed= tileVegetDesc.getVegetableSeed(distType);
66 uint numVegetable= (uint)vegetableList.size();
68 // If no vegetables at all, skip.
69 if(numVegetable==0)
70 return;
72 // If any layer (2nd or 3rd) is set, but has no vegetable, then skip too
73 // This is to ensure "no vegetable under buildings".
74 if( Tiles[tt * OrderS + ts].Tile[1]!=NL_TILE_ELM_LAYER_EMPTY )
76 uint tileId1= Tiles[tt * OrderS + ts].Tile[1];
77 uint tileId2= Tiles[tt * OrderS + ts].Tile[2];
78 // NB: test distType
79 if(getLandscape()->getTileVegetableDesc(tileId1).empty())
80 return;
81 if(tileId2!=NL_TILE_ELM_LAYER_EMPTY && getLandscape()->getTileVegetableDesc(tileId2).empty())
82 return;
86 // compute approximate tile position and normal: get the middle
87 float tileU= (ts + 0.5f) / (float)OrderS;
88 float tileV= (tt + 0.5f) / (float)OrderT;
89 CBezierPatch *bpatch= unpackIntoCache();
90 // Get approximate position for the tile (useful for noise). NB: eval() is faster than computeVertex().
91 CVector tilePos= bpatch->eval(tileU, tileV);
92 // Get also the normal used for all instances on this tile (not precise,
93 // don't take noise into account, but faster).
94 CVector tileNormal= bpatch->evalNormal(tileU, tileV);
96 // Compute also position on middle of 4 edges of this tile, for generateGroupBiLinear().
97 CVector tilePosBiLinear[4];
98 float OOos= 1.0f / OrderS;
99 float OOot= 1.0f / OrderT;
100 tilePosBiLinear[0]= bpatch->eval( (ts + 0.0f) * OOos, (tt + 0.5f) * OOot);
101 tilePosBiLinear[1]= bpatch->eval( (ts + 1.0f) * OOos, (tt + 0.5f) * OOot);
102 tilePosBiLinear[2]= bpatch->eval( (ts + 0.5f) * OOos, (tt + 0.0f) * OOot);
103 tilePosBiLinear[3]= bpatch->eval( (ts + 0.5f) * OOos, (tt + 1.0f) * OOot);
106 // compute a rotation matrix with the normal
107 CMatrix matInstance;
108 matInstance.setRot(CVector::I, CVector::J, tileNormal);
109 // must normalize the matrix. use the vector which is the most orthogonal to tileNormal
110 // If tileNormal is much more a J vector, then use plane (I,tileNormal), and vice-versa
111 if(fabs(tileNormal.y) > fabs(tileNormal.x))
112 matInstance.normalize(CMatrix::ZXY);
113 else
114 matInstance.normalize(CMatrix::ZYX);
117 // prepare color / lighting
118 // =========================
120 // say that ambient never change. VegetableManager handle the ambient and diffuse itself (for precomputeLighting)
121 CRGBAF ambientF= CRGBAF(1,1,1,1);
123 // Compute the tileLightmap (not modified by tileColor).
124 static uint8 tileLumelmap[NL_LUMEL_BY_TILE * NL_LUMEL_BY_TILE];
125 getTileLumelmapPrecomputed(ts, tt, tileLumelmap, NL_LUMEL_BY_TILE);
126 // compute diffuse color by substracting from ambient.
127 CRGBAF diffuseColorF[NL_LUMEL_BY_TILE * NL_LUMEL_BY_TILE];
128 // TODO_VEGET_OPTIM: optimize this.
129 // For all lumel of this tile.
130 for(i= 0; i<NL_LUMEL_BY_TILE*NL_LUMEL_BY_TILE; i++)
132 // mul by 2, because shade is done twice here: by vertex, and by landscape.
133 sint tileLumel= 2*tileLumelmap[i];
134 tileLumel= min(tileLumel, 255);
135 float tlf= tileLumel / 255.f;
136 diffuseColorF[i].R= tlf;
137 diffuseColorF[i].G= tlf;
138 diffuseColorF[i].B= tlf;
139 diffuseColorF[i].A= 1;
142 // Compute The CVegetableLightEx, adding pointLight effect to vegetation
143 // First get pointLight at this tiles.
144 static vector<CPointLightInfluence> lightList;
145 lightList.clear();
146 appendTileLightInfluences( CUV(tileU, tileV), lightList);
147 // for each light, modulate the factor of influence
148 for(i=0; i<lightList.size();i++)
150 CPointLight *pl= lightList[i].PointLight;
151 // compute the attenuation to the pos of the tile
152 float att= pl->computeLinearAttenuation(tilePos);
153 // modulate the influence with this factor
154 lightList[i].BkupInfluence= lightList[i].Influence;
155 lightList[i].Influence*= att;
157 // sort the light by influence
158 sort(lightList.begin(), lightList.end());
159 // Setup the vegetLex directly in the ig.
160 CVegetableLightEx &vegetLex= vegetIg->VegetableLightEx;
161 // take only 2 first, computing direction to tilePos and computing attenuation.
162 vegetLex.NumLights= min((uint)CVegetableLightEx::MaxNumLight, (uint)lightList.size());
163 for(i=0;i<vegetLex.NumLights;i++)
165 // WARNING: can C cast to CPointLightNamed here because comes from CPatch::appendTileLightInfluences() only!
166 CPointLightNamed *pl= (CPointLightNamed*)(lightList[i].PointLight);
167 // copy to vegetLex.
168 vegetLex.PointLight[i]= pl;
169 // get the attenuation
170 vegetLex.PointLightFactor[i]= (uint)(256* lightList[i].Influence);
171 // Setup the direction from pointLight.
172 vegetLex.Direction[i]= tilePos - pl->getPosition();
173 vegetLex.Direction[i].normalize();
175 // compute now the current colors of the vegetLex.
176 vegetLex.computeCurrentColors();
179 // Compute Dynamic Lightmap UV for this tile.
180 nlassert(_DLMContext);
181 CUV dlmUV;
182 // get coordinate in 0..1 in texture.
183 dlmUV.U= _DLMContext->DLMUBias + _DLMContext->DLMUScale * tileU;
184 dlmUV.V= _DLMContext->DLMVBias + _DLMContext->DLMVScale * tileV;
185 // get coordinate in 0..255.
186 CVegetableUV8 dlmUV8;
187 dlmUV8.U= (uint8)NLMISC::OptFastFloor(dlmUV.U * 255 + 0.5f);
188 dlmUV8.V= (uint8)NLMISC::OptFastFloor(dlmUV.V * 255 + 0.5f);
189 // bound them, ensuring 8Bits UV "uncompressed" by driver are in the lightmap area.
190 clamp(dlmUV8.U, _DLMContext->MinU8, _DLMContext->MaxU8);
191 clamp(dlmUV8.V, _DLMContext->MinV8, _DLMContext->MaxV8);
194 // for all vegetable of this list, generate instances.
195 // =========================
197 // Get an array for each vegetable (static for speed).
198 typedef std::vector<NLMISC::CVector2f> TPositionVector;
199 static std::vector<TPositionVector> instanceUVArray;
200 // realloc if necessary.
201 if(instanceUVArray.size() < numVegetable)
203 // clean.
204 contReset(instanceUVArray);
205 // realloc.
206 instanceUVArray.resize(numVegetable);
209 // First, for each vegetable, generate the number of instance to create, and their relative position.
210 for(i= 0; i<numVegetable; i++)
212 // get the vegetable
213 const CVegetable &veget= vegetableList[i];
215 // generate instance for this vegetable.
216 veget.generateGroupBiLinear(tilePos, tilePosBiLinear, tileNormal, NL3D_PATCH_TILE_AREA, i + distAddSeed, instanceUVArray[i]);
219 // Then, now that we kno how many instance to generate for each vegetable, reserve space.
220 CVegetableInstanceGroupReserve vegetIgReserve;
221 for(i= 0; i<numVegetable; i++)
223 // get the vegetable
224 const CVegetable &veget= vegetableList[i];
226 // reseve instance space for this vegetable.
227 // instanceUVArray[i].size() is the number of instances to create.
228 veget.reserveIgAddInstances(vegetIgReserve, (CVegetable::TVegetableWater)vegetWaterState, (uint)instanceUVArray[i].size());
230 // actual reseve memory of the ig.
231 getLandscape()->_VegetableManager->reserveIgCompile(vegetIg, vegetIgReserve);
234 // generate the instances for all the vegetables.
235 for(i= 0; i<numVegetable; i++)
237 // get the vegetable
238 const CVegetable &veget= vegetableList[i];
240 // get the relatives position of the instances
241 std::vector<CVector2f> &instanceUV= instanceUVArray[i];
243 // For all instance, generate the real instances.
244 for(uint j=0; j<instanceUV.size(); j++)
246 // generate the position in world Space.
247 // instanceUV is in [0..1] interval, which maps to a tile, so explode to the patch
248 CVector instancePos;
249 vbCreateCtx.eval(ts, tt, instanceUV[j].x, instanceUV[j].y, instancePos);
250 // NB: use same normal for rotation for all instances in a same tile.
251 matInstance.setPos( instancePos );
253 // peek color into the lightmap.
254 sint lumelS= NLMISC::OptFastFloor(instanceUV[j].x * NL_LUMEL_BY_TILE);
255 sint lumelT= NLMISC::OptFastFloor(instanceUV[j].y * NL_LUMEL_BY_TILE);
256 clamp(lumelS, 0, NL_LUMEL_BY_TILE-1);
257 clamp(lumelT, 0, NL_LUMEL_BY_TILE-1);
259 // generate the instance of the vegetable
260 veget.generateInstance(vegetIg, matInstance, ambientF,
261 diffuseColorF[ (lumelT<<NL_LUMEL_BY_TILE_SHIFT) + lumelS ],
262 (distType+1) * NL3D_VEGETABLE_BLOCK_ELTDIST, (CVegetable::TVegetableWater)vegetWaterState, dlmUV8);
268 // ***************************************************************************
269 void CPatch::recreateAllVegetableIgs()
271 // For all TessBlocks, try to release their VegetableBlock
272 for(uint numtb=0; numtb<TessBlocks.size(); numtb++)
274 // if the vegetableBlock is deleted, and if there is at least one Material in the tessBlock, and if possible
275 if( TessBlocks[numtb].VegetableBlock==NULL && TessBlocks[numtb].TileMaterialRefCount>0
276 && getLandscape()->isVegetableActive())
278 // compute tessBlock coordinate
279 uint tbWidth= OrderS>>1;
280 uint ts= numtb&(tbWidth-1);
281 uint tt= numtb/tbWidth;
282 // crate the vegetable with tilecooridante (ie tessBlock coord *2);
283 createVegetableBlock(numtb, ts*2, tt*2);
290 // ***************************************************************************
291 void CPatch::deleteAllVegetableIgs()
293 // For all TessBlocks, try to release their VegetableBlock
294 for(uint i=0; i<TessBlocks.size(); i++)
296 releaseVegetableBlock(i);
302 // ***************************************************************************
303 void CPatch::createVegetableBlock(uint numTb, uint ts, uint tt)
305 // TessBlock width
306 uint tbWidth= OrderS >> 1;
307 // clipBlock width
308 uint nTbPerCb= NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK;
309 uint cbWidth= (tbWidth + nTbPerCb-1) >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
311 // compute tessBlock coordinate.
312 uint tbs ,tbt;
313 tbs= ts >> 1;
314 tbt= tt >> 1;
315 // compute clipBlock coordinate.
316 uint cbs,cbt;
317 cbs= tbs >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
318 cbt= tbt >> NL3D_PATCH_VEGETABLE_NUM_TESSBLOCK_PER_CLIPBLOCK_SHIFT;
320 // create the vegetable block.
321 CLandscapeVegetableBlock *vegetBlock= new CLandscapeVegetableBlock;
322 // Init / append to list.
323 // compute center of the vegetableBlock (approx).
324 CBezierPatch *bpatch= unpackIntoCache();
325 CVector center= bpatch->eval( (float)(tbs*2+1)/OrderS, (float)(tbt*2+1)/OrderT );
326 // Lower-Left tile is (tbs*2, tbt*2)
327 vegetBlock->init(center, getLandscape()->_VegetableManager, VegetableClipBlocks[cbt *cbWidth + cbs], this, tbs*2, tbt*2, getLandscape()->_VegetableBlockList);
329 // set in the tessBlock
330 TessBlocks[numTb].VegetableBlock= vegetBlock;
334 // ***************************************************************************
335 void CPatch::releaseVegetableBlock(uint numTb)
337 // if exist, must delete the VegetableBlock.
338 if(TessBlocks[numTb].VegetableBlock)
340 // delete Igs, and remove from list.
341 TessBlocks[numTb].VegetableBlock->release(getLandscape()->_VegetableManager, getLandscape()->_VegetableBlockList);
342 // delete.
343 delete TessBlocks[numTb].VegetableBlock;
344 TessBlocks[numTb].VegetableBlock= NULL;
352 } // NL3D