Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / pacs / surface_quad.cpp
blob308dc00549e083ff3108acbd86c8b9e6dc7602da
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 "stdpacs.h"
18 #include "nel/pacs/surface_quad.h"
20 #include "nel/misc/file.h"
22 #ifdef DEBUG_NEW
23 #define new DEBUG_NEW
24 #endif
26 using namespace NLMISC;
27 using namespace std;
29 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree()
31 _Root = NULL;
32 _MaxThickness = FLT_MAX;
33 _MaxLevel = 1;
34 _BBox.setCenter(CVector::Null);
35 _BBox.setSize(CVector::Null);
38 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree(const NLPACS::CSurfaceQuadTree &quad)
40 *this = quad;
43 NLPACS::CSurfaceQuadTree &NLPACS::CSurfaceQuadTree::operator = (const NLPACS::CSurfaceQuadTree &quad)
45 if (&quad == this)
46 return *this;
48 _MaxThickness = quad._MaxThickness;
49 _MaxLevel = quad._MaxLevel;
50 _BBox = quad._BBox;
52 _Root = NULL;
53 if (quad._Root != NULL)
55 if (quad._Root->isLeaf())
57 CQuadLeaf *newLeaf = new CQuadLeaf();
58 *newLeaf = *((CQuadLeaf *)(quad._Root));
59 _Root = newLeaf;
61 else
63 CQuadBranch *newBranch = new CQuadBranch();
64 *newBranch = *((CQuadBranch *)(quad._Root));
65 _Root = newBranch;
69 return *this;
72 void NLPACS::CSurfaceQuadTree::clear()
74 delete _Root;
75 _Root = NULL;
78 void NLPACS::CSurfaceQuadTree::init(float maxThickness, uint maxLevel, const CVector &center, float halfSize)
80 nlassert(maxLevel > 0);
81 clear();
82 _MaxThickness = maxThickness;
83 _MaxLevel = uint8(maxLevel);
84 _BBox.setCenter(center);
85 _BBox.setHalfSize(CVector(halfSize, halfSize, 10000.0f));
88 void NLPACS::CSurfaceQuadTree::addVertex(const CVector &v)
90 if (!_BBox.include(v))
91 return;
93 if (_Root == NULL)
95 if (_MaxLevel == 1)
97 _Root = new CQuadLeaf(_MaxLevel);
99 else
101 _Root = new CQuadBranch(_MaxLevel);
104 _Root->_MaxThickness = _MaxThickness;
105 _Root->_HalfSize = _BBox.getHalfSize().x;
106 _Root->_MinHeight = FLT_MAX;
107 _Root->_MaxHeight = -FLT_MAX;
108 _Root->_XCenter = _BBox.getCenter().x;
109 _Root->_YCenter = _BBox.getCenter().y;
112 _Root->addVertex(v);
115 void NLPACS::CSurfaceQuadTree::compile()
117 if (_Root != NULL &&
118 !_Root->isLeaf() &&
119 _Root->getMaxHeight()-_Root->getMinHeight() <= _MaxThickness)
121 CQuadLeaf *leaf = new CQuadLeaf();
122 *((IQuadNode *)leaf) = *_Root;
123 delete _Root;
124 _Root = leaf;
126 else if (_Root != NULL &&
127 !_Root->isLeaf())
129 ((CQuadBranch *)_Root)->reduceChildren();
134 NLPACS::CQuadBranch::CQuadBranch(const NLPACS::CQuadBranch &branch) : NLPACS::IQuadNode(branch)
136 *this = branch;
139 NLPACS::CQuadBranch &NLPACS::CQuadBranch::operator = (const NLPACS::CQuadBranch &branch)
141 IQuadNode::operator=(branch);
143 uint child;
144 for (child=0; child<4; ++child)
146 _Children[child] = NULL;
147 if (branch._Children[child] != NULL)
149 if (branch._Children[child]->isLeaf())
151 CQuadLeaf *newLeaf = new CQuadLeaf();
152 *newLeaf = *((CQuadLeaf *)(branch._Children[child]));
153 _Children[child] = newLeaf;
155 else
157 CQuadBranch *newBranch = new CQuadBranch();
158 *newBranch = *((CQuadBranch *)(branch._Children[child]));
159 _Children[child] = newBranch;
163 return *this;
166 void NLPACS::CQuadBranch::reduceChildren()
168 uint i;
170 for (i=0; i<4; ++i)
172 if (_Children[i] != NULL &&
173 !_Children[i]->isLeaf() &&
174 _Children[i]->getMaxHeight()-_Children[i]->getMinHeight() <= _MaxThickness)
176 CQuadLeaf *leaf = new CQuadLeaf();
177 *((IQuadNode *)leaf) = *_Children[i];
178 delete _Children[i];
179 _Children[i] = leaf;
181 else if (_Children[i] != NULL &&
182 !_Children[i]->isLeaf())
184 ((CQuadBranch *)_Children[i])->reduceChildren();
189 void NLPACS::CQuadBranch::addVertex(const CVector &v)
191 IQuadNode::addVertex(v);
192 uint child;
193 if (v.x > _XCenter)
194 child = (v.y > _YCenter) ? 2 : 1;
195 else
196 child = (v.y > _YCenter) ? 3 : 0;
198 if (_Children[child] == NULL)
200 if (_Level == 2)
202 _Children[child] = new CQuadLeaf(_Level-1);
204 else
206 _Children[child] = new CQuadBranch(_Level-1);
209 _Children[child]->_MaxThickness = _MaxThickness;
210 _Children[child]->_HalfSize = _HalfSize/2.0f;
211 _Children[child]->_MinHeight = FLT_MAX;
212 _Children[child]->_MaxHeight = -FLT_MAX;
213 _Children[child]->_XCenter = _XCenter+_Children[child]->_HalfSize*((child == 1 || child == 2) ? 1.0f : -1.0f);
214 _Children[child]->_YCenter = _YCenter+_Children[child]->_HalfSize*((child == 2 || child == 3) ? 1.0f : -1.0f);
217 _Children[child]->addVertex(v);
220 bool NLPACS::CQuadBranch::check() const
222 if (!IQuadNode::check())
223 return false;
225 uint child;
226 for (child=0; child<4; ++child)
227 if (_Children[child] != NULL && !_Children[child]->check())
228 return false;
229 return true;
234 * Serialization methods...
238 void NLPACS::CQuadBranch::serial(NLMISC::IStream &f)
240 IQuadNode::serial(f);
242 uint child;
243 for (child=0; child<4; ++child)
245 uint8 childType = 0;
247 if (f.isReading())
249 CQuadLeaf *leaf;
250 CQuadBranch *branch;
251 f.serial(childType);
252 switch (childType)
254 case NoChild:
255 _Children[child] = NULL;
256 break;
257 case LeafChild:
258 leaf = new CQuadLeaf();
259 _Children[child] = leaf;
260 leaf->serial(f);
261 break;
262 case BranchChild:
263 branch = new CQuadBranch();;
264 _Children[child] = branch;
265 branch->serial(f);
266 break;
267 default:
268 nlerror("While serializing (read) CQuadBranch: unknown child type");
269 break;
272 else
274 if (_Children[child] == NULL)
276 childType = NoChild;
277 f.serial(childType);
279 else
281 childType = uint8(_Children[child]->isLeaf() ? LeafChild : BranchChild);
282 f.serial(childType);
283 _Children[child]->serial(f);
289 bool NLPACS::CSurfaceQuadTree::check() const
291 if (_Root != NULL)
292 return _Root->check();
293 return true;
296 const NLPACS::CQuadLeaf *NLPACS::CSurfaceQuadTree::getLeaf(const CVector &v) const
298 CVector pos = CVector(v.x, v.y, 0.0f);
299 if (_Root == NULL || !_BBox.include(pos))
300 return NULL;
302 const IQuadNode *node = _Root;
304 while (node != NULL && !node->isLeaf())
306 nlassert(node->getBBox().include(pos));
307 uint child;
309 if (pos.x > node->_XCenter)
310 child = ((pos.y > node->_YCenter) ? 2 : 1);
311 else
312 child = ((pos.y > node->_YCenter) ? 3 : 0);
314 node = node->getChild(child);
317 return (const CQuadLeaf *)node;
321 void NLPACS::CSurfaceQuadTree::serial(NLMISC::IStream &f)
324 Version 0:
325 - base version.
327 (void)f.serialVersion(0);
329 uint8 childType = 0;
330 f.serial(_MaxThickness);
331 f.serial(_MaxLevel);
332 f.serial(_BBox);
333 if (f.isReading())
335 CQuadLeaf *leaf;
336 CQuadBranch *branch;
338 f.serial(childType);
339 switch (childType)
341 case CQuadBranch::NoChild:
342 _Root = NULL;
343 break;
344 case CQuadBranch::LeafChild:
345 leaf = new CQuadLeaf();
346 _Root = leaf;
347 leaf->serial(f);
348 break;
349 case CQuadBranch::BranchChild:
350 branch = new CQuadBranch();
351 _Root = branch;
352 branch->serial(f);
353 break;
354 default:
355 nlerror("While serializing (read) CQuadBranch: unknown child type");
356 break;
359 else
361 if (_Root == NULL)
363 childType = CQuadBranch::NoChild;
364 f.serial(childType);
366 else
368 childType = uint8(_Root->isLeaf() ? CQuadBranch::LeafChild : CQuadBranch::BranchChild);
369 f.serial(childType);
370 _Root->serial(f);
376 float NLPACS::CSurfaceQuadTree::getInterpZ(const CVector &v) const
378 // first get final leaf for position
379 CVector pos = CVector(v.x, v.y, 0.0f);
380 if (_Root == NULL || !_BBox.include(pos))
381 return v.z; // return unmodified z
383 const IQuadNode *node = _Root;
384 vector<uint> children;
385 vector<const IQuadNode*> nodes;
387 while (node != NULL && !node->isLeaf())
389 nodes.push_back(node);
391 nlassert(node->getBBox().include(pos));
392 uint child;
394 if (pos.x > node->_XCenter)
395 child = ((pos.y > node->_YCenter) ? 2 : 1);
396 else
397 child = ((pos.y > node->_YCenter) ? 3 : 0);
399 children.push_back(child);
401 node = node->getChild(child);
404 if (node == NULL)
405 return v.z; // return unmodified z
407 nodes.push_back(node);
409 vector<const CQuadLeaf*> leaves;
410 vector<const IQuadNode*> explore;
412 leaves.push_back((const CQuadLeaf*)node);
414 // for each side of the leaf, find neighbor leaves
415 uint side;
416 for (side=0; side<4; ++side)
418 static const sint ct[4][4] = { {-1, 1, 3,-1}, {-1,-1, 2, 0}, { 1,-1,-1, 3}, { 0, 2,-1,-1} }; // child table
419 static const sint nt[4][4] = { { 3, 1, 3, 1}, { 2, 0, 2, 0}, { 1, 3, 1, 3}, { 0, 2, 0, 2} }; // neighbor table
421 sint nlev = (sint)nodes.size()-1;
422 sint child = -1;
424 while (nlev > 0)
426 child = ct[children[nlev-1]][side];
428 if (child >= 0)
429 break;
431 --nlev;
434 // neighbor not found in root, leave
435 if (nlev == 0)
436 continue;
438 // get father
439 node = nodes[nlev-1];
441 while (nlev < (sint)nodes.size() && node!=NULL && !node->isLeaf())
443 child = nt[children[nlev-1]][side];
444 node = node->getChild(child);
446 ++nlev;
449 if (node == NULL)
450 continue;
452 if (node->isLeaf())
454 leaves.push_back((const CQuadLeaf*)node);
456 else
458 explore.push_back(node);
460 while (!explore.empty())
462 node = explore.back();
463 explore.pop_back();
465 if (node == NULL)
466 continue;
468 if (node->isLeaf())
469 leaves.push_back((const CQuadLeaf*)node);
470 else
472 explore.push_back(node->getChild((side+2)&3));
473 explore.push_back(node->getChild((side+3)&3));
479 uint i;
480 float di, wi;
481 float sum = 0.0;
482 float interpZ = 0.0;
484 for (i=0; i<leaves.size(); ++i)
486 di = (float)sqrt(sqr(v.x-leaves[i]->_XCenter)+sqr(v.y-leaves[i]->_YCenter))*(float)pow(1.5, leaves[i]->_Level);
487 wi = 1.0f/di;
488 sum += wi;
489 interpZ += (leaves[i]->getMinHeight()+leaves[i]->getMaxHeight())*0.5f*wi;
492 return interpZ / sum;