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/>.
18 #include "nel/pacs/surface_quad.h"
20 #include "nel/misc/file.h"
26 using namespace NLMISC
;
29 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree()
32 _MaxThickness
= FLT_MAX
;
34 _BBox
.setCenter(CVector::Null
);
35 _BBox
.setSize(CVector::Null
);
38 NLPACS::CSurfaceQuadTree::CSurfaceQuadTree(const NLPACS::CSurfaceQuadTree
&quad
)
43 NLPACS::CSurfaceQuadTree
&NLPACS::CSurfaceQuadTree::operator = (const NLPACS::CSurfaceQuadTree
&quad
)
48 _MaxThickness
= quad
._MaxThickness
;
49 _MaxLevel
= quad
._MaxLevel
;
53 if (quad
._Root
!= NULL
)
55 if (quad
._Root
->isLeaf())
57 CQuadLeaf
*newLeaf
= new CQuadLeaf();
58 *newLeaf
= *((CQuadLeaf
*)(quad
._Root
));
63 CQuadBranch
*newBranch
= new CQuadBranch();
64 *newBranch
= *((CQuadBranch
*)(quad
._Root
));
72 void NLPACS::CSurfaceQuadTree::clear()
78 void NLPACS::CSurfaceQuadTree::init(float maxThickness
, uint maxLevel
, const CVector
¢er
, float halfSize
)
80 nlassert(maxLevel
> 0);
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
))
97 _Root
= new CQuadLeaf(_MaxLevel
);
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
;
115 void NLPACS::CSurfaceQuadTree::compile()
119 _Root
->getMaxHeight()-_Root
->getMinHeight() <= _MaxThickness
)
121 CQuadLeaf
*leaf
= new CQuadLeaf();
122 *((IQuadNode
*)leaf
) = *_Root
;
126 else if (_Root
!= NULL
&&
129 ((CQuadBranch
*)_Root
)->reduceChildren();
134 NLPACS::CQuadBranch::CQuadBranch(const NLPACS::CQuadBranch
&branch
) : NLPACS::IQuadNode(branch
)
139 NLPACS::CQuadBranch
&NLPACS::CQuadBranch::operator = (const NLPACS::CQuadBranch
&branch
)
141 IQuadNode::operator=(branch
);
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
;
157 CQuadBranch
*newBranch
= new CQuadBranch();
158 *newBranch
= *((CQuadBranch
*)(branch
._Children
[child
]));
159 _Children
[child
] = newBranch
;
166 void NLPACS::CQuadBranch::reduceChildren()
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
];
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
);
194 child
= (v
.y
> _YCenter
) ? 2 : 1;
196 child
= (v
.y
> _YCenter
) ? 3 : 0;
198 if (_Children
[child
] == NULL
)
202 _Children
[child
] = new CQuadLeaf(_Level
-1);
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())
226 for (child
=0; child
<4; ++child
)
227 if (_Children
[child
] != NULL
&& !_Children
[child
]->check())
234 * Serialization methods...
238 void NLPACS::CQuadBranch::serial(NLMISC::IStream
&f
)
240 IQuadNode::serial(f
);
243 for (child
=0; child
<4; ++child
)
255 _Children
[child
] = NULL
;
258 leaf
= new CQuadLeaf();
259 _Children
[child
] = leaf
;
263 branch
= new CQuadBranch();;
264 _Children
[child
] = branch
;
268 nlerror("While serializing (read) CQuadBranch: unknown child type");
274 if (_Children
[child
] == NULL
)
281 childType
= uint8(_Children
[child
]->isLeaf() ? LeafChild
: BranchChild
);
283 _Children
[child
]->serial(f
);
289 bool NLPACS::CSurfaceQuadTree::check() const
292 return _Root
->check();
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
))
302 const IQuadNode
*node
= _Root
;
304 while (node
!= NULL
&& !node
->isLeaf())
306 nlassert(node
->getBBox().include(pos
));
309 if (pos
.x
> node
->_XCenter
)
310 child
= ((pos
.y
> node
->_YCenter
) ? 2 : 1);
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
)
327 (void)f
.serialVersion(0);
330 f
.serial(_MaxThickness
);
341 case CQuadBranch::NoChild
:
344 case CQuadBranch::LeafChild
:
345 leaf
= new CQuadLeaf();
349 case CQuadBranch::BranchChild
:
350 branch
= new CQuadBranch();
355 nlerror("While serializing (read) CQuadBranch: unknown child type");
363 childType
= CQuadBranch::NoChild
;
368 childType
= uint8(_Root
->isLeaf() ? CQuadBranch::LeafChild
: CQuadBranch::BranchChild
);
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
));
394 if (pos
.x
> node
->_XCenter
)
395 child
= ((pos
.y
> node
->_YCenter
) ? 2 : 1);
397 child
= ((pos
.y
> node
->_YCenter
) ? 3 : 0);
399 children
.push_back(child
);
401 node
= node
->getChild(child
);
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
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;
426 child
= ct
[children
[nlev
-1]][side
];
434 // neighbor not found in root, leave
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
);
454 leaves
.push_back((const CQuadLeaf
*)node
);
458 explore
.push_back(node
);
460 while (!explore
.empty())
462 node
= explore
.back();
469 leaves
.push_back((const CQuadLeaf
*)node
);
472 explore
.push_back(node
->getChild((side
+2)&3));
473 explore
.push_back(node
->getChild((side
+3)&3));
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
);
489 interpZ
+= (leaves
[i
]->getMinHeight()+leaves
[i
]->getMaxHeight())*0.5f
*wi
;
492 return interpZ
/ sum
;