/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * 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 * OpenSceneGraph Public License for more details. */ #ifndef OSG_GEOMETRY #define OSG_GEOMETRY 1 #include #include #include #include #include #include namespace osg { class OSG_EXPORT Geometry : public Drawable { public: Geometry(); /** Copy constructor using CopyOp to manage deep vs shallow copy. */ Geometry(const Geometry& geometry,const CopyOp& copyop=CopyOp::SHALLOW_COPY); virtual Object* cloneType() const { return new Geometry(); } virtual Object* clone(const CopyOp& copyop) const { return new Geometry(*this,copyop); } virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } virtual const char* libraryName() const { return "osg"; } virtual const char* className() const { return "Geometry"; } virtual Geometry* asGeometry() { return this; } virtual const Geometry* asGeometry() const { return this; } bool empty() const; enum AttributeBinding { BIND_OFF=0, BIND_OVERALL, BIND_PER_PRIMITIVE_SET, BIND_PER_PRIMITIVE, BIND_PER_VERTEX }; struct OSG_EXPORT ArrayData { ArrayData(): binding(BIND_OFF), normalize(GL_FALSE), offset(0) {} ArrayData(const ArrayData& data,const CopyOp& copyop=CopyOp::SHALLOW_COPY); ArrayData(Array* a, AttributeBinding b, GLboolean n = GL_FALSE): array(a), indices(0), binding(b), normalize(n), offset(0) {} ArrayData(Array* a, IndexArray* i, AttributeBinding b, GLboolean n = GL_FALSE): array(a), indices(i), binding(b), normalize(n), offset(0) {} ArrayData& operator = (const ArrayData& rhs) { array = rhs.array; indices = rhs.indices; binding = rhs.binding; normalize = rhs.normalize; offset = rhs.offset; return *this; } inline bool empty() const { return !array.valid(); } ref_ptr array; ref_ptr indices; AttributeBinding binding; GLboolean normalize; mutable unsigned int offset; }; struct OSG_EXPORT Vec3ArrayData { Vec3ArrayData(): binding(BIND_OFF), normalize(GL_FALSE), offset(0) {} Vec3ArrayData(const Vec3ArrayData& data,const CopyOp& copyop=CopyOp::SHALLOW_COPY); Vec3ArrayData(Vec3Array* a, AttributeBinding b, GLboolean n = GL_FALSE): array(a), indices(0), binding(b), normalize(n), offset(0) {} Vec3ArrayData(Vec3Array* a, IndexArray* i, AttributeBinding b, GLboolean n = GL_FALSE): array(a), indices(i), binding(b), normalize(n), offset(0) {} Vec3ArrayData& operator = (const Vec3ArrayData& rhs) { array = rhs.array; indices = rhs.indices; binding = rhs.binding; normalize = rhs.normalize; offset = rhs.offset; return *this; } inline bool empty() const { return !array.valid(); } ref_ptr array; ref_ptr indices; AttributeBinding binding; GLboolean normalize; mutable unsigned int offset; }; /** Static ArrayData which is returned from getTexCoordData(i) const and getVertexAttribData(i) const * when i is out of range. */ static const ArrayData s_InvalidArrayData; typedef std::vector< ArrayData > ArrayList; void setVertexArray(Array* array) { _vertexData.array = array; dirtyDisplayList(); dirtyBound(); } Array* getVertexArray() { return _vertexData.array.get(); } const Array* getVertexArray() const { return _vertexData.array.get(); } void setVertexIndices(IndexArray* array) { _vertexData.indices = array; computeFastPathsUsed(); dirtyDisplayList(); dirtyBound(); } IndexArray* getVertexIndices() { return _vertexData.indices.get(); } const IndexArray* getVertexIndices() const { return _vertexData.indices.get(); } void setVertexData(const ArrayData& arrayData) { _vertexData = arrayData; } ArrayData& getVertexData() { return _vertexData; } const ArrayData& getVertexData() const { return _vertexData; } void setNormalBinding(AttributeBinding ab) { _normalData.binding = ab; dirtyDisplayList(); computeFastPathsUsed(); } AttributeBinding getNormalBinding() const { return _normalData.binding; } void setNormalArray(Vec3Array* array) { _normalData.array = array; if (!_normalData.array.valid()) _normalData.binding=BIND_OFF; computeFastPathsUsed(); dirtyDisplayList(); } Vec3Array* getNormalArray() { return _normalData.array.get(); } const Vec3Array* getNormalArray() const { return _normalData.array.get(); } void setNormalIndices(IndexArray* array) { _normalData.indices = array; computeFastPathsUsed(); dirtyDisplayList(); } IndexArray* getNormalIndices() { return _normalData.indices.get(); } const IndexArray* getNormalIndices() const { return _normalData.indices.get(); } void setNormalData(const Vec3ArrayData& arrayData) { _normalData = arrayData; } Vec3ArrayData& getNormalData() { return _normalData; } const Vec3ArrayData& getNormalData() const { return _normalData; } void setColorBinding(AttributeBinding ab) { _colorData.binding = ab; computeFastPathsUsed();} AttributeBinding getColorBinding() const { return _colorData.binding; } void setColorArray(Array* array) { _colorData.array = array; if (!_colorData.array.valid()) _colorData.binding=BIND_OFF; computeFastPathsUsed(); dirtyDisplayList(); } Array* getColorArray() { return _colorData.array.get(); } const Array* getColorArray() const { return _colorData.array.get(); } void setColorIndices(IndexArray* array) { _colorData.indices = array; computeFastPathsUsed(); dirtyDisplayList(); } IndexArray* getColorIndices() { return _colorData.indices.get(); } const IndexArray* getColorIndices() const { return _colorData.indices.get(); } void setColorData(const ArrayData& arrayData) { _colorData = arrayData; } ArrayData& getColorData() { return _colorData; } const ArrayData& getColorData() const { return _colorData; } void setSecondaryColorBinding(AttributeBinding ab) { _secondaryColorData.binding = ab; computeFastPathsUsed();} AttributeBinding getSecondaryColorBinding() const { return _secondaryColorData.binding; } void setSecondaryColorArray(Array* array) { _secondaryColorData.array = array; if (!_secondaryColorData.array.valid()) _secondaryColorData.binding=BIND_OFF; computeFastPathsUsed(); dirtyDisplayList(); } Array* getSecondaryColorArray() { return _secondaryColorData.array.get(); } const Array* getSecondaryColorArray() const { return _secondaryColorData.array.get(); } void setSecondaryColorIndices(IndexArray* array) { _secondaryColorData.indices = array; computeFastPathsUsed(); dirtyDisplayList(); } IndexArray* getSecondaryColorIndices() { return _secondaryColorData.indices.get(); } const IndexArray* getSecondaryColorIndices() const { return _secondaryColorData.indices.get(); } void setSecondaryColorData(const ArrayData& arrayData) { _secondaryColorData = arrayData; } ArrayData& getSecondaryColorData() { return _secondaryColorData; } const ArrayData& getSecondaryColorData() const { return _secondaryColorData; } void setFogCoordBinding(AttributeBinding ab) { _fogCoordData.binding = ab; computeFastPathsUsed();} AttributeBinding getFogCoordBinding() const { return _fogCoordData.binding; } void setFogCoordArray(Array* array) { _fogCoordData.array = array; if (!_fogCoordData.array.valid()) _fogCoordData.binding=BIND_OFF; dirtyDisplayList(); } Array* getFogCoordArray() { return _fogCoordData.array.get(); } const Array* getFogCoordArray() const { return _fogCoordData.array.get(); } void setFogCoordIndices(IndexArray* array) { _fogCoordData.indices = array; dirtyDisplayList(); } IndexArray* getFogCoordIndices() { return _fogCoordData.indices.get(); } const IndexArray* getFogCoordIndices() const { return _fogCoordData.indices.get(); } void setFogCoordData(const ArrayData& arrayData) { _fogCoordData = arrayData; } ArrayData& getFogCoordData() { return _fogCoordData; } const ArrayData& getFogCoordData() const { return _fogCoordData; } void setTexCoordArray(unsigned int unit,Array*); Array* getTexCoordArray(unsigned int unit); const Array* getTexCoordArray(unsigned int unit) const; void setTexCoordIndices(unsigned int unit,IndexArray*); IndexArray* getTexCoordIndices(unsigned int unit); const IndexArray* getTexCoordIndices(unsigned int unit) const; void setTexCoordData(unsigned int index,const ArrayData& arrayData); ArrayData& getTexCoordData(unsigned int index); const ArrayData& getTexCoordData(unsigned int index) const; unsigned int getNumTexCoordArrays() const { return _texCoordList.size(); } ArrayList& getTexCoordArrayList() { return _texCoordList; } const ArrayList& getTexCoordArrayList() const { return _texCoordList; } void setVertexAttribArray(unsigned int index,Array* array); Array *getVertexAttribArray(unsigned int index); const Array *getVertexAttribArray(unsigned int index) const; void setVertexAttribIndices(unsigned int index,IndexArray* array); IndexArray* getVertexAttribIndices(unsigned int index); const IndexArray* getVertexAttribIndices(unsigned int index) const; void setVertexAttribBinding(unsigned int index,AttributeBinding ab); AttributeBinding getVertexAttribBinding(unsigned int index) const; void setVertexAttribNormalize(unsigned int index,GLboolean norm); GLboolean getVertexAttribNormalize(unsigned int index) const; void setVertexAttribData(unsigned int index,const ArrayData& arrayData); ArrayData& getVertexAttribData(unsigned int index); const ArrayData& getVertexAttribData(unsigned int index) const; unsigned int getNumVertexAttribArrays() const { return _vertexAttribList.size(); } ArrayList& getVertexAttribArrayList() { return _vertexAttribList; } const ArrayList& getVertexAttribArrayList() const { return _vertexAttribList; } typedef std::vector< ref_ptr > PrimitiveSetList; void setPrimitiveSetList(const PrimitiveSetList& primitives) { _primitives = primitives; dirtyDisplayList(); dirtyBound(); } PrimitiveSetList& getPrimitiveSetList() { return _primitives; } const PrimitiveSetList& getPrimitiveSetList() const { return _primitives; } unsigned int getNumPrimitiveSets() const { return _primitives.size(); } PrimitiveSet* getPrimitiveSet(unsigned int pos) { return _primitives[pos].get(); } const PrimitiveSet* getPrimitiveSet(unsigned int pos) const { return _primitives[pos].get(); } /** Add a primitive set to the geometry. */ bool addPrimitiveSet(PrimitiveSet* primitiveset); /** Set a primitive set to the specified position in geometry's primitive set list. */ bool setPrimitiveSet(unsigned int i,PrimitiveSet* primitiveset); /** Insert a primitive set to the specified position in geometry's primitive set list. */ bool insertPrimitiveSet(unsigned int i,PrimitiveSet* primitiveset); /** Remove primitive set(s) from the specified position in geometry's primitive set list. */ bool removePrimitiveSet(unsigned int i,unsigned int numElementsToRemove=1); /** Get the index number of a primitive set, return a value between * 0 and getNumPrimitiveSet()-1 if found, if not found then return getNumPrimitiveSet(). * When checking for a valid find value use if ((value=geometry->getPrimitiveSetIndex(primitive))!=geometry.getNumPrimitiveSet()) */ unsigned int getPrimitiveSetIndex(const PrimitiveSet* primitiveset) const; /** Set whether fast paths should be used when supported. */ void setFastPathHint(bool on) { _fastPathHint = on; } /** Get whether fast paths should be used when supported. */ bool getFastPathHint() const { return _fastPathHint; } /** Return true if OpenGL fast paths will be used with drawing this Geometry. * Fast paths use vertex arrays, and glDrawArrays/glDrawElements. Slow paths * use glBegin()/glVertex.../glEnd(). Use of per primitive bindings or per vertex indexed * arrays will drop the rendering path off the fast path. */ inline bool areFastPathsUsed() const { return _fastPath && _fastPathHint; } bool computeFastPathsUsed(); bool verifyBindings() const; void computeCorrectBindingsAndArraySizes(); bool suitableForOptimization() const; void copyToAndOptimize(Geometry& target); void computeInternalOptimizedGeometry(); void removeInternalOptimizedGeometry() { _internalOptimizedGeometry = 0; } void setInternalOptimizedGeometry(osg::Geometry* geometry) { _internalOptimizedGeometry = geometry; } osg::Geometry* getInternalOptimizedGeometry() { return _internalOptimizedGeometry.get(); } const osg::Geometry* getInternalOptimizedGeometry() const { return _internalOptimizedGeometry.get(); } /** Return the estimated size of GLObjects (display lists/vertex buffer objects) that are associated with this drawable. * This size is used a hint for reuse of deleteed display lists/vertex buffer objects. */ virtual unsigned int getGLObjectSizeHint() const; /** Draw Geometry 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 Geometry for user-drawn objects. */ virtual void drawImplementation(State& state) const; /** Return true, osg::Geometry does support accept(AttributeFunctor&). */ virtual bool supports(const AttributeFunctor&) const { return true; } /** Accept an AttributeFunctor and call its methods to tell it about the interal attributes that this Drawable has. */ virtual void accept(AttributeFunctor& af); /** Return true, osg::Geometry does support accept(ConstAttributeFunctor&). */ virtual bool supports(const ConstAttributeFunctor&) const { return true; } /** Accept a ConstAttributeFunctor and call its methods to tell it about the interal attributes that this Drawable has. */ virtual void accept(ConstAttributeFunctor& af) const; /** Return true, osg::Geometry does support accept(PrimitiveFunctor&). */ virtual bool supports(const PrimitiveFunctor&) const { return true; } /** Accept a PrimitiveFunctor and call its methods to tell it about the interal primitives that this Drawable has. */ virtual void accept(PrimitiveFunctor& pf) const; /** Return true, osg::Geometry does support accept(PrimitiveIndexFunctor&). */ virtual bool supports(const PrimitiveIndexFunctor&) const { return true; } /** Accept a PrimitiveFunctor and call its methods to tell it about the interal primitives that this Drawable has. */ virtual void accept(PrimitiveIndexFunctor& pf) const; protected: Geometry& operator = (const Geometry&) { return *this;} virtual ~Geometry(); bool verifyBindings(const ArrayData& arrayData) const; bool verifyBindings(const Vec3ArrayData& arrayData) const; void computeCorrectBindingsAndArraySizes(ArrayData& arrayData,const char* arrayName); void computeCorrectBindingsAndArraySizes(Vec3ArrayData& arrayData,const char* arrayName); PrimitiveSetList _primitives; ArrayData _vertexData; Vec3ArrayData _normalData; ArrayData _colorData; ArrayData _secondaryColorData; ArrayData _fogCoordData; ArrayList _texCoordList; ArrayList _vertexAttribList; mutable bool _fastPath; bool _fastPathHint; ref_ptr _internalOptimizedGeometry; }; /** Convenience function to be used for creating quad geometry with texture coords. * Tex coords go from left bottom (l,b) to right top (r,t). */ extern OSG_EXPORT Geometry* createTexturedQuadGeometry(const Vec3& corner,const Vec3& widthVec,const Vec3& heightVec, float l, float b, float r, float t); /** Convenience function to be used for creating quad geometry with texture coords. * Tex coords go from bottom left (0,0) to top right (s,t). */ inline Geometry* createTexturedQuadGeometry(const Vec3& corner,const Vec3& widthVec,const Vec3& heightVec, float s=1.0f, float t=1.0f) { return createTexturedQuadGeometry(corner,widthVec,heightVec, 0.0f, 0.0f, s, t); } } #endif