Files
simgear/simgear/bvh/BVHStaticGeometryBuilder.hxx
T
Mathias Froehlich 7a879e2abf bvh: Introduce BVHMaterial independent of SGMaterial.
The bounding volumes in core should not depend on scenery.
Therefore reference material properties relevant for the BVH
tree in BVHMaterial.
2012-08-24 21:25:11 +02:00

229 lines
7.2 KiB
C++

// Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef BVHStaticGeometryBuilder_hxx
#define BVHStaticGeometryBuilder_hxx
#include <algorithm>
#include <map>
#include <set>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include "BVHVisitor.hxx"
#include "BVHNode.hxx"
#include "BVHGroup.hxx"
#include "BVHTransform.hxx"
#include "BVHStaticData.hxx"
#include "BVHStaticNode.hxx"
#include "BVHStaticLeaf.hxx"
#include "BVHStaticTriangle.hxx"
#include "BVHStaticBinary.hxx"
#include "BVHStaticGeometry.hxx"
namespace simgear {
class BVHStaticGeometryBuilder : public SGReferenced {
public:
BVHStaticGeometryBuilder() :
_staticData(new BVHStaticData),
_currentMaterial(0),
_currentMaterialIndex(~0u)
{ }
virtual ~BVHStaticGeometryBuilder()
{ }
struct LeafRef {
LeafRef(const BVHStaticLeaf* leaf, const BVHStaticData& data) :
_leaf(leaf),
_box(_leaf->computeBoundingBox(data)),
_center(_leaf->computeCenter(data))
{ }
SGSharedPtr<const BVHStaticLeaf> _leaf;
SGBoxf _box;
SGVec3f _center;
};
typedef std::list<LeafRef> LeafRefList;
struct LeafRefLess : public std::binary_function<LeafRef, LeafRef, bool> {
LeafRefLess(unsigned sortAxis) : _sortAxis(sortAxis) {}
bool operator()(const LeafRef& x, const LeafRef& y)
{ return x._center[_sortAxis] < y._center[_sortAxis]; }
unsigned _sortAxis;
};
SGSharedPtr<BVHStaticData> _staticData;
LeafRefList _leafRefList;
typedef std::map<SGVec3f, unsigned> VertexMap;
VertexMap _vertexMap;
typedef std::set<SGVec3<unsigned> > TriangleSet;
TriangleSet _triangleSet;
void setCurrentMaterial(const BVHMaterial* material)
{
_currentMaterial = material;
_currentMaterialIndex = addMaterial(material);
}
const BVHMaterial* getCurrentMaterial() const
{
return _currentMaterial;
}
unsigned addMaterial(const BVHMaterial* material)
{
MaterialMap::const_iterator i = _materialMap.find(material);
if (i != _materialMap.end())
return i->second;
unsigned index = _staticData->addMaterial(material);
_materialMap[material] = index;
return index;
}
typedef std::map<const BVHMaterial*, unsigned> MaterialMap;
MaterialMap _materialMap;
const BVHMaterial* _currentMaterial;
unsigned _currentMaterialIndex;
void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
{
unsigned indices[3] = { addVertex(v1), addVertex(v2), addVertex(v3) };
std::sort(indices, indices + 3);
SGVec3<unsigned> indexKey(indices);
if (_triangleSet.find(indexKey) != _triangleSet.end())
return;
_triangleSet.insert(indexKey);
BVHStaticTriangle* staticTriangle;
staticTriangle = new BVHStaticTriangle(_currentMaterialIndex, indices);
_leafRefList.push_back(LeafRef(staticTriangle, *_staticData));
}
unsigned addVertex(const SGVec3f& v)
{
VertexMap::const_iterator i = _vertexMap.find(v);
if (i != _vertexMap.end())
return i->second;
unsigned index = _staticData->addVertex(v);
_vertexMap[v] = index;
return index;
}
BVHStaticGeometry* buildTree()
{
const BVHStaticNode* tree = buildTreeRecursive(_leafRefList);
if (!tree)
return 0;
_staticData->trim();
return new BVHStaticGeometry(tree, _staticData);
}
private:
static void
centerSplitLeafs(unsigned splitAxis, const double& splitValue,
LeafRefList& leafs, LeafRefList split[2])
{
while (!leafs.empty()) {
if (leafs.front()._center[splitAxis] < splitValue) {
split[0].splice(split[0].begin(), leafs, leafs.begin());
} else {
split[1].splice(split[1].begin(), leafs, leafs.begin());
}
}
}
static void
equalSplitLeafs(unsigned splitAxis, LeafRefList& leafs,
LeafRefList split[2])
{
leafs.sort(LeafRefLess(splitAxis));
while (true) {
if (leafs.empty())
break;
split[0].splice(split[0].begin(), leafs, leafs.begin());
if (leafs.empty())
break;
split[1].splice(split[1].begin(), leafs, --leafs.end());
}
}
static const BVHStaticNode* buildTreeRecursive(LeafRefList& leafs)
{
// recursion termination
if (leafs.empty())
return 0;
// FIXME size is O(n)!!!
// if (leafs.size() == 1)
if (++leafs.begin() == leafs.end())
return leafs.front()._leaf;
SGBoxf box;
for (LeafRefList::const_iterator i = leafs.begin();
i != leafs.end(); ++i)
box.expandBy(i->_box);
// // FIXME ...
// if (length(box.getSize()) < 1)
// return new BVHBox(box);
if (box.empty())
return 0;
unsigned splitAxis = box.getBroadestAxis();
LeafRefList splitLeafs[2];
double splitValue = box.getCenter()[splitAxis];
centerSplitLeafs(splitAxis, splitValue, leafs, splitLeafs);
if (splitLeafs[0].empty() || splitLeafs[1].empty()) {
for (unsigned i = 0; i < 3 ; ++i) {
if (i == splitAxis)
continue;
leafs.swap(splitLeafs[0]);
leafs.splice(leafs.begin(), splitLeafs[1]);
splitValue = box.getCenter()[i];
centerSplitLeafs(i, splitValue, leafs, splitLeafs);
if (!splitLeafs[0].empty() && !splitLeafs[1].empty()) {
splitAxis = i;
break;
}
}
}
if (splitLeafs[0].empty() || splitLeafs[1].empty()) {
leafs.swap(splitLeafs[0]);
leafs.splice(leafs.begin(), splitLeafs[1]);
equalSplitLeafs(splitAxis, leafs, splitLeafs);
}
const BVHStaticNode* child0 = buildTreeRecursive(splitLeafs[0]);
const BVHStaticNode* child1 = buildTreeRecursive(splitLeafs[1]);
if (!child0)
return child1;
if (!child1)
return child0;
return new BVHStaticBinary(splitAxis, child0, child1, box);
}
};
}
#endif