diff --git a/examples/osggeometry/osggeometry.cpp b/examples/osggeometry/osggeometry.cpp index ba218fc22..40f418407 100644 --- a/examples/osggeometry/osggeometry.cpp +++ b/examples/osggeometry/osggeometry.cpp @@ -17,7 +17,7 @@ */ #include -#include +#include #include #include #include @@ -37,6 +37,7 @@ #include + // This demo illustrates how to create the various different types of geometry that // the osg::Geometry class can represent. This demo uses the OpenGL red book diagram of different // OpenGL Primitives as a template for all the equivalent OpenSceneGraph Primitives. The OpenSceneGraph @@ -92,7 +93,7 @@ osg::Node* createScene() // create POINTS { // create Geometry object to store all the vertices and points primitive. - osg::Geometry* pointsGeom = new osg::Geometry(); + osg::GeometryNew* pointsGeom = new osg::GeometryNew(); // create a Vec3Array and add to it all my coordinates. // Like all the *Array variants (see include/osg/Array) , Vec3Array is derived from both osg::Array @@ -121,14 +122,14 @@ osg::Node* createScene() // pass the color array to points geometry, note the binding to tell the geometry // that only use one color for the whole object. pointsGeom->setColorArray(colors); - pointsGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + pointsGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); pointsGeom->setNormalArray(normals); - pointsGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + pointsGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // create and add a DrawArray Primitive (see include/osg/Primitive). The first @@ -146,7 +147,7 @@ osg::Node* createScene() // create LINES { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* linesGeom = new osg::Geometry(); + osg::GeometryNew* linesGeom = new osg::GeometryNew(); // this time we'll preallocate the vertex array to the size we // need and then simple set them as array elements, 8 points @@ -169,14 +170,14 @@ osg::Node* createScene() osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f,1.0f,0.0f,1.0f)); linesGeom->setColorArray(colors); - linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); linesGeom->setNormalArray(normals); - linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -191,7 +192,7 @@ osg::Node* createScene() // create LINE_STRIP { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* linesGeom = new osg::Geometry(); + osg::GeometryNew* linesGeom = new osg::GeometryNew(); // this time we'll preallocate the vertex array to the size // and then use an iterator to fill in the values, a bit perverse @@ -211,14 +212,14 @@ osg::Node* createScene() osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f,1.0f,0.0f,1.0f)); linesGeom->setColorArray(colors); - linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); linesGeom->setNormalArray(normals); - linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -233,7 +234,7 @@ osg::Node* createScene() // create LINE_LOOP { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* linesGeom = new osg::Geometry(); + osg::GeometryNew* linesGeom = new osg::GeometryNew(); // this time we'll a C arrays to initialize the vertices. @@ -258,14 +259,14 @@ osg::Node* createScene() osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f,1.0f,0.0f,1.0f)); linesGeom->setColorArray(colors); - linesGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); linesGeom->setNormalArray(normals); - linesGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + linesGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -306,7 +307,7 @@ osg::Node* createScene() // create POLYGON { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* polyGeom = new osg::Geometry(); + osg::GeometryNew* polyGeom = new osg::GeometryNew(); // this time we'll use C arrays to initialize the vertices. // note, anticlockwise ordering. @@ -332,12 +333,12 @@ osg::Node* createScene() // use the shared color array. polyGeom->setColorArray(shared_colors.get()); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // use the shared normal array. polyGeom->setNormalArray(shared_normals.get()); - polyGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -354,7 +355,7 @@ osg::Node* createScene() // create QUADS { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* polyGeom = new osg::Geometry(); + osg::GeometryNew* polyGeom = new osg::GeometryNew(); // note, anticlockwise ordering. osg::Vec3 myCoords[] = @@ -379,12 +380,12 @@ osg::Node* createScene() // use the shared color array. polyGeom->setColorArray(shared_colors.get()); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // use the shared normal array. polyGeom->setNormalArray(shared_normals.get()); - polyGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -401,7 +402,7 @@ osg::Node* createScene() // create QUAD_STRIP { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* polyGeom = new osg::Geometry(); + osg::GeometryNew* polyGeom = new osg::GeometryNew(); // note, first coord at top, second at bottom, reverse to that buggy OpenGL image.. osg::Vec3 myCoords[] = @@ -428,12 +429,12 @@ osg::Node* createScene() // use the shared color array. polyGeom->setColorArray(shared_colors.get()); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // use the shared normal array. polyGeom->setNormalArray(shared_normals.get()); - polyGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -450,7 +451,7 @@ osg::Node* createScene() // create TRIANGLES, TRIANGLE_STRIP and TRIANGLE_FAN all in one Geometry/ { // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* polyGeom = new osg::Geometry(); + osg::GeometryNew* polyGeom = new osg::GeometryNew(); // note, first coord at top, second at bottom, reverse to that buggy OpenGL image.. osg::Vec3 myCoords[] = @@ -496,12 +497,12 @@ osg::Node* createScene() // use the shared color array. polyGeom->setColorArray(shared_colors.get()); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // use the shared normal array. polyGeom->setNormalArray(shared_normals.get()); - polyGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); // This time we simply use primitive, and hardwire the number of coords to use @@ -570,7 +571,7 @@ osg::Node* createBackground() // create Geometry object to store all the vertices and lines primitive. - osg::Geometry* polyGeom = new osg::Geometry(); + osg::GeometryNew* polyGeom = new osg::GeometryNew(); // note, anticlockwise ordering. osg::Vec3 myCoords[] = @@ -589,14 +590,14 @@ osg::Node* createBackground() osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); polyGeom->setColorArray(colors); - polyGeom->setColorBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setColorBinding(osg::GeometryNew::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); polyGeom->setNormalArray(normals); - polyGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); + polyGeom->setNormalBinding(osg::GeometryNew::BIND_OVERALL); osg::Vec2 myTexCoords[] = { diff --git a/include/osg/GeometryNew b/include/osg/GeometryNew new file mode 100644 index 000000000..21bd98a46 --- /dev/null +++ b/include/osg/GeometryNew @@ -0,0 +1,401 @@ +/* -*-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_GEOMETRYNEW +#define OSG_GEOMETRYNEW 1 + +#include +#include +#include +#include +#include +#include + +namespace osg { + + +class OSG_EXPORT GeometryNew : public Drawable +{ + public: + + GeometryNew(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy. */ + GeometryNew(const GeometryNew& geometry,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + virtual Object* cloneType() const { return new GeometryNew(); } + virtual Object* clone(const CopyOp& copyop) const { return new GeometryNew(*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 "GeometryNew"; } + +#if 0 + virtual Geometry* asGeometry() { return this; } + virtual const Geometry* asGeometry() const { return this; } +#endif + + 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) {} + + ArrayData(const ArrayData& data,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + ArrayData(Array* a, AttributeBinding b, GLboolean n = GL_FALSE): + array(a), + binding(b), + normalize(n) {} + + ArrayData(Array* a, IndexArray* i, AttributeBinding b, GLboolean n = GL_FALSE): + array(a), + binding(b), + normalize(n) {} + + ArrayData& operator = (const ArrayData& rhs) + { + array = rhs.array; + binding = rhs.binding; + normalize = rhs.normalize; + return *this; + } + + inline bool empty() const { return !array.valid(); } + + ref_ptr array; + AttributeBinding binding; + GLboolean normalize; + }; + + struct OSG_EXPORT Vec3ArrayData + { + Vec3ArrayData(): + binding(BIND_OFF), + normalize(GL_FALSE) {} + + Vec3ArrayData(const Vec3ArrayData& data,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + Vec3ArrayData(Vec3Array* a, AttributeBinding b, GLboolean n = GL_FALSE): + array(a), + binding(b), + normalize(n) {} + + Vec3ArrayData(Vec3Array* a, IndexArray* i, AttributeBinding b, GLboolean n = GL_FALSE): + array(a), + binding(b), + normalize(n) {} + + Vec3ArrayData& operator = (const Vec3ArrayData& rhs) + { + array = rhs.array; + binding = rhs.binding; + normalize = rhs.normalize; + return *this; + } + + inline bool empty() const { return !array.valid(); } + + ref_ptr array; + AttributeBinding binding; + GLboolean normalize; + }; + + /** 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 > ArrayDataList; + + + void setVertexArray(Array* array); + Array* getVertexArray() { return _vertexData.array.get(); } + const Array* getVertexArray() const { return _vertexData.array.get(); } + + void setVertexData(const ArrayData& arrayData); + ArrayData& getVertexData() { return _vertexData; } + const ArrayData& getVertexData() const { return _vertexData; } + + + void setNormalBinding(AttributeBinding ab); + AttributeBinding getNormalBinding() const { return _normalData.binding; } + + void setNormalArray(Array* array); + Array* getNormalArray() { return _normalData.array.get(); } + const Array* getNormalArray() const { return _normalData.array.get(); } + + void setNormalData(const ArrayData& arrayData); + ArrayData& getNormalData() { return _normalData; } + const ArrayData& getNormalData() const { return _normalData; } + + void setColorBinding(AttributeBinding ab); + AttributeBinding getColorBinding() const { return _colorData.binding; } + + void setColorArray(Array* array); + Array* getColorArray() { return _colorData.array.get(); } + const Array* getColorArray() const { return _colorData.array.get(); } + + void setColorData(const ArrayData& arrayData); + ArrayData& getColorData() { return _colorData; } + const ArrayData& getColorData() const { return _colorData; } + + + void setSecondaryColorBinding(AttributeBinding ab); + AttributeBinding getSecondaryColorBinding() const { return _secondaryColorData.binding; } + + void setSecondaryColorArray(Array* array); + Array* getSecondaryColorArray() { return _secondaryColorData.array.get(); } + const Array* getSecondaryColorArray() const { return _secondaryColorData.array.get(); } + + void setSecondaryColorData(const ArrayData& arrayData); + ArrayData& getSecondaryColorData() { return _secondaryColorData; } + const ArrayData& getSecondaryColorData() const { return _secondaryColorData; } + + + void setFogCoordBinding(AttributeBinding ab); + AttributeBinding getFogCoordBinding() const { return _fogCoordData.binding; } + + void setFogCoordArray(Array* array); + Array* getFogCoordArray() { return _fogCoordData.array.get(); } + const Array* getFogCoordArray() const { return _fogCoordData.array.get(); } + + void setFogCoordData(const ArrayData& 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 setTexCoordData(unsigned int index,const ArrayData& arrayData); + ArrayData& getTexCoordData(unsigned int index); + const ArrayData& getTexCoordData(unsigned int index) const; + + unsigned int getNumTexCoordArrays() const { return static_cast(_texCoordList.size()); } + ArrayDataList& getTexCoordArrayList() { return _texCoordList; } + const ArrayDataList& getTexCoordArrayList() const { return _texCoordList; } + + + + void setVertexAttribArray(unsigned int index,Array* array); + Array *getVertexAttribArray(unsigned int index); + const Array *getVertexAttribArray(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 static_cast(_vertexAttribList.size()); } + ArrayDataList& getVertexAttribArrayList() { return _vertexAttribList; } + const ArrayDataList& getVertexAttribArrayList() const { return _vertexAttribList; } + + + + typedef std::vector< ref_ptr > PrimitiveSetList; + + void setPrimitiveSetList(const PrimitiveSetList& primitives); + + PrimitiveSetList& getPrimitiveSetList() { return _primitives; } + const PrimitiveSetList& getPrimitiveSetList() const { return _primitives; } + + unsigned int getNumPrimitiveSets() const { return static_cast(_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; + + + + + /** When set to true, ignore the setUseDisplayList() settings, and hints to the drawImplementation + method to use OpenGL vertex buffer objects for rendering.*/ + virtual void setUseVertexBufferObjects(bool flag); + + /** Force a recompile on next draw() of any OpenGL display list associated with this geoset.*/ + virtual void dirtyDisplayList(); + + + /** 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; + + typedef std::vector ArrayList; + bool getArrayList(ArrayList& arrayList) const; + + typedef std::vector DrawElementsList; + bool getDrawElementsList(DrawElementsList& drawElementsList) const; + + osg::VertexBufferObject* getOrCreateVertexBufferObject(); + + osg::ElementBufferObject* getOrCreateElementBufferObject(); + + + /** 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 directly use vertex arrays, and glDrawArrays/glDrawElements so have low CPU overhead. + * With Slow paths the osg::Geometry::drawImplementation has to dynamically assemble OpenGL + * compatible vertex arrays from the osg::Geometry arrays data and then dispatch these to OpenGL, + * so have higher CPU overhead than the Fast paths. + * 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(); + + /** check whether the arrays, indices, bindings and primitives all match correctly, return false is .*/ + bool verifyArrays(std::ostream& out) const; + + + bool containsSharedArrays() const; + + void duplicateSharedArrays(); + + + + /** 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 deleted display lists/vertex buffer objects. */ + virtual unsigned int getGLObjectSizeHint() const; + + /** Immediately compile this \c Drawable into an OpenGL Display List/VertexBufferObjects. + * @note Operation is ignored if \c _useDisplayList is \c false or VertexBufferObjects are not used. + */ + virtual void compileGLObjects(RenderInfo& renderInfo) 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(RenderInfo& renderInfo) const; + + /** Return true, osg::Geometry does support accept(Drawable::AttributeFunctor&). */ + virtual bool supports(const Drawable::AttributeFunctor&) const { return true; } + + /** Accept an Drawable::AttributeFunctor and call its methods to tell it about the internal attributes that this Drawable has. */ + virtual void accept(Drawable::AttributeFunctor& af); + + /** Return true, osg::Geometry 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::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 internal 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 internal primitives that this Drawable has. */ + virtual void accept(PrimitiveIndexFunctor& pf) const; + + + protected: + + GeometryNew& operator = (const GeometryNew&) { return *this;} + + virtual ~GeometryNew(); + + 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); + + void addVertexBufferObjectIfRequired(osg::Array* array); + void addElementBufferObjectIfRequired(osg::PrimitiveSet* primitiveSet); + + + PrimitiveSetList _primitives; + ArrayData _vertexData; + ArrayData _normalData; + ArrayData _colorData; + ArrayData _secondaryColorData; + ArrayData _fogCoordData; + ArrayDataList _texCoordList; + ArrayDataList _vertexAttribList; + + mutable bool _fastPath; + bool _fastPathHint; +}; + +/** 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 GeometryNew* createTexturedQuadGeometryNew(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 GeometryNew* createTexturedQuadGeometryNew(const Vec3& corner,const Vec3& widthVec,const Vec3& heightVec, float s=1.0f, float t=1.0f) +{ + return createTexturedQuadGeometryNew(corner,widthVec,heightVec, 0.0f, 0.0f, s, t); +} + + +} + +#endif diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index 5d77ba265..94db33d22 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -256,6 +256,7 @@ SET(TARGET_SRC FrontFace.cpp Geode.cpp Geometry.cpp + GeometryNew.cpp GL2Extensions.cpp GLExtensions.cpp GLBeginEndAdapter.cpp diff --git a/src/osg/GeometryNew.cpp b/src/osg/GeometryNew.cpp new file mode 100644 index 000000000..21453a3cc --- /dev/null +++ b/src/osg/GeometryNew.cpp @@ -0,0 +1,1963 @@ +/* -*-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. +*/ +#include + +#include +#include +#include + +using namespace osg; + +const GeometryNew::ArrayData GeometryNew::s_InvalidArrayData; + +GeometryNew::ArrayData::ArrayData(const ArrayData& data,const CopyOp& copyop): + array(copyop(data.array.get())), + binding(data.binding), + normalize(data.normalize) +{ +} + +GeometryNew::Vec3ArrayData::Vec3ArrayData(const Vec3ArrayData& data,const CopyOp& copyop): + array(dynamic_cast(copyop(data.array.get()))), + binding(data.binding), + normalize(data.normalize) +{ +} + +GeometryNew::GeometryNew() +{ + // temporary test + // setSupportsDisplayList(false); + + _vertexData.binding = BIND_PER_VERTEX; + + _fastPath = false; + _fastPathHint = true; +} + +GeometryNew::GeometryNew(const GeometryNew& geometry,const CopyOp& copyop): + Drawable(geometry,copyop), + _vertexData(geometry._vertexData,copyop), + _normalData(geometry._normalData,copyop), + _colorData(geometry._colorData,copyop), + _secondaryColorData(geometry._secondaryColorData,copyop), + _fogCoordData(geometry._fogCoordData,copyop), + _fastPath(geometry._fastPath), + _fastPathHint(geometry._fastPathHint) +{ + // temporary test + // setSupportsDisplayList(false); + + for(PrimitiveSetList::const_iterator pitr=geometry._primitives.begin(); + pitr!=geometry._primitives.end(); + ++pitr) + { + PrimitiveSet* primitive = copyop(pitr->get()); + if (primitive) _primitives.push_back(primitive); + } + + for(ArrayDataList::const_iterator titr=geometry._texCoordList.begin(); + titr!=geometry._texCoordList.end(); + ++titr) + { + _texCoordList.push_back(ArrayData(*titr, copyop)); + } + + for(ArrayDataList::const_iterator vitr=geometry._vertexAttribList.begin(); + vitr!=geometry._vertexAttribList.end(); + ++vitr) + { + _vertexAttribList.push_back(ArrayData(*vitr, copyop)); + } + + if ((copyop.getCopyFlags() & osg::CopyOp::DEEP_COPY_ARRAYS)) + { + if (_useVertexBufferObjects) + { + // copying of arrays doesn't set up buffer objects so we'll need to force + // Geometry to assign these, we'll do this by switching off VBO's then renabling them. + setUseVertexBufferObjects(false); + setUseVertexBufferObjects(true); + } + } + +} + +GeometryNew::~GeometryNew() +{ + // do dirty here to keep the getGLObjectSizeHint() estimate on the ball + dirtyDisplayList(); + + // no need to delete, all automatically handled by ref_ptr :-) +} + +bool GeometryNew::empty() const +{ + if (!_primitives.empty()) return false; + if (!_vertexData.empty()) return false; + if (!_normalData.empty()) return false; + if (!_colorData.empty()) return false; + if (!_secondaryColorData.empty()) return false; + if (!_fogCoordData.empty()) return false; + if (!_texCoordList.empty()) return false; + if (!_vertexAttribList.empty()) return false; + return true; +} + +void GeometryNew::setVertexArray(Array* array) +{ + _vertexData.array = array; + computeFastPathsUsed(); + dirtyDisplayList(); + dirtyBound(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +void GeometryNew::setVertexData(const ArrayData& arrayData) +{ + _vertexData = arrayData; + computeFastPathsUsed(); + dirtyDisplayList(); + dirtyBound(); + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + +void GeometryNew::setNormalArray(Array* array) +{ + _normalData.array = array; + if (!_normalData.array.valid()) _normalData.binding=BIND_OFF; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +void GeometryNew::setNormalData(const ArrayData& arrayData) +{ + _normalData = arrayData; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + +void GeometryNew::setColorArray(Array* array) +{ + _colorData.array = array; + if (!_colorData.array.valid()) _colorData.binding=BIND_OFF; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +void GeometryNew::setColorData(const ArrayData& arrayData) +{ + _colorData = arrayData; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + + +void GeometryNew::setSecondaryColorArray(Array* array) +{ + _secondaryColorData.array = array; + if (!_secondaryColorData.array.valid()) _secondaryColorData.binding=BIND_OFF; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +void GeometryNew::setSecondaryColorData(const ArrayData& arrayData) +{ + _secondaryColorData = arrayData; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + +void GeometryNew::setFogCoordArray(Array* array) +{ + _fogCoordData.array = array; + if (!_fogCoordData.array.valid()) _fogCoordData.binding=BIND_OFF; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +void GeometryNew::setFogCoordData(const ArrayData& arrayData) +{ + _fogCoordData = arrayData; + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + +void GeometryNew::setNormalBinding(AttributeBinding ab) +{ + if (_normalData.binding == ab) return; + + _normalData.binding = ab; + computeFastPathsUsed(); + dirtyDisplayList(); +} + +void GeometryNew::setColorBinding(AttributeBinding ab) +{ + if (_colorData.binding == ab) return; + + _colorData.binding = ab; + computeFastPathsUsed(); + dirtyDisplayList(); +} + +void GeometryNew::setSecondaryColorBinding(AttributeBinding ab) +{ + if (_secondaryColorData.binding == ab) return; + + _secondaryColorData.binding = ab; + computeFastPathsUsed(); + dirtyDisplayList(); +} + +void GeometryNew::setFogCoordBinding(AttributeBinding ab) +{ + if (_fogCoordData.binding == ab) return; + + _fogCoordData.binding = ab; + computeFastPathsUsed(); + dirtyDisplayList(); +} + +void GeometryNew::setTexCoordData(unsigned int unit,const ArrayData& arrayData) +{ + if (_texCoordList.size()<=unit) + _texCoordList.resize(unit+1); + + _texCoordList[unit] = arrayData; + + if (_useVertexBufferObjects && arrayData.array.valid()) addVertexBufferObjectIfRequired(arrayData.array.get()); +} + +GeometryNew::ArrayData& GeometryNew::getTexCoordData(unsigned int unit) +{ + if (_texCoordList.size()<=unit) + _texCoordList.resize(unit+1); + + return _texCoordList[unit]; +} + +const GeometryNew::ArrayData& GeometryNew::getTexCoordData(unsigned int unit) const +{ + if (_texCoordList.size()<=unit) + return s_InvalidArrayData; + + return _texCoordList[unit]; +} + +void GeometryNew::setTexCoordArray(unsigned int unit,Array* array) +{ + getTexCoordData(unit).binding = BIND_PER_VERTEX; + getTexCoordData(unit).array = array; + + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) + { + addVertexBufferObjectIfRequired(array); + } +} + +Array* GeometryNew::getTexCoordArray(unsigned int unit) +{ + if (unit<_texCoordList.size()) return _texCoordList[unit].array.get(); + else return 0; +} + +const Array* GeometryNew::getTexCoordArray(unsigned int unit) const +{ + if (unit<_texCoordList.size()) return _texCoordList[unit].array.get(); + else return 0; +} + + +void GeometryNew::setVertexAttribData(unsigned int index, const GeometryNew::ArrayData& attrData) +{ + if (_vertexAttribList.size()<=index) + _vertexAttribList.resize(index+1); + + _vertexAttribList[index] = attrData; + + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && attrData.array.valid()) addVertexBufferObjectIfRequired(attrData.array.get()); +} + +GeometryNew::ArrayData& GeometryNew::getVertexAttribData(unsigned int index) +{ + if (_vertexAttribList.size()<=index) + _vertexAttribList.resize(index+1); + + return _vertexAttribList[index]; +} + +const GeometryNew::ArrayData& GeometryNew::getVertexAttribData(unsigned int index) const +{ + if (_vertexAttribList.size()<=_vertexAttribList.size()) + return s_InvalidArrayData; + + return _vertexAttribList[index]; +} + +void GeometryNew::setVertexAttribArray(unsigned int index, Array* array) +{ + getVertexAttribData(index).array = array; + + computeFastPathsUsed(); + dirtyDisplayList(); + + if (_useVertexBufferObjects && array) addVertexBufferObjectIfRequired(array); +} + +Array *GeometryNew::getVertexAttribArray(unsigned int index) +{ + if (index<_vertexAttribList.size()) return _vertexAttribList[index].array.get(); + else return 0; +} + +const Array *GeometryNew::getVertexAttribArray(unsigned int index) const +{ + if (index<_vertexAttribList.size()) return _vertexAttribList[index].array.get(); + else return 0; +} + +void GeometryNew::setVertexAttribBinding(unsigned int index,AttributeBinding ab) +{ + if (getVertexAttribData(index).binding == ab) + return; + getVertexAttribData(index).binding = ab; + computeFastPathsUsed(); + dirtyDisplayList(); +} + +GeometryNew::AttributeBinding GeometryNew::getVertexAttribBinding(unsigned int index) const +{ + if (index<_vertexAttribList.size()) return _vertexAttribList[index].binding; + else return BIND_OFF; +} + +void GeometryNew::setVertexAttribNormalize(unsigned int index,GLboolean norm) +{ + getVertexAttribData(index).normalize = norm; + + dirtyDisplayList(); +} + +GLboolean GeometryNew::getVertexAttribNormalize(unsigned int index) const +{ + if (index<_vertexAttribList.size()) return _vertexAttribList[index].normalize; + else return GL_FALSE; +} + +bool GeometryNew::addPrimitiveSet(PrimitiveSet* primitiveset) +{ + if (primitiveset) + { + if (_useVertexBufferObjects) addElementBufferObjectIfRequired(primitiveset); + + _primitives.push_back(primitiveset); + dirtyDisplayList(); + dirtyBound(); + return true; + } + OSG_WARN<<"Warning: invalid index i or primitiveset passed to osg::GeometryNew::addPrimitiveSet(i,primitiveset), ignoring call."<getTotalDataSize(); + + if (_normalData.array.valid()) totalSize += _normalData.array->getTotalDataSize(); + + if (_colorData.array.valid()) totalSize += _colorData.array->getTotalDataSize(); + + if (_secondaryColorData.array.valid()) totalSize += _secondaryColorData.array->getTotalDataSize(); + + if (_fogCoordData.array.valid()) totalSize += _fogCoordData.array->getTotalDataSize(); + + + unsigned int unit; + for(unit=0;unit<_texCoordList.size();++unit) + { + const Array* array = _texCoordList[unit].array.get(); + if (array) totalSize += array->getTotalDataSize(); + + } + + bool handleVertexAttributes = true; + if (handleVertexAttributes) + { + unsigned int index; + for( index = 0; index < _vertexAttribList.size(); ++index ) + { + const Array* array = _vertexAttribList[index].array.get(); + if (array) totalSize += array->getTotalDataSize(); + } + } + + for(PrimitiveSetList::const_iterator itr=_primitives.begin(); + itr!=_primitives.end(); + ++itr) + { + + totalSize += 4*(*itr)->getNumIndices(); + + } + + + // do a very simply mapping of display list size proportional to vertex datasize. + return totalSize; +} + +bool GeometryNew::getArrayList(ArrayList& arrayList) const +{ + unsigned int startSize = arrayList.size(); + + if (_vertexData.array.valid()) arrayList.push_back(_vertexData.array.get()); + if (_normalData.array.valid()) arrayList.push_back(_normalData.array.get()); + if (_colorData.array.valid()) arrayList.push_back(_colorData.array.get()); + if (_secondaryColorData.array.valid()) arrayList.push_back(_secondaryColorData.array.get()); + if (_fogCoordData.array.valid()) arrayList.push_back(_fogCoordData.array.get()); + + for(unsigned int unit=0;unit<_texCoordList.size();++unit) + { + Array* array = _texCoordList[unit].array.get(); + if (array) arrayList.push_back(array); + } + + for(unsigned int index = 0; index < _vertexAttribList.size(); ++index ) + { + Array* array = _vertexAttribList[index].array.get(); + if (array) arrayList.push_back(array); + } + + return arrayList.size()!=startSize; +} + +bool GeometryNew::getDrawElementsList(DrawElementsList& drawElementsList) const +{ + unsigned int startSize = drawElementsList.size(); + + for(PrimitiveSetList::const_iterator itr = _primitives.begin(); + itr != _primitives.end(); + ++itr) + { + osg::DrawElements* de = (*itr)->getDrawElements(); + if (de) drawElementsList.push_back(de); + } + + return drawElementsList.size()!=startSize; +} + +void GeometryNew::addVertexBufferObjectIfRequired(osg::Array* array) +{ + if (_useVertexBufferObjects) + { + if (!array->getVertexBufferObject()) + { + array->setVertexBufferObject(getOrCreateVertexBufferObject()); + } + } +} + +void GeometryNew::addElementBufferObjectIfRequired(osg::PrimitiveSet* primitiveSet) +{ + if (_useVertexBufferObjects) + { + osg::DrawElements* drawElements = primitiveSet->getDrawElements(); + if (drawElements && !drawElements->getElementBufferObject()) + { + drawElements->setElementBufferObject(getOrCreateElementBufferObject()); + } + } +} + +osg::VertexBufferObject* GeometryNew::getOrCreateVertexBufferObject() +{ + ArrayList arrayList; + getArrayList(arrayList); + + ArrayList::iterator vitr; + for(vitr = arrayList.begin(); + vitr != arrayList.end(); + ++vitr) + { + osg::Array* array = *vitr; + if (array->getVertexBufferObject()) return array->getVertexBufferObject(); + } + + return new osg::VertexBufferObject; +} + +osg::ElementBufferObject* GeometryNew::getOrCreateElementBufferObject() +{ + DrawElementsList drawElementsList; + getDrawElementsList(drawElementsList); + + DrawElementsList::iterator deitr; + for(deitr = drawElementsList.begin(); + deitr != drawElementsList.end(); + ++deitr) + { + osg::DrawElements* elements = *deitr; + if (elements->getElementBufferObject()) return elements->getElementBufferObject(); + } + + return new osg::ElementBufferObject; +} + +void GeometryNew::setUseVertexBufferObjects(bool flag) +{ + // flag = true; + + // OSG_NOTICE<<"GeometryNew::setUseVertexBufferObjects("< VertexBufferObjectList; + typedef std::vector ElementBufferObjectList; + + if (_useVertexBufferObjects) + { + if (!arrayList.empty()) + { + + VertexBufferObjectList vboList; + + osg::ref_ptr vbo; + + ArrayList::iterator vitr; + for(vitr = arrayList.begin(); + vitr != arrayList.end() && !vbo; + ++vitr) + { + osg::Array* array = *vitr; + if (array->getVertexBufferObject()) vbo = array->getVertexBufferObject(); + } + + if (!vbo) vbo = new osg::VertexBufferObject; + + for(vitr = arrayList.begin(); + vitr != arrayList.end(); + ++vitr) + { + osg::Array* array = *vitr; + if (!array->getVertexBufferObject()) array->setVertexBufferObject(vbo.get()); + } + } + + if (!drawElementsList.empty()) + { + ElementBufferObjectList eboList; + + osg::ref_ptr ebo; + + DrawElementsList::iterator deitr; + for(deitr = drawElementsList.begin(); + deitr != drawElementsList.end(); + ++deitr) + { + osg::DrawElements* elements = *deitr; + if (elements->getElementBufferObject()) ebo = elements->getElementBufferObject(); + } + + if (!ebo) ebo = new osg::ElementBufferObject; + + for(deitr = drawElementsList.begin(); + deitr != drawElementsList.end(); + ++deitr) + { + osg::DrawElements* elements = *deitr; + if (!elements->getElementBufferObject()) elements->setElementBufferObject(ebo.get()); + } + } + } + else + { + for(ArrayList::iterator vitr = arrayList.begin(); + vitr != arrayList.end(); + ++vitr) + { + osg::Array* array = *vitr; + if (array->getVertexBufferObject()) array->setVertexBufferObject(0); + } + + for(DrawElementsList::iterator deitr = drawElementsList.begin(); + deitr != drawElementsList.end(); + ++deitr) + { + osg::DrawElements* elements = *deitr; + if (elements->getElementBufferObject()) elements->setElementBufferObject(0); + } + } +} + +void GeometryNew::dirtyDisplayList() +{ + Drawable::dirtyDisplayList(); +} + +void GeometryNew::resizeGLObjectBuffers(unsigned int maxSize) +{ + Drawable::resizeGLObjectBuffers(maxSize); + + ArrayList arrays; + if (getArrayList(arrays)) + { + for(ArrayList::iterator itr = arrays.begin(); + itr != arrays.end(); + ++itr) + { + (*itr)->resizeGLObjectBuffers(maxSize); + } + } + + DrawElementsList drawElements; + if (getDrawElementsList(drawElements)) + { + for(DrawElementsList::iterator itr = drawElements.begin(); + itr != drawElements.end(); + ++itr) + { + (*itr)->resizeGLObjectBuffers(maxSize); + } + } +} + +void GeometryNew::releaseGLObjects(State* state) const +{ + Drawable::releaseGLObjects(state); + + ArrayList arrays; + if (getArrayList(arrays)) + { + for(ArrayList::iterator itr = arrays.begin(); + itr != arrays.end(); + ++itr) + { + (*itr)->releaseGLObjects(state); + } + } + + DrawElementsList drawElements; + if (getDrawElementsList(drawElements)) + { + for(DrawElementsList::iterator itr = drawElements.begin(); + itr != drawElements.end(); + ++itr) + { + (*itr)->releaseGLObjects(state); + } + } + +} + +void GeometryNew::compileGLObjects(RenderInfo& renderInfo) const +{ + bool useVertexArrays = _supportsVertexBufferObjects && + _useVertexBufferObjects && + renderInfo.getState()->isVertexBufferObjectSupported() && + areFastPathsUsed(); + if (useVertexArrays) + { + // OSG_NOTICE<<"GeometryNew::compileGLObjects() use VBO's "< BufferObjects; + BufferObjects bufferObjects; + + // first collect all the active unique BufferObjects + if (_vertexData.array.valid() && _vertexData.array->getBufferObject()) bufferObjects.insert(_vertexData.array->getBufferObject()); + if (_normalData.array.valid() && _normalData.array->getBufferObject()) bufferObjects.insert(_normalData.array->getBufferObject()); + if (_colorData.array.valid() && _colorData.array->getBufferObject()) bufferObjects.insert(_colorData.array->getBufferObject()); + if (_secondaryColorData.array.valid() && _secondaryColorData.array->getBufferObject()) bufferObjects.insert(_secondaryColorData.array->getBufferObject()); + if (_fogCoordData.array.valid() && _fogCoordData.array->getBufferObject()) bufferObjects.insert(_fogCoordData.array->getBufferObject()); + + for(ArrayDataList::const_iterator itr = _texCoordList.begin(); + itr != _texCoordList.end(); + ++itr) + { + if (itr->array.valid() && itr->array->getBufferObject()) bufferObjects.insert(itr->array->getBufferObject()); + } + + for(ArrayDataList::const_iterator itr = _vertexAttribList.begin(); + itr != _vertexAttribList.end(); + ++itr) + { + if (itr->array.valid() && itr->array->getBufferObject()) bufferObjects.insert(itr->array->getBufferObject()); + } + + for(PrimitiveSetList::const_iterator itr = _primitives.begin(); + itr != _primitives.end(); + ++itr) + { + if ((*itr)->getBufferObject()) bufferObjects.insert((*itr)->getBufferObject()); + } + + //osg::ElapsedTime timer; + + // now compile any buffer objects that require it. + for(BufferObjects::iterator itr = bufferObjects.begin(); + itr != bufferObjects.end(); + ++itr) + { + GLBufferObject* glBufferObject = (*itr)->getOrCreateGLBufferObject(contextID); + if (glBufferObject && glBufferObject->isDirty()) + { + // OSG_NOTICE<<"Compile buffer "<compileBuffer(); + } + } + + // OSG_NOTICE<<"Time to compile "<glBindBuffer(GL_ARRAY_BUFFER_ARB,0); + extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,0); + + } + else + { + Drawable::compileGLObjects(renderInfo); + } +} + +void GeometryNew::drawImplementation(RenderInfo& renderInfo) const +{ +#if 0 + if (!validGeometryNew()) + { + OSG_NOTICE<<"Error, osg::Geometry has invalid array/primitive set usage"<draw(state, usingVertexBufferObjects); + } + else + { + GLenum mode=primitiveset->getMode(); + + unsigned int primLength; + switch(mode) + { + case(GL_POINTS): primLength=1; break; + case(GL_LINES): primLength=2; break; + case(GL_TRIANGLES): primLength=3; break; + case(GL_QUADS): primLength=4; break; + default: primLength=0; break; // compute later when =0. + } + + // draw primitives by the more flexible "slow" path, + // sending OpenGL glBegin/glVertex.../glEnd(). + switch(primitiveset->getType()) + { + case(PrimitiveSet::DrawArraysPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawArrays* drawArray = static_cast(primitiveset); + arrayDispatchers.Begin(mode); + + unsigned int primCount=0; + unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount(); + for(unsigned int vindex=drawArray->getFirst(); + vindex(primitiveset); + unsigned int vindex=drawArrayLengths->getFirst(); + for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); + primItr!=drawArrayLengths->end(); + ++primItr) + { + unsigned int localPrimLength; + if (primLength==0) localPrimLength=*primItr; + else localPrimLength=primLength; + + arrayDispatchers.Begin(mode); + + for(GLsizei primCount=0; + primCount<*primItr; + ++vindex,++primCount) + { + if (bindPerPrimitiveActive && (primCount%localPrimLength)==0) + { + arrayDispatchers.dispatch(BIND_PER_PRIMITIVE, primitiveNum++); + } + arrayDispatchers.dispatch(BIND_PER_VERTEX, vindex); + } + + arrayDispatchers.End(); + + } + break; + } + case(PrimitiveSet::DrawElementsUBytePrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUByte* drawElements = static_cast(primitiveset); + arrayDispatchers.Begin(mode); + + unsigned int primCount=0; + for(DrawElementsUByte::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + + if (bindPerPrimitiveActive && (primCount%primLength)==0) + { + arrayDispatchers.dispatch(BIND_PER_PRIMITIVE, primitiveNum++); + } + + unsigned int vindex=*primItr; + arrayDispatchers.dispatch(BIND_PER_VERTEX, vindex); + } + + arrayDispatchers.End(); + break; + } + case(PrimitiveSet::DrawElementsUShortPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUShort* drawElements = static_cast(primitiveset); + arrayDispatchers.Begin(mode); + + unsigned int primCount=0; + for(DrawElementsUShort::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + if (bindPerPrimitiveActive && (primCount%primLength)==0) + { + arrayDispatchers.dispatch(BIND_PER_PRIMITIVE, primitiveNum++); + } + + unsigned int vindex=*primItr; + arrayDispatchers.dispatch(BIND_PER_VERTEX, vindex); + } + + arrayDispatchers.End(); + break; + } + case(PrimitiveSet::DrawElementsUIntPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUInt* drawElements = static_cast(primitiveset); + arrayDispatchers.Begin(mode); + + unsigned int primCount=0; + for(DrawElementsUInt::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + if (bindPerPrimitiveActive && (primCount%primLength)==0) + { + arrayDispatchers.dispatch(BIND_PER_PRIMITIVE, primitiveNum++); + } + + unsigned int vindex=*primItr; + arrayDispatchers.dispatch(BIND_PER_VERTEX, vindex); + } + + arrayDispatchers.End(); + break; + } + default: + { + break; + } + } + } + } + + // unbind the VBO's if any are used. + state.unbindVertexBufferObject(); + state.unbindElementBufferObject(); + + if (checkForGLErrors) state.checkGLErrors("end of GeometryNew::drawImplementation()."); +} + +class AttributeFunctorArrayVisitor : public ArrayVisitor +{ + public: + + AttributeFunctorArrayVisitor(Drawable::AttributeFunctor& af): + _af(af), + _type(0) {} + + virtual ~AttributeFunctorArrayVisitor() {} + + virtual void apply(ByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(ShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(IntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(UByteArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(UShortArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(UIntArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec4ubArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(FloatArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec2Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec3Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec4Array& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(DoubleArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec2dArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec3dArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + virtual void apply(Vec4dArray& array) { if (!array.empty()) _af.apply(_type,array.size(),&(array.front())); } + + + inline void applyArray(Drawable::AttributeType type,Array* array) + { + if (array) + { + _type = type; + array->accept(*this); + } + } + + protected: + + AttributeFunctorArrayVisitor& operator = (const AttributeFunctorArrayVisitor&) { return *this; } + Drawable::AttributeFunctor& _af; + Drawable::AttributeType _type; +}; + +void GeometryNew::accept(AttributeFunctor& af) +{ + AttributeFunctorArrayVisitor afav(af); + + if (_vertexData.array.valid()) + { + afav.applyArray(VERTICES,_vertexData.array.get()); + } + else if (_vertexAttribList.size()>0) + { + OSG_INFO<<"GeometryNew::accept(AttributeFunctor& af): Using vertex attribute instead"<accept(*this); + } + } + +protected: + + ConstAttributeFunctorArrayVisitor& operator = (const ConstAttributeFunctorArrayVisitor&) { return *this; } + + Drawable::ConstAttributeFunctor& _af; + Drawable::AttributeType _type; +}; + +void GeometryNew::accept(ConstAttributeFunctor& af) const +{ + ConstAttributeFunctorArrayVisitor afav(af); + + if (_vertexData.array.valid()) + { + afav.applyArray(VERTICES,_vertexData.array.get()); + } + else if (_vertexAttribList.size()>0) + { + OSG_INFO<<"GeometryNew::accept(ConstAttributeFunctor& af): Using vertex attribute instead"<0) + { + OSG_INFO<<"Using vertex attribute instead"<getNumElements()==0) return; + + switch(vertices->getType()) + { + case(Array::Vec2ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec3ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec4ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec2dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec3dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec4dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + default: + OSG_WARN<<"Warning: GeometryNew::accept(PrimitiveFunctor&) cannot handle Vertex Array type"<getType()<accept(functor); + } +} + +void GeometryNew::accept(PrimitiveIndexFunctor& functor) const +{ + const osg::Array* vertices = _vertexData.array.get(); + + if (!vertices && _vertexAttribList.size()>0) + { + OSG_INFO<<"GeometryNew::accept(PrimitiveIndexFunctor& functor): Using vertex attribute instead"<getNumElements()==0) return; + + switch(vertices->getType()) + { + case(Array::Vec2ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec3ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec4ArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec2dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec3dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + case(Array::Vec4dArrayType): + functor.setVertexArray(vertices->getNumElements(),static_cast(vertices->getDataPointer())); + break; + default: + OSG_WARN<<"Warning: GeometryNew::accept(PrimitiveIndexFunctor&) cannot handle Vertex Array type"<getType()<accept(functor); + } +} + +unsigned int _computeNumberOfPrimitives(const osg::GeometryNew& geom) +{ + + unsigned int totalNumberOfPrimitives = 0; + + for(GeometryNew::PrimitiveSetList::const_iterator itr=geom.getPrimitiveSetList().begin(); + itr!=geom.getPrimitiveSetList().end(); + ++itr) + { + const PrimitiveSet* primitiveset = itr->get(); + GLenum mode=primitiveset->getMode(); + + unsigned int primLength; + switch(mode) + { + case(GL_POINTS): primLength=1; OSG_INFO<<"prim=GL_POINTS"<getType()) + { + case(PrimitiveSet::DrawArrayLengthsPrimitiveType): + { + + const DrawArrayLengths* drawArrayLengths = static_cast(primitiveset); + for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); + primItr!=drawArrayLengths->end(); + ++primItr) + { + if (primLength==0) totalNumberOfPrimitives += 1; + else totalNumberOfPrimitives += *primItr/primLength; + } + break; + } + default: + { + if (primLength==0) { totalNumberOfPrimitives += 1; OSG_INFO<<" totalNumberOfPrimitives="<getNumIndices()/primLength; OSG_INFO<<" primitiveset->getNumIndices()="<getNumIndices()<<" totalNumberOfPrimitives="< +bool _verifyBindings(const osg::GeometryNew& geom, const A& arrayData) +{ + unsigned int numElements = arrayData.array.valid()?arrayData.array->getNumElements():0; + + switch(arrayData.binding) + { + case(osg::GeometryNew::BIND_OFF): + if (numElements>0) return false; + break; + case(osg::GeometryNew::BIND_OVERALL): + if (numElements!=1) return false; + break; + case(osg::GeometryNew::BIND_PER_PRIMITIVE_SET): + if (numElements!=geom.getPrimitiveSetList().size()) return false; + break; + case(osg::GeometryNew::BIND_PER_PRIMITIVE): + if (numElements!=_computeNumberOfPrimitives(geom)) return false; + break; + case(osg::GeometryNew::BIND_PER_VERTEX): + { + unsigned int numVertices = geom.getVertexArray()?geom.getVertexArray()->getNumElements():0; + if (numElements!=numVertices) return false; + break; + } + } + return true; +} + +template +void _computeCorrectBindingsAndArraySizes(std::ostream& out, const osg::GeometryNew& geom, A& arrayData, const char* arrayName) +{ + unsigned int numElements = arrayData.array.valid()?arrayData.array->getNumElements():0; + + // check to see if binding matches 0 elements required. + if (numElements==0) + { + // correct binding if not correct. + if (arrayData.binding!=osg::GeometryNew::BIND_OFF) + { + out<<"Warning: in osg::GeometryNew::computeCorrectBindingsAndArraySizes() "<getNumElements():0; + + if ( numVertices==0 ) + { + if (arrayData.binding!=osg::GeometryNew::BIND_OFF) + { + arrayData.array = 0; + arrayData.binding = osg::GeometryNew::BIND_OFF; + out<<"Warning: in osg::GeometryNew::computeCorrectBindingsAndArraySizes() vertex array is empty but "<numVertices) + { + arrayData.binding = osg::GeometryNew::BIND_PER_VERTEX; + return; + } + if (numElements>numPrimitives) + { + arrayData.binding = osg::GeometryNew::BIND_PER_PRIMITIVE; + return; + } + if (numElements>numPrimitiveSets) + { + arrayData.binding = osg::GeometryNew::BIND_PER_PRIMITIVE_SET; + return; + } + if (numElements>=1) + { + arrayData.binding = osg::GeometryNew::BIND_OVERALL; + return; + } + arrayData.binding = osg::GeometryNew::BIND_OFF; + +} + +bool GeometryNew::verifyBindings(const ArrayData& arrayData) const +{ + return _verifyBindings(*this,arrayData); +} + +bool GeometryNew::verifyBindings(const Vec3ArrayData& arrayData) const +{ + return _verifyBindings(*this,arrayData); +} + +void GeometryNew::computeCorrectBindingsAndArraySizes(ArrayData& arrayData, const char* arrayName) +{ + _computeCorrectBindingsAndArraySizes(osg::notify(osg::INFO),*this,arrayData,arrayName); +} + +void GeometryNew::computeCorrectBindingsAndArraySizes(Vec3ArrayData& arrayData, const char* arrayName) +{ + _computeCorrectBindingsAndArraySizes(osg::notify(osg::INFO),*this,arrayData,arrayName); +} + +bool GeometryNew::verifyBindings() const +{ + if (!verifyBindings(_normalData)) return false; + if (!verifyBindings(_colorData)) return false; + if (!verifyBindings(_secondaryColorData)) return false; + if (!verifyBindings(_fogCoordData)) return false; + + for(ArrayDataList::const_iterator titr=_texCoordList.begin(); + titr!=_texCoordList.end(); + ++titr) + { + if (!verifyBindings(*titr)) return false; + } + + for(ArrayDataList::const_iterator vitr=_vertexAttribList.begin(); + vitr!=_vertexAttribList.end(); + ++vitr) + { + if (!verifyBindings(*vitr)) return false; + } + + return true; +} + +void GeometryNew::computeCorrectBindingsAndArraySizes() +{ + // if (verifyBindings()) return; + + computeCorrectBindingsAndArraySizes(_normalData,"_normalData"); + computeCorrectBindingsAndArraySizes(_colorData,"_colorData"); + computeCorrectBindingsAndArraySizes(_secondaryColorData,"_secondaryColorData"); + computeCorrectBindingsAndArraySizes(_fogCoordData,"_fogCoordData"); + + for(ArrayDataList::iterator titr=_texCoordList.begin(); + titr!=_texCoordList.end(); + ++titr) + { + computeCorrectBindingsAndArraySizes(*titr,"_texCoordList[]"); + } + + for(ArrayDataList::iterator vitr=_vertexAttribList.begin(); + vitr!=_vertexAttribList.end(); + ++vitr) + { + computeCorrectBindingsAndArraySizes(*vitr,"_vertAttribList[]"); + } +} + + +bool GeometryNew::containsSharedArrays() const +{ + unsigned int numSharedArrays = 0; + + if (getVertexArray() && getVertexArray()->referenceCount()>1) ++numSharedArrays; + if (getNormalArray() && getNormalArray()->referenceCount()>1) ++numSharedArrays; + if (getColorArray() && getColorArray()->referenceCount()>1) ++numSharedArrays; + if (getSecondaryColorArray() && getSecondaryColorArray()->referenceCount()>1) ++numSharedArrays; + if (getFogCoordArray() && getFogCoordArray()->referenceCount()>1) ++numSharedArrays; + + for(unsigned int ti=0;tireferenceCount()>1) ++numSharedArrays; + } + + for(unsigned int vi=0;vi<_vertexAttribList.size();++vi) + { + const ArrayData& arrayData = _vertexAttribList[vi]; + if (arrayData.array.valid() && arrayData.array->referenceCount()>1) ++numSharedArrays; + } + return numSharedArrays!=0; +} + +void GeometryNew::duplicateSharedArrays() +{ + #define DUPLICATE_IF_REQUIRED(A) \ + if (get##A() && get##A()->referenceCount()>1) \ + { \ + set##A(osg::clone(get##A(), osg::CopyOp::DEEP_COPY_ARRAYS)); \ + } + + DUPLICATE_IF_REQUIRED(VertexArray) + DUPLICATE_IF_REQUIRED(NormalArray) + DUPLICATE_IF_REQUIRED(ColorArray) + DUPLICATE_IF_REQUIRED(SecondaryColorArray) + DUPLICATE_IF_REQUIRED(FogCoordArray) + + for(unsigned int ti=0;tireferenceCount()>1) + { + setTexCoordArray(ti, osg::clone(getTexCoordArray(ti),osg::CopyOp::DEEP_COPY_ARRAYS)); + } + } + + for(unsigned int vi=0;vi<_vertexAttribList.size();++vi) + { + ArrayData& arrayData = _vertexAttribList[vi]; + if (arrayData.array.valid() && arrayData.array->referenceCount()>1) + { + arrayData.array = osg::clone(arrayData.array.get(), osg::CopyOp::DEEP_COPY_ARRAYS); + } + } +} + +class CheckArrayValidity +{ +public: + CheckArrayValidity(const osg::GeometryNew* geometry) + { + numPrimitiveSets = geometry->getNumPrimitiveSets(); + primitiveNum = 0; + maxVertexNumber = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // draw the primitives themselves. + // + for(unsigned int primitiveSetNum=0; primitiveSetNum != numPrimitiveSets; ++primitiveSetNum) + { + const PrimitiveSet* primitiveset = geometry->getPrimitiveSet(primitiveSetNum); + + GLenum mode=primitiveset->getMode(); + + unsigned int primLength; + switch(mode) + { + case(GL_POINTS): primLength=1; break; + case(GL_LINES): primLength=2; break; + case(GL_TRIANGLES): primLength=3; break; + case(GL_QUADS): primLength=4; break; + default: primLength=0; break; // compute later when =0. + } + + // draw primitives by the more flexible "slow" path, + // sending OpenGL glBegin/glVertex.../glEnd(). + switch(primitiveset->getType()) + { + case(PrimitiveSet::DrawArraysPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawArrays* drawArray = static_cast(primitiveset); + + unsigned int primCount=0; + unsigned int indexEnd = drawArray->getFirst()+drawArray->getCount(); + for(unsigned int vindex=drawArray->getFirst(); + vindex maxVertexNumber) maxVertexNumber = (indexEnd-1); + break; + } + case(PrimitiveSet::DrawArrayLengthsPrimitiveType): + { + const DrawArrayLengths* drawArrayLengths = static_cast(primitiveset); + unsigned int vindex=drawArrayLengths->getFirst(); + for(DrawArrayLengths::const_iterator primItr=drawArrayLengths->begin(); + primItr!=drawArrayLengths->end(); + ++primItr) + { + unsigned int localPrimLength; + if (primLength==0) localPrimLength=*primItr; + else localPrimLength=primLength; + + for(GLsizei primCount=0; + primCount<*primItr; + ++vindex,++primCount) + { + if ((primCount%localPrimLength)==0) + { + primitiveNum++; + } + } + + } + if ((vindex-1) > maxVertexNumber) maxVertexNumber = (vindex-1); + break; + } + case(PrimitiveSet::DrawElementsUBytePrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUByte* drawElements = static_cast(primitiveset); + + unsigned int primCount=0; + for(DrawElementsUByte::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + if ((primCount%primLength)==0) + { + primitiveNum++; + } + unsigned int vindex = *primItr; + if (vindex > maxVertexNumber) maxVertexNumber = vindex; + } + + break; + } + case(PrimitiveSet::DrawElementsUShortPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUShort* drawElements = static_cast(primitiveset); + unsigned int primCount=0; + for(DrawElementsUShort::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + if ((primCount%primLength)==0) + { + primitiveNum++; + } + unsigned int vindex = *primItr; + if (vindex > maxVertexNumber) maxVertexNumber = vindex; + } + + break; + } + case(PrimitiveSet::DrawElementsUIntPrimitiveType): + { + if (primLength==0) primLength=primitiveset->getNumIndices(); + + const DrawElementsUInt* drawElements = static_cast(primitiveset); + unsigned int primCount=0; + for(DrawElementsUInt::const_iterator primItr=drawElements->begin(); + primItr!=drawElements->end(); + ++primCount,++primItr) + { + if ((primCount%primLength)==0) + { + primitiveNum++; + } + unsigned int vindex = *primItr; + if (vindex > maxVertexNumber) maxVertexNumber = vindex; + } + break; + } + default: + { + break; + } + } + } + } + + bool validArray(std::ostream& out, const osg::GeometryNew::ArrayData& arrayData, const char* arrayName) + { + unsigned int numRequired = 0; + switch(arrayData.binding) + { + case(osg::GeometryNew::BIND_OFF): numRequired = 0; break; + case(osg::GeometryNew::BIND_OVERALL): numRequired = 1; break; + case(osg::GeometryNew::BIND_PER_PRIMITIVE): numRequired = primitiveNum; break; + case(osg::GeometryNew::BIND_PER_PRIMITIVE_SET): numRequired = numPrimitiveSets; break; + case(osg::GeometryNew::BIND_PER_VERTEX): numRequired = maxVertexNumber+1; break; + } + + { + unsigned int numElements = arrayData.array.valid() ? arrayData.array->getNumElements() : 0; + if (numElementssetVertexArray(coords); + + Vec2Array* tcoords = new Vec2Array(4); + (*tcoords)[0].set(l,t); + (*tcoords)[1].set(l,b); + (*tcoords)[2].set(r,b); + (*tcoords)[3].set(r,t); + geom->setTexCoordArray(0,tcoords); + + osg::Vec4Array* colours = new osg::Vec4Array(1); + (*colours)[0].set(1.0f,1.0f,1.0,1.0f); + geom->setColorArray(colours); + geom->setColorBinding(GeometryNew::BIND_OVERALL); + + osg::Vec3Array* normals = new osg::Vec3Array(1); + (*normals)[0] = widthVec^heightVec; + (*normals)[0].normalize(); + geom->setNormalArray(normals); + geom->setNormalBinding(GeometryNew::BIND_OVERALL); + +#if defined(OSG_GLES1_AVAILABLE) || !defined(OSG_GLES2_AVAILABLE) + DrawElementsUByte* elems = new DrawElementsUByte(PrimitiveSet::TRIANGLES); + elems->push_back(0); + elems->push_back(1); + elems->push_back(2); + + elems->push_back(2); + elems->push_back(3); + elems->push_back(0); + geom->addPrimitiveSet(elems); +#else + geom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS,0,4)); +#endif + + return geom; +}