/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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_PRIMITIVESET #define OSG_PRIMITIVESET 1 #include #include #include #include #include #include #include #include #include #include #include #include namespace osg { typedef MixinVector VectorGLsizei; typedef MixinVector VectorGLubyte; typedef MixinVector VectorGLushort; typedef MixinVector VectorGLuint; class State; /** A \c PrimitiveFunctor is used (in conjunction with * osg::Drawable::accept (PrimitiveFunctor&)) to get access to the * primitives that compose the things drawn by OSG. *

If \c osg::Drawable::accept() is called with a \c PrimitiveFunctor * parameter, the \c Drawable will "pretend" it is drawing itself, but instead * of calling real OpenGL functions, it will call PrimitiveFunctor's * member functions that "mimic" the OpenGL calls. *

Concrete subclasses of \c PrimitiveFunctor must implement these methods * so that they performs whatever they want. */ class PrimitiveFunctor { public: virtual ~PrimitiveFunctor() {} /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec2* vertices) = 0; /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec3* vertices) = 0; /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec4* vertices) = 0; /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec2d* vertices) = 0; /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec3d* vertices) = 0; /** Sets the array of vertices used to describe the primitives. Somehow * mimics the OpenGL \c glVertexPointer() function. */ virtual void setVertexArray(unsigned int count,const Vec4d* vertices) = 0; /// Mimics the OpenGL \c glDrawArrays() function. virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0; /// Mimics the OpenGL \c glDrawElements() function. virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) = 0; /// Mimics the OpenGL \c glDrawElements() function. virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) = 0; /// Mimics the OpenGL \c glDrawElements() function. virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) = 0; /// Mimics the OpenGL \c glBegin() function. virtual void begin(GLenum mode) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(const Vec2& vert) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(const Vec3& vert) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(const Vec4& vert) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(float x,float y) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(float x,float y,float z) = 0; /// Mimics the OpenGL \c glVertex() "family of functions". virtual void vertex(float x,float y,float z,float w) = 0; /// Mimics the OpenGL \c glEnd() function. virtual void end() = 0; }; class PrimitiveIndexFunctor { public: virtual ~PrimitiveIndexFunctor() {} virtual void setVertexArray(unsigned int count,const Vec2* vertices) = 0; virtual void setVertexArray(unsigned int count,const Vec3* vertices) = 0; virtual void setVertexArray(unsigned int count,const Vec4* vertices) = 0; virtual void setVertexArray(unsigned int count,const Vec2d* vertices) = 0; virtual void setVertexArray(unsigned int count,const Vec3d* vertices) = 0; virtual void setVertexArray(unsigned int count,const Vec4d* vertices) = 0; virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0; virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) = 0; virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) = 0; virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) = 0; virtual void begin(GLenum mode) = 0; virtual void vertex(unsigned int pos) = 0; virtual void end() = 0; }; class DrawElements; class OSG_EXPORT PrimitiveSet : public Object { public: enum Type { PrimitiveType, DrawArraysPrimitiveType, DrawArrayLengthsPrimitiveType, DrawElementsUBytePrimitiveType, DrawElementsUShortPrimitiveType, DrawElementsUIntPrimitiveType }; enum Mode { POINTS = GL_POINTS, LINES = GL_LINES, LINE_STRIP = GL_LINE_STRIP, LINE_LOOP = GL_LINE_LOOP, TRIANGLES = GL_TRIANGLES, TRIANGLE_STRIP = GL_TRIANGLE_STRIP, TRIANGLE_FAN = GL_TRIANGLE_FAN, QUADS = GL_QUADS, QUAD_STRIP = GL_QUAD_STRIP, POLYGON = GL_POLYGON }; PrimitiveSet(Type primType=PrimitiveType,GLenum mode=0, int numInstances=0): _primitiveType(primType), _numInstances(numInstances), _mode(mode), _modifiedCount(0), _rangeModifiedCount(0) {} PrimitiveSet(const PrimitiveSet& prim,const CopyOp& copyop=CopyOp::SHALLOW_COPY): Object(prim,copyop), _primitiveType(prim._primitiveType), _numInstances(prim._numInstances), _mode(prim._mode), _modifiedCount(0), _rangeModifiedCount(0) {} 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 "PrimitiveSet"; } Type getType() const { return _primitiveType; } virtual const GLvoid* getDataPointer() const { return 0; } virtual unsigned int getTotalDataSize() const { return 0; } virtual bool supportsBufferObject() const { return false; } virtual DrawElements* getDrawElements() { return 0; } virtual const DrawElements* getDrawElements() const { return 0; } void setNumInstances(int n) { _numInstances = n; } int getNumInstances() const { return _numInstances; } void setMode(GLenum mode) { _mode = mode; } GLenum getMode() const { return _mode; } virtual void draw(State& state, bool useVertexBufferObjects) const = 0; virtual void accept(PrimitiveFunctor& functor) const = 0; virtual void accept(PrimitiveIndexFunctor& functor) const = 0; virtual unsigned int index(unsigned int pos) const = 0; virtual unsigned int getNumIndices() const = 0; virtual void offsetIndices(int offset) = 0; virtual unsigned int getNumPrimitives() const; /** Dirty the primitive, which increments the modified count, to force buffer objects to update. */ virtual void dirty() { ++_modifiedCount; } /** Set the modified count value.*/ inline void setModifiedCount(unsigned int value) { _modifiedCount=value; } /** Get modified count value.*/ inline unsigned int getModifiedCount() const { return _modifiedCount; } /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int /*maxSize*/) {} /** If State is non-zero, this function releases OpenGL objects for * the specified graphics context. Otherwise, releases OpenGL objects * for all graphics contexts. */ virtual void releaseGLObjects(State* /*state*/=0) const {} virtual void computeRange() const {} protected: virtual ~PrimitiveSet() {} Type _primitiveType; int _numInstances; GLenum _mode; unsigned int _modifiedCount; mutable unsigned int _rangeModifiedCount; struct ObjectIDModifiedCountPair { ObjectIDModifiedCountPair(): _objectID(0), _modifiedCount(0) {} ObjectIDModifiedCountPair(const ObjectIDModifiedCountPair& obj): _objectID(obj._objectID), _modifiedCount(obj._modifiedCount) {} ObjectIDModifiedCountPair& operator = (const ObjectIDModifiedCountPair& obj) { _objectID = obj._objectID; _modifiedCount = obj._modifiedCount; return *this; } GLuint _objectID; unsigned int _modifiedCount; }; typedef osg::buffered_object GLObjectList; }; class OSG_EXPORT DrawArrays : public PrimitiveSet { public: DrawArrays(GLenum mode=0): PrimitiveSet(DrawArraysPrimitiveType,mode), _first(0), _count(0) {} DrawArrays(GLenum mode, GLint first, GLsizei count, int numInstances=0): PrimitiveSet(DrawArraysPrimitiveType, mode, numInstances), _first(first), _count(count) {} DrawArrays(const DrawArrays& da,const CopyOp& copyop=CopyOp::SHALLOW_COPY): PrimitiveSet(da,copyop), _first(da._first), _count(da._count) {} virtual Object* cloneType() const { return new DrawArrays(); } virtual Object* clone(const CopyOp& copyop) const { return new DrawArrays(*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 "DrawArrays"; } void set(GLenum mode,GLint first, GLsizei count) { _mode = mode; _first = first; _count = count; } void setFirst(GLint first) { _first = first; } GLint getFirst() const { return _first; } void setCount(GLsizei count) { _count = count; } GLsizei getCount() const { return _count; } virtual void draw(State& state, bool useVertexBufferObjects) const; virtual void accept(PrimitiveFunctor& functor) const; virtual void accept(PrimitiveIndexFunctor& functor) const; virtual unsigned int getNumIndices() const { return static_cast(_count); } virtual unsigned int index(unsigned int pos) const { return static_cast(_first)+pos; } virtual void offsetIndices(int offset) { _first += offset; } protected: virtual ~DrawArrays() {} GLint _first; GLsizei _count; }; class OSG_EXPORT DrawArrayLengths : public PrimitiveSet, public VectorGLsizei { public: typedef VectorGLsizei vector_type; DrawArrayLengths(GLenum mode=0): PrimitiveSet(DrawArrayLengthsPrimitiveType,mode), _first(0) {} DrawArrayLengths(const DrawArrayLengths& dal,const CopyOp& copyop=CopyOp::SHALLOW_COPY): PrimitiveSet(dal,copyop), vector_type(dal), _first(dal._first) {} DrawArrayLengths(GLenum mode, GLint first, unsigned int no, GLsizei* ptr) : PrimitiveSet(DrawArrayLengthsPrimitiveType,mode), vector_type(ptr,ptr+no), _first(first) {} DrawArrayLengths(GLenum mode,GLint first, unsigned int no) : PrimitiveSet(DrawArrayLengthsPrimitiveType,mode), vector_type(no), _first(first) {} DrawArrayLengths(GLenum mode,GLint first) : PrimitiveSet(DrawArrayLengthsPrimitiveType,mode), vector_type(), _first(first) {} virtual Object* cloneType() const { return new DrawArrayLengths(); } virtual Object* clone(const CopyOp& copyop) const { return new DrawArrayLengths(*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 "DrawArrayLengths"; } void setFirst(GLint first) { _first = first; } GLint getFirst() const { return _first; } virtual void draw(State& state, bool useVertexBufferObjects) const; virtual void accept(PrimitiveFunctor& functor) const; virtual void accept(PrimitiveIndexFunctor& functor) const; virtual unsigned int getNumIndices() const; virtual unsigned int index(unsigned int pos) const { return _first+pos; } virtual void offsetIndices(int offset) { _first += offset; } virtual unsigned int getNumPrimitives() const; protected: virtual ~DrawArrayLengths() {} GLint _first; }; class DrawElements : public PrimitiveSet { public: DrawElements(Type primType=PrimitiveType, GLenum mode=0, int numInstances=0): PrimitiveSet(primType,mode, numInstances), _eboOffset(0) {} DrawElements(const DrawElements& copy,const CopyOp& copyop=CopyOp::SHALLOW_COPY): PrimitiveSet(copy,copyop), _eboOffset(0) {} virtual DrawElements* getDrawElements() { return this; } virtual const DrawElements* getDrawElements() const { return this; } virtual void dirty() { ++_modifiedCount; if (_ebo.valid()) _ebo->dirty(); } /** Set the ElementBufferObject.*/ inline void setElementBufferObject(osg::ElementBufferObject* ebo) { if (_ebo == ebo) return; if (_ebo.valid()) { _ebo->removeDrawElements(this); } _ebo = ebo; if (_ebo.valid()) { _ebo->addDrawElements(this); } } /** Get the ElementBufferObject. If no EBO is assigned returns NULL*/ inline osg::ElementBufferObject* getElementBufferObject() { return _ebo.get(); } /** Get the const ElementBufferObject. If no EBO is assigned returns NULL*/ inline const osg::ElementBufferObject* getElementBufferObject() const { return _ebo.get(); } /** Set the offset into the ElementBufferObject, if used.*/ inline void setElementBufferObjectOffset(const GLvoid* offset) const { _eboOffset = offset; } /** Get the offset into the ElementBufferOffset, if used.*/ inline const GLvoid* getElementBufferObjectOffset() const { return _eboOffset; } /** Resize any per context GLObject buffers to specified size. */ virtual void resizeGLObjectBuffers(unsigned int maxSize) { if (_ebo.valid()) _ebo->resizeGLObjectBuffers(maxSize); } /** If State is non-zero, this function releases OpenGL objects for * the specified graphics context. Otherwise, releases OpenGL objects * for all graphics contexts. */ virtual void releaseGLObjects(State* state=0) const { if (_ebo.valid()) _ebo->releaseGLObjects(state); } virtual void reserveElements(unsigned int numIndices) = 0; virtual void setElement(unsigned int, unsigned int) = 0; virtual unsigned int getElement(unsigned int) = 0; virtual void addElement(unsigned int) = 0; protected: virtual ~DrawElements() { if (_ebo.valid()) { _ebo->removeDrawElements(this); } } osg::ref_ptr _ebo; mutable const GLvoid* _eboOffset; }; class OSG_EXPORT DrawElementsUByte : public DrawElements, public VectorGLubyte { public: typedef VectorGLubyte vector_type; DrawElementsUByte(GLenum mode=0): DrawElements(DrawElementsUBytePrimitiveType,mode) {} DrawElementsUByte(const DrawElementsUByte& array, const CopyOp& copyop=CopyOp::SHALLOW_COPY): DrawElements(array,copyop), vector_type(array) {} DrawElementsUByte(GLenum mode, unsigned int no, const GLubyte* ptr, int numInstances=0) : DrawElements(DrawElementsUBytePrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUByte(GLenum mode, unsigned int no) : DrawElements(DrawElementsUBytePrimitiveType,mode), vector_type(no) {} virtual Object* cloneType() const { return new DrawElementsUByte(); } virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsUByte(*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 "DrawElementsUByte"; } virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } virtual unsigned int getTotalDataSize() const { return static_cast(size()); } virtual bool supportsBufferObject() const { return false; } virtual void draw(State& state, bool useVertexBufferObjects) const ; virtual void accept(PrimitiveFunctor& functor) const; virtual void accept(PrimitiveIndexFunctor& functor) const; virtual unsigned int getNumIndices() const { return static_cast(size()); } virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } virtual void offsetIndices(int offset); virtual void computeRange() const { if (empty()) { _minIndex = 0; _maxIndex = 0; _rangeModifiedCount = _modifiedCount; return; } _minIndex = front(); _maxIndex = _minIndex; for(vector_type::const_iterator itr=begin(); itr!=end(); ++itr) { if (*itr<_minIndex) _minIndex = *itr; if (*itr>_maxIndex) _maxIndex = *itr; } _rangeModifiedCount = _modifiedCount; } virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } virtual void addElement(unsigned int v) { push_back(GLubyte(v)); } protected: virtual ~DrawElementsUByte(); mutable unsigned int _minIndex; mutable unsigned int _maxIndex; }; class OSG_EXPORT DrawElementsUShort : public DrawElements, public VectorGLushort { public: typedef VectorGLushort vector_type; DrawElementsUShort(GLenum mode=0): DrawElements(DrawElementsUShortPrimitiveType,mode) {} DrawElementsUShort(const DrawElementsUShort& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY): DrawElements(array,copyop), vector_type(array) {} DrawElementsUShort(GLenum mode, unsigned int no, const GLushort* ptr, int numInstances=0) : DrawElements(DrawElementsUShortPrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUShort(GLenum mode, unsigned int no) : DrawElements(DrawElementsUShortPrimitiveType,mode), vector_type(no) {} template DrawElementsUShort(GLenum mode, InputIterator first,InputIterator last) : DrawElements(DrawElementsUShortPrimitiveType,mode), vector_type(first,last) {} virtual Object* cloneType() const { return new DrawElementsUShort(); } virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsUShort(*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 "DrawElementsUShort"; } virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } virtual unsigned int getTotalDataSize() const { return 2u*static_cast(size()); } virtual bool supportsBufferObject() const { return false; } virtual void draw(State& state, bool useVertexBufferObjects) const; virtual void accept(PrimitiveFunctor& functor) const; virtual void accept(PrimitiveIndexFunctor& functor) const; virtual unsigned int getNumIndices() const { return static_cast(size()); } virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } virtual void offsetIndices(int offset); virtual void computeRange() const { if (empty()) { _minIndex = 0; _maxIndex = 0; _rangeModifiedCount = _modifiedCount; return; } _minIndex = front(); _maxIndex = _minIndex; for(vector_type::const_iterator itr=begin(); itr!=end(); ++itr) { if (*itr<_minIndex) _minIndex = *itr; if (*itr>_maxIndex) _maxIndex = *itr; } _rangeModifiedCount = _modifiedCount; } virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } virtual void addElement(unsigned int v) { push_back(GLushort(v)); } protected: virtual ~DrawElementsUShort(); mutable unsigned int _minIndex; mutable unsigned int _maxIndex; }; class OSG_EXPORT DrawElementsUInt : public DrawElements, public VectorGLuint { public: typedef VectorGLuint vector_type; DrawElementsUInt(GLenum mode=0): DrawElements(DrawElementsUIntPrimitiveType,mode) {} DrawElementsUInt(const DrawElementsUInt& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY): DrawElements(array,copyop), vector_type(array) {} DrawElementsUInt(GLenum mode, unsigned int no, const GLuint* ptr, int numInstances=0) : DrawElements(DrawElementsUIntPrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUInt(GLenum mode, unsigned int no) : DrawElements(DrawElementsUIntPrimitiveType,mode), vector_type(no) {} template DrawElementsUInt(GLenum mode, InputIterator first,InputIterator last) : DrawElements(DrawElementsUIntPrimitiveType,mode), vector_type(first,last) {} virtual Object* cloneType() const { return new DrawElementsUInt(); } virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsUInt(*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 "DrawElementsUInt"; } virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } virtual unsigned int getTotalDataSize() const { return 4u*static_cast(size()); } virtual bool supportsBufferObject() const { return false; } virtual void draw(State& state, bool useVertexBufferObjects) const; virtual void accept(PrimitiveFunctor& functor) const; virtual void accept(PrimitiveIndexFunctor& functor) const; virtual unsigned int getNumIndices() const { return static_cast(size()); } virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } virtual void offsetIndices(int offset); virtual void computeRange() const { if (empty()) { _minIndex = 0; _maxIndex = 0; _rangeModifiedCount = _modifiedCount; return; } _minIndex = front(); _maxIndex = _minIndex; for(vector_type::const_iterator itr=begin(); itr!=end(); ++itr) { if (*itr<_minIndex) _minIndex = *itr; if (*itr>_maxIndex) _maxIndex = *itr; } _rangeModifiedCount = _modifiedCount; } virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } virtual void addElement(unsigned int v) { push_back(GLuint(v)); } protected: virtual ~DrawElementsUInt(); mutable unsigned int _minIndex; mutable unsigned int _maxIndex; }; } #endif