Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / landscape_vegetable_block.cpp
blobec015916bc3e491624b06b70c7ed958c205d6656
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"
19 #include "nel/3d/landscape_vegetable_block.h"
20 #include "nel/3d/vegetable_manager.h"
21 #include "nel/3d/vegetable_clip_block.h"
22 #include "nel/3d/vegetable_instance_group.h"
23 #include "nel/3d/patch.h"
24 #include "nel/3d/bezier_patch.h"
27 using namespace std;
28 using namespace NLMISC;
30 #ifdef DEBUG_NEW
31 #define new DEBUG_NEW
32 #endif
34 namespace NL3D
38 // ***************************************************************************
40 Distances type squared.
42 class CLVBSqrDistLUT
44 public:
45 static float Array[NL3D_VEGETABLE_BLOCK_NUMDIST+1];
47 CLVBSqrDistLUT()
49 // 0, 10, 20, 30, 40, 50
50 for(uint i=0;i<NL3D_VEGETABLE_BLOCK_NUMDIST+1;i++)
52 Array[i]= i*NL3D_VEGETABLE_BLOCK_ELTDIST;
53 Array[i]= sqr(Array[i]);
60 CLVBSqrDistLUT NL3D_InitSqrDistLUT;
61 float CLVBSqrDistLUT::Array[NL3D_VEGETABLE_BLOCK_NUMDIST+1];
64 // ***************************************************************************
65 CLandscapeVegetableBlock::CLandscapeVegetableBlock()
67 _VegetableClipBlock= NULL;
68 _CurDistType= NL3D_VEGETABLE_BLOCK_NUMDIST;
70 for(uint j=0;j<NL3D_TESSBLOCK_TILESIZE;j++)
72 _VegetableSortBlock[j]= NULL;
73 for(uint i=0;i<NL3D_VEGETABLE_BLOCK_NUMDIST;i++)
75 _VegetableIG[j][i]= NULL;
82 // ***************************************************************************
83 void CLandscapeVegetableBlock::init(const CVector &center, CVegetableManager *vegetManager,
84 CVegetableClipBlock *vegetableClipBlock, CPatch *patch, uint ts, uint tt, CTessList<CLandscapeVegetableBlock> &vblist)
86 nlassert(patch);
87 _Center= center;
88 _VegetableClipBlock= vegetableClipBlock;
89 _Patch= patch;
90 _Ts= uint8(ts);
91 _Tt= uint8(tt);
93 // Create the Vegetable SortBlocks
94 sint tms,tmt;
95 // for all tiles
96 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
97 for(tmt= _Tt; tmt<_Tt+2; tmt++)
99 for(tms= _Ts; tms<_Ts+2; tms++)
101 // compute approximate center of the tile.
102 float s= (tms + 0.5f) / _Patch->getOrderS();
103 float t= (tmt + 0.5f) / _Patch->getOrderT();
104 CBezierPatch *bpatch= _Patch->unpackIntoCache();
105 CVector center= bpatch->eval(s, t);
107 // create the sortBlock. NB: very approximate SortBlock radius....
108 _VegetableSortBlock[(tmt-_Tt)*2 + (tms-_Ts)]= vegetManager->createSortBlock(_VegetableClipBlock, center, NL3D_PATCH_TILE_RADIUS);
112 // append to list.
113 vblist.append(this);
117 // ***************************************************************************
118 void CLandscapeVegetableBlock::release(CVegetableManager *vegeManager, CTessList<CLandscapeVegetableBlock> &vblist)
120 // release all Igs, and all Sbs.
121 for(uint j=0;j<NL3D_TESSBLOCK_TILESIZE;j++)
123 // release IGs first.
124 for(uint i=0;i<NL3D_VEGETABLE_BLOCK_NUMDIST;i++)
126 if(_VegetableIG[j][i])
128 vegeManager->deleteIg(_VegetableIG[j][i]);
129 _VegetableIG[j][i]= NULL;
133 // release SB
134 if(_VegetableSortBlock[j])
136 vegeManager->deleteSortBlock(_VegetableSortBlock[j]);
137 _VegetableSortBlock[j]= NULL;
141 // reset state.
142 _CurDistType= NL3D_VEGETABLE_BLOCK_NUMDIST;
144 // remove from list.
145 vblist.remove(this);
148 // ***************************************************************************
149 void CLandscapeVegetableBlock::update(const CVector &viewCenter, CVegetableManager *vegeManager)
151 float sqrDist= (viewCenter-_Center).sqrnorm();
153 // compute new distance type. Incremental mode.
154 uint newDistType= _CurDistType;
155 while(sqrDist<CLVBSqrDistLUT::Array[newDistType])
157 newDistType--;
159 while(newDistType<NL3D_VEGETABLE_BLOCK_NUMDIST && sqrDist>CLVBSqrDistLUT::Array[newDistType+1])
161 newDistType++;
164 NB: to test but may be better than
165 newDistType= floor()(delta.norm() / NL3D_VEGETABLE_BLOCK_ELTDIST);
169 // Change of distance type??
170 if(newDistType!=_CurDistType)
172 // Erase or create IGs.
173 if(newDistType>_CurDistType)
175 // For all tiles
176 for(uint j=0;j<NL3D_TESSBLOCK_TILESIZE;j++)
178 // Erase no more needed Igs.
179 for(uint i=_CurDistType; i<newDistType; i++)
181 if(_VegetableIG[j][i])
183 vegeManager->deleteIg(_VegetableIG[j][i]);
184 _VegetableIG[j][i]= NULL;
188 // update the sort block for this tile
189 _VegetableSortBlock[j]->updateSortBlock(*vegeManager);
192 else
194 // Create a context for creation.
195 CLandscapeVegetableBlockCreateContext ctx;
196 ctx.init(_Patch, _Ts, _Tt);
198 // create new Igs, for all tiles
199 for(uint i=newDistType; i<_CurDistType; i++)
201 createVegetableIGForDistType(i, vegeManager, ctx);
204 // For all tiles
205 for(uint j=0;j<NL3D_TESSBLOCK_TILESIZE;j++)
207 // update the sort block for this tile
208 _VegetableSortBlock[j]->updateSortBlock(*vegeManager);
212 // copy new dist type.
213 _CurDistType= uint8(newDistType);
220 // ***************************************************************************
221 void CLandscapeVegetableBlock::createVegetableIGForDistType(uint i, CVegetableManager *vegeManager,
222 CLandscapeVegetableBlockCreateContext &vbCreateCtx)
224 // check
225 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
226 nlassert(_VegetableIG[0][i]==NULL);
227 nlassert(_VegetableIG[1][i]==NULL);
228 nlassert(_VegetableIG[2][i]==NULL);
229 nlassert(_VegetableIG[3][i]==NULL);
231 // Create vegetables instances per tile_material.
232 sint tms,tmt;
233 // for all tiles
234 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
235 for(tmt= _Tt; tmt<_Tt+2; tmt++)
237 for(tms= _Ts; tms<_Ts+2; tms++)
239 uint tileId= tms-_Ts + (tmt-_Tt)*2;
241 // create the instance group in the good sortBlock
242 CVegetableInstanceGroup *vegetIg= vegeManager->createIg(_VegetableSortBlock[tileId]);
243 _VegetableIG[tileId][i]= vegetIg;
245 // generate
246 _Patch->generateTileVegetable(vegetIg, i, tms, tmt, vbCreateCtx);
248 // If the ig is empty, delete him. This optimize rendering because no useless ig are
249 // tested for rendering. This speed up some 1/10 of ms...
250 if(vegetIg->isEmpty())
252 vegeManager->deleteIg(vegetIg);
253 _VegetableIG[tileId][i]= NULL;
256 // NB: vegtable SortBlock is updated in CLandscapeVegetableBlock::update() after
263 // ***************************************************************************
264 // ***************************************************************************
265 // CLandscapeVegetableIGCreateContext
266 // ***************************************************************************
267 // ***************************************************************************
270 // ***************************************************************************
271 CLandscapeVegetableBlockCreateContext::CLandscapeVegetableBlockCreateContext()
273 _Patch= NULL;
277 // ***************************************************************************
278 void CLandscapeVegetableBlockCreateContext::init(CPatch *patch, uint ts, uint tt)
280 nlassert(patch);
281 _Empty= true;
282 _Patch= patch;
283 _Ts= ts;
284 _Tt= tt;
288 // ***************************************************************************
289 void CLandscapeVegetableBlockCreateContext::eval(uint ts, uint tt, float x, float y, CVector &pos)
291 nlassert(NL3D_TESSBLOCK_TILESIZE==4);
293 // If never created, do it now
294 // ==================
295 if(_Empty)
297 // Eval Position and normals for the 9 vertices (around the 2x2 tiles)
298 for(uint j=0; j<3;j++)
300 float t= (float)(_Tt+j)/_Patch->getOrderT();
301 for(uint i=0; i<3;i++)
303 float s= (float)(_Ts+i)/_Patch->getOrderS();
304 // eval position.
305 // use computeVertex() and not bpatch->eval() because vegetables must follow the
306 // noise (at least at tile precision...). It is slower but necessary.
307 _Pos[j*3+i]= _Patch->computeVertex(s, t);
311 // Ok, it's done
312 _Empty= false;
316 // Eval, with simple bilinear
317 // ==================
318 nlassert(ts==_Ts || ts==_Ts+1);
319 nlassert(tt==_Tt || tt==_Tt+1);
320 uint ds= ts-_Ts;
321 uint dt= tt-_Tt;
322 // Indices.
323 uint v00= dt*3 + ds;
324 uint v10= v00 + 1;
325 uint v01= v00 + 3;
326 uint v11= v00 + 4;
327 // BiLinearFactor.
328 float dxdy= (1-x)*(1-y);
329 float dx2dy= x*(1-y);
330 float dxdy2= (1-x)*y;
331 float dx2dy2= x*y;
333 // Compute Pos.
334 pos = _Pos[v00] * dxdy;
335 pos+= _Pos[v10] * dx2dy;
336 pos+= _Pos[v01] * dxdy2;
337 pos+= _Pos[v11] * dx2dy2;
341 } // NL3D