1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
28 using namespace NLMISC
;
38 // ***************************************************************************
40 Distances type squared.
45 static float Array
[NL3D_VEGETABLE_BLOCK_NUMDIST
+1];
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
¢er
, CVegetableManager
*vegetManager
,
84 CVegetableClipBlock
*vegetableClipBlock
, CPatch
*patch
, uint ts
, uint tt
, CTessList
<CLandscapeVegetableBlock
> &vblist
)
88 _VegetableClipBlock
= vegetableClipBlock
;
93 // Create the Vegetable SortBlocks
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
);
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
;
134 if(_VegetableSortBlock
[j
])
136 vegeManager
->deleteSortBlock(_VegetableSortBlock
[j
]);
137 _VegetableSortBlock
[j
]= NULL
;
142 _CurDistType
= NL3D_VEGETABLE_BLOCK_NUMDIST
;
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
])
159 while(newDistType
<NL3D_VEGETABLE_BLOCK_NUMDIST
&& sqrDist
>CLVBSqrDistLUT::Array
[newDistType
+1])
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
)
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
);
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
);
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
)
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.
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
;
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()
277 // ***************************************************************************
278 void CLandscapeVegetableBlockCreateContext::init(CPatch
*patch
, uint ts
, uint 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 // ==================
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();
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
);
316 // Eval, with simple bilinear
317 // ==================
318 nlassert(ts
==_Ts
|| ts
==_Ts
+1);
319 nlassert(tt
==_Tt
|| tt
==_Tt
+1);
328 float dxdy
= (1-x
)*(1-y
);
329 float dx2dy
= x
*(1-y
);
330 float dxdy2
= (1-x
)*y
;
334 pos
= _Pos
[v00
] * dxdy
;
335 pos
+= _Pos
[v10
] * dx2dy
;
336 pos
+= _Pos
[v01
] * dxdy2
;
337 pos
+= _Pos
[v11
] * dx2dy2
;