1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#ifndef OSG_SHAPE
15#define OSG_SHAPE 1
16
17#include <osg/Object>
18#include <osg/Vec3>
19#include <osg/Quat>
20#include <osg/Plane>
21#include <osg/Array>
22
23namespace osg {
24
25// forward declare visitors.
26class ShapeVisitor;
27class ConstShapeVisitor;
28
29
30/** META_StateAttribute macro define the standard clone, isSameKindAs,
31  * className and getType methods.
32  * Use when subclassing from Object to make it more convenient to define
33  * the standard pure virtual methods which are required for all Object
34  * subclasses.*/
35#define META_Shape(library,name) \
36        virtual osg::Object* cloneType() const { return new name(); } \
37        virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new name (*this,copyop); } \
38        virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const name *>(obj)!=NULL; } \
39        virtual const char* libraryName() const { return #library; } \
40        virtual const char* className() const { return #name; } \
41        virtual void accept(osg::ShapeVisitor& sv) { sv.apply(*this); } \
42        virtual void accept(osg::ConstShapeVisitor& csv) const { csv.apply(*this); }
43
44/** Base class for all shape types.
45  * Shapes are used to either for culling and collision detection or
46  * to define the geometric shape of procedurally generate Geometry.
47*/
48class OSG_EXPORT Shape : public Object
49{
50    public:
51
52        Shape() {}
53
54        Shape(const Shape& sa,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
55            Object(sa,copyop) {}
56
57        /** Clone the type of an attribute, with Object* return type.
58            Must be defined by derived classes.*/
59        virtual Object* cloneType() const = 0;
60
61        /** Clone an attribute, with Object* return type.
62            Must be defined by derived classes.*/
63        virtual Object* clone(const CopyOp&) const = 0;
64
65
66        /** return true if this and obj are of the same kind of object.*/
67        virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const Shape*>(obj)!=NULL; }
68
69        /** return the name of the attribute's library.*/
70        virtual const char* libraryName() const { return "osg"; }
71
72        /** return the name of the attribute's class type.*/
73        virtual const char* className() const { return "Shape"; }
74
75        /** accept a non const shape visitor which can be used on non const shape objects.
76            Must be defined by derived classes.*/
77        virtual void accept(ShapeVisitor&)=0;
78
79        /** accept a const shape visitor which can be used on const shape objects.
80            Must be defined by derived classes.*/
81        virtual void accept(ConstShapeVisitor&) const =0;
82
83    protected:
84
85        virtual ~Shape();
86};
87
88// forward declarations of Shape types.
89class Sphere;
90class Box;
91class Cone;
92class Cylinder;
93class Capsule;
94class InfinitePlane;
95
96class TriangleMesh;
97class ConvexHull;
98class HeightField;
99
100class CompositeShape;
101
102class OSG_EXPORT ShapeVisitor
103{
104    public:
105
106        ShapeVisitor() {}
107        virtual ~ShapeVisitor();
108
109        virtual void apply(Shape&) {}
110        virtual void apply(Sphere&) {}
111        virtual void apply(Box&) {}
112        virtual void apply(Cone&) {}
113        virtual void apply(Cylinder&) {}
114        virtual void apply(Capsule&) {}
115        virtual void apply(InfinitePlane&) {}
116
117        virtual void apply(TriangleMesh&) {}
118        virtual void apply(ConvexHull&) {}
119        virtual void apply(HeightField&) {}
120
121        virtual void apply(CompositeShape&) {}
122};
123
124class OSG_EXPORT ConstShapeVisitor
125{
126    public:
127
128        ConstShapeVisitor() {}
129        virtual ~ConstShapeVisitor();
130
131        virtual void apply(const Shape&) {}
132        virtual void apply(const Sphere&) {}
133        virtual void apply(const Box&) {}
134        virtual void apply(const Cone&) {}
135        virtual void apply(const Cylinder&) {}
136        virtual void apply(const Capsule&) {}
137        virtual void apply(const InfinitePlane&) {}
138
139        virtual void apply(const TriangleMesh&) {}
140        virtual void apply(const ConvexHull&) {}
141        virtual void apply(const HeightField&) {}
142
143        virtual void apply(const CompositeShape&) {}
144};
145
146class OSG_EXPORT Sphere : public Shape
147{
148    public:
149
150        Sphere():
151            _center(0.0f,0.0f,0.0f),
152            _radius(1.0f) {}
153
154        Sphere(const osg::Vec3& center,float radius):
155            _center(center),
156            _radius(radius) {}
157
158        Sphere(const Sphere& sphere,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
159            Shape(sphere,copyop),
160            _center(sphere._center),
161            _radius(sphere._radius) {}
162
163        META_Shape(osg, Sphere);
164
165        inline bool valid() const { return _radius>=0.0f; }
166
167        inline void set(const Vec3& center,float radius)
168        {
169            _center = center;
170            _radius = radius;
171        }
172
173        inline void setCenter(const Vec3& center) { _center = center; }
174        inline const Vec3& getCenter() const { return _center; }
175
176        inline void setRadius(float radius) { _radius = radius; }
177        inline float getRadius() const { return _radius; }
178
179    protected:
180
181        virtual ~Sphere();
182
183        Vec3    _center;
184        float   _radius;
185
186};
187
188class OSG_EXPORT Box : public Shape
189{
190    public:
191
192        Box():
193            _center(0.0f,0.0f,0.0f),
194            _halfLengths(0.5f,0.5f,0.5f) {}
195
196        Box(const osg::Vec3& center,float width):
197            _center(center),
198            _halfLengths(width*0.5f,width*0.5f,width*0.5f) {}
199
200        Box(const osg::Vec3& center,float lengthX,float lengthY, float lengthZ):
201            _center(center),
202            _halfLengths(lengthX*0.5f,lengthY*0.5f,lengthZ*0.5f) {}
203
204        Box(const Box& box,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
205            Shape(box,copyop),
206            _center(box._center),
207            _halfLengths(box._halfLengths),
208            _rotation(box._rotation) {}
209
210        META_Shape(osg, Box);
211
212        inline bool valid() const { return _halfLengths.x()>=0.0f; }
213
214        inline void set(const Vec3& center,const Vec3& halfLengths)
215        {
216            _center = center;
217            _halfLengths = halfLengths;
218        }
219
220        inline void setCenter(const Vec3& center) { _center = center; }
221        inline const Vec3& getCenter() const { return _center; }
222
223        inline void setHalfLengths(const Vec3& halfLengths) { _halfLengths = halfLengths; }
224        inline const Vec3& getHalfLengths() const { return _halfLengths; }
225
226        inline void setRotation(const Quat& quat) { _rotation = quat; }
227        inline const Quat&  getRotation() const { return _rotation; }
228        inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
229        inline bool zeroRotation() const { return _rotation.zeroRotation(); }
230
231    protected:
232
233        virtual ~Box();
234
235        Vec3    _center;
236        Vec3    _halfLengths;
237        Quat    _rotation;
238
239};
240
241
242
243class OSG_EXPORT Cone : public Shape
244{
245    public:
246
247        Cone():
248            _center(0.0f,0.0f,0.0f),
249            _radius(1.0f),
250            _height(1.0f) {}
251
252        Cone(const osg::Vec3& center,float radius,float height):
253            _center(center),
254            _radius(radius),
255            _height(height) {}
256
257        Cone(const Cone& cone,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
258            Shape(cone,copyop),
259            _center(cone._center),
260            _radius(cone._radius),
261            _height(cone._height),
262            _rotation(cone._rotation) {}
263
264        META_Shape(osg, Cone);
265
266        inline bool valid() const { return _radius>=0.0f; }
267
268        inline void set(const Vec3& center,float radius, float height)
269        {
270            _center = center;
271            _radius = radius;
272            _height = height;
273        }
274
275        inline void setCenter(const Vec3& center) { _center = center; }
276        inline const Vec3& getCenter() const { return _center; }
277
278        inline void setRadius(float radius) { _radius = radius; }
279        inline float getRadius() const { return _radius; }
280
281        inline void setHeight(float height) { _height = height; }
282        inline float getHeight() const { return _height; }
283
284        inline void setRotation(const Quat& quat) { _rotation = quat; }
285        inline const Quat& getRotation() const { return _rotation; }
286        inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
287        inline bool zeroRotation() const { return _rotation.zeroRotation(); }
288
289        inline float getBaseOffsetFactor() const { return 0.25f; }
290        inline float getBaseOffset() const { return -getBaseOffsetFactor()*getHeight(); }
291
292    protected:
293
294        virtual ~Cone();
295
296        Vec3    _center;
297        float   _radius;
298        float   _height;
299
300        Quat    _rotation;
301};
302
303class OSG_EXPORT Cylinder : public Shape
304{
305    public:
306
307        Cylinder():
308            _center(0.0f,0.0f,0.0f),
309            _radius(1.0f),
310            _height(1.0f) {}
311
312        Cylinder(const osg::Vec3& center,float radius,float height):
313            _center(center),
314            _radius(radius),
315            _height(height) {}
316
317        Cylinder(const Cylinder& cylinder,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
318            Shape(cylinder,copyop),
319            _center(cylinder._center),
320            _radius(cylinder._radius),
321            _height(cylinder._height),
322            _rotation(cylinder._rotation) {}
323
324        META_Shape(osg, Cylinder);
325
326        inline bool valid() const { return _radius>=0.0f; }
327
328        inline void set(const Vec3& center,float radius, float height)
329        {
330            _center = center;
331            _radius = radius;
332            _height = height;
333        }
334
335        inline void setCenter(const Vec3& center) { _center = center; }
336        inline const Vec3& getCenter() const { return _center; }
337
338        inline void setRadius(float radius) { _radius = radius; }
339        inline float getRadius() const { return _radius; }
340
341        inline void setHeight(float height) { _height = height; }
342        inline float getHeight() const { return _height; }
343
344        inline void setRotation(const Quat& quat) { _rotation = quat; }
345        inline const Quat& getRotation() const { return _rotation; }
346        inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
347        bool zeroRotation() const { return _rotation.zeroRotation(); }
348
349    protected:
350
351        virtual ~Cylinder();
352
353        Vec3    _center;
354        float   _radius;
355        float   _height;
356        Quat    _rotation;
357};
358
359class OSG_EXPORT Capsule : public Shape
360{
361    public:
362
363        Capsule():
364            _center(0.0f,0.0f,0.0f),
365            _radius(1.0f),
366            _height(1.0f) {}
367
368        Capsule(const osg::Vec3& center,float radius,float height):
369            _center(center),
370            _radius(radius),
371            _height(height) {}
372
373        Capsule(const Capsule& capsule,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
374            Shape(capsule,copyop),
375            _center(capsule._center),
376            _radius(capsule._radius),
377            _height(capsule._height),
378            _rotation(capsule._rotation) {}
379
380        META_Shape(osg, Capsule);
381
382        inline bool valid() const { return _radius>=0.0f; }
383
384        inline void set(const Vec3& center,float radius, float height)
385        {
386            _center = center;
387            _radius = radius;
388            _height = height;
389        }
390
391        inline void setCenter(const Vec3& center) { _center = center; }
392        inline const Vec3& getCenter() const { return _center; }
393
394        inline void setRadius(float radius) { _radius = radius; }
395        inline float getRadius() const { return _radius; }
396
397        inline void setHeight(float height) { _height = height; }
398        inline float getHeight() const { return _height; }
399
400        inline void setRotation(const Quat& quat) { _rotation = quat; }
401        inline const Quat& getRotation() const { return _rotation; }
402        inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
403        bool zeroRotation() const { return _rotation.zeroRotation(); }
404
405    protected:
406
407        virtual ~Capsule();
408
409        Vec3    _center;
410        float   _radius;
411        float   _height;
412        Quat    _rotation;
413};
414
415class OSG_EXPORT InfinitePlane : public Shape, public Plane
416{
417    public:
418        InfinitePlane() {}
419
420        InfinitePlane(const InfinitePlane& plane,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
421            Shape(plane,copyop),
422            Plane(plane) {}
423
424        META_Shape(osg, InfinitePlane);
425
426     protected:
427
428        virtual ~InfinitePlane();
429};
430
431/** Exists to support collision detection engines not for doing rendering, use \ref osg::Geometry instead.
432 */
433class OSG_EXPORT TriangleMesh : public Shape
434{
435    public:
436
437        TriangleMesh() {}
438
439        TriangleMesh(const TriangleMesh& mesh,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
440            Shape(mesh,copyop),
441            _vertices(mesh._vertices),
442            _indices(mesh._indices) {}
443
444        META_Shape(osg, TriangleMesh);
445
446
447        void setVertices(Vec3Array* vertices) { _vertices = vertices; }
448        Vec3Array* getVertices() { return _vertices.get(); }
449        const Vec3Array* getVertices() const { return _vertices.get(); }
450
451
452        void setIndices(IndexArray* indices) { _indices = indices; }
453        IndexArray* getIndices() { return _indices.get(); }
454        const IndexArray* getIndices() const { return _indices.get(); }
455
456    protected:
457
458        virtual ~TriangleMesh();
459
460        ref_ptr<Vec3Array> _vertices;
461        ref_ptr<IndexArray> _indices;
462
463};
464
465class OSG_EXPORT ConvexHull : public TriangleMesh
466{
467    public:
468
469        ConvexHull() {}
470
471        ConvexHull(const ConvexHull& hull,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
472            TriangleMesh(hull,copyop) {}
473
474        META_Shape(osg, TriangleMesh);
475
476    protected:
477
478        virtual ~ConvexHull();
479};
480
481class OSG_EXPORT HeightField : public Shape
482{
483    public:
484
485        HeightField();
486
487        HeightField(const HeightField& mesh,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
488
489        META_Shape(osg, HeightField);
490
491        typedef std::vector<float> HeightList;
492
493        void allocate(unsigned int numColumns,unsigned int numRows);
494
495        inline unsigned int getNumColumns() const { return _columns; }
496        inline unsigned int getNumRows() const { return _rows; }
497
498        inline void setOrigin(const osg::Vec3& origin) { _origin = origin; }
499        inline const osg::Vec3& getOrigin() const { return _origin; }
500
501        inline void setXInterval(float dx) { _dx = dx; }
502        inline float getXInterval() const { return _dx; }
503
504        inline void setYInterval(float dy) { _dy = dy; }
505        inline float getYInterval() const { return _dy; }
506
507        /** Get the FloatArray height data.*/
508        osg::FloatArray* getFloatArray() { return _heights.get(); }
509
510        /** Get the const FloatArray height data.*/
511        const osg::FloatArray* getFloatArray() const { return _heights.get(); }
512
513        HeightList& getHeightList() { return _heights->asVector(); }
514
515        const HeightList& getHeightList() const { return _heights->asVector(); }
516
517        /** Set the height of the skirt to render around the edge of HeightField.
518          * The skirt is used as a means of disguising edge boundaries between adjacent HeightField,
519          * particularly of ones with different resolutions.*/
520        void setSkirtHeight(float skirtHeight) { _skirtHeight = skirtHeight; }
521
522        /** Get the height of the skirt to render around the edge of HeightField.*/
523        float getSkirtHeight() const { return _skirtHeight; }
524
525        /** Set the width in number of cells in from the edge that the height field should be rendered from.
526          * This exists to allow gradient and curvature continutity to be maintained between adjacent HeightField, where
527          * the border cells will overlap adjacent HeightField.*/
528        void setBorderWidth(unsigned int borderWidth) { _borderWidth = borderWidth; }
529
530        /** Get the width in number of cells in from the edge that the height field should be rendered from.*/
531        unsigned int getBorderWidth() const { return _borderWidth; }
532
533        inline void setRotation(const Quat& quat) { _rotation = quat; }
534        inline const Quat& getRotation() const { return _rotation; }
535        inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
536        inline bool zeroRotation() const { return _rotation.zeroRotation(); }
537
538        /* set a single height point in the height field */
539        inline void setHeight(unsigned int c,unsigned int r,float value)
540        {
541           (*_heights)[c+r*_columns] = value;
542        }
543
544        /* Get address of single height point in the height field, allows user to change. */
545        inline float& getHeight(unsigned int c,unsigned int r)
546        {
547           return (*_heights)[c+r*_columns];
548        }
549
550        /* Get value of single height point in the height field, not editable. */
551        inline float getHeight(unsigned int c,unsigned int r) const
552        {
553           return (*_heights)[c+r*_columns];
554        }
555
556        inline Vec3 getVertex(unsigned int c,unsigned int r) const
557        {
558            return Vec3(_origin.x()+getXInterval()*(float)c,
559                        _origin.y()+getYInterval()*(float)r,
560                        _origin.z()+(*_heights)[c+r*_columns]);
561        }
562
563        Vec3 getNormal(unsigned int c,unsigned int r) const;
564
565        Vec2 getHeightDelta(unsigned int c,unsigned int r) const;
566
567    protected:
568
569        virtual ~HeightField();
570
571        unsigned int                    _columns,_rows;
572
573        osg::Vec3                       _origin; // _origin is the min value of the X and Y coordinates.
574        float                           _dx;
575        float                           _dy;
576
577        float                           _skirtHeight;
578        unsigned int                    _borderWidth;
579
580        Quat                            _rotation;
581        osg::ref_ptr<osg::FloatArray>   _heights;
582
583};
584
585typedef HeightField Grid;
586
587
588class OSG_EXPORT CompositeShape : public Shape
589{
590    public:
591
592
593
594        typedef std::vector< ref_ptr<Shape> > ChildList;
595
596        CompositeShape() {}
597
598        CompositeShape(const CompositeShape& cs,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
599            Shape(cs,copyop),
600            _children(cs._children) {}
601
602        META_Shape(osg, CompositeShape);
603
604        /** Set the shape that encloses all of the children.*/
605        void setShape(Shape* shape) { _shape = shape; }
606
607        /** Get the shape that encloses all of the children.*/
608        Shape* getShape() { return _shape.get(); }
609
610        /** Get the const shape that encloses all of the children.*/
611        const Shape* getShape() const { return _shape.get(); }
612
613        /** Get the number of children of this composite shape.*/
614        unsigned int getNumChildren() const { return static_cast<unsigned int>(_children.size()); }
615
616        /** Get a child.*/
617        Shape* getChild(unsigned int i) { return _children[i].get(); }
618
619        /** Get a const child.*/
620        const Shape* getChild(unsigned int i) const { return _children[i].get(); }
621
622        /** Add a child to the list.*/
623        void addChild(Shape* shape) { _children.push_back(shape); }
624
625        template<class T> void addChild( const ref_ptr<T>& child ) { addChild(child.get()); }
626
627        /** remove a child from the list.*/
628        void removeChild(unsigned int i) { _children.erase(_children.begin()+i); }
629
630        /** find the index number of child, if child is not found then it returns getNumChildren(),
631          * so should be used in similar style to STL's result!=end().*/
632        unsigned int findChildNo(Shape* shape) const
633        {
634            for (unsigned int childNo=0;childNo<_children.size();++childNo)
635            {
636                if (_children[childNo]==shape) return childNo;
637            }
638            return static_cast<unsigned int>(_children.size()); // node not found.
639
640        }
641
642    protected:
643
644        virtual ~CompositeShape();
645
646        ref_ptr<Shape>  _shape;
647        ChildList       _children;
648
649};
650
651}
652
653#endif
654