Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / quad_grid_clip_manager.cpp
blob0fe69e46e669b8771971db22ee2cf7faf136c8e0
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/quad_grid_clip_manager.h"
20 #include "nel/3d/scene.h"
21 #include "nel/3d/transform_shape.h"
22 #include "nel/3d/clip_trav.h"
23 #include "nel/misc/aabbox.h"
24 #include "nel/3d/cluster.h"
25 #include "nel/misc/hierarchical_timer.h"
28 using namespace std;
29 using namespace NLMISC;
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 namespace NL3D
39 // ***************************************************************************
40 void CQuadGridClipManager::registerBasic()
42 CScene::registerModel(QuadGridClipManagerId, TransformId, CQuadGridClipManager::creator);
46 // ***************************************************************************
47 CQuadGridClipManager::CQuadGridClipManager()
49 _ClusterSize= 0;
50 _X= _Y= 0;
51 _Width= _Height= 0;
53 // ***************************************************************************
54 CQuadGridClipManager::~CQuadGridClipManager()
56 reset();
60 // ***************************************************************************
61 void CQuadGridClipManager::init(float clusterSize, uint numDist, float maxDist, float radiusMax )
63 // reset first.
64 reset();
66 // copy params.
67 nlassert(clusterSize>0);
68 _ClusterSize= clusterSize;
69 _MaxDist= maxDist;
70 _NumDist= numDist;
71 _RadiusMax= radiusMax;
74 // ***************************************************************************
75 void CQuadGridClipManager::reset()
77 // delete the clusters.
78 if(getOwnerScene())
80 sint oldX0, oldX1, oldY0, oldY1;
82 oldX0= _X;
83 oldX1= _X+_Width;
84 oldY0= _Y;
85 oldY1= _Y+_Height;
87 for(sint y=oldY0; y<oldY1; y++)
89 for(sint x=oldX0; x<oldX1; x++)
91 deleteCaseModels(&getOwnerScene()->getClipTrav(), x,y);
95 // clear the grid.
96 _QuadGridClusterCases.clear();
99 // reset others params.
100 _ClusterSize= 0;
101 _X= _Y= 0;
102 _Width= _Height= 0;
105 // ***************************************************************************
106 void CQuadGridClipManager::updateClustersFromCamera(const CVector &camPos)
108 H_AUTO( NL3D_QuadClip_updateClusters );
110 CClipTrav *pClipTrav= &getOwnerScene()->getClipTrav();
112 sint newX0, newX1, newY0, newY1;
113 sint oldX0, oldX1, oldY0, oldY1;
115 oldX0= _X;
116 oldX1= _X+_Width;
117 oldY0= _Y;
118 oldY1= _Y+_Height;
120 // compute the new square of clusters to build.
121 newX0= (sint)floor( (camPos.x - _RadiusMax) / _ClusterSize);
122 newX1= (sint)ceil( (camPos.x + _RadiusMax) / _ClusterSize);
123 newY0= (sint)floor( (camPos.y - _RadiusMax) / _ClusterSize);
124 newY1= (sint)ceil( (camPos.y + _RadiusMax) / _ClusterSize);
126 // keep an histeresis of one cluster: do not delete "young" clusters created before.
127 if(newX0>= oldX0+1) // NB: if newX0==oldX0+1, then newX0= _X => no change.
128 newX0--;
129 if(newY0>= oldY0+1) // same reasoning.
130 newY0--;
131 if(newX1<= oldX1-1) // NB: if newX1==oldX1-1, then newX1= oldX1 => no change.
132 newX1++;
133 if(newY1<= oldY1-1) // same reasoning.
134 newY1++;
136 // Have we got to update the array.
137 if(newX0!=oldX0 || newX1!=oldX1 || newY0!=oldY0 || newY1!=oldY1)
139 sint x,y;
141 // delete olds models.
142 // simple: test all cases
143 for(y=oldY0; y<oldY1; y++)
145 for(x=oldX0; x<oldX1; x++)
147 // if out the new square?
148 if(x<newX0 || x>=newX1 || y<newY0 || y>=newY1)
149 deleteCaseModels(pClipTrav, x,y);
153 // build new array
154 // satic for alloc optimisation.
155 static vector<CQuadGridClipCluster*> newQuadGridClusterCases;
156 sint newWidth= newX1-newX0;
157 sint newHeight= newY1-newY0;
158 newQuadGridClusterCases.resize(newWidth * newHeight);
159 // simple: test all cases
160 for(y=newY0; y<newY1; y++)
162 for(x=newX0; x<newX1; x++)
164 CQuadGridClipCluster *&newCase= newQuadGridClusterCases[ (y-newY0)*newWidth + (x-newX0) ];
166 // if out the old square?
167 if(x<oldX0 || x>=oldX1 || y<oldY0 || y>=oldY1)
169 // build the 2D bbox where the models should fit.
170 CAABBox pivotBBox;
171 pivotBBox.setMinMax(
172 CVector(x*_ClusterSize,y*_ClusterSize,0),
173 CVector((x+1)*_ClusterSize,(y+1)*_ClusterSize,0) );
174 // build new case. Clusters are empty.
175 newCaseModels(newCase, pivotBBox);
177 else
179 // copy from old.
180 CQuadGridClipCluster *oldCase= _QuadGridClusterCases[ (y-_Y)*_Width + (x-_X) ];
182 newCase= oldCase;
187 // just copy from new.
188 _QuadGridClusterCases= newQuadGridClusterCases;
189 _X= newX0;
190 _Y= newY0;
191 _Width= newWidth;
192 _Height= newHeight;
197 // ***************************************************************************
198 bool CQuadGridClipManager::linkModel(CTransformShape *pTfmShp)
200 H_AUTO( NL3D_QuadClip_linkModel );
202 // use the position to get the cluster to use.
203 CAABBox box;
204 pTfmShp->getAABBox (box);
206 // Transform the box in the world
207 const CMatrix &wm = pTfmShp->getWorldMatrix();
208 // compute center in world.
209 CVector cLocal = box.getCenter();
210 CVector cWorld = wm * cLocal;
211 // prepare bbox.
212 CAABBox worldBBox;
213 worldBBox.setCenter(cWorld);
214 CVector hs = box.getHalfSize();
216 // For 8 corners.
217 for(uint i=0;i<8;i++)
219 CVector corner;
220 // compute the corner of the bbox.
221 corner= cLocal;
222 if(i&1) corner.x+=hs.x;
223 else corner.x-=hs.x;
224 if((i/2)&1) corner.y+=hs.y;
225 else corner.y-=hs.y;
226 if((i/4)&1) corner.z+=hs.z;
227 else corner.z-=hs.z;
228 // Transform the corner in world.
229 corner = wm * corner;
230 // Extend the bbox with it.
231 worldBBox.extend(corner);
235 // Position in the grid.
236 sint x,y;
237 x= (sint)floor( cWorld.x / _ClusterSize);
238 y= (sint)floor( cWorld.y / _ClusterSize);
240 // verify if IN the current grid of clusters created.
241 if( x>=_X && x<_X+_Width && y>=_Y && y<_Y+_Height )
243 // add the model and extend the bbox of this cluster.
244 CQuadGridClipCluster *cluster= _QuadGridClusterCases[ (y-_Y)*_Width + (x-_X) ];
246 // if this cluster is empty, add it now to the list of not empty (do the test before add)
247 if( cluster->isEmpty() )
249 _NotEmptyQuadGridClipClusters.insert(cluster, &cluster->ListNode);
252 // add the model => no more empty
253 cluster->addModel(worldBBox, pTfmShp);
255 return true;
257 else
259 return false;
265 // ***************************************************************************
266 void CQuadGridClipManager::deleteCaseModels(CClipTrav *pClipTrav, sint x, sint y)
268 H_AUTO( NL3D_QuadClip_deleteCaseModels );
270 nlassert(x>=_X && x<_X+_Width && y>=_Y && y<_Y+_Height);
272 CQuadGridClipCluster *cluster= _QuadGridClusterCases[ (y-_Y)*_Width + (x-_X) ];
274 // first, unlink all sons from cluster, and link thems to RootCluster.
275 cluster->resetSons(pClipTrav);
277 // delete the cluster. NB: auto-unlinked from _NotEmptyQuadGridClipClusters
278 delete cluster;
280 // NB: do not delete array for alloc/free optimisation.
284 // ***************************************************************************
285 void CQuadGridClipManager::newCaseModels(CQuadGridClipCluster *&cluster, const NLMISC::CAABBox &pivotBbox)
287 H_AUTO( NL3D_QuadClip_newCaseModels );
289 // create clusters.
290 cluster= new CQuadGridClipCluster(_NumDist, _MaxDist, pivotBbox);
294 // ***************************************************************************
295 void CQuadGridClipManager::traverseClip()
297 CClipTrav *pClipTrav= &getOwnerScene()->getClipTrav();
299 // Run All NotEmpty Clusters,
300 CQuadGridClipCluster **it;
301 it= _NotEmptyQuadGridClipClusters.begin();
302 uint numClusters= _NotEmptyQuadGridClipClusters.size();
303 for(;numClusters>0;numClusters--,it++)
305 (*it)->clip(pClipTrav);
310 // ***************************************************************************
311 void CQuadGridClipManager::profile() const
313 nlinfo(" ***** CQuadGridClipManager stats");
314 nlinfo(" There is %d clusters", _Width*_Height );
315 sint numEmptyClusters= 0;
316 float minAreaRatio= 1000;
317 float maxAreaRatio= 0;
318 float meanAreaRatio= 0;
320 // test all cases
321 for(sint y=0;y<_Height;y++)
323 for(sint x=0;x<_Width;x++)
325 const CQuadGridClipCluster *cluster= _QuadGridClusterCases[y*_Width+x];
326 if( cluster->isEmpty() )
327 numEmptyClusters++;
328 else
330 CAABBox bb= cluster->getBBox();
331 float area= (bb.getSize().x*bb.getSize().y) / (_ClusterSize*_ClusterSize);
332 meanAreaRatio+= area;
333 minAreaRatio= min( minAreaRatio, area);
334 maxAreaRatio= max( maxAreaRatio, area);
339 // display
340 if( numEmptyClusters==_Width*_Height )
342 nlinfo( " The ClipManager is completely Empty!!!!");
344 else
346 sint numClusters= _Width*_Height-numEmptyClusters;
347 nlinfo( " This Level has %d clusters not empty over %d", numClusters, _Width*_Height);
348 meanAreaRatio/= numClusters;
349 nlinfo(" . minAreaRatio= %f", minAreaRatio);
350 nlinfo(" . maxAreaRatio= %f", maxAreaRatio);
351 nlinfo(" . meanAreaRatio= %f", meanAreaRatio);
353 // Do Stats per distance setup
354 for(uint lvl=0;lvl<_NumDist+1;lvl++)
356 nlinfo(" * Stats for Distance up to %f m", lvl<_NumDist?(lvl+1)*_MaxDist/_NumDist:-1.0f);
357 sint minNumChildren= 100000000;
358 sint maxNumChildren= 0;
359 float meanNumChildren= 0;
360 sint totalNumChildren= 0;
362 // test all cases
363 for(sint y=0;y<_Height;y++)
365 for(sint x=0;x<_Width;x++)
367 const CQuadGridClipCluster *cluster= _QuadGridClusterCases[y*_Width+x];
368 if( cluster->isEmpty() )
369 numEmptyClusters++;
370 else
372 // count number of sons
373 sint numSons;
374 numSons= cluster->profileNumChildren(lvl);
375 meanNumChildren+= numSons;
376 totalNumChildren+= numSons;
377 minNumChildren= min( minNumChildren, numSons);
378 maxNumChildren= max( maxNumChildren, numSons);
383 // display
384 meanNumChildren/= numClusters;
385 nlinfo(" . minNumChildren= %d", minNumChildren);
386 nlinfo(" . maxNumChildren= %d", maxNumChildren);
387 nlinfo(" . meanNumChildren= %f", meanNumChildren);
388 nlinfo(" . totalNumChildren= %d", totalNumChildren);
394 } // NL3D