diff --git a/examples/osgshape/osgshape.cpp b/examples/osgshape/osgshape.cpp index e9c03086a..35d191784 100644 --- a/examples/osgshape/osgshape.cpp +++ b/examples/osgshape/osgshape.cpp @@ -41,6 +41,7 @@ osg::Geode* createShapes() geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(2.0f,0.0f,0.0f),2*radius),hints)); geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f,0.0f,0.0f),radius,height),hints)); geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(6.0f,0.0f,0.0f),radius,height),hints)); + geode->addDrawable(new osg::ShapeDrawable(new osg::Capsule(osg::Vec3(8.0f,0.0f,0.0f),radius,height),hints)); osg::HeightField* grid = new osg::HeightField; grid->allocateGrid(38,39); @@ -58,10 +59,10 @@ osg::Geode* createShapes() osg::ConvexHull* mesh = new osg::ConvexHull; osg::Vec3Array* vertices = new osg::Vec3Array(4); - (*vertices)[0].set(7.0+0.0f,-1.0f+2.0f,-1.0f+0.0f); - (*vertices)[1].set(7.0+1.0f,-1.0f+0.0f,-1.0f+0.0f); - (*vertices)[2].set(7.0+2.0f,-1.0f+2.0f,-1.0f+0.0f); - (*vertices)[3].set(7.0+1.0f,-1.0f+1.0f,-1.0f+2.0f); + (*vertices)[0].set(9.0+0.0f,-1.0f+2.0f,-1.0f+0.0f); + (*vertices)[1].set(9.0+1.0f,-1.0f+0.0f,-1.0f+0.0f); + (*vertices)[2].set(9.0+2.0f,-1.0f+2.0f,-1.0f+0.0f); + (*vertices)[3].set(9.0+1.0f,-1.0f+1.0f,-1.0f+2.0f); osg::UByteArray* indices = new osg::UByteArray(12); (*indices)[0]=0; (*indices)[1]=2; diff --git a/include/osg/Shape b/include/osg/Shape index 4bd58f5fa..7271ee2f5 100644 --- a/include/osg/Shape +++ b/include/osg/Shape @@ -90,6 +90,7 @@ class Sphere; class Box; class Cone; class Cylinder; +class Capsule; class InfinitePlane; class TriangleMesh; @@ -108,6 +109,7 @@ class ShapeVisitor virtual void apply(Box&) {} virtual void apply(Cone&) {} virtual void apply(Cylinder&) {} + virtual void apply(Capsule&) {} virtual void apply(InfinitePlane&) {} virtual void apply(TriangleMesh&) {} @@ -127,6 +129,7 @@ class ConstShapeVisitor 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&) {} @@ -350,6 +353,63 @@ class Cylinder : public Shape Quat _rotation; }; +class Capsule : public Shape +{ + public: + + Capsule(): + _center(0.0f,0.0f,0.0f), + _radius(1.0f), + _height(1.0f) {} + + Capsule(const osg::Vec3& center,float radius,float height): + _center(center), + _radius(radius), + _height(height) {} + + Capsule(const Capsule& capsule,const CopyOp& copyop=CopyOp::SHALLOW_COPY): + Shape(capsule,copyop), + _center(capsule._center), + _radius(capsule._radius), + _height(capsule._height), + _rotation(capsule._rotation) {} + + META_Shape(osg, Capsule); + + inline bool valid() const { return _radius>=0.0f; } + + inline void set(const Vec3& center,float radius, float height) + { + _center = center; + _radius = radius; + _height = height; + } + + inline void setCenter(const Vec3& center) { _center = center; } + inline const Vec3& getCenter() const { return _center; } + + inline void setRadius(float radius) { _radius = radius; } + inline float getRadius() const { return _radius; } + + inline void setHeight(float height) { _height = height; } + inline float getHeight() const { return _height; } + + inline void setRotation(const Quat& quat) { _rotation = quat; } + inline const Quat& getRotation() const { return _rotation; } + inline Matrix getRotationMatrix() const { return Matrix(_rotation); } + bool zeroRotation() const { return _rotation.zeroRotation(); } + + protected: + + virtual ~Capsule() {} + + Vec3 _center; + float _radius; + float _height; + + Quat _rotation; +}; + class InfinitePlane : public Shape, public Plane { public: diff --git a/src/osg/ShapeDrawable.cpp b/src/osg/ShapeDrawable.cpp index 7245443da..1356b769d 100644 --- a/src/osg/ShapeDrawable.cpp +++ b/src/osg/ShapeDrawable.cpp @@ -46,6 +46,7 @@ class DrawShapeVisitor : public ConstShapeVisitor 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&); @@ -56,12 +57,223 @@ class DrawShapeVisitor : public ConstShapeVisitor State& _state; const TessellationHints* _hints; + + protected: + 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); }; +void DrawShapeVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height) +{ + const float angleDelta = 2.0f*osg::PI/(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 + + glBegin(GL_QUAD_STRIP); + + if (drawFrontFace) { + + for(unsigned int bodyi=0; + bodyigetCreateFrontFace() : true; + bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; + + float angleDelta = osg::PI*2.0f/(float)numSegments; + float texCoordHorzDelta = 1.0f/(float)numSegments; + + float lBase=-osg::PI*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; rowigetCreateBody() : true); + bool createTop = (_hints ? _hints->getCreateTop() : true); + bool createBottom = (_hints ? _hints->getCreateBottom() : true); + + unsigned int numSegments = 40; + unsigned int numRows = 20; + if (_hints && _hints->getDetailRatio() != 1.0f) { + float ratio = _hints->getDetailRatio(); + 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; + } + + + // 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); + + glPopMatrix(); +} + void DrawShapeVisitor::apply(const InfinitePlane& plane) { std::cout << "draw a Plane ("<