diff --git a/simgear/scene/bvh/.cvsignore b/simgear/scene/bvh/.cvsignore new file mode 100644 index 00000000..e9955884 --- /dev/null +++ b/simgear/scene/bvh/.cvsignore @@ -0,0 +1,3 @@ +.deps +Makefile +Makefile.in diff --git a/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx b/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx new file mode 100644 index 00000000..8fc9db9f --- /dev/null +++ b/simgear/scene/bvh/BVHBoundingBoxVisitor.hxx @@ -0,0 +1,83 @@ +// 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 BVHBoundingBoxVisitor_hxx +#define BVHBoundingBoxVisitor_hxx + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHLineGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" +#include "BVHStaticGeometry.hxx" + +namespace simgear { + +class BVHBoundingBoxVisitor : public BVHVisitor { +public: + virtual ~BVHBoundingBoxVisitor() {} + + void clear() + { _box.clear(); } + + virtual void apply(BVHGroup& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHTransform& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHMotionTransform& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHLineGeometry& node) + { expandBy(node.getBoundingSphere()); } + virtual void apply(BVHStaticGeometry& node) + { expandBy(node.getBoundingSphere()); } + + virtual void apply(const BVHStaticBinary& node, const BVHStaticData& data) + { expandBy(node.getBoundingBox()); } + virtual void apply(const BVHStaticLeaf& node, const BVHStaticData& data) + { expandBy(node.computeBoundingBox(data)); } + virtual void apply(const BVHStaticTriangle& node, const BVHStaticData& data) + { expandBy(node.computeBoundingBox(data)); } + + const SGBoxf& getBox() const + { return _box; } + +private: + void expandBy(const SGSphered& sphere) + { + SGVec3f v0(sphere.getCenter() - sphere.getRadius()*SGVec3d(1, 1, 1)); + SGVec3f v1(sphere.getCenter() + sphere.getRadius()*SGVec3d(1, 1, 1)); + _box.expandBy(SGBoxf(v0, v1)); + } + void expandBy(const SGBoxf& box) + { _box.expandBy(box); } + + SGBoxf _box; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHDebugCollectVisitor.hxx b/simgear/scene/bvh/BVHDebugCollectVisitor.hxx new file mode 100644 index 00000000..540ee45f --- /dev/null +++ b/simgear/scene/bvh/BVHDebugCollectVisitor.hxx @@ -0,0 +1,222 @@ +// 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 BVHDebugCollectVisitor_hxx +#define BVHDebugCollectVisitor_hxx + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHStaticGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" + +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +class BVHNode; +class BVHStaticNode; + +class BVHDebugCollectVisitor : public BVHVisitor { +public: + BVHDebugCollectVisitor(unsigned level = ~0u) : + _group(new osg::Group), + _level(level), + _currentLevel(0) + { + osg::StateSet* stateSet = _group->getOrCreateStateSet(); + stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + stateSet->setAttribute(new osg::Depth(osg::Depth::LESS, 0, 1, false)); + osg::BlendFunc *blendFunc; + blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, + osg::BlendFunc::DST_ALPHA); + stateSet->setAttributeAndModes(blendFunc); + osg::PolygonOffset* polygonOffset = new osg::PolygonOffset(-1, -1); + stateSet->setAttributeAndModes(polygonOffset); + } + virtual ~BVHDebugCollectVisitor() + { } + + virtual void apply(BVHGroup& node) + { + addNodeSphere(node); + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + } + virtual void apply(BVHTransform& node) + { + addNodeSphere(node); + osg::ref_ptr oldGroup = _group; + osg::ref_ptr transform = new osg::MatrixTransform; + transform->setMatrix(osg::Matrix(node.getToWorldTransform().data())); + _group = transform; + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + _group = oldGroup; + if (transform->getNumChildren()) + _group->addChild(transform.get()); + } + virtual void apply(BVHMotionTransform& node) + { + addNodeSphere(node); + osg::ref_ptr oldGroup = _group; + osg::ref_ptr transform; + transform = new osg::PositionAttitudeTransform; + double tt = node.getReferenceTime() - node.getEndTime(); + tt = 100*tt; + tt += node.getReferenceTime(); +// transform->setPosition(node.getPosition(node.getEndTime()).osg()); + transform->setPosition(node.getPosition().osg()); + transform->setAttitude(inverse(node.getOrientation(tt)).osg()); +// transform->setPosition(node.getPosition().osg()); +// transform->setAttitude(inverse(node.getOrientation()).osg()); + _group = transform; + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + _group = oldGroup; + if (transform->getNumChildren()) + _group->addChild(transform.get()); + } + virtual void apply(BVHLineGeometry&) + { + } + virtual void apply(BVHStaticGeometry& node) + { + addNodeSphere(node); + ++_currentLevel; + node.traverse(*this); + --_currentLevel; + } + + virtual void apply(const BVHStaticBinary& node, const BVHStaticData& data) + { + addNodeBox(node, data); + ++_currentLevel; + node.traverse(*this, data); + --_currentLevel; + } + virtual void apply(const BVHStaticLeaf& node, const BVHStaticData& data) + { + addNodeBox(node, data); + } + virtual void apply(const BVHStaticTriangle& node, const BVHStaticData& data) + { + addNodeBox(node, data); + addTriangle(node.getTriangle(data), osg::Vec4(0.5, 0, 0.5, 0.2)); + } + + osg::Node* getNode() const { return _group.get(); } + + static unsigned allLevels() { return ~0u; } + static unsigned triangles() { return ~0u - 1; } + +private: + void addTriangle(const SGTrianglef& triangle, const osg::Vec4& color) + { + if (_level != triangles()) + return; + + osg::Geometry* geometry = new osg::Geometry; + + osg::Vec3Array* vertices = new osg::Vec3Array; + vertices->push_back(triangle.getVertex(0).osg()); + vertices->push_back(triangle.getVertex(1).osg()); + vertices->push_back(triangle.getVertex(2).osg()); + + osg::Vec4Array* colors = new osg::Vec4Array; + colors->push_back(color); + + geometry->setVertexArray(vertices); + geometry->setColorArray(colors); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + + geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 3)); + + osg::Geode* geode = new osg::Geode; + geode->addDrawable(geometry); + _group->addChild(geode); + } + + void addNodeSphere(const BVHNode& node) + { + if (_level != ~0u && _level != _currentLevel) + return; + SGSphered sphere = node.getBoundingSphere(); + osg::Sphere* shape = new osg::Sphere; + shape->setCenter(SGVec3f(sphere.getCenter()).osg()); + shape->setRadius(sphere.getRadius()); + addShape(shape, osg::Vec4(0.5f, 0.5f, 0.5f, 0.1f)); + } + + void addNodeBox(const BVHStaticNode& node, const BVHStaticData& data) + { + if (_level != ~0u && _level != _currentLevel) + return; + BVHBoundingBoxVisitor bbv; + node.accept(bbv, data); + osg::Box* shape = new osg::Box; + shape->setCenter(bbv.getBox().getCenter().osg()); + shape->setHalfLengths((0.5*bbv.getBox().getSize()).osg()); + addShape(shape, osg::Vec4(0.5f, 0, 0, 0.1f)); + } + + void addShape(osg::Shape* shape, const osg::Vec4& color) + { + osg::ShapeDrawable* shapeDrawable = new osg::ShapeDrawable; + shapeDrawable->setColor(color); + shapeDrawable->setShape(shape); + osg::Geode* geode = new osg::Geode; + geode->addDrawable(shapeDrawable); + _group->addChild(geode); + } + + osg::ref_ptr _group; + const unsigned _level; + unsigned _currentLevel; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHGroup.cxx b/simgear/scene/bvh/BVHGroup.cxx new file mode 100644 index 00000000..4fbba4a3 --- /dev/null +++ b/simgear/scene/bvh/BVHGroup.cxx @@ -0,0 +1,88 @@ +// 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. +// + +#include "BVHGroup.hxx" + +#include + +namespace simgear { + +BVHGroup::BVHGroup() +{ +} + +BVHGroup::~BVHGroup() +{ + ChildList::iterator i; + for (i = _children.begin(); i != _children.end(); ++i) { + (*i)->removeParent(this); + *i = 0; + } +} + +void +BVHGroup::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHGroup::clear() +{ + _children.clear(); + invalidateBound(); +} + +void +BVHGroup::addChild(BVHNode* child) +{ + if (!child) + return; + ChildList::iterator i; + i = std::find(_children.begin(), _children.end(), child); + if (i != _children.end()) + return; + invalidateBound(); + child->addParent(this); + _children.push_back(child); +} + +void +BVHGroup::removeChild(BVHNode* child) +{ + if (!child) + return; + ChildList::iterator i; + i = std::find(_children.begin(), _children.end(), child); + if (i == _children.end()) + return; + invalidateBound(); + child->removeParent(this); + _children.erase(i); +} + +SGSphered +BVHGroup::computeBoundingSphere() const +{ + SGSphered sphere; + ChildList::const_iterator i; + for (i = _children.begin(); i != _children.end(); ++i) + sphere.expandBy((*i)->getBoundingSphere()); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHGroup.hxx b/simgear/scene/bvh/BVHGroup.hxx new file mode 100644 index 00000000..d0b58363 --- /dev/null +++ b/simgear/scene/bvh/BVHGroup.hxx @@ -0,0 +1,61 @@ +// 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 BVHGroup_hxx +#define BVHGroup_hxx + +#include +#include "BVHNode.hxx" +#include "BVHVisitor.hxx" + +namespace simgear { + +class BVHGroup : public BVHNode { +public: + BVHGroup(); + virtual ~BVHGroup(); + + virtual void accept(BVHVisitor& visitor); + + void traverse(BVHVisitor& visitor) + { + ChildList::const_iterator i; + for (i = _children.begin(); i != _children.end(); ++i) + (*i)->accept(visitor); + } + + void clear(); + void addChild(BVHNode* child); + void removeChild(BVHNode* child); + + unsigned getNumChildren() const + { return _children.size(); } + const BVHNode* getChild(unsigned i) const + { if (_children.size() <= i) return 0; return _children[i]; } + BVHNode* getChild(unsigned i) + { if (_children.size() <= i) return 0; return _children[i]; } + + virtual SGSphered computeBoundingSphere() const; + +private: + typedef std::vector > ChildList; + ChildList _children; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHLineGeometry.cxx b/simgear/scene/bvh/BVHLineGeometry.cxx new file mode 100644 index 00000000..679a4675 --- /dev/null +++ b/simgear/scene/bvh/BVHLineGeometry.cxx @@ -0,0 +1,49 @@ +// 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. +// + +#include "BVHLineGeometry.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHLineGeometry::BVHLineGeometry(const SGLineSegmentf& lineSegment, Type type) : + _lineSegment(lineSegment), + _type(type) +{ +} + +BVHLineGeometry::~BVHLineGeometry() +{ +} + +void +BVHLineGeometry::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +SGSphered +BVHLineGeometry::computeBoundingSphere() const +{ + SGSphered sphere; + sphere.expandBy(SGVec3d(_lineSegment.getStart())); + sphere.expandBy(SGVec3d(_lineSegment.getEnd())); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHLineGeometry.hxx b/simgear/scene/bvh/BVHLineGeometry.hxx new file mode 100644 index 00000000..d0d87211 --- /dev/null +++ b/simgear/scene/bvh/BVHLineGeometry.hxx @@ -0,0 +1,53 @@ +// 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 BVHLineGeometry_hxx +#define BVHLineGeometry_hxx + +#include +#include "BVHNode.hxx" + +namespace simgear { + +class BVHLineGeometry : public BVHNode { +public: + enum Type { + CarrierCatapult, + CarrierWire + }; + + BVHLineGeometry(const SGLineSegmentf& lineSegment, Type type); + virtual ~BVHLineGeometry(); + + virtual void accept(BVHVisitor& visitor); + + const SGLineSegmentf& getLineSegment() const + { return _lineSegment; } + + Type getType() const + { return _type; } + + virtual SGSphered computeBoundingSphere() const; + +private: + SGLineSegmentf _lineSegment; + Type _type; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHLineSegmentVisitor.cxx b/simgear/scene/bvh/BVHLineSegmentVisitor.cxx new file mode 100644 index 00000000..d4dbd194 --- /dev/null +++ b/simgear/scene/bvh/BVHLineSegmentVisitor.cxx @@ -0,0 +1,157 @@ +// 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. +// + +#include "BVHLineSegmentVisitor.hxx" + +#include + +#include "BVHVisitor.hxx" + +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHTransform.hxx" +#include "BVHMotionTransform.hxx" +#include "BVHLineGeometry.hxx" +#include "BVHStaticGeometry.hxx" + +#include "BVHStaticData.hxx" + +#include "BVHStaticNode.hxx" +#include "BVHStaticLeaf.hxx" +#include "BVHStaticTriangle.hxx" +#include "BVHStaticBinary.hxx" + +namespace simgear { + +void +BVHLineSegmentVisitor::apply(BVHGroup& group) +{ + if (!intersects(_lineSegment, group.getBoundingSphere())) + return; + group.traverse(*this); +} + +void +BVHLineSegmentVisitor::apply(BVHTransform& transform) +{ + if (!intersects(_lineSegment, transform.getBoundingSphere())) + return; + + bool haveHit = _haveHit; + _haveHit = false; + + // Push the line segment + SGLineSegmentd lineSegment = getLineSegment(); + _lineSegment = transform.lineSegmentToLocal(lineSegment); + + transform.traverse(*this); + + if (_haveHit) { + _linearVelocity = transform.vecToWorld(_linearVelocity); + _angularVelocity = transform.vecToWorld(_angularVelocity); + SGVec3d point(transform.ptToWorld(_lineSegment.getEnd())); + _lineSegment.set(lineSegment.getStart(), point); + _normal = transform.vecToWorld(_normal); + } else { + _lineSegment = lineSegment; + _haveHit = haveHit; + } +} + +void +BVHLineSegmentVisitor::apply(BVHMotionTransform& transform) +{ + if (!intersects(_lineSegment, transform.getBoundingSphere())) + return; + + bool haveHit = _haveHit; + _haveHit = false; + + // Push the line segment + SGLineSegmentd lineSegment = getLineSegment(); + SGMatrixd toLocal = transform.getToLocalTransform(_time); + _lineSegment = lineSegment.transform(toLocal); + + transform.traverse(*this); + + if (_haveHit) { + SGMatrixd toWorld = transform.getToWorldTransform(_time); + SGVec3d localStart = _lineSegment.getStart(); + _linearVelocity += transform.getLinearVelocityAt(localStart); + _angularVelocity += transform.getAngularVelocity(); + _linearVelocity = toWorld.xformVec(_linearVelocity); + _angularVelocity = toWorld.xformVec(_angularVelocity); + SGVec3d localEnd = _lineSegment.getEnd(); + _lineSegment.set(lineSegment.getStart(), toWorld.xformPt(localEnd)); + _normal = toWorld.xformVec(_normal); + } else { + _lineSegment = lineSegment; + _haveHit = haveHit; + } +} + +void +BVHLineSegmentVisitor::apply(BVHLineGeometry&) +{ +} + +void +BVHLineSegmentVisitor::apply(BVHStaticGeometry& node) +{ + if (!intersects(_lineSegment, node.getBoundingSphere())) + return; + node.traverse(*this); +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticBinary& node, + const BVHStaticData& data) +{ + if (!intersects(SGLineSegmentf(_lineSegment), node.getBoundingBox())) + return; + + // The first box to enter is the one the startpoint is in. + // this increases the probability, that on exit of that box we do not + // even need to walk the other one, since the line segment is + // then already short enough to not intersect the other one anymore. + node.traverse(*this, data, _lineSegment.getStart()); +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticLeaf& node, + const BVHStaticData& data) +{ +} + +void +BVHLineSegmentVisitor::apply(const BVHStaticTriangle& triangle, + const BVHStaticData& data) +{ + SGTrianglef tri = triangle.getTriangle(data); + SGVec3f point; + if (!intersects(point, tri, SGLineSegmentf(_lineSegment), 1e-4f)) + return; + setLineSegmentEnd(SGVec3d(point)); + _normal = SGVec3d(tri.getNormal()); + _linearVelocity = SGVec3d::zeros(); + _angularVelocity = SGVec3d::zeros(); + _material = data.getMaterial(triangle.getMaterialIndex()); + _haveHit = true; +} + + +} diff --git a/simgear/scene/bvh/BVHLineSegmentVisitor.hxx b/simgear/scene/bvh/BVHLineSegmentVisitor.hxx new file mode 100644 index 00000000..aec9c081 --- /dev/null +++ b/simgear/scene/bvh/BVHLineSegmentVisitor.hxx @@ -0,0 +1,94 @@ +// 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 BVHLineSegmentVisitor_hxx +#define BVHLineSegmentVisitor_hxx + +#include +#include +#include + +#include "BVHVisitor.hxx" + +namespace simgear { + +class BVHLineSegmentVisitor : public BVHVisitor { +public: + BVHLineSegmentVisitor(const SGLineSegmentd& lineSegment, + const double& t = 0) : + _lineSegment(lineSegment), + _time(t), + _material(0), + _haveHit(false) + { } + virtual ~BVHLineSegmentVisitor() + { } + + bool empty() const + { return !_haveHit; } + + const SGLineSegmentd& getLineSegment() const + { return _lineSegment; } + + SGVec3d getPoint() const + { return _lineSegment.getEnd(); } + const SGVec3d& getNormal() const + { return _normal; } + const SGVec3d& getLinearVelocity() const + { return _linearVelocity; } + const SGVec3d& getAngularVelocity() const + { return _angularVelocity; } + const SGMaterial* getMaterial() const + { return _material; } + + virtual void apply(BVHGroup& group); + virtual void apply(BVHTransform& transform); + virtual void apply(BVHMotionTransform& transform); + virtual void apply(BVHLineGeometry&); + virtual void apply(BVHStaticGeometry& node); + + virtual void apply(const BVHStaticBinary&, const BVHStaticData&); + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&); + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&); + +protected: + bool setLineSegmentEnd(const SGVec3d& end) + { + // Ok, you need to make sure that the new end is in the previous + // direction and that the line segment is not enlarged by that call. +#ifndef _NDEBUG + // FIXME insert code to check this... +#endif + _lineSegment.set(_lineSegment.getStart(), end); + } + +private: + SGLineSegmentd _lineSegment; + double _time; + + // belongs in a derived class + SGVec3d _normal; + SGVec3d _linearVelocity; + SGVec3d _angularVelocity; + const SGMaterial* _material; + + bool _haveHit; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHMotionTransform.cxx b/simgear/scene/bvh/BVHMotionTransform.cxx new file mode 100644 index 00000000..d97b66f1 --- /dev/null +++ b/simgear/scene/bvh/BVHMotionTransform.cxx @@ -0,0 +1,111 @@ +// 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. +// + +#include "BVHMotionTransform.hxx" + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +BVHMotionTransform::BVHMotionTransform() : + _toWorldReference(SGMatrixd::unit()), + _toLocalReference(SGMatrixd::unit()), + _toWorldAmplification(1), + _toLocalAmplification(1), + _linearVelocity(0, 0, 0), + _angularVelocity(0, 0, 0), + _referenceTime(0), + _endTime(0) +{ +} + +BVHMotionTransform::~BVHMotionTransform() +{ +} + +void +BVHMotionTransform::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHMotionTransform::setTransform(const BVHMotionTransform& transform) +{ + _toWorldReference = transform._toWorldReference; + _toLocalReference = transform._toLocalReference; + _toWorldAmplification = transform._toWorldAmplification; + _toLocalAmplification = transform._toLocalAmplification; + _linearVelocity = transform._linearVelocity; + _angularVelocity = transform._angularVelocity; + _referenceTime = transform._referenceTime; + _endTime = transform._endTime; + invalidateParentBound(); +} + +void +BVHMotionTransform::setToWorldTransform(const SGMatrixd& transform) +{ + _toWorldReference = transform; + invert(_toLocalReference, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +void +BVHMotionTransform::setToLocalTransform(const SGMatrixd& transform) +{ + _toLocalReference = transform; + invert(_toWorldReference, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +SGSphered +BVHMotionTransform::computeBoundingSphere() const +{ + SGSphered sphere(BVHGroup::computeBoundingSphere()); + if (sphere.empty()) + return sphere; + SGVec3d centerStart = _toWorldReference.xformPt(sphere.getCenter()); + SGMatrixd toWorldEnd = getToWorldTransform(_endTime); + SGVec3d centerEnd = toWorldEnd.xformPt(sphere.getCenter()); + double rad = 0.5*length(centerStart - centerEnd) + sphere.getRadius(); + rad *= _toWorldAmplification; + return SGSphered(0.5*(centerStart + centerEnd), rad); +} + +void +BVHMotionTransform::updateAmplificationFactors() +{ + // Hmm, this is just a hint, true? + // But anyway, almost all transforms in a scenegraph will + // have them equal to 1 ... + double r = norm(_toWorldReference.xformVec(SGVec3d(1, 0, 0))); + r = std::max(r, norm(_toWorldReference.xformVec(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(_toWorldReference.xformVec(SGVec3d(0, 0, 1)))); + _toWorldAmplification = r; + + r = norm(_toLocalReference.xformVec(SGVec3d(1, 0, 0))); + r = std::max(r, norm(_toLocalReference.xformVec(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(_toLocalReference.xformVec(SGVec3d(0, 0, 1)))); + _toLocalAmplification = r; +} + +} diff --git a/simgear/scene/bvh/BVHMotionTransform.hxx b/simgear/scene/bvh/BVHMotionTransform.hxx new file mode 100644 index 00000000..6e51e7ee --- /dev/null +++ b/simgear/scene/bvh/BVHMotionTransform.hxx @@ -0,0 +1,113 @@ +// 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 BVHMotionTransform_hxx +#define BVHMotionTransform_hxx + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +class BVHMotionTransform : public BVHGroup { +public: + BVHMotionTransform(); + virtual ~BVHMotionTransform(); + + virtual void accept(BVHVisitor& visitor); + + void setTransform(const BVHMotionTransform& transform); + void setToWorldTransform(const SGMatrixd& transform); + void setToLocalTransform(const SGMatrixd& transform); + + void setLinearVelocity(const SGVec3d& linearVelocity) + { _linearVelocity = linearVelocity; } + const SGVec3d& getLinearVelocity() const + { return _linearVelocity; } + + void setAngularVelocity(const SGVec3d& angularVelocity) + { _angularVelocity = angularVelocity; } + const SGVec3d& getAngularVelocity() const + { return _angularVelocity; } + + void setReferenceTime(const double& referenceTime) + { _referenceTime = referenceTime; } + const double& getReferenceTime() const + { return _referenceTime; } + + void setEndTime(const double& endTime) + { _endTime = endTime; } + const double& getEndTime() const + { return _endTime; } + + SGMatrixd getToWorldTransform(const double& t) const + { + double dt = t - _referenceTime; + if (0 == dt) + return _toWorldReference; + SGMatrixd matrix(_toWorldReference); + matrix.postMultRotate(SGQuatd::fromAngleAxis(dt*_angularVelocity)); + matrix.postMultTranslate(dt*_linearVelocity); + return matrix; + } + SGMatrixd getToLocalTransform(const double& t) const + { + double dt = _referenceTime - t; + if (0 == dt) + return _toLocalReference; + SGMatrixd matrix(_toLocalReference); + matrix.preMultRotate(SGQuatd::fromAngleAxis(dt*_angularVelocity)); + matrix.preMultTranslate(dt*_linearVelocity); + return matrix; + } + + const SGMatrixd& getToWorldReferenceTransform() const + { return _toWorldReference; } + const SGMatrixd& getToLocalReferenceTransform() const + { return _toLocalReference; } + + SGVec3d getLinearVelocityAt(const SGVec3d& reference) const + { return _linearVelocity + cross(_angularVelocity, reference); } + + SGSphered sphereToLocal(const SGSphered& sphere, const double& t) const + { + SGMatrixd matrix = getToLocalTransform(t); + SGVec3d center = matrix.xformPt(sphere.getCenter()); + double radius = _toLocalAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + +private: + virtual SGSphered computeBoundingSphere() const; + void updateAmplificationFactors(); + + SGMatrixd _toWorldReference; + SGMatrixd _toLocalReference; + double _toWorldAmplification; + double _toLocalAmplification; + + SGVec3d _linearVelocity; + SGVec3d _angularVelocity; + + double _referenceTime; + double _endTime; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHNode.cxx b/simgear/scene/bvh/BVHNode.cxx new file mode 100644 index 00000000..5d8f39f3 --- /dev/null +++ b/simgear/scene/bvh/BVHNode.cxx @@ -0,0 +1,72 @@ +// 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. +// + +#include "BVHNode.hxx" + +#include +#include + +namespace simgear { + +BVHNode::BVHNode() : + _dirtyBoundingSphere(true) +{ +} + +BVHNode::~BVHNode() +{ +} + +void +BVHNode::addParent(BVHNode* parent) +{ + // should not happen, but be paranoid ... + ParentList::iterator i; + i = std::find(_parents.begin(), _parents.end(), parent); + if (i != _parents.end()) + return; + // add to the parents list ... + _parents.push_back(parent); +} + +void +BVHNode::removeParent(BVHNode* parent) +{ + ParentList::iterator i; + i = std::find(_parents.begin(), _parents.end(), parent); + if (i == _parents.end()) + return; + _parents.erase(i); +} + +void +BVHNode::invalidateParentBound() +{ + for (ParentList::iterator i = _parents.begin(); i != _parents.end(); ++i) + (*i)->invalidateBound(); +} + +void +BVHNode::invalidateBound() +{ + if (_dirtyBoundingSphere) + return; + invalidateParentBound(); + _dirtyBoundingSphere = true; +} + +} diff --git a/simgear/scene/bvh/BVHNode.hxx b/simgear/scene/bvh/BVHNode.hxx new file mode 100644 index 00000000..3bdce72f --- /dev/null +++ b/simgear/scene/bvh/BVHNode.hxx @@ -0,0 +1,67 @@ +// 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 BVHNode_hxx +#define BVHNode_hxx + +#include +#include +#include + +namespace simgear { + +class BVHGroup; +class BVHVisitor; + +// Base for the tree nodes +class BVHNode : public SGReferenced { +public: + BVHNode(); + virtual ~BVHNode(); + + // visitors ... + virtual void accept(BVHVisitor& visitor) = 0; + + const SGSphered& getBoundingSphere() const + { + if (_dirtyBoundingSphere) { + _boundingSphere = computeBoundingSphere(); + _dirtyBoundingSphere = false; + } + return _boundingSphere; + } + virtual SGSphered computeBoundingSphere() const = 0; + +protected: + friend class BVHGroup; + void addParent(BVHNode* parent); + void removeParent(BVHNode* parent); + + void invalidateParentBound(); + virtual void invalidateBound(); + +private: + mutable bool _dirtyBoundingSphere; + mutable SGSphered _boundingSphere; + + typedef std::vector ParentList; + ParentList _parents; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticBinary.cxx b/simgear/scene/bvh/BVHStaticBinary.cxx new file mode 100644 index 00000000..d98a35e0 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticBinary.cxx @@ -0,0 +1,45 @@ +// 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. +// + +#include "BVHStaticBinary.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticBinary::BVHStaticBinary(unsigned splitAxis, + const BVHStaticNode* leftChild, + const BVHStaticNode* rightChild, + const SGBoxf& boundingBox) : + _splitAxis(splitAxis), + _leftChild(leftChild), + _rightChild(rightChild), + _boundingBox(boundingBox) +{ +} + +BVHStaticBinary::~BVHStaticBinary() +{ +} + +void +BVHStaticBinary::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +} diff --git a/simgear/scene/bvh/BVHStaticBinary.hxx b/simgear/scene/bvh/BVHStaticBinary.hxx new file mode 100644 index 00000000..05b8aa3b --- /dev/null +++ b/simgear/scene/bvh/BVHStaticBinary.hxx @@ -0,0 +1,78 @@ +// 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 BVHStaticBinary_hxx +#define BVHStaticBinary_hxx + +#include +#include +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticBinary : public BVHStaticNode { +public: + BVHStaticBinary(unsigned splitAxis, const BVHStaticNode* leftChild, + const BVHStaticNode* rightChild, const SGBoxf& box); + virtual ~BVHStaticBinary(); + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + void traverse(BVHVisitor& visitor, const BVHStaticData& data) const + { + _leftChild->accept(visitor, data); + _rightChild->accept(visitor, data); + } + + // Traverse call that first enters the child node that is potentially closer + // to the given point than the other. + template + void traverse(BVHVisitor& visitor, const BVHStaticData& data, + const SGVec3& pt) const + { + float center = 0.5f*(_boundingBox.getMin()[_splitAxis] + + _boundingBox.getMax()[_splitAxis]); + if (pt[_splitAxis] < center) { + _leftChild->accept(visitor, data); + _rightChild->accept(visitor, data); + } else { + _rightChild->accept(visitor, data); + _leftChild->accept(visitor, data); + } + } + + unsigned getSplitAxis() const + { return _splitAxis; } + + const BVHStaticNode* getLeftChild() const + { return _leftChild; } + const BVHStaticNode* getRightChild() const + { return _rightChild; } + + const SGBoxf& getBoundingBox() const + { return _boundingBox; } + +private: + // Note the order of the members, this is to avoid padding + unsigned _splitAxis; + SGSharedPtr _leftChild; + SGSharedPtr _rightChild; + SGBoxf _boundingBox; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticData.hxx b/simgear/scene/bvh/BVHStaticData.hxx new file mode 100644 index 00000000..27bacef2 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticData.hxx @@ -0,0 +1,55 @@ +// 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 BVHStaticData_hxx +#define BVHStaticData_hxx + +#include +#include +#include +#include + +/// FIXME, the SGMaterial class is too much tied to the scenegraph aspects of +/// the materials. Use some class more decribing the +/// nature of the surface we live on ... +class SGMaterial; + +namespace simgear { + +class BVHStaticData : public SGReferenced { +public: + virtual ~BVHStaticData() {} + + unsigned addVertex(const SGVec3f& vertex) + { _vertices.push_back(vertex); return _vertices.size() - 1; } + const SGVec3f& getVertex(unsigned i) const + { return _vertices[i]; } + + + unsigned addMaterial(const SGMaterial* material) + { _materials.push_back(material); return _materials.size() - 1; } + const SGMaterial* getMaterial(unsigned i) const + { if (_materials.size() <= i) return 0; return _materials[i]; } + +private: + std::vector _vertices; + std::vector _materials; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticGeometry.cxx b/simgear/scene/bvh/BVHStaticGeometry.cxx new file mode 100644 index 00000000..a8479565 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometry.cxx @@ -0,0 +1,51 @@ +// 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. +// + +#include "BVHStaticGeometry.hxx" + +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +BVHStaticGeometry::BVHStaticGeometry(const BVHStaticNode* staticNode, + const BVHStaticData* staticData) : + _staticNode(staticNode), + _staticData(staticData) +{ +} + +BVHStaticGeometry::~BVHStaticGeometry() +{ +} + +void +BVHStaticGeometry::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +SGSphered +BVHStaticGeometry::computeBoundingSphere() const +{ + BVHBoundingBoxVisitor bbv; + _staticNode->accept(bbv, *_staticData); + SGSphered sphere; + sphere.expandBy(SGBoxd(bbv.getBox())); + return sphere; +} + +} diff --git a/simgear/scene/bvh/BVHStaticGeometry.hxx b/simgear/scene/bvh/BVHStaticGeometry.hxx new file mode 100644 index 00000000..693d4ff8 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometry.hxx @@ -0,0 +1,56 @@ +// 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 BVHStaticGeometry_hxx +#define BVHStaticGeometry_hxx + +#include +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHStaticData.hxx" +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticGeometry : public BVHNode { +public: + BVHStaticGeometry(const BVHStaticNode* staticNode, + const BVHStaticData* staticData); + virtual ~BVHStaticGeometry(); + + virtual void accept(BVHVisitor& visitor); + + void traverse(BVHVisitor& visitor) const + { _staticNode->accept(visitor, *_staticData); } + + const BVHStaticData* getStaticData() const + { return _staticData; } + const BVHStaticNode* getStaticNode() const + { return _staticNode; } + + virtual SGSphered computeBoundingSphere() const; + +private: + SGSharedPtr _staticNode; + SGSharedPtr _staticData; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx b/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx new file mode 100644 index 00000000..88bfd8e4 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticGeometryBuilder.hxx @@ -0,0 +1,215 @@ +// 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 +#include + +#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 _leaf; + SGBoxf _box; + SGVec3f _center; + }; + typedef std::list LeafRefList; + + struct LeafRefLess : public std::binary_function { + LeafRefLess(unsigned sortAxis) : _sortAxis(sortAxis) {} + bool operator()(const LeafRef& x, const LeafRef& y) + { return x._center[_sortAxis] < y._center[_sortAxis]; } + unsigned _sortAxis; + }; + + SGSharedPtr _staticData; + LeafRefList _leafRefList; + + typedef std::map VertexMap; + VertexMap _vertexMap; + + void setCurrentMaterial(const SGMaterial* material) + { + _currentMaterial = material; + _currentMaterialIndex = addMaterial(material); + } + const SGMaterial* getCurrentMaterial() const + { + return _currentMaterial; + } + unsigned addMaterial(const SGMaterial* 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 MaterialMap; + MaterialMap _materialMap; + const SGMaterial* _currentMaterial; + unsigned _currentMaterialIndex; + + void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3) + { + unsigned indices[3] = { addVertex(v1), addVertex(v2), addVertex(v3) }; + 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; + 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 diff --git a/simgear/scene/bvh/BVHStaticLeaf.cxx b/simgear/scene/bvh/BVHStaticLeaf.cxx new file mode 100644 index 00000000..67137530 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticLeaf.cxx @@ -0,0 +1,33 @@ +// 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. +// + +#include "BVHStaticLeaf.hxx" +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticLeaf::~BVHStaticLeaf() +{ +} + +void +BVHStaticLeaf::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +} diff --git a/simgear/scene/bvh/BVHStaticLeaf.hxx b/simgear/scene/bvh/BVHStaticLeaf.hxx new file mode 100644 index 00000000..3a7682f7 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticLeaf.hxx @@ -0,0 +1,38 @@ +// 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 BVHStaticLeaf_hxx +#define BVHStaticLeaf_hxx + +#include +#include "BVHStaticNode.hxx" + +namespace simgear { + +class BVHStaticLeaf : public BVHStaticNode { +public: + virtual ~BVHStaticLeaf(); + + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + virtual SGBoxf computeBoundingBox(const BVHStaticData&) const = 0; + virtual SGVec3f computeCenter(const BVHStaticData&) const = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticNode.cxx b/simgear/scene/bvh/BVHStaticNode.cxx new file mode 100644 index 00000000..4ab67c3f --- /dev/null +++ b/simgear/scene/bvh/BVHStaticNode.cxx @@ -0,0 +1,26 @@ +// 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. +// + +#include "BVHStaticNode.hxx" + +namespace simgear { + +BVHStaticNode::~BVHStaticNode() +{ +} + +} diff --git a/simgear/scene/bvh/BVHStaticNode.hxx b/simgear/scene/bvh/BVHStaticNode.hxx new file mode 100644 index 00000000..8134599a --- /dev/null +++ b/simgear/scene/bvh/BVHStaticNode.hxx @@ -0,0 +1,37 @@ +// 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 BVHStaticNode_hxx +#define BVHStaticNode_hxx + +#include + +namespace simgear { + +class BVHStaticData; +class BVHVisitor; + +class BVHStaticNode : public SGReferenced { +public: + virtual ~BVHStaticNode(); + + virtual void accept(BVHVisitor&, const BVHStaticData&) const = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHStaticTriangle.cxx b/simgear/scene/bvh/BVHStaticTriangle.cxx new file mode 100644 index 00000000..53572060 --- /dev/null +++ b/simgear/scene/bvh/BVHStaticTriangle.cxx @@ -0,0 +1,58 @@ +// 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. +// + +#include "BVHStaticTriangle.hxx" + +#include "BVHVisitor.hxx" + +namespace simgear { + +BVHStaticTriangle::BVHStaticTriangle(unsigned material, + const unsigned indices[3]) : + _material(material) +{ + for (unsigned i = 0; i < 3; ++i) + _indices[i] = indices[i]; +} + +BVHStaticTriangle::~BVHStaticTriangle() +{ +} + +void +BVHStaticTriangle::accept(BVHVisitor& visitor, const BVHStaticData& data) const +{ + visitor.apply(*this, data); +} + +SGBoxf +BVHStaticTriangle::computeBoundingBox(const BVHStaticData& data) const +{ + SGBoxf box; + box.expandBy(data.getVertex(_indices[0])); + box.expandBy(data.getVertex(_indices[1])); + box.expandBy(data.getVertex(_indices[2])); + return box; +} + +SGVec3f +BVHStaticTriangle::computeCenter(const BVHStaticData& data) const +{ + return getTriangle(data).getCenter(); +} + +} diff --git a/simgear/scene/bvh/BVHStaticTriangle.hxx b/simgear/scene/bvh/BVHStaticTriangle.hxx new file mode 100644 index 00000000..79ff391f --- /dev/null +++ b/simgear/scene/bvh/BVHStaticTriangle.hxx @@ -0,0 +1,54 @@ +// 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 BVHStaticTriangle_hxx +#define BVHStaticTriangle_hxx + +#include +#include "BVHStaticData.hxx" +#include "BVHStaticLeaf.hxx" + +namespace simgear { + +class BVHStaticTriangle : public BVHStaticLeaf { +public: + BVHStaticTriangle(unsigned material, const unsigned indices[3]); + virtual ~BVHStaticTriangle(); + + virtual void accept(BVHVisitor& visitor, const BVHStaticData& data) const; + + virtual SGBoxf computeBoundingBox(const BVHStaticData& data) const; + virtual SGVec3f computeCenter(const BVHStaticData& data) const; + + SGTrianglef getTriangle(const BVHStaticData& data) const + { + return SGTrianglef(data.getVertex(_indices[0]), + data.getVertex(_indices[1]), + data.getVertex(_indices[2])); + } + + unsigned getMaterialIndex() const + { return _material; } + +private: + unsigned _indices[3]; + unsigned _material; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHSubTreeCollector.cxx b/simgear/scene/bvh/BVHSubTreeCollector.cxx new file mode 100644 index 00000000..cc7596be --- /dev/null +++ b/simgear/scene/bvh/BVHSubTreeCollector.cxx @@ -0,0 +1,258 @@ +// 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. +// + +#include "BVHSubTreeCollector.hxx" + +#include + +#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" +#include "BVHBoundingBoxVisitor.hxx" + +namespace simgear { + +BVHSubTreeCollector::BVHSubTreeCollector(const SGSphered& sphere) : + _sphere(sphere) +{ +} + +BVHSubTreeCollector::~BVHSubTreeCollector() +{ +} + +void +BVHSubTreeCollector::apply(BVHGroup& group) +{ + if (!intersects(_sphere, group.getBoundingSphere())) + return; + + // The _nodeList content is somehow the 'return value' of the subtree. + // Set it to zero to see if we have something to collect down there. + NodeList parentNodeList; + pushNodeList(parentNodeList); + + group.traverse(*this); + + popNodeList(parentNodeList); +} + +void +BVHSubTreeCollector::apply(BVHTransform& transform) +{ + if (!intersects(_sphere, transform.getBoundingSphere())) + return; + + SGSphered sphere = _sphere; + _sphere = transform.sphereToLocal(sphere); + + NodeList parentNodeList; + pushNodeList(parentNodeList); + + transform.traverse(*this); + + if (haveChildren()) { + BVHTransform* currentBvTransform = new BVHTransform; + currentBvTransform->setTransform(transform); + popNodeList(parentNodeList, currentBvTransform); + } else { + popNodeList(parentNodeList); + } + + _sphere = sphere; +} + +void +BVHSubTreeCollector::apply(BVHMotionTransform& transform) +{ + if (!intersects(_sphere, transform.getBoundingSphere())) + return; + + SGSphered sphere = _sphere; + _sphere = transform.sphereToLocal(sphere, transform.getReferenceTime()); + _sphere.expandBy(transform.sphereToLocal(sphere, transform.getEndTime())); + + NodeList parentNodeList; + pushNodeList(parentNodeList); + + transform.traverse(*this); + + if (haveChildren()) { + BVHMotionTransform* currentBvTransform = new BVHMotionTransform; + currentBvTransform->setTransform(transform); + popNodeList(parentNodeList, currentBvTransform); + } else { + popNodeList(parentNodeList); + } + + _sphere = sphere; +} + +void +BVHSubTreeCollector::apply(BVHLineGeometry& lineSegment) +{ + if (!intersects(_sphere, lineSegment.getBoundingSphere())) + return; + addNode(&lineSegment); +} + +void +BVHSubTreeCollector::apply(BVHStaticGeometry& node) +{ + if (!intersects(_sphere, node.getBoundingSphere())) + return; + + assert(!_staticNode); + node.traverse(*this); + if (!_staticNode) + return; + + BVHStaticGeometry* staticTree; + staticTree = new BVHStaticGeometry(_staticNode, node.getStaticData()); + addNode(staticTree); + _staticNode = 0; +} + +void +BVHSubTreeCollector::apply(const BVHStaticBinary& node, + const BVHStaticData& data) +{ + assert(!_staticNode); + + if (!intersects(_sphere, node.getBoundingBox())) + return; + + SGVec3d corner(node.getBoundingBox().getFarestCorner(_sphere.getCenter())); + if (intersects(_sphere, corner)) { + // If the box is totally contained in the sphere, just take it all + _staticNode = &node; + + } else { + // We have still a chance to seperate something out, try it. + + node.getLeftChild()->accept(*this, data); + SGSharedPtr leftStaticNode = _staticNode; + _staticNode = 0; + node.getRightChild()->accept(*this, data); + SGSharedPtr rightStaticNode = _staticNode; + _staticNode = 0; + + if (leftStaticNode) { + if (rightStaticNode) { + BVHBoundingBoxVisitor bbv; + leftStaticNode->accept(bbv, data); + rightStaticNode->accept(bbv, data); + _staticNode + = new BVHStaticBinary(node.getSplitAxis(), leftStaticNode, + rightStaticNode, bbv.getBox()); + } else { + _staticNode = leftStaticNode; + } + } else { + if (rightStaticNode) { + _staticNode = rightStaticNode; + } else { + // Nothing to report to parents ... + } + } + } +} + +void +BVHSubTreeCollector::apply(const BVHStaticLeaf& node, + const BVHStaticData& data) +{ + if (!intersects(_sphere, node.computeBoundingBox(data))) + return; + _staticNode = &node; +} + +void +BVHSubTreeCollector::apply(const BVHStaticTriangle& node, + const BVHStaticData& data) +{ + if (!intersects(_sphere, node.computeBoundingBox(data))) + return; + _staticNode = &node; +} + +void +BVHSubTreeCollector::addNode(BVHNode* node) +{ + if (!node) + return; + if (!_nodeList.capacity()) + _nodeList.reserve(64); + _nodeList.push_back(node); +} + +void +BVHSubTreeCollector::popNodeList(NodeList& parentNodeList, BVHGroup* transform) +{ + // Only do something if we really have children + if (!_nodeList.empty()) { + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + transform->addChild(*i); + parentNodeList.push_back(transform); + } + _nodeList.swap(parentNodeList); +} + +void +BVHSubTreeCollector::popNodeList(NodeList& parentNodeList) +{ + // Only do something if we really have children + if (!_nodeList.empty()) { + if (_nodeList.size() == 1) { + parentNodeList.push_back(_nodeList.front()); + } else { + BVHGroup* group = new BVHGroup; + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + group->addChild(*i); + parentNodeList.push_back(group); + } + } + _nodeList.swap(parentNodeList); +} + +SGSharedPtr +BVHSubTreeCollector::getNode() const +{ + if (_nodeList.empty()) + return 0; + + if (_nodeList.size() == 1) + return _nodeList.front(); + + BVHGroup* group = new BVHGroup; + NodeList::const_iterator i; + for (i = _nodeList.begin(); i != _nodeList.end(); ++i) + group->addChild(*i); + return group; +} + +} diff --git a/simgear/scene/bvh/BVHSubTreeCollector.hxx b/simgear/scene/bvh/BVHSubTreeCollector.hxx new file mode 100644 index 00000000..b29d6274 --- /dev/null +++ b/simgear/scene/bvh/BVHSubTreeCollector.hxx @@ -0,0 +1,82 @@ +// 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 BVHSubTreeCollector_hxx +#define BVHSubTreeCollector_hxx + +#include + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" +#include "BVHStaticNode.hxx" + +namespace simgear { + +/// Visitor to subcollect parts of an existing bounding volume tree. +/// Given a sphere, it takes those sub parts of the tree that intersect the +/// sphere. Transform nodes of any kind are preserved to be able to ask for +/// intersections a different times. The subcollected tree is kept as small as +/// possible as it does avoid having groups with single childs. +/// Also the BVHStaticGeometry parts are seached for subtrees that are outside +/// the sphere. + +class BVHSubTreeCollector : public BVHVisitor { +public: + typedef std::vector > NodeList; + + BVHSubTreeCollector(const SGSphered& sphere = SGSphered()); + virtual ~BVHSubTreeCollector(); + + virtual void apply(BVHGroup&); + virtual void apply(BVHTransform&); + virtual void apply(BVHMotionTransform&); + virtual void apply(BVHLineGeometry&); + virtual void apply(BVHStaticGeometry&); + + virtual void apply(const BVHStaticBinary&, const BVHStaticData&); + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&); + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&); + + void setSphere(const SGSphered& sphere) + { _sphere = sphere; } + const SGSphered& getSphere() const + { return _sphere; } + + bool haveChildren() const + { return !_nodeList.empty(); } + + void addNode(BVHNode* node); + + void pushNodeList(NodeList& parentNodeList) + { _nodeList.swap(parentNodeList); } + void popNodeList(NodeList& parentNodeList, BVHGroup* transform); + void popNodeList(NodeList& parentNodeList); + + SGSharedPtr getNode() const; + +protected: + NodeList _nodeList; + SGSharedPtr _staticNode; + +private: + SGSphered _sphere; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHTransform.cxx b/simgear/scene/bvh/BVHTransform.cxx new file mode 100644 index 00000000..27b615ad --- /dev/null +++ b/simgear/scene/bvh/BVHTransform.cxx @@ -0,0 +1,95 @@ +// 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. +// + +#include "BVHTransform.hxx" + +#include "BVHVisitor.hxx" +#include "BVHNode.hxx" +#include "BVHGroup.hxx" + +namespace simgear { + +BVHTransform::BVHTransform() : + _toWorld(SGMatrixd::unit()), + _toLocal(SGMatrixd::unit()), + _toWorldAmplification(1), + _toLocalAmplification(1) +{ +} + +BVHTransform::~BVHTransform() +{ +} + +void +BVHTransform::accept(BVHVisitor& visitor) +{ + visitor.apply(*this); +} + +void +BVHTransform::setTransform(const BVHTransform& transform) +{ + _toWorld = transform._toWorld; + _toLocal = transform._toLocal; + _toWorldAmplification = transform._toWorldAmplification; + _toLocalAmplification = transform._toLocalAmplification; + invalidateParentBound(); +} + +void +BVHTransform::setToWorldTransform(const SGMatrixd& transform) +{ + _toWorld = transform; + invert(_toLocal, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +void +BVHTransform::setToLocalTransform(const SGMatrixd& transform) +{ + _toLocal = transform; + invert(_toWorld, transform); + updateAmplificationFactors(); + invalidateParentBound(); +} + +SGSphered +BVHTransform::computeBoundingSphere() const +{ + return sphereToWorld(BVHGroup::computeBoundingSphere()); +} + +void +BVHTransform::updateAmplificationFactors() +{ + // Hmm, this is just a hint, true? + // But anyway, almost all transforms in a scenegraph will + // have them equal to 1 ... + double r = norm(vecToWorld(SGVec3d(1, 0, 0))); + r = std::max(r, norm(vecToWorld(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(vecToWorld(SGVec3d(0, 0, 1)))); + _toWorldAmplification = r; + + r = norm(vecToLocal(SGVec3d(1, 0, 0))); + r = std::max(r, norm(vecToLocal(SGVec3d(0, 1, 0)))); + r = std::max(r, norm(vecToLocal(SGVec3d(0, 0, 1)))); + _toLocalAmplification = r; +} + +} diff --git a/simgear/scene/bvh/BVHTransform.hxx b/simgear/scene/bvh/BVHTransform.hxx new file mode 100644 index 00000000..d8b5096c --- /dev/null +++ b/simgear/scene/bvh/BVHTransform.hxx @@ -0,0 +1,82 @@ +// 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 BVHTransform_hxx +#define BVHTransform_hxx + +#include "BVHGroup.hxx" + +namespace simgear { + +class BVHTransform : public BVHGroup { +public: + BVHTransform(); + virtual ~BVHTransform(); + + virtual void accept(BVHVisitor& visitor); + + void setTransform(const BVHTransform& transform); + + void setToWorldTransform(const SGMatrixd& transform); + const SGMatrixd& getToWorldTransform() const + { return _toWorld; } + + void setToLocalTransform(const SGMatrixd& transform); + const SGMatrixd& getToLocalTransform() const + { return _toLocal; } + + SGVec3d ptToWorld(const SGVec3d& point) const + { return _toWorld.xformPt(point); } + SGVec3d ptToLocal(const SGVec3d& point) const + { return _toLocal.xformPt(point); } + + SGVec3d vecToWorld(const SGVec3d& vec) const + { return _toWorld.xformVec(vec); } + SGVec3d vecToLocal(const SGVec3d& vec) const + { return _toLocal.xformVec(vec); } + + SGLineSegmentd lineSegmentToWorld(const SGLineSegmentd& lineSeg) const + { return lineSeg.transform(_toWorld); } + SGLineSegmentd lineSegmentToLocal(const SGLineSegmentd& lineSeg) const + { return lineSeg.transform(_toLocal); } + + SGSphered sphereToWorld(const SGSphered& sphere) const + { + SGVec3d center = ptToWorld(sphere.getCenter()); + double radius = _toWorldAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + SGSphered sphereToLocal(const SGSphered& sphere) const + { + SGVec3d center = ptToLocal(sphere.getCenter()); + double radius = _toLocalAmplification*sphere.getRadius(); + return SGSphered(center, radius); + } + +private: + virtual SGSphered computeBoundingSphere() const; + void updateAmplificationFactors(); + + SGMatrixd _toWorld; + SGMatrixd _toLocal; + double _toWorldAmplification; + double _toLocalAmplification; +}; + +} + +#endif diff --git a/simgear/scene/bvh/BVHVisitor.hxx b/simgear/scene/bvh/BVHVisitor.hxx new file mode 100644 index 00000000..058cf27c --- /dev/null +++ b/simgear/scene/bvh/BVHVisitor.hxx @@ -0,0 +1,58 @@ +// 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 BVHVisitor_hxx +#define BVHVisitor_hxx + +namespace simgear { + +class BVHStaticData; + +class BVHGroup; +class BVHTransform; +class BVHMotionTransform; +class BVHStaticGeometry; +class BVHLineGeometry; + +class BVHStaticBinary; +class BVHStaticLeaf; +class BVHStaticTriangle; + +class BVHVisitor { +public: + // The magnitudes of pure virtuals is because of the fact that this chaining + // just takes needless runtime. This declaration should force the user of + // this classes to implement a common functionality that should be called + // from each apropriate apply method directly. + virtual ~BVHVisitor() {} + + // High level nodes to handle + virtual void apply(BVHGroup&) = 0; + virtual void apply(BVHTransform&) = 0; + virtual void apply(BVHMotionTransform&) = 0; + virtual void apply(BVHLineGeometry&) = 0; + virtual void apply(BVHStaticGeometry&) = 0; + + // Static tree nodes to handle + virtual void apply(const BVHStaticBinary&, const BVHStaticData&) = 0; + virtual void apply(const BVHStaticLeaf&, const BVHStaticData&) = 0; + virtual void apply(const BVHStaticTriangle&, const BVHStaticData&) = 0; +}; + +} + +#endif diff --git a/simgear/scene/bvh/Makefile.am b/simgear/scene/bvh/Makefile.am new file mode 100644 index 00000000..0b1be985 --- /dev/null +++ b/simgear/scene/bvh/Makefile.am @@ -0,0 +1,46 @@ +includedir = @includedir@/scene/bvh + +check_PROGRAMS = bvhtest +TESTS = $(check_PROGRAMS) + +bvhtest_SOURCES = bvhtest.cxx +bvhtest_LDADD = libsgbvh.a -lsgstructure -lsgmath $(base_LIBS) + +lib_LIBRARIES = libsgbvh.a + +noinst_HEADERS = + +include_HEADERS = \ + BVHBoundingBoxVisitor.hxx \ + BVHDebugCollectVisitor.hxx \ + BVHGroup.hxx \ + BVHLineSegmentVisitor.hxx \ + BVHLineGeometry.hxx \ + BVHMotionTransform.hxx \ + BVHNode.hxx \ + BVHStaticBinary.hxx \ + BVHStaticData.hxx \ + BVHStaticGeometry.hxx \ + BVHStaticGeometryBuilder.hxx \ + BVHStaticLeaf.hxx \ + BVHStaticNode.hxx \ + BVHStaticTriangle.hxx \ + BVHSubTreeCollector.hxx \ + BVHTransform.hxx \ + BVHVisitor.hxx + +libsgbvh_a_SOURCES = \ + BVHGroup.cxx \ + BVHLineGeometry.cxx \ + BVHLineSegmentVisitor.cxx \ + BVHMotionTransform.cxx \ + BVHNode.cxx \ + BVHStaticBinary.cxx \ + BVHStaticGeometry.cxx \ + BVHStaticLeaf.cxx \ + BVHStaticNode.cxx \ + BVHStaticTriangle.cxx \ + BVHSubTreeCollector.cxx \ + BVHTransform.cxx + +INCLUDES = -I$(top_srcdir) diff --git a/simgear/scene/bvh/bvhtest.cxx b/simgear/scene/bvh/bvhtest.cxx new file mode 100644 index 00000000..797299cb --- /dev/null +++ b/simgear/scene/bvh/bvhtest.cxx @@ -0,0 +1,118 @@ +// 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. +// + +#include +#include + +#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" + +#include "BVHBoundingBoxVisitor.hxx" +#include "BVHSubTreeCollector.hxx" +#include "BVHLineSegmentVisitor.hxx" + +using namespace simgear; + +BVHNode* +buildSingleTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3) +{ + BVHStaticData* staticData = new BVHStaticData; + unsigned indices[3] = { + staticData->addVertex(v1), + staticData->addVertex(v2), + staticData->addVertex(v3) + }; + BVHStaticTriangle* staticTriangle = new BVHStaticTriangle(~0u, indices); + return new BVHStaticGeometry(staticTriangle, staticData); +} + +bool +testLineIntersections() +{ + SGVec3f v1(-1, -1, 0); + SGVec3f v2(1, -1, 0); + SGVec3f v3(-1, 1, 0); + SGSharedPtr node = buildSingleTriangle(v1, v2, v3); + + SGLineSegmentd lineSegment(SGVec3d(0, 0, -1), SGVec3d(0, 0, 1)); + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment); + node->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + } + + SGVec3d position(1000, 1000, 1000); + SGMatrixd matrix(position); + SGSharedPtr transform1 = new BVHTransform; + transform1->setToWorldTransform(matrix); + transform1->addChild(node); + + SGSharedPtr transform2 = new BVHTransform; + transform2->setToLocalTransform(matrix); + transform2->addChild(transform1); + + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment); + transform2->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + } + + SGSharedPtr transform3 = new BVHMotionTransform; + transform3->setLinearVelocity(SGVec3d(0, 0, 1)); + transform3->setAngularVelocity(SGVec3d(1, 0, 0)); + transform3->addChild(node); + + { + BVHLineSegmentVisitor lineSegmentVisitor(lineSegment, 0); + transform3->accept(lineSegmentVisitor); + if (lineSegmentVisitor.empty()) + return false; + if (!equivalent(lineSegmentVisitor.getPoint(), SGVec3d(0, 0, 0))) + return false; + if (!equivalent(lineSegmentVisitor.getLinearVelocity(), + SGVec3d(0, 1, 1))) + return false; + if (!equivalent(lineSegmentVisitor.getAngularVelocity(), + SGVec3d(1, 0, 0))) + return false; + } + + return true; +} + +int +main(int argc, char** argv) +{ + if (!testLineIntersections()) + return EXIT_FAILURE; + return EXIT_SUCCESS; +}