scene: Factor out a common primitive functor.

This kind of work is done two times for different
flavours of bounding volume generation. Factor
out and use this in BVHPageNodeOSG.cxx and
BoundingVolumeBuildVisitor.hxx.
This commit is contained in:
Mathias Froehlich 2012-09-25 23:42:14 +02:00
parent cafbf860be
commit 63aa16b97c
5 changed files with 490 additions and 618 deletions

View File

@ -31,7 +31,6 @@
#include <osg/PagedLOD> #include <osg/PagedLOD>
#include <osg/ProxyNode> #include <osg/ProxyNode>
#include <osg/Transform> #include <osg/Transform>
#include <osg/TriangleFunctor>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
#include <simgear/scene/material/mat.hxx> #include <simgear/scene/material/mat.hxx>
@ -43,303 +42,40 @@
#include <simgear/bvh/BVHStaticGeometryBuilder.hxx> #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
#include "PrimitiveCollector.hxx"
namespace simgear { namespace simgear {
class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor { class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor {
public: public:
class PFunctor : public osg::PrimitiveFunctor { class _PrimitiveCollector : public PrimitiveCollector {
public: public:
PFunctor() : _PrimitiveCollector() :
_modeCache(0) _geometryBuilder(new BVHStaticGeometryBuilder)
{ { }
_geometryBuilder = new BVHStaticGeometryBuilder; virtual ~_PrimitiveCollector()
}
virtual ~PFunctor()
{ } { }
virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices) virtual void addPoint(const osg::Vec3d& v1)
{ }
virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2)
{ }
virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3)
{ {
_vertices.resize(count); _geometryBuilder->addTriangle(toVec3f(toSG(v1)), toVec3f(toSG(v2)), toVec3f(toSG(v3)));
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
}
virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
vertices[i][1]/vertices[i][3],
vertices[i][2]/vertices[i][3]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
}
virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
vertices[i][1]/vertices[i][3],
vertices[i][2]/vertices[i][3]);
}
virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
{
if (_vertices.empty() || count <= 0)
return;
GLsizei end = first + count;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = first; i < end - 2; i += 3) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_QUADS):
for (GLsizei i = first; i < end - 3; i += 4) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = first; i < end - 3; i += 2) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
case (GL_TRIANGLE_FAN):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(first, i + 1, i + 2);
}
break;
case (GL_POINTS):
for (GLsizei i = first; i < end; ++i) {
addPoint(i);
}
break;
case (GL_LINES):
for (GLsizei i = first; i < end - 1; i += 2) {
addLine(i, i + 1);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
addLine(end - 1, first);
break;
default:
break;
}
}
virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void begin(GLenum mode)
{
_modeCache = mode;
_vertices.resize(0);
}
virtual void vertex(const osg::Vec2& v)
{
_vertices.push_back(SGVec3f(v[0], v[1], 0));
}
virtual void vertex(const osg::Vec3& v)
{
_vertices.push_back(SGVec3f(v[0], v[1], v[2]));
}
virtual void vertex(const osg::Vec4& v)
{
_vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
}
virtual void vertex(float x, float y)
{
_vertices.push_back(SGVec3f(x, y, 0));
}
virtual void vertex(float x, float y, float z)
{
_vertices.push_back(SGVec3f(x, y, z));
}
virtual void vertex(float x, float y, float z, float w)
{
_vertices.push_back(SGVec3f(x/w, y/w, z/w));
}
virtual void end()
{
if (_vertices.empty())
return;
drawArrays(_modeCache, 0, _vertices.size());
}
template<typename index_type>
void drawElementsTemplate(GLenum mode, GLsizei count,
const index_type* indices)
{
if (_vertices.empty() || indices == 0 || count <= 0)
return;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = 0; i < count - 2; i += 3) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_QUADS):
for (GLsizei i = 0; i < count - 3; i += 4) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = 0; i < count - 3; i += 2) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_POLYGON):
case (GL_TRIANGLE_FAN):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[0], indices[i + 1], indices[i + 2]);
}
break;
case (GL_POINTS):
for(GLsizei i = 0; i < count; ++i) {
addPoint(indices[i]);
}
break;
case (GL_LINES):
for (GLsizei i = 0; i < count - 1; i += 2) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
addLine(indices[count - 1], indices[0]);
break;
default:
break;
}
}
void addPoint(unsigned i1)
{
addPoint(_vertices[i1]);
}
void addLine(unsigned i1, unsigned i2)
{
addLine(_vertices[i1], _vertices[i2]);
}
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
{
addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
}
void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
{
addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
}
void addPoint(const SGVec3f& v1)
{
}
void addLine(const SGVec3f& v1, const SGVec3f& v2)
{
}
void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
{
_geometryBuilder->addTriangle(v1, v2, v3);
}
void addQuad(const SGVec3f& v1, const SGVec3f& v2,
const SGVec3f& v3, const SGVec3f& v4)
{
_geometryBuilder->addTriangle(v1, v2, v3);
_geometryBuilder->addTriangle(v1, v3, v4);
} }
BVHNode* buildTreeAndClear() BVHNode* buildTreeAndClear()
{ {
BVHNode* bvNode = _geometryBuilder->buildTree(); BVHNode* bvNode = _geometryBuilder->buildTree();
_geometryBuilder = new BVHStaticGeometryBuilder; _geometryBuilder = new BVHStaticGeometryBuilder;
_vertices.clear();
return bvNode; return bvNode;
} }
void swap(PFunctor& primitiveFunctor) void swap(_PrimitiveCollector& primitiveCollector)
{ {
_vertices.swap(primitiveFunctor._vertices); PrimitiveCollector::swap(primitiveCollector);
std::swap(_modeCache, primitiveFunctor._modeCache); std::swap(_geometryBuilder, primitiveCollector._geometryBuilder);
std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
} }
void setCurrentMaterial(const BVHMaterial* material) void setCurrentMaterial(const BVHMaterial* material)
@ -351,9 +87,6 @@ public:
return _geometryBuilder->getCurrentMaterial(); return _geometryBuilder->getCurrentMaterial();
} }
std::vector<SGVec3f> _vertices;
GLenum _modeCache;
SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder; SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
}; };
@ -368,10 +101,10 @@ public:
const BVHMaterial* pushMaterial(osg::Geode* geode) const BVHMaterial* pushMaterial(osg::Geode* geode)
{ {
const BVHMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial(); const BVHMaterial* oldMaterial = _primitiveCollector.getCurrentMaterial();
const BVHMaterial* material = SGMaterialLib::findMaterial(geode); const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
if (material) if (material)
_primitiveFunctor.setCurrentMaterial(material); _primitiveCollector.setCurrentMaterial(material);
return oldMaterial; return oldMaterial;
} }
@ -380,9 +113,9 @@ public:
const BVHMaterial* oldMaterial = pushMaterial(&geode); const BVHMaterial* oldMaterial = pushMaterial(&geode);
for(unsigned i = 0; i < geode.getNumDrawables(); ++i) for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
geode.getDrawable(i)->accept(_primitiveFunctor); geode.getDrawable(i)->accept(_primitiveCollector);
_primitiveFunctor.setCurrentMaterial(oldMaterial); _primitiveCollector.setCurrentMaterial(oldMaterial);
} }
virtual void apply(osg::Group& group) virtual void apply(osg::Group& group)
@ -390,11 +123,11 @@ public:
// FIXME optimize this to collapse more leafs // FIXME optimize this to collapse more leafs
// push the current active primitive list // push the current active primitive list
PFunctor previousPrimitives; _PrimitiveCollector previousPrimitives;
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
const BVHMaterial* mat = previousPrimitives.getCurrentMaterial(); const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
_primitiveFunctor.setCurrentMaterial(mat); _primitiveCollector.setCurrentMaterial(mat);
NodeVector nodeVector; NodeVector nodeVector;
_nodeVector.swap(nodeVector); _nodeVector.swap(nodeVector);
@ -422,7 +155,7 @@ public:
} }
// pop the current active primitive list // pop the current active primitive list
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
} }
virtual void apply(osg::Transform& transform) virtual void apply(osg::Transform& transform)
@ -435,11 +168,11 @@ public:
return; return;
// push the current active primitive list // push the current active primitive list
PFunctor previousPrimitives; _PrimitiveCollector previousPrimitives;
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
const BVHMaterial* mat = previousPrimitives.getCurrentMaterial(); const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
_primitiveFunctor.setCurrentMaterial(mat); _primitiveCollector.setCurrentMaterial(mat);
NodeVector nodeVector; NodeVector nodeVector;
_nodeVector.swap(nodeVector); _nodeVector.swap(nodeVector);
@ -455,7 +188,7 @@ public:
_nodeVector.swap(nodeVector); _nodeVector.swap(nodeVector);
// pop the current active primitive list // pop the current active primitive list
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
if (!nodeVector.empty()) { if (!nodeVector.empty()) {
SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform; SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform;
@ -479,7 +212,7 @@ public:
void addBoundingVolumeTreeToNode() void addBoundingVolumeTreeToNode()
{ {
// Build the flat tree. // Build the flat tree.
BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear(); BVHNode* bvNode = _primitiveCollector.buildTreeAndClear();
// Nothing in there? // Nothing in there?
if (!bvNode) if (!bvNode)
@ -553,7 +286,7 @@ public:
} }
private: private:
PFunctor _primitiveFunctor; _PrimitiveCollector _primitiveCollector;
typedef std::vector<SGSharedPtr<BVHNode> > NodeVector; typedef std::vector<SGSharedPtr<BVHNode> > NodeVector;
NodeVector _nodeVector; NodeVector _nodeVector;
}; };

View File

@ -29,309 +29,47 @@
#include <simgear/scene/material/mat.hxx> #include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx> #include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx> #include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx> #include <simgear/scene/util/SGSceneUserData.hxx>
#include <simgear/math/SGGeometry.hxx> #include <simgear/math/SGGeometry.hxx>
#include <simgear/bvh/BVHStaticGeometryBuilder.hxx> #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
#include "PrimitiveCollector.hxx"
namespace simgear { namespace simgear {
class BoundingVolumeBuildVisitor : public osg::NodeVisitor { class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
public: public:
class PFunctor : public osg::PrimitiveFunctor { class _PrimitiveCollector : public PrimitiveCollector {
public: public:
PFunctor() : _PrimitiveCollector() :
_modeCache(0) _geometryBuilder(new BVHStaticGeometryBuilder)
{ { }
_geometryBuilder = new BVHStaticGeometryBuilder; virtual ~_PrimitiveCollector()
}
virtual ~PFunctor()
{ } { }
virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices) virtual void addPoint(const osg::Vec3d& v1)
{ }
virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2)
{ }
virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3)
{ {
_vertices.resize(count); _geometryBuilder->addTriangle(toVec3f(toSG(v1)), toVec3f(toSG(v2)), toVec3f(toSG(v3)));
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
}
virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
vertices[i][1]/vertices[i][3],
vertices[i][2]/vertices[i][3]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
}
virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
}
virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
{
_vertices.resize(count);
for (unsigned i = 0; i < count; ++i)
_vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
vertices[i][1]/vertices[i][3],
vertices[i][2]/vertices[i][3]);
}
virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
{
if (_vertices.empty() || count <= 0)
return;
GLsizei end = first + count;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = first; i < end - 2; i += 3) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_QUADS):
for (GLsizei i = first; i < end - 3; i += 4) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = first; i < end - 3; i += 2) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
case (GL_TRIANGLE_FAN):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(first, i + 1, i + 2);
}
break;
case (GL_POINTS):
for (GLsizei i = first; i < end; ++i) {
addPoint(i);
}
break;
case (GL_LINES):
for (GLsizei i = first; i < end - 1; i += 2) {
addLine(i, i + 1);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
addLine(end - 1, first);
break;
default:
break;
}
}
virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
{
drawElementsTemplate(mode, count, indices);
}
virtual void begin(GLenum mode)
{
_modeCache = mode;
_vertices.resize(0);
}
virtual void vertex(const osg::Vec2& v)
{
_vertices.push_back(SGVec3f(v[0], v[1], 0));
}
virtual void vertex(const osg::Vec3& v)
{
_vertices.push_back(SGVec3f(v[0], v[1], v[2]));
}
virtual void vertex(const osg::Vec4& v)
{
_vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
}
virtual void vertex(float x, float y)
{
_vertices.push_back(SGVec3f(x, y, 0));
}
virtual void vertex(float x, float y, float z)
{
_vertices.push_back(SGVec3f(x, y, z));
}
virtual void vertex(float x, float y, float z, float w)
{
_vertices.push_back(SGVec3f(x/w, y/w, z/w));
}
virtual void end()
{
if (_vertices.empty())
return;
drawArrays(_modeCache, 0, _vertices.size());
}
template<typename index_type>
void drawElementsTemplate(GLenum mode, GLsizei count,
const index_type* indices)
{
if (_vertices.empty() || indices == 0 || count <= 0)
return;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = 0; i < count - 2; i += 3) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_QUADS):
for (GLsizei i = 0; i < count - 3; i += 4) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = 0; i < count - 3; i += 2) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_POLYGON):
case (GL_TRIANGLE_FAN):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[0], indices[i + 1], indices[i + 2]);
}
break;
case (GL_POINTS):
for(GLsizei i = 0; i < count; ++i) {
addPoint(indices[i]);
}
break;
case (GL_LINES):
for (GLsizei i = 0; i < count - 1; i += 2) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
addLine(indices[count - 1], indices[0]);
break;
default:
break;
}
}
void addPoint(unsigned i1)
{
addPoint(_vertices[i1]);
}
void addLine(unsigned i1, unsigned i2)
{
addLine(_vertices[i1], _vertices[i2]);
}
void addTriangle(unsigned i1, unsigned i2, unsigned i3)
{
addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
}
void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
{
addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
}
void addPoint(const SGVec3f& v1)
{
}
void addLine(const SGVec3f& v1, const SGVec3f& v2)
{
}
void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
{
_geometryBuilder->addTriangle(v1, v2, v3);
}
void addQuad(const SGVec3f& v1, const SGVec3f& v2,
const SGVec3f& v3, const SGVec3f& v4)
{
_geometryBuilder->addTriangle(v1, v2, v3);
_geometryBuilder->addTriangle(v1, v3, v4);
} }
BVHNode* buildTreeAndClear() BVHNode* buildTreeAndClear()
{ {
BVHNode* bvNode = _geometryBuilder->buildTree(); BVHNode* bvNode = _geometryBuilder->buildTree();
_geometryBuilder = new BVHStaticGeometryBuilder; _geometryBuilder = new BVHStaticGeometryBuilder;
_vertices.clear();
return bvNode; return bvNode;
} }
void swap(PFunctor& primitiveFunctor) void swap(_PrimitiveCollector& primitiveCollector)
{ {
_vertices.swap(primitiveFunctor._vertices); PrimitiveCollector::swap(primitiveCollector);
std::swap(_modeCache, primitiveFunctor._modeCache); std::swap(_geometryBuilder, primitiveCollector._geometryBuilder);
std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
} }
void setCurrentMaterial(const BVHMaterial* material) void setCurrentMaterial(const BVHMaterial* material)
@ -343,37 +81,9 @@ public:
return _geometryBuilder->getCurrentMaterial(); return _geometryBuilder->getCurrentMaterial();
} }
std::vector<SGVec3f> _vertices;
GLenum _modeCache;
SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder; SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
}; };
// class PrimitiveIndexFunctor
// {
// public:
// virtual ~PrimitiveIndexFunctor() {}
// virtual void setVertexArray(unsigned int count,const Vec2* vertices) = 0;
// virtual void setVertexArray(unsigned int count,const Vec3* vertices) = 0;
// virtual void setVertexArray(unsigned int count,const Vec4* vertices) = 0;
// virtual void setVertexArray(unsigned int count,const Vec2d* vertices) = 0;
// virtual void setVertexArray(unsigned int count,const Vec3d* vertices) = 0;
// virtual void setVertexArray(unsigned int count,const Vec4d* vertices) = 0;
// virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0;
// virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) = 0;
// virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) = 0;
// virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) = 0;
// virtual void begin(GLenum mode) = 0;
// virtual void vertex(unsigned int pos) = 0;
// virtual void end() = 0;
// };
BoundingVolumeBuildVisitor(bool dumpIntoLeafs) : BoundingVolumeBuildVisitor(bool dumpIntoLeafs) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN), osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_dumpIntoLeafs(dumpIntoLeafs) _dumpIntoLeafs(dumpIntoLeafs)
@ -386,16 +96,16 @@ public:
const BVHMaterial* pushMaterial(osg::Geode* geode) const BVHMaterial* pushMaterial(osg::Geode* geode)
{ {
const BVHMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial(); const BVHMaterial* oldMaterial = _primitiveCollector.getCurrentMaterial();
const BVHMaterial* material = SGMaterialLib::findMaterial(geode); const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
if (material) if (material)
_primitiveFunctor.setCurrentMaterial(material); _primitiveCollector.setCurrentMaterial(material);
return oldMaterial; return oldMaterial;
} }
void fillWith(osg::Drawable* drawable) void fillWith(osg::Drawable* drawable)
{ {
drawable->accept(_primitiveFunctor); drawable->accept(_primitiveCollector);
} }
virtual void apply(osg::Geode& geode) virtual void apply(osg::Geode& geode)
@ -408,11 +118,11 @@ public:
bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs; bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs;
if (flushHere) { if (flushHere) {
// push the current active primitive list // push the current active primitive list
PFunctor previousPrimitives; _PrimitiveCollector previousPrimitives;
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
const BVHMaterial* mat = previousPrimitives.getCurrentMaterial(); const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
_primitiveFunctor.setCurrentMaterial(mat); _primitiveCollector.setCurrentMaterial(mat);
// walk the children // walk the children
for(unsigned i = 0; i < geode.getNumDrawables(); ++i) for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
@ -422,13 +132,13 @@ public:
addBoundingVolumeTreeToNode(geode); addBoundingVolumeTreeToNode(geode);
// pop the current active primitive list // pop the current active primitive list
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
} else { } else {
for(unsigned i = 0; i < geode.getNumDrawables(); ++i) for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
fillWith(geode.getDrawable(i)); fillWith(geode.getDrawable(i));
} }
_primitiveFunctor.setCurrentMaterial(oldMaterial); _primitiveCollector.setCurrentMaterial(oldMaterial);
} }
virtual void apply(osg::Group& group) virtual void apply(osg::Group& group)
@ -455,11 +165,11 @@ public:
return; return;
// push the current active primitive list // push the current active primitive list
PFunctor previousPrimitives; _PrimitiveCollector previousPrimitives;
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
const BVHMaterial* mat = previousPrimitives.getCurrentMaterial(); const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
_primitiveFunctor.setCurrentMaterial(mat); _primitiveCollector.setCurrentMaterial(mat);
// walk the children // walk the children
traverse(node); traverse(node);
@ -470,7 +180,7 @@ public:
addBoundingVolumeTreeToNode(node); addBoundingVolumeTreeToNode(node);
// pop the current active primitive list // pop the current active primitive list
_primitiveFunctor.swap(previousPrimitives); _primitiveCollector.swap(previousPrimitives);
} }
void traverseAndCollect(osg::Node& node) void traverseAndCollect(osg::Node& node)
@ -495,7 +205,7 @@ public:
void addBoundingVolumeTreeToNode(osg::Node& node) void addBoundingVolumeTreeToNode(osg::Node& node)
{ {
// Build the flat tree. // Build the flat tree.
BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear(); BVHNode* bvNode = _primitiveCollector.buildTreeAndClear();
// Nothing in there? // Nothing in there?
if (!bvNode) if (!bvNode)
@ -518,7 +228,7 @@ public:
} }
private: private:
PFunctor _primitiveFunctor; _PrimitiveCollector _primitiveCollector;
bool _dumpIntoLeafs; bool _dumpIntoLeafs;
}; };

View File

@ -7,6 +7,7 @@ set(HEADERS
CheckSceneryVisitor.hxx CheckSceneryVisitor.hxx
ConditionNode.hxx ConditionNode.hxx
ModelRegistry.hxx ModelRegistry.hxx
PrimitiveCollector.hxx
SGClipGroup.hxx SGClipGroup.hxx
SGInteractionAnimation.hxx SGInteractionAnimation.hxx
SGMaterialAnimation.hxx SGMaterialAnimation.hxx
@ -29,6 +30,7 @@ set(SOURCES
CheckSceneryVisitor.cxx CheckSceneryVisitor.cxx
ConditionNode.cxx ConditionNode.cxx
ModelRegistry.cxx ModelRegistry.cxx
PrimitiveCollector.cxx
SGClipGroup.cxx SGClipGroup.cxx
SGInteractionAnimation.cxx SGInteractionAnimation.cxx
SGLightAnimation.cxx SGLightAnimation.cxx

View File

@ -0,0 +1,350 @@
// Copyright (C) 2008 - 2012 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.
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "PrimitiveCollector.hxx"
#include <simgear/scene/util/OsgMath.hxx>
namespace simgear {
PrimitiveCollector::PrimitiveCollector() :
_mode(0)
{
}
PrimitiveCollector::~PrimitiveCollector()
{
}
void
PrimitiveCollector::swap(PrimitiveCollector& primitiveFunctor)
{
_vertices.swap(primitiveFunctor._vertices);
std::swap(_mode, primitiveFunctor._mode);
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec2* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec3d(vertices[i][0], vertices[i][1], 0));
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec3* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec3d(vertices[i][0], vertices[i][1], vertices[i][2]));
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec4* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec4d(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]));
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec2d* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec3d(vertices[i][0], vertices[i][1], 0));
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec3d* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec3d(vertices[i][0], vertices[i][1], vertices[i][2]));
}
void
PrimitiveCollector::setVertexArray(unsigned int count, const osg::Vec4d* vertices)
{
_vertices.resize(0);
_vertices.reserve(count);
for (unsigned i = 0; i < count; ++i)
addVertex(osg::Vec4d(vertices[i][0], vertices[i][1], vertices[i][2], vertices[i][3]));
}
void
PrimitiveCollector::drawArrays(GLenum mode, GLint first, GLsizei count)
{
if (_vertices.empty() || count <= 0)
return;
GLsizei end = first + count;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = first; i < end - 2; i += 3) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(i, i + 1, i + 2);
}
break;
case (GL_QUADS):
for (GLsizei i = first; i < end - 3; i += 4) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = first; i < end - 3; i += 2) {
addQuad(i, i + 1, i + 2, i + 3);
}
break;
case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
case (GL_TRIANGLE_FAN):
for (GLsizei i = first; i < end - 2; ++i) {
addTriangle(first, i + 1, i + 2);
}
break;
case (GL_POINTS):
for (GLsizei i = first; i < end; ++i) {
addPoint(i);
}
break;
case (GL_LINES):
for (GLsizei i = first; i < end - 1; i += 2) {
addLine(i, i + 1);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = first; i < end - 1; ++i) {
addLine(i, i + 1);
}
addLine(end - 1, first);
break;
default:
break;
}
}
template<typename index_type>
void
PrimitiveCollector::drawElementsTemplate(GLenum mode, GLsizei count, const index_type* indices)
{
if (_vertices.empty() || indices == 0 || count <= 0)
return;
switch(mode) {
case (GL_TRIANGLES):
for (GLsizei i = 0; i < count - 2; i += 3) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_TRIANGLE_STRIP):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[i], indices[i + 1], indices[i + 2]);
}
break;
case (GL_QUADS):
for (GLsizei i = 0; i < count - 3; i += 4) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_QUAD_STRIP):
for (GLsizei i = 0; i < count - 3; i += 2) {
addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
}
break;
case (GL_POLYGON):
case (GL_TRIANGLE_FAN):
for (GLsizei i = 0; i < count - 2; ++i) {
addTriangle(indices[0], indices[i + 1], indices[i + 2]);
}
break;
case (GL_POINTS):
for(GLsizei i = 0; i < count; ++i) {
addPoint(indices[i]);
}
break;
case (GL_LINES):
for (GLsizei i = 0; i < count - 1; i += 2) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_STRIP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
break;
case (GL_LINE_LOOP):
for (GLsizei i = 0; i < count - 1; ++i) {
addLine(indices[i], indices[i + 1]);
}
addLine(indices[count - 1], indices[0]);
break;
default:
break;
}
}
void
PrimitiveCollector::drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
{
drawElementsTemplate(mode, count, indices);
}
void PrimitiveCollector::drawElements(GLenum mode, GLsizei count, const GLushort* indices)
{
drawElementsTemplate(mode, count, indices);
}
void
PrimitiveCollector::drawElements(GLenum mode, GLsizei count, const GLuint* indices)
{
drawElementsTemplate(mode, count, indices);
}
void
PrimitiveCollector::begin(GLenum mode)
{
_mode = mode;
_vertices.resize(0);
}
void
PrimitiveCollector::vertex(const osg::Vec2& v)
{
addVertex(osg::Vec3d(v[0], v[1], 0));
}
void
PrimitiveCollector::vertex(const osg::Vec3& v)
{
addVertex(osg::Vec3d(v[0], v[1], v[2]));
}
void
PrimitiveCollector::vertex(const osg::Vec4& v)
{
addVertex(osg::Vec4d(v[0], v[1], v[2], v[3]));
}
void
PrimitiveCollector::vertex(float x, float y)
{
addVertex(osg::Vec3d(x, y, 0));
}
void
PrimitiveCollector::vertex(float x, float y, float z)
{
addVertex(osg::Vec3d(x, y, z));
}
void
PrimitiveCollector::vertex(float x, float y, float z, float w)
{
addVertex(osg::Vec4d(x, y, z, w));
}
void
PrimitiveCollector::end()
{
if (_vertices.empty())
return;
drawArrays(_mode, 0, _vertices.size());
}
void
PrimitiveCollector::addVertex(const osg::Vec3d& v)
{
_vertices.push_back(v);
}
void
PrimitiveCollector::addVertex(const osg::Vec4d& v)
{
_vertices.push_back(osg::Vec3d(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
}
void
PrimitiveCollector::addPoint(unsigned i1)
{
if (_vertices.size() <= i1)
return;
addPoint(_vertices[i1]);
}
void
PrimitiveCollector::addLine(unsigned i1, unsigned i2)
{
size_t size = _vertices.size();
if (size <= i1 || size <= i2)
return;
addLine(_vertices[i1], _vertices[i2]);
}
void
PrimitiveCollector::addTriangle(unsigned i1, unsigned i2, unsigned i3)
{
size_t size = _vertices.size();
if (size <= i1 || size <= i2 || size <= i3)
return;
addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
}
void
PrimitiveCollector::addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
{
addTriangle(i1, i2, i3);
addTriangle(i1, i3, i4);
}
}

View File

@ -0,0 +1,77 @@
// Copyright (C) 2008 - 2012 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 SIMGEAR_PRIMITIVE_COLLECTOR_HXX
#define SIMGEAR_PRIMITIVE_COLLECTOR_HXX
#include <osg/Matrix>
#include <osg/PrimitiveSet>
namespace simgear {
class PrimitiveCollector : public osg::PrimitiveFunctor {
public:
PrimitiveCollector();
virtual ~PrimitiveCollector();
void swap(PrimitiveCollector& primitiveFunctor);
virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices);
virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices);
virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices);
virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices);
virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices);
virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices);
virtual void drawArrays(GLenum mode, GLint first, GLsizei count);
template<typename index_type>
void drawElementsTemplate(GLenum mode, GLsizei count, const index_type* indices);
virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices);
virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices);
virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices);
virtual void begin(GLenum mode);
virtual void vertex(const osg::Vec2& v);
virtual void vertex(const osg::Vec3& v);
virtual void vertex(const osg::Vec4& v);
virtual void vertex(float x, float y);
virtual void vertex(float x, float y, float z);
virtual void vertex(float x, float y, float z, float w);
virtual void end();
void addVertex(const osg::Vec3d& v);
void addVertex(const osg::Vec4d& v);
void addPoint(unsigned i1);
void addLine(unsigned i1, unsigned i2);
void addTriangle(unsigned i1, unsigned i2, unsigned i3);
void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4);
/// The callback functions that are called on an apropriate primitive
virtual void addPoint(const osg::Vec3d& v1) = 0;
virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2) = 0;
virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3) = 0;
private:
std::vector<osg::Vec3d> _vertices;
GLenum _mode;
};
}
#endif