From caa3a06c70b31075ba17e6f00bb371bdce2bfd8b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 4 Jun 2013 09:32:59 +0000 Subject: [PATCH] Introduced GeometryNew which is a cleaned up version of Geometry that removes support for array indices. GeometryNew is only temporary and will be renamed to Geometry on the completion of refactoring work and feedback from community. Ported osggeometry across to use GeometryNew. --- examples/osggeometry/osggeometry.cpp | 57 +- include/osg/GeometryNew | 401 ++++++ src/osg/CMakeLists.txt | 1 + src/osg/GeometryNew.cpp | 1963 ++++++++++++++++++++++++++ 4 files changed, 2394 insertions(+), 28 deletions(-) create mode 100644 include/osg/GeometryNew create mode 100644 src/osg/GeometryNew.cpp 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; +}