From 83b5cabac95a1b17aebccd06e3067fbd3bf5710b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 17 Aug 2016 21:34:32 +0100 Subject: [PATCH] Refactored ShapeDrawable so that it is subclassed from osg::Geometry rather than osg::Drawable. Created a BuildShapeGeometryVisitor visitor that can create osg::Geometry for osg::Shape objects --- include/osg/Drawable | 2 +- include/osg/Shape | 151 +++ include/osg/ShapeDrawable | 139 +-- src/osg/Shape.cpp | 1014 +++++++++++++++++++ src/osg/ShapeDrawable.cpp | 1983 +------------------------------------ 5 files changed, 1210 insertions(+), 2079 deletions(-) diff --git a/include/osg/Drawable b/include/osg/Drawable index 13be012c0..c4857af54 100644 --- a/include/osg/Drawable +++ b/include/osg/Drawable @@ -185,7 +185,7 @@ class OSG_EXPORT Drawable : public Node * geometry generation. * @see osg::Shape. */ - inline void setShape(Shape* shape) { _shape = shape; } + virtual void setShape(Shape* shape) { _shape = shape; } template void setShape(const ref_ptr& shape) { setShape(shape.get()); } diff --git a/include/osg/Shape b/include/osg/Shape index d5be8ae7c..09ea6e8c8 100644 --- a/include/osg/Shape +++ b/include/osg/Shape @@ -650,6 +650,157 @@ class OSG_EXPORT CompositeShape : public Shape }; + +/** Describe several hints that can be passed to a Tessellator (like the one used + * by \c ShapeDrawable) as a mean to try to influence the way it works. + */ +class TessellationHints : public Object +{ + public: + + TessellationHints(): + _TessellationMode(USE_SHAPE_DEFAULTS), + _detailRatio(1.0f), + _targetNumFaces(100), + _createFrontFace(true), + _createBackFace(false), + _createNormals(true), + _createTextureCoords(false), + _createTop(true), + _createBody(true), + _createBottom(true) {} + + + TessellationHints(const TessellationHints& tess, const CopyOp& copyop=CopyOp::SHALLOW_COPY): + Object(tess,copyop), + _TessellationMode(tess._TessellationMode), + _detailRatio(tess._detailRatio), + _targetNumFaces(tess._targetNumFaces), + _createFrontFace(tess._createFrontFace), + _createBackFace(tess._createBackFace), + _createNormals(tess._createNormals), + _createTextureCoords(tess._createTextureCoords), + _createTop(tess._createTop), + _createBody(tess._createBody), + _createBottom(tess._createBottom) {} + + META_Object(osg,TessellationHints); + + + enum TessellationMode + { + USE_SHAPE_DEFAULTS, + USE_TARGET_NUM_FACES + }; + + inline void setTessellationMode(TessellationMode mode) { _TessellationMode=mode; } + inline TessellationMode getTessellationMode() const { return _TessellationMode; } + + inline void setDetailRatio(float ratio) { _detailRatio = ratio; } + inline float getDetailRatio() const { return _detailRatio; } + + inline void setTargetNumFaces(unsigned int target) { _targetNumFaces=target; } + inline unsigned int getTargetNumFaces() const { return _targetNumFaces; } + + inline void setCreateFrontFace(bool on) { _createFrontFace=on; } + inline bool getCreateFrontFace() const { return _createFrontFace; } + + inline void setCreateBackFace(bool on) { _createBackFace=on; } + inline bool getCreateBackFace() const { return _createBackFace; } + + inline void setCreateNormals(bool on) { _createNormals=on; } + inline bool getCreateNormals() const { return _createNormals; } + + inline void setCreateTextureCoords(bool on) { _createTextureCoords=on; } + inline bool getCreateTextureCoords() const { return _createTextureCoords; } + + inline void setCreateTop(bool on) { _createTop=on; } + inline bool getCreateTop() const { return _createTop; } + + inline void setCreateBody(bool on) { _createBody=on; } + inline bool getCreateBody() const { return _createBody; } + + inline void setCreateBottom(bool on) { _createBottom=on; } + inline bool getCreateBottom() const { return _createBottom; } + + protected: + + ~TessellationHints() {} + + + TessellationMode _TessellationMode; + + float _detailRatio; + unsigned int _targetNumFaces; + + bool _createFrontFace; + bool _createBackFace; + bool _createNormals; + bool _createTextureCoords; + + bool _createTop; + bool _createBody; + bool _createBottom; + +}; + +// forward declare; +class Geometry; + +/** Convinience class for populating an osg::Geomtry with vertex, normals, texture coords and primitives that can render a Shape. */ +class OSG_EXPORT BuildShapeGeometryVisitor : public ConstShapeVisitor +{ + public: + + BuildShapeGeometryVisitor(Geometry* geometry, TessellationHints* hints); + + virtual void apply(const Sphere&); + virtual void apply(const Box&); + virtual void apply(const Cone&); + virtual void apply(const Cylinder&); + virtual void apply(const Capsule&); + virtual void apply(const InfinitePlane&); + + virtual void apply(const TriangleMesh&); + virtual void apply(const ConvexHull&); + virtual void apply(const HeightField&); + + virtual void apply(const CompositeShape&); + + void Normal(const Vec3f& v) { _normals->push_back(v); } + void Normal3f(float x, float y, float z) { _normals->push_back(Vec3(x,y,z)); } + void TexCoord2f(float x, float y) { _texcoords->push_back(Vec2(x,y)); } + void Vertex(const Vec3f& v) { _vertices->push_back(v); } + void Vertex3f(float x, float y, float z) { _vertices->push_back(Vec3(x,y,z)); } + + void setMatrix(const osg::Matrixd& m); + + void Begin(GLenum mode); + void End(); + +protected: + + BuildShapeGeometryVisitor& operator = (const BuildShapeGeometryVisitor&) { return *this; } + + enum SphereHalf { SphereTopHalf, SphereBottomHalf }; + + // helpers for apply( Cylinder | Sphere | Capsule ) + void drawCylinderBody(unsigned int numSegments, float radius, float height); + void drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset = 0.0f); + + Geometry* _geometry; + const TessellationHints* _hints; + + ref_ptr _vertices; + ref_ptr _normals; + ref_ptr _texcoords; + + GLenum _mode; + unsigned int _start_index; + Matrixd _matrix; + Matrixd _inverse; +}; + } #endif diff --git a/include/osg/ShapeDrawable b/include/osg/ShapeDrawable index 4da4cae6d..0950a1a6c 100644 --- a/include/osg/ShapeDrawable +++ b/include/osg/ShapeDrawable @@ -14,108 +14,10 @@ #ifndef OSG_SHAPEDRAWABLE #define OSG_SHAPEDRAWABLE 1 -#include -#include -#include -#include -#include -#include +#include namespace osg { -/** Describe several hints that can be passed to a Tessellator (like the one used - * by \c ShapeDrawable) as a mean to try to influence the way it works. - */ -class TessellationHints : public Object -{ - public: - - TessellationHints(): - _TessellationMode(USE_SHAPE_DEFAULTS), - _detailRatio(1.0f), - _targetNumFaces(100), - _createFrontFace(true), - _createBackFace(false), - _createNormals(true), - _createTextureCoords(false), - _createTop(true), - _createBody(true), - _createBottom(true) {} - - - TessellationHints(const TessellationHints& tess, const CopyOp& copyop=CopyOp::SHALLOW_COPY): - Object(tess,copyop), - _TessellationMode(tess._TessellationMode), - _detailRatio(tess._detailRatio), - _targetNumFaces(tess._targetNumFaces), - _createFrontFace(tess._createFrontFace), - _createBackFace(tess._createBackFace), - _createNormals(tess._createNormals), - _createTextureCoords(tess._createTextureCoords), - _createTop(tess._createTop), - _createBody(tess._createBody), - _createBottom(tess._createBottom) {} - - META_Object(osg,TessellationHints); - - - enum TessellationMode - { - USE_SHAPE_DEFAULTS, - USE_TARGET_NUM_FACES - }; - - inline void setTessellationMode(TessellationMode mode) { _TessellationMode=mode; } - inline TessellationMode getTessellationMode() const { return _TessellationMode; } - - inline void setDetailRatio(float ratio) { _detailRatio = ratio; } - inline float getDetailRatio() const { return _detailRatio; } - - inline void setTargetNumFaces(unsigned int target) { _targetNumFaces=target; } - inline unsigned int getTargetNumFaces() const { return _targetNumFaces; } - - inline void setCreateFrontFace(bool on) { _createFrontFace=on; } - inline bool getCreateFrontFace() const { return _createFrontFace; } - - inline void setCreateBackFace(bool on) { _createBackFace=on; } - inline bool getCreateBackFace() const { return _createBackFace; } - - inline void setCreateNormals(bool on) { _createNormals=on; } - inline bool getCreateNormals() const { return _createNormals; } - - inline void setCreateTextureCoords(bool on) { _createTextureCoords=on; } - inline bool getCreateTextureCoords() const { return _createTextureCoords; } - - inline void setCreateTop(bool on) { _createTop=on; } - inline bool getCreateTop() const { return _createTop; } - - inline void setCreateBody(bool on) { _createBody=on; } - inline bool getCreateBody() const { return _createBody; } - - inline void setCreateBottom(bool on) { _createBottom=on; } - inline bool getCreateBottom() const { return _createBottom; } - - protected: - - ~TessellationHints() {} - - - TessellationMode _TessellationMode; - - float _detailRatio; - unsigned int _targetNumFaces; - - bool _createFrontFace; - bool _createBackFace; - bool _createNormals; - bool _createTextureCoords; - - bool _createTop; - bool _createBody; - bool _createBottom; - -}; - /** Allow the use of Shapes as Drawables, so that they can * be rendered with reduced effort. The implementation of \c ShapeDrawable is @@ -124,7 +26,7 @@ class TessellationHints : public Object * as the right way to render basic shapes in some efficiency-critical section * of code. */ -class OSG_EXPORT ShapeDrawable : public Drawable +class OSG_EXPORT ShapeDrawable : public osg::Geometry { public: @@ -133,11 +35,8 @@ class OSG_EXPORT ShapeDrawable : public Drawable ShapeDrawable(Shape* shape, TessellationHints* hints=0); template ShapeDrawable(const ref_ptr& shape, TessellationHints* hints=0): - _color(1.0f,1.0f,1.0f,1.0f), _tessellationHints(hints) { setShape(shape.get()); } - - /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ ShapeDrawable(const ShapeDrawable& pg,const CopyOp& copyop=CopyOp::SHALLOW_COPY); @@ -147,6 +46,8 @@ class OSG_EXPORT ShapeDrawable : public Drawable virtual const char* libraryName() const { return "osg"; } virtual const char* className() const { return "ShapeDrawable"; } + virtual void setShape(Shape* shape); + /** Set the color of the shape.*/ void setColor(const Vec4& color); @@ -158,36 +59,8 @@ class OSG_EXPORT ShapeDrawable : public Drawable TessellationHints* getTessellationHints() { return _tessellationHints.get(); } const TessellationHints* getTessellationHints() const { return _tessellationHints.get(); } - - - /** Draw ShapeDrawable directly ignoring an OpenGL display list which - * could be attached. This is the internal draw method which does the - * drawing itself, and is the method to override when deriving from - * ShapeDrawable for user-drawn objects. - */ - virtual void drawImplementation(RenderInfo& renderInfo) const; - - /* Not all virtual overloads of these methods are overridden in this class, so - bring the base class implementation in to avoid hiding the non-used ones. */ - using Drawable::supports; - using Drawable::accept; - - /** Return false, osg::ShapeDrawable does not support accept(AttributeFunctor&).*/ - virtual bool supports(const AttributeFunctor&) const { return false; } - - /** Return true, osg::ShapeDrawable does support accept(Drawable::ConstAttributeFunctor&).*/ - virtual bool supports(const Drawable::ConstAttributeFunctor&) const { return true; } - - /** Accept a Drawable::ConstAttributeFunctor and call its methods to tell it about the internal attributes that this Drawable has.*/ - virtual void accept(Drawable::ConstAttributeFunctor& af) const; - - /** Return true, osg::ShapeDrawable does support accept(PrimitiveFunctor&) .*/ - virtual bool supports(const PrimitiveFunctor&) const { return true; } - - /** Accept a PrimitiveFunctor and call its methods to tell it about the internal primitives that this Drawable has.*/ - virtual void accept(PrimitiveFunctor& pf) const; - - virtual BoundingBox computeBoundingBox() const; + /** method to invoke to rebuild the geometry that renders the shape.*/ + void build(); protected: diff --git a/src/osg/Shape.cpp b/src/osg/Shape.cpp index 806db52c0..6b7b9bb51 100644 --- a/src/osg/Shape.cpp +++ b/src/osg/Shape.cpp @@ -11,6 +11,8 @@ * OpenSceneGraph Public License for more details. */ #include +#include + #include using namespace osg; @@ -173,3 +175,1015 @@ CompositeShape::~CompositeShape() { } +//////////////////////////////////////////////////////////////////////////////////////////////// +// +// BuildShapeGeometryVisitor +// + +// arbitrary minima for rows & segments +const unsigned int MIN_NUM_ROWS = 3; +const unsigned int MIN_NUM_SEGMENTS = 5; + +BuildShapeGeometryVisitor::BuildShapeGeometryVisitor(Geometry* geometry, TessellationHints* hints): + _geometry(geometry), + _hints(hints) +{ + _vertices = dynamic_cast(geometry->getVertexArray()); + _normals = dynamic_cast(geometry->getNormalArray()); + _texcoords = dynamic_cast(geometry->getTexCoordArray(0)); + + bool requiresClearOfPrimitiveSets = false; + + if (!_vertices || _vertices->getBinding()!=Array::BIND_PER_VERTEX) + { + requiresClearOfPrimitiveSets = true; + _vertices = new Vec3Array(Array::BIND_PER_VERTEX); + _geometry->setVertexArray(_vertices.get()); + } + + if (!_normals || (_normals->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_normals->size())) + { + requiresClearOfPrimitiveSets = true; + _normals = new Vec3Array(Array::BIND_PER_VERTEX); + _geometry->setNormalArray(_normals.get()); + } + + if (!_texcoords || (_texcoords->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_texcoords->size())) + { + requiresClearOfPrimitiveSets = true; + _texcoords = new Vec2Array(Array::BIND_PER_VERTEX); + _geometry->setTexCoordArray(0, _texcoords.get()); + } + + if (requiresClearOfPrimitiveSets && !_geometry->getPrimitiveSetList().empty()) + { + OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor() Geometry contains compatible arrays, resetting before shape build."<getPrimitiveSetList().clear(); + } + + _mode = 0; + _start_index = 0; +} + +void BuildShapeGeometryVisitor::setMatrix(const osg::Matrixd& m) +{ + _matrix = m; + + _inverse.invert(m); + _inverse.setTrans(0.0,0.0,0.0); +} + +void BuildShapeGeometryVisitor::Begin(GLenum mode) +{ + _mode = mode; + _start_index = _vertices->size(); +} + +void BuildShapeGeometryVisitor::End() +{ + if (_start_index>=_vertices->size()) return; + + _geometry->addPrimitiveSet(new DrawArrays(_mode, _start_index, _vertices->size()-_start_index)); + + for(unsigned int i=_start_index; i<_vertices->size(); ++i) + { + osg::Vec3& v = (*_vertices)[i]; + v = v * _matrix; + + osg::Vec3& n = (*_normals)[i]; + n = _inverse * n; + n.normalize(); + } + + _vertices->dirty(); + _normals->dirty(); + _texcoords->dirty(); + _geometry->dirtyGLObjects(); + + _start_index = _vertices->size(); +} + +void BuildShapeGeometryVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height) +{ + const float angleDelta = 2.0f*osg::PIf/(float)numSegments; + const float texCoordDelta = 1.0f/(float)numSegments; + + const float r = radius; + const float h = height; + + float basez = -h*0.5f; + float topz = h*0.5f; + + float angle = 0.0f; + float texCoord = 0.0f; + + bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true; + bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; + + // The only difference between the font & back face loops is that the + // normals are inverted and the order of the vertex pairs is reversed. + // The code is mostly duplicated in order to hoist the back/front face + // test out of the loop for efficiency + + Begin(GL_QUAD_STRIP); + + if (drawFrontFace) + { + for(unsigned int bodyi=0; + bodyigetCreateFrontFace() : true; + bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; + + float angleDelta = osg::PIf*2.0f/(float)numSegments; + float texCoordHorzDelta = 1.0f/(float)numSegments; + + float lBase=-osg::PIf*0.5f + (top?(lDelta*(numRows/2)):0.0f); + float rBase=(top?(cosf(lBase)*radius):0.0f); + float zBase=(top?(sinf(lBase)*radius):-radius); + float vBase=(top?(vDelta*(numRows/2)):0.0f); + float nzBase=(top?(sinf(lBase)):-1.0f); + float nRatioBase=(top?(cosf(lBase)):0.0f); + + unsigned int rowbegin = top?numRows/2:0; + unsigned int rowend = top?numRows:numRows/2; + + for(unsigned int rowi=rowbegin; rowigetCreateFrontFace() : true; + bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; + + setMatrix(osg::Matrixd::translate(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z())); + + unsigned int numSegments = 40; + unsigned int numRows = 20; + float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); + if (ratio > 0.0f && ratio != 1.0f) { + numRows = (unsigned int) (numRows * ratio); + if (numRows < MIN_NUM_ROWS) + numRows = MIN_NUM_ROWS; + numSegments = (unsigned int) (numSegments * ratio); + if (numSegments < MIN_NUM_SEGMENTS) + numSegments = MIN_NUM_SEGMENTS; + } + + float lDelta = osg::PIf/(float)numRows; + float vDelta = 1.0f/(float)numRows; + + float angleDelta = osg::PIf*2.0f/(float)numSegments; + float texCoordHorzDelta = 1.0f/(float)numSegments; + + if (drawBackFace) + { + float lBase=-osg::PIf*0.5f; + float rBase=0.0f; + float zBase=-sphere.getRadius(); + float vBase=0.0f; + float nzBase=-1.0f; + float nRatioBase=0.0f; + + for(unsigned int rowi=0; rowigetCreateBody() : true); + bool createTop = (_hints ? _hints->getCreateTop() : true); + bool createBottom = (_hints ? _hints->getCreateBottom() : true); + + float dx = box.getHalfLengths().x(); + float dy = box.getHalfLengths().y(); + float dz = box.getHalfLengths().z(); + + setMatrix(box.computeRotationMatrix() * Matrixd::translate(box.getCenter())); + + Begin(GL_QUADS); + + if (createBody) { + // -ve y plane + Normal3f(0.0f,-1.0f,0.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(-dx,-dy,dz); + + Normal3f(0.0f,-1.0f,0.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(-dx,-dy,-dz); + + Normal3f(0.0f,-1.0f,0.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(dx,-dy,-dz); + + Normal3f(0.0f,-1.0f,0.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(dx,-dy,dz); + + // +ve y plane + Normal3f(0.0f,1.0f,0.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(dx,dy,dz); + + Normal3f(0.0f,1.0f,0.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(dx,dy,-dz); + + Normal3f(0.0f,1.0f,0.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(-dx,dy,-dz); + + Normal3f(0.0f,1.0f,0.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(-dx,dy,dz); + + // +ve x plane + Normal3f(1.0f,0.0f,0.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(dx,-dy,dz); + + Normal3f(1.0f,0.0f,0.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(dx,-dy,-dz); + + Normal3f(1.0f,0.0f,0.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(dx,dy,-dz); + + Normal3f(1.0f,0.0f,0.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(dx,dy,dz); + + // -ve x plane + Normal3f(-1.0f,0.0f,0.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(-dx,dy,dz); + + Normal3f(-1.0f,0.0f,0.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(-dx,dy,-dz); + + Normal3f(-1.0f,0.0f,0.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(-dx,-dy,-dz); + + Normal3f(-1.0f,0.0f,0.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(-dx,-dy,dz); + } + + if (createTop) { + // +ve z plane + Normal3f(0.0f,0.0f,1.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(-dx,dy,dz); + + Normal3f(0.0f,0.0f,1.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(-dx,-dy,dz); + + Normal3f(0.0f,0.0f,1.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(dx,-dy,dz); + + Normal3f(0.0f,0.0f,1.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(dx,dy,dz); + } + + if (createBottom) { + // -ve z plane + Normal3f(0.0f,0.0f,-1.0f); + TexCoord2f(0.0f,1.0f); + Vertex3f(dx,dy,-dz); + + Normal3f(0.0f,0.0f,-1.0f); + TexCoord2f(0.0f,0.0f); + Vertex3f(dx,-dy,-dz); + + Normal3f(0.0f,0.0f,-1.0f); + TexCoord2f(1.0f,0.0f); + Vertex3f(-dx,-dy,-dz); + + Normal3f(0.0f,0.0f,-1.0f); + TexCoord2f(1.0f,1.0f); + Vertex3f(-dx,dy,-dz); + } + + End(); +} + +void BuildShapeGeometryVisitor::apply(const Cone& cone) +{ + setMatrix(cone.computeRotationMatrix() * Matrixd::translate(cone.getCenter())); + + // evaluate hints + bool createBody = (_hints ? _hints->getCreateBody() : true); + bool createBottom = (_hints ? _hints->getCreateBottom() : true); + + unsigned int numSegments = 40; + unsigned int numRows = 10; + float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); + if (ratio > 0.0f && ratio != 1.0f) { + numRows = (unsigned int) (numRows * ratio); + if (numRows < MIN_NUM_ROWS) + numRows = MIN_NUM_ROWS; + numSegments = (unsigned int) (numSegments * ratio); + if (numSegments < MIN_NUM_SEGMENTS) + numSegments = MIN_NUM_SEGMENTS; + } + + float r = cone.getRadius(); + float h = cone.getHeight(); + + float normalz = r/(sqrtf(r*r+h*h)); + float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz)); + normalz *= normalRatio; + + float angleDelta = 2.0f*osg::PIf/(float)numSegments; + float texCoordHorzDelta = 1.0/(float)numSegments; + float texCoordRowDelta = 1.0/(float)numRows; + float hDelta = cone.getHeight()/(float)numRows; + float rDelta = cone.getRadius()/(float)numRows; + + float topz=cone.getHeight()+cone.getBaseOffset(); + float topr=0.0f; + float topv=1.0f; + float basez=topz-hDelta; + float baser=rDelta; + float basev=topv-texCoordRowDelta; + float angle; + float texCoord; + + if (createBody) { + for(unsigned int rowi=0; rowigetCreateBody() : true); + bool createTop = (_hints ? _hints->getCreateTop() : true); + bool createBottom = (_hints ? _hints->getCreateBottom() : true); + + unsigned int numSegments = 40; + float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); + if (ratio > 0.0f && ratio != 1.0f) { + numSegments = (unsigned int) (numSegments * ratio); + if (numSegments < MIN_NUM_SEGMENTS) + numSegments = MIN_NUM_SEGMENTS; + } + + + // cylinder body + if (createBody) + drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight()); + + float angleDelta = 2.0f*osg::PIf/(float)numSegments; + float texCoordDelta = 1.0f/(float)numSegments; + + float r = cylinder.getRadius(); + float h = cylinder.getHeight(); + + float basez = -h*0.5f; + float topz = h*0.5f; + + float angle = 0.0f; + float texCoord = 0.0f; + + + // cylinder top + if (createTop) { + + Begin(GL_TRIANGLE_FAN); + + Normal3f(0.0f,0.0f,1.0f); + TexCoord2f(0.5f,0.5f); + Vertex3f(0.0f,0.0f,topz); + + angle = 0.0f; + texCoord = 0.0f; + for(unsigned int topi=0; + topigetCreateBody() : true); + bool createTop = (_hints ? _hints->getCreateTop() : true); + bool createBottom = (_hints ? _hints->getCreateBottom() : true); + + unsigned int numSegments = 40; + unsigned int numRows = 20; + float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); + if (ratio > 0.0f && ratio != 1.0f) { + numSegments = (unsigned int) (numSegments * ratio); + if (numSegments < MIN_NUM_SEGMENTS) + numSegments = MIN_NUM_SEGMENTS; + numRows = (unsigned int) (numRows * ratio); + if (numRows < MIN_NUM_ROWS) + numRows = MIN_NUM_ROWS; + } + + // if numRows is odd the top and bottom halves of sphere won't match, so bump up to the next event numRows + if ((numRows%2)!=0) ++numRows; + + // capsule cylindrical body + if (createBody) + drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight()); + + // capsule top cap + if (createTop) + drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f); + + // capsule bottom cap + if (createBottom) + drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f); + +} + +void BuildShapeGeometryVisitor::apply(const InfinitePlane&) +{ + OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor::apply(const InfinitePlane& plane) not yet implemented. "<getNumElements();i+=3) + { + const osg::Vec3& v1=(*vertices)[indices->index(i)]; + const osg::Vec3& v2=(*vertices)[indices->index(i+1)]; + const osg::Vec3& v3=(*vertices)[indices->index(i+2)]; + Vec3 normal = (v2-v1)^(v3-v2); + normal.normalize(); + + Normal(normal); + Vertex(v1); + + Normal(normal); + Vertex(v2); + + Normal(normal); + Vertex(v3); + + } + + End(); + } +} + +void BuildShapeGeometryVisitor::apply(const ConvexHull& hull) +{ + apply((const TriangleMesh&)hull); +} + +void BuildShapeGeometryVisitor::apply(const HeightField& field) +{ + if (field.getNumColumns()==0 || field.getNumRows()==0) return; + + setMatrix(field.computeRotationMatrix() * Matrixd::translate(field.getOrigin())); + + float dx = field.getXInterval(); + float dy = field.getYInterval(); + + float du = 1.0f/((float)field.getNumColumns()-1.0f); + float dv = 1.0f/((float)field.getNumRows()-1.0f); + + float vBase = 0.0f; + + Vec3 vertTop; + Vec3 normTop; + + Vec3 vertBase; + Vec3 normBase; + + if (field.getSkirtHeight()!=0.0f) + { + Begin(GL_QUAD_STRIP); + + float u = 0.0f; + + // draw bottom skirt + unsigned int col; + vertTop.y() = 0.0f; + for(col=0;colaccept(*this); + } +} diff --git a/src/osg/ShapeDrawable.cpp b/src/osg/ShapeDrawable.cpp index 2e2ce8fea..f7bf94ffb 100644 --- a/src/osg/ShapeDrawable.cpp +++ b/src/osg/ShapeDrawable.cpp @@ -16,1937 +16,52 @@ using namespace osg; -// arbitrary minima for rows & segments -const unsigned int MIN_NUM_ROWS = 3; -const unsigned int MIN_NUM_SEGMENTS = 5; - - -/////////////////////////////////////////////////////////////////////////////// -// -// draw shape -// - -class DrawShapeVisitor : public ConstShapeVisitor +ShapeDrawable::ShapeDrawable() { - public: - - DrawShapeVisitor(State& state,const TessellationHints* hints): - _state(state), - _hints(hints) - { -#if 0 - if (hints) - { - OSG_NOTICE<<"Warning: TessellationHints ignored in present osg::ShapeDrawable implementation."<getCreateFrontFace() : true; - bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; - - // The only difference between the font & back face loops is that the - // normals are inverted and the order of the vertex pairs is reversed. - // The code is mostly duplicated in order to hoist the back/front face - // test out of the loop for efficiency - - GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter(); - - gl.Begin(GL_QUAD_STRIP); - - if (drawFrontFace) { - - for(unsigned int bodyi=0; - bodyigetCreateFrontFace() : true; - bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; - - float angleDelta = osg::PIf*2.0f/(float)numSegments; - float texCoordHorzDelta = 1.0f/(float)numSegments; - - float lBase=-osg::PIf*0.5f + (top?(lDelta*(numRows/2)):0.0f); - float rBase=(top?(cosf(lBase)*radius):0.0f); - float zBase=(top?(sinf(lBase)*radius):-radius); - float vBase=(top?(vDelta*(numRows/2)):0.0f); - float nzBase=(top?(sinf(lBase)):-1.0f); - float nRatioBase=(top?(cosf(lBase)):0.0f); - - unsigned int rowbegin = top?numRows/2:0; - unsigned int rowend = top?numRows:numRows/2; - - GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter(); - - for(unsigned int rowi=rowbegin; rowigetCreateFrontFace() : true; - bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; - - unsigned int numSegments = 40; - unsigned int numRows = 20; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - float lDelta = osg::PIf/(float)numRows; - float vDelta = 1.0f/(float)numRows; - - float angleDelta = osg::PIf*2.0f/(float)numSegments; - float texCoordHorzDelta = 1.0f/(float)numSegments; - - if (drawBackFace) - { - float lBase=-osg::PIf*0.5f; - float rBase=0.0f; - float zBase=-sphere.getRadius(); - float vBase=0.0f; - float nzBase=-1.0f; - float nRatioBase=0.0f; - - for(unsigned int rowi=0; rowigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - float dx = box.getHalfLengths().x(); - float dy = box.getHalfLengths().y(); - float dz = box.getHalfLengths().z(); - - gl.PushMatrix(); - - gl.Translated(box.getCenter().x(),box.getCenter().y(),box.getCenter().z()); - - if (!box.zeroRotation()) - { - Matrixd rotation(box.computeRotationMatrix()); - gl.MultMatrixd(rotation.ptr()); - } - - gl.Begin(GL_QUADS); - - if (createBody) { - // -ve y plane - gl.Normal3f(0.0f,-1.0f,0.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(-dx,-dy,dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(-dx,-dy,-dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(dx,-dy,-dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(dx,-dy,dz); - - // +ve y plane - gl.Normal3f(0.0f,1.0f,0.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(dx,dy,dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(dx,dy,-dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(-dx,dy,-dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(-dx,dy,dz); - - // +ve x plane - gl.Normal3f(1.0f,0.0f,0.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(dx,-dy,dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(dx,-dy,-dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(dx,dy,-dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(dx,dy,dz); - - // -ve x plane - gl.Normal3f(-1.0f,0.0f,0.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(-dx,dy,dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(-dx,dy,-dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(-dx,-dy,-dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(-dx,-dy,dz); - } - - if (createTop) { - // +ve z plane - gl.Normal3f(0.0f,0.0f,1.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(-dx,dy,dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(-dx,-dy,dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(dx,-dy,dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(dx,dy,dz); - } - - if (createBottom) { - // -ve z plane - gl.Normal3f(0.0f,0.0f,-1.0f); - - gl.TexCoord2f(0.0f,1.0f); - gl.Vertex3f(dx,dy,-dz); - - gl.TexCoord2f(0.0f,0.0f); - gl.Vertex3f(dx,-dy,-dz); - - gl.TexCoord2f(1.0f,0.0f); - gl.Vertex3f(-dx,-dy,-dz); - - gl.TexCoord2f(1.0f,1.0f); - gl.Vertex3f(-dx,dy,-dz); - } - - gl.End(); - - gl.PopMatrix(); - -} - -void DrawShapeVisitor::apply(const Cone& cone) -{ - GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter(); - - gl.PushMatrix(); - - gl.Translated(cone.getCenter().x(),cone.getCenter().y(),cone.getCenter().z()); - - if (!cone.zeroRotation()) - { - Matrixd rotation(cone.computeRotationMatrix()); - gl.MultMatrixd(rotation.ptr()); - } - - // evaluate hints - bool createBody = (_hints ? _hints->getCreateBody() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - unsigned int numSegments = 40; - unsigned int numRows = 10; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - float r = cone.getRadius(); - float h = cone.getHeight(); - - float normalz = r/(sqrtf(r*r+h*h)); - float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz)); - normalz *= normalRatio; - - float angleDelta = 2.0f*osg::PIf/(float)numSegments; - float texCoordHorzDelta = 1.0/(float)numSegments; - float texCoordRowDelta = 1.0/(float)numRows; - float hDelta = cone.getHeight()/(float)numRows; - float rDelta = cone.getRadius()/(float)numRows; - - float topz=cone.getHeight()+cone.getBaseOffset(); - float topr=0.0f; - float topv=1.0f; - float basez=topz-hDelta; - float baser=rDelta; - float basev=topv-texCoordRowDelta; - float angle; - float texCoord; - - if (createBody) { - for(unsigned int rowi=0; rowigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - unsigned int numSegments = 40; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - - // cylinder body - if (createBody) - drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight()); - - float angleDelta = 2.0f*osg::PIf/(float)numSegments; - float texCoordDelta = 1.0f/(float)numSegments; - - float r = cylinder.getRadius(); - float h = cylinder.getHeight(); - - float basez = -h*0.5f; - float topz = h*0.5f; - - float angle = 0.0f; - float texCoord = 0.0f; - - // cylinder top - if (createTop) { - gl.Begin(GL_TRIANGLE_FAN); - - gl.Normal3f(0.0f,0.0f,1.0f); - gl.TexCoord2f(0.5f,0.5f); - gl.Vertex3f(0.0f,0.0f,topz); - - angle = 0.0f; - texCoord = 0.0f; - for(unsigned int topi=0; - topigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - unsigned int numSegments = 40; - unsigned int numRows = 20; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - } - - // if numRows is odd the top and bottom halves of sphere won't match, so bump up to the next event numRows - if ((numRows%2)!=0) ++numRows; - - - // capsule cylindrical body - if (createBody) - drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight()); - - // capsule top cap - if (createTop) - drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f); - - // capsule bottom cap - if (createBottom) - drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f); - - gl.PopMatrix(); -} - -void DrawShapeVisitor::apply(const InfinitePlane&) -{ - OSG_NOTICE<<"Warning: DrawShapeVisitor::apply(const InfinitePlane& plane) not yet implemented. "<getNumElements();i+=3) - { - const osg::Vec3& v1=(*vertices)[indices->index(i)]; - const osg::Vec3& v2=(*vertices)[indices->index(i+1)]; - const osg::Vec3& v3=(*vertices)[indices->index(i+2)]; - Vec3 normal = (v2-v1)^(v3-v2); - normal.normalize(); - - gl.Normal3fv(normal.ptr()); - gl.Vertex3fv(v1.ptr()); - gl.Vertex3fv(v2.ptr()); - gl.Vertex3fv(v3.ptr()); - - } - - gl.End(); - } -} - -void DrawShapeVisitor::apply(const ConvexHull& hull) -{ - apply((const TriangleMesh&)hull); -} - -void DrawShapeVisitor::apply(const HeightField& field) -{ - if (field.getNumColumns()==0 || field.getNumRows()==0) return; - - GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter(); - - gl.PushMatrix(); - - gl.Translated(field.getOrigin().x(),field.getOrigin().y(),field.getOrigin().z()); - - - if (!field.zeroRotation()) - { - Matrixd rotation(field.computeRotationMatrix()); - gl.MultMatrixd(rotation.ptr()); - } - - float dx = field.getXInterval(); - float dy = field.getYInterval(); - - float du = 1.0f/((float)field.getNumColumns()-1.0f); - float dv = 1.0f/((float)field.getNumRows()-1.0f); - - float vBase = 0.0f; - - Vec3 vertTop; - Vec3 normTop; - - Vec3 vertBase; - Vec3 normBase; - - if (field.getSkirtHeight()!=0.0f) - { - gl.Begin(GL_QUAD_STRIP); - - float u = 0.0f; - - // draw bottom skirt - unsigned int col; - vertTop.y() = 0.0f; - for(col=0;colaccept(*this); - } -} - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Compute bounding of shape -// - -class ComputeBoundShapeVisitor : public ConstShapeVisitor -{ - public: - - ComputeBoundShapeVisitor(BoundingBox& bb):_bb(bb) {} - - virtual void apply(const Sphere&); - virtual void apply(const Box&); - virtual void apply(const Cone&); - virtual void apply(const Cylinder&); - virtual void apply(const Capsule&); - virtual void apply(const InfinitePlane&); - - virtual void apply(const TriangleMesh&); - virtual void apply(const ConvexHull&); - virtual void apply(const HeightField&); - - virtual void apply(const CompositeShape&); - - BoundingBox& _bb; - - protected: - - ComputeBoundShapeVisitor& operator = (const ComputeBoundShapeVisitor&) { return *this; } - -}; - - -void ComputeBoundShapeVisitor::apply(const Sphere& sphere) -{ - Vec3 halfLengths(sphere.getRadius(),sphere.getRadius(),sphere.getRadius()); - _bb.expandBy(sphere.getCenter()-halfLengths); - _bb.expandBy(sphere.getCenter()+halfLengths); -} - -void ComputeBoundShapeVisitor::apply(const Box& box) -{ - if (box.zeroRotation()) - { - _bb.expandBy(box.getCenter()-box.getHalfLengths()); - _bb.expandBy(box.getCenter()+box.getHalfLengths()); - } - else - { - float x = box.getHalfLengths().x(); - float y = box.getHalfLengths().y(); - float z = box.getHalfLengths().z(); - - Vec3 base_1(Vec3(-x,-y,-z)); - Vec3 base_2(Vec3(x,-y,-z)); - Vec3 base_3(Vec3(x,y,-z)); - Vec3 base_4(Vec3(-x,y,-z)); - - Vec3 top_1(Vec3(-x,-y,z)); - Vec3 top_2(Vec3(x,-y,z)); - Vec3 top_3(Vec3(x,y,z)); - Vec3 top_4(Vec3(-x,y,z)); - - Matrix matrix = box.computeRotationMatrix(); - _bb.expandBy(box.getCenter()+base_1*matrix); - _bb.expandBy(box.getCenter()+base_2*matrix); - _bb.expandBy(box.getCenter()+base_3*matrix); - _bb.expandBy(box.getCenter()+base_4*matrix); - - _bb.expandBy(box.getCenter()+top_1*matrix); - _bb.expandBy(box.getCenter()+top_2*matrix); - _bb.expandBy(box.getCenter()+top_3*matrix); - _bb.expandBy(box.getCenter()+top_4*matrix); - } -} - -void ComputeBoundShapeVisitor::apply(const Cone& cone) -{ - if (cone.zeroRotation()) - { - _bb.expandBy(cone.getCenter()+Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset())); - _bb.expandBy(cone.getCenter()+Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset())); - - } - else - { - Vec3 top(Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset())); - Vec3 base_1(Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset())); - Vec3 base_2(Vec3(cone.getRadius(),-cone.getRadius(),cone.getBaseOffset())); - Vec3 base_3(Vec3(cone.getRadius(),cone.getRadius(),cone.getBaseOffset())); - Vec3 base_4(Vec3(-cone.getRadius(),cone.getRadius(),cone.getBaseOffset())); - - Matrix matrix = cone.computeRotationMatrix(); - _bb.expandBy(cone.getCenter()+base_1*matrix); - _bb.expandBy(cone.getCenter()+base_2*matrix); - _bb.expandBy(cone.getCenter()+base_3*matrix); - _bb.expandBy(cone.getCenter()+base_4*matrix); - _bb.expandBy(cone.getCenter()+top*matrix); - } -} - -void ComputeBoundShapeVisitor::apply(const Cylinder& cylinder) -{ - if (cylinder.zeroRotation()) - { - Vec3 halfLengths(cylinder.getRadius(),cylinder.getRadius(),cylinder.getHeight()*0.5f); - _bb.expandBy(cylinder.getCenter()-halfLengths); - _bb.expandBy(cylinder.getCenter()+halfLengths); - - } - else - { - float r = cylinder.getRadius(); - float z = cylinder.getHeight()*0.5f; - - Vec3 base_1(Vec3(-r,-r,-z)); - Vec3 base_2(Vec3(r,-r,-z)); - Vec3 base_3(Vec3(r,r,-z)); - Vec3 base_4(Vec3(-r,r,-z)); - - Vec3 top_1(Vec3(-r,-r,z)); - Vec3 top_2(Vec3(r,-r,z)); - Vec3 top_3(Vec3(r,r,z)); - Vec3 top_4(Vec3(-r,r,z)); - - Matrix matrix = cylinder.computeRotationMatrix(); - _bb.expandBy(cylinder.getCenter()+base_1*matrix); - _bb.expandBy(cylinder.getCenter()+base_2*matrix); - _bb.expandBy(cylinder.getCenter()+base_3*matrix); - _bb.expandBy(cylinder.getCenter()+base_4*matrix); - - _bb.expandBy(cylinder.getCenter()+top_1*matrix); - _bb.expandBy(cylinder.getCenter()+top_2*matrix); - _bb.expandBy(cylinder.getCenter()+top_3*matrix); - _bb.expandBy(cylinder.getCenter()+top_4*matrix); - } -} - -void ComputeBoundShapeVisitor::apply(const Capsule& capsule) -{ - if (capsule.zeroRotation()) - { - Vec3 halfLengths(capsule.getRadius(),capsule.getRadius(),capsule.getHeight()*0.5f + capsule.getRadius()); - _bb.expandBy(capsule.getCenter()-halfLengths); - _bb.expandBy(capsule.getCenter()+halfLengths); - - } - else - { - float r = capsule.getRadius(); - float z = capsule.getHeight()*0.5f + capsule.getRadius(); - - Vec3 base_1(Vec3(-r,-r,-z)); - Vec3 base_2(Vec3(r,-r,-z)); - Vec3 base_3(Vec3(r,r,-z)); - Vec3 base_4(Vec3(-r,r,-z)); - - Vec3 top_1(Vec3(-r,-r,z)); - Vec3 top_2(Vec3(r,-r,z)); - Vec3 top_3(Vec3(r,r,z)); - Vec3 top_4(Vec3(-r,r,z)); - - Matrix matrix = capsule.computeRotationMatrix(); - _bb.expandBy(capsule.getCenter()+base_1*matrix); - _bb.expandBy(capsule.getCenter()+base_2*matrix); - _bb.expandBy(capsule.getCenter()+base_3*matrix); - _bb.expandBy(capsule.getCenter()+base_4*matrix); - - _bb.expandBy(capsule.getCenter()+top_1*matrix); - _bb.expandBy(capsule.getCenter()+top_2*matrix); - _bb.expandBy(capsule.getCenter()+top_3*matrix); - _bb.expandBy(capsule.getCenter()+top_4*matrix); - } -} - -void ComputeBoundShapeVisitor::apply(const InfinitePlane&) -{ - // can't compute the bounding box of an infinite plane!!! :-) -} - -void ComputeBoundShapeVisitor::apply(const TriangleMesh& mesh) -{ - const Vec3Array* vertices = mesh.getVertices(); - const IndexArray* indices = mesh.getIndices(); - - if (vertices && indices) - { - for(unsigned int i=0;igetNumElements();++i) - { - const osg::Vec3& v=(*vertices)[indices->index(i)]; - _bb.expandBy(v); - } - } -} - -void ComputeBoundShapeVisitor::apply(const ConvexHull& hull) -{ - apply((const TriangleMesh&)hull); -} - -void ComputeBoundShapeVisitor::apply(const HeightField& field) -{ - float zMin=FLT_MAX; - float zMax=-FLT_MAX; - - for(unsigned int row=0;rowzMax) zMax = z; - } - } - - if (zMin>zMax) - { - // no valid entries so don't reset the bounding box - return; - } - - - if (field.zeroRotation()) - { - _bb.expandBy(field.getOrigin()+osg::Vec3(0.0f,0.0f,zMin)); - _bb.expandBy(field.getOrigin()+osg::Vec3(field.getXInterval()*(field.getNumColumns()-1),field.getYInterval()*(field.getNumRows()-1),zMax)); - } - else - { - float x = field.getXInterval()*(field.getNumColumns()-1); - float y = field.getYInterval()*(field.getNumRows()-1); - - Vec3 base_1(Vec3(0,0,zMin)); - Vec3 base_2(Vec3(x,0,zMin)); - Vec3 base_3(Vec3(x,y,zMin)); - Vec3 base_4(Vec3(0,y,zMin)); - - Vec3 top_1(Vec3(0,0,zMax)); - Vec3 top_2(Vec3(x,0,zMax)); - Vec3 top_3(Vec3(x,y,zMax)); - Vec3 top_4(Vec3(0,y,zMax)); - - Matrix matrix = field.computeRotationMatrix(); - _bb.expandBy(field.getOrigin()+base_1*matrix); - _bb.expandBy(field.getOrigin()+base_2*matrix); - _bb.expandBy(field.getOrigin()+base_3*matrix); - _bb.expandBy(field.getOrigin()+base_4*matrix); - - _bb.expandBy(field.getOrigin()+top_1*matrix); - _bb.expandBy(field.getOrigin()+top_2*matrix); - _bb.expandBy(field.getOrigin()+top_3*matrix); - _bb.expandBy(field.getOrigin()+top_4*matrix); - } - -} - -void ComputeBoundShapeVisitor::apply(const CompositeShape& group) -{ - for(unsigned int i=0;iaccept(*this); - } -} - - - - -/////////////////////////////////////////////////////////////////////////////// -// -// Accept a primitive functor for each of the shapes. -// - -class PrimitiveShapeVisitor : public ConstShapeVisitor -{ - public: - - PrimitiveShapeVisitor(PrimitiveFunctor& functor,const TessellationHints* hints): - _functor(functor), - _hints(hints) {} - - virtual void apply(const Sphere&); - virtual void apply(const Box&); - virtual void apply(const Cone&); - virtual void apply(const Cylinder&); - virtual void apply(const Capsule&); - virtual void apply(const InfinitePlane&); - - virtual void apply(const TriangleMesh&); - virtual void apply(const ConvexHull&); - virtual void apply(const HeightField&); - - virtual void apply(const CompositeShape&); - - PrimitiveFunctor& _functor; - const TessellationHints* _hints; - - private: - - PrimitiveShapeVisitor& operator = (const PrimitiveShapeVisitor&) { return *this; } - - // helpers for apply( Cylinder | Sphere | Capsule ) - void createCylinderBody(unsigned int numSegments, float radius, float height, const osg::Matrix& matrix); - void createHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, int which, float zOffset, const osg::Matrix& matrix); -}; - - - -void PrimitiveShapeVisitor::createCylinderBody(unsigned int numSegments, float radius, float height, const osg::Matrix& matrix) -{ - const float angleDelta = 2.0f*osg::PIf/(float)numSegments; - - const float r = radius; - const float h = height; - - float basez = -h*0.5f; - float topz = h*0.5f; - - float angle = 0.0f; - - _functor.begin(GL_QUAD_STRIP); - - for(unsigned int bodyi=0; - bodyigetDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - float lDelta = osg::PIf/(float)numRows; - float vDelta = 1.0f/(float)numRows; - - float angleDelta = osg::PIf*2.0f/(float)numSegments; - - float lBase=-osg::PIf*0.5f; - float rBase=0.0f; - float zBase=-sphere.getRadius(); - float vBase=0.0f; - - for(unsigned int rowi=0; - rowigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - float x = box.getHalfLengths().x(); - float y = box.getHalfLengths().y(); - float z = box.getHalfLengths().z(); - - Vec3 base_1(-x,-y,-z); - Vec3 base_2(x,-y,-z); - Vec3 base_3(x,y,-z); - Vec3 base_4(-x,y,-z); - - Vec3 top_1(-x,-y,z); - Vec3 top_2(x,-y,z); - Vec3 top_3(x,y,z); - Vec3 top_4(-x,y,z); - - if (box.zeroRotation()) - { - base_1 += box.getCenter(); - base_2 += box.getCenter(); - base_3 += box.getCenter(); - base_4 += box.getCenter(); - - top_1 += box.getCenter(); - top_2 += box.getCenter(); - top_3 += box.getCenter(); - top_4 += box.getCenter(); - } - else - { - Matrix matrix = box.computeRotationMatrix(); - matrix.setTrans(box.getCenter()); - - base_1 = base_1*matrix; - base_2 = base_2*matrix; - base_3 = base_3*matrix; - base_4 = base_4*matrix; - - top_1 = top_1*matrix; - top_2 = top_2*matrix; - top_3 = top_3*matrix; - top_4 = top_4*matrix; - } - - _functor.begin(GL_QUADS); - if (createBody) - { - _functor.vertex(top_1); - _functor.vertex(base_1); - _functor.vertex(base_2); - _functor.vertex(top_2); - - _functor.vertex(top_2); - _functor.vertex(base_2); - _functor.vertex(base_3); - _functor.vertex(top_3); - - _functor.vertex(top_3); - _functor.vertex(base_3); - _functor.vertex(base_4); - _functor.vertex(top_4); - - _functor.vertex(top_4); - _functor.vertex(base_4); - _functor.vertex(base_1); - _functor.vertex(top_1); - } - - if (createTop) - { - _functor.vertex(top_4); - _functor.vertex(top_1); - _functor.vertex(top_2); - _functor.vertex(top_3); - } - - if (createBottom) - { - _functor.vertex(base_4); - _functor.vertex(base_3); - _functor.vertex(base_2); - _functor.vertex(base_1); - } - - _functor.end(); - -} - -void PrimitiveShapeVisitor::apply(const Cone& cone) -{ - // evaluate hints - bool createBody = (_hints ? _hints->getCreateBody() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - Matrix matrix = cone.computeRotationMatrix(); - matrix.setTrans(cone.getCenter()); - - unsigned int numSegments = 40; - unsigned int numRows = 20; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - float r = cone.getRadius(); - float h = cone.getHeight(); - - float normalz = r/(sqrtf(r*r+h*h)); - float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz)); - normalz *= normalRatio; - - float angleDelta = 2.0f*osg::PIf/(float)numSegments; - float hDelta = cone.getHeight()/(float)numRows; - float rDelta = cone.getRadius()/(float)numRows; - - float topz=cone.getHeight()+cone.getBaseOffset(); - float topr=0.0f; - float basez=topz-hDelta; - float baser=rDelta; - float angle; - - if (createBody) - { - for(unsigned int rowi=0; - rowigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - Matrix matrix = cylinder.computeRotationMatrix(); - matrix.setTrans(cylinder.getCenter()); - - unsigned int numSegments = 40; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - float angleDelta = 2.0f*osg::PIf/(float)numSegments; - - float r = cylinder.getRadius(); - float h = cylinder.getHeight(); - - float basez = -h*0.5f; - float topz = h*0.5f; - float angle; - - // cylinder body - if (createBody) - createCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight(), matrix); - - // cylinder top - if (createTop) - { - _functor.begin(GL_TRIANGLE_FAN); - - _functor.vertex(Vec3(0.0f,0.0f,topz)*matrix); - - angle = 0.0f; - for(unsigned int topi=0; - topigetCreateBody() : true); - bool createTop = (_hints ? _hints->getCreateTop() : true); - bool createBottom = (_hints ? _hints->getCreateBottom() : true); - - Matrix matrix = capsule.computeRotationMatrix(); - matrix.setTrans(capsule.getCenter()); - - unsigned int numSegments = 40; - unsigned int numRows = 20; - float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); - if (ratio > 0.0f && ratio != 1.0f) { - numRows = (unsigned int) (numRows * ratio); - if (numRows < MIN_NUM_ROWS) - numRows = MIN_NUM_ROWS; - numSegments = (unsigned int) (numSegments * ratio); - if (numSegments < MIN_NUM_SEGMENTS) - numSegments = MIN_NUM_SEGMENTS; - } - - // if numRows is odd the top and bottom halves of sphere won't match, so bump up to the next event numRows - if ((numRows%2)!=0) ++numRows; - - // capsule body - if (createBody) - createCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight(), matrix); - - // capsule top cap - if (createTop) - createHalfSphere(numSegments, numRows, capsule.getRadius(), 0, capsule.getHeight()/2.0f, matrix); - - // capsule bottom cap - if (createBottom) - createHalfSphere(numSegments, numRows, capsule.getRadius(), 1, -capsule.getHeight()/2.0f, matrix); - -} - -void PrimitiveShapeVisitor::apply(const InfinitePlane&) -{ - OSG_NOTICE<<"Warning: PrimitiveShapeVisitor::apply(const InfinitePlane& plane) not yet implemented. "<getNumElements();i+=3) - { - _functor.vertex((*vertices)[indices->index(i)]); - _functor.vertex((*vertices)[indices->index(i+1)]); - _functor.vertex((*vertices)[indices->index(i+2)]); - } - - _functor.end(); - } - - -} - -void PrimitiveShapeVisitor::apply(const ConvexHull& hull) -{ - apply((const TriangleMesh&)hull); -} - -void PrimitiveShapeVisitor::apply(const HeightField& field) -{ - if (field.getNumColumns()==0 || field.getNumRows()==0) return; - - Matrix matrix = field.computeRotationMatrix(); - matrix.setTrans(field.getOrigin()); - - float dx = field.getXInterval(); - float dy = field.getYInterval(); - - for(unsigned int row=0;rowaccept(*this); - } -} - - -/////////////////////////////////////////////////////////////////////////////// -// -// ShapeDrawable itself.. -// - - -ShapeDrawable::ShapeDrawable(): - _color(1.0f,1.0f,1.0f,1.0f) -{ - //setUseDisplayList(false); } ShapeDrawable::ShapeDrawable(Shape* shape,TessellationHints* hints): - _color(1.0f,1.0f,1.0f,1.0f), - _tessellationHints(hints) + _tessellationHints(hints) { setShape(shape); - //setUseDisplayList(false); } ShapeDrawable::ShapeDrawable(const ShapeDrawable& pg,const CopyOp& copyop): - Drawable(pg,copyop), - _color(pg._color), + Geometry(pg,copyop), _tessellationHints(pg._tessellationHints) { - //setUseDisplayList(false); } ShapeDrawable::~ShapeDrawable() { } +void ShapeDrawable::setShape(Shape* shape) +{ + if (_shape==shape) return; + + _shape = shape; + + build(); +} + + void ShapeDrawable::setColor(const Vec4& color) { - if (_color!=color) + if (color==_color) return; + + _color = color; + + Vec4Array* colors = dynamic_cast(_colorArray.get()); + if (!colors || colors->empty() || colors->getBinding()!=Array::BIND_OVERALL) { - _color = color; dirtyGLObjects(); + _colorArray = colors = new Vec4Array(Array::BIND_OVERALL, 1); } + + (*colors)[0] = color; + colors->dirty(); + + dirtyGLObjects(); } void ShapeDrawable::setTessellationHints(TessellationHints* hints) @@ -1954,47 +69,25 @@ void ShapeDrawable::setTessellationHints(TessellationHints* hints) if (_tessellationHints!=hints) { _tessellationHints = hints; - dirtyGLObjects(); + build(); } } -void ShapeDrawable::drawImplementation(RenderInfo& renderInfo) const +void ShapeDrawable::build() { - osg::State& state = *renderInfo.getState(); - GLBeginEndAdapter& gl = state.getGLBeginEndAdapter(); + // reset all the properties. + setVertexArray(0); + setNormalArray(0); + setColorArray(0); + setSecondaryColorArray(0); + setFogCoordArray(0); + getTexCoordArrayList().clear(); + getVertexAttribArrayList().clear(); + getPrimitiveSetList().clear(); - if (_shape.valid()) + if (_shape) { - gl.Color4fv(_color.ptr()); - - DrawShapeVisitor dsv(state,_tessellationHints.get()); - + BuildShapeGeometryVisitor dsv(this, _tessellationHints.get()); _shape->accept(dsv); } } - -void ShapeDrawable::accept(ConstAttributeFunctor&) const -{ -} - -void ShapeDrawable::accept(PrimitiveFunctor& pf) const -{ - if (_shape.valid()) - { - PrimitiveShapeVisitor psv(pf,_tessellationHints.get()); - _shape->accept(psv); - } -} - - -BoundingBox ShapeDrawable::computeBoundingBox() const -{ - BoundingBox bbox; - if (_shape.valid()) - { - ComputeBoundShapeVisitor cbsv(bbox); - _shape->accept(cbsv); - } - return bbox; -} -