From 353b18b27b2c6fd762557f7ce73a19dbd1ce5ba7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 28 Jun 2013 13:43:46 +0000 Subject: [PATCH] From Aurelien Albert, Added support for glPrimitiveRestartIndex. "The idea of this new OpenGL feature is : - set RestartIndex = "n" - draw elements strip -> when the index is "n", the strip is "stopped" and restarted It's very usefull for drawing tiles with a single strip and a "restart" at the end of each row. The idea a an OSG StateAttribute is : Usually we use to build geometry from code, because software modelers rarely support it (and 3d file formats doesn't support it) : -RootNode <= "PrimitiveRestartIndex=0" // So now, we know that our restart index is 0 for all drawables under this node | - Drawable 1 : triangles => as usual | - Drawable 2 : triangles strip => as usual | - Drawable 3 : triangles strip + "GL_PRIMITIVE_RESTART" mode = ON => use the restart index | - Drawable 4 : triangles strip + "GL_PRIMITIVE_RESTART" mode = ON => use the restart index | - Drawable 5 : triangles strip => as usual With a StateAttribute, it's easy for the developper to say "0 will be my restart index for all this object" and then activate the mode only on some nodes. The main problem is if you set and restart index value which is not included in the vertex array (for exemple set restart index = 100 but you have only 50 vertex). There is no problem with OpenGL, but some OSG algorithms will try to access the vertex[100] and will segfault. To solve this, I think there is two ways : 1/ add restart index in osg::PrimitiveSet and use this value in all algorithms. It's a lot of work, maybe dangerous, and it concern only a few situations : developpers who use this extension should be aware of advanced OpenGL (and OSG) data management 2/ use a StateAttribute, and choose a "correct" restart index. In my applications, I always use "0" as a restart index and duplicate the first vertex (vertex[0] = vertex[1]). So there is no difference for OpenGL and all OSG algorithms works properly. " --- include/osg/PrimitiveRestartIndex | 93 ++++++++++++ include/osg/StateAttribute | 1 + src/osg/CMakeLists.txt | 2 + src/osg/PrimitiveRestartIndex.cpp | 141 ++++++++++++++++++ .../serializers/osg/PrimitiveRestartIndex.cpp | 34 +++++ 5 files changed, 271 insertions(+) create mode 100644 include/osg/PrimitiveRestartIndex create mode 100644 src/osg/PrimitiveRestartIndex.cpp create mode 100644 src/osgWrappers/serializers/osg/PrimitiveRestartIndex.cpp diff --git a/include/osg/PrimitiveRestartIndex b/include/osg/PrimitiveRestartIndex new file mode 100644 index 000000000..5872311ba --- /dev/null +++ b/include/osg/PrimitiveRestartIndex @@ -0,0 +1,93 @@ +/* -*-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_PRIMITIVERESTARTINDEX +#define OSG_PRIMITIVERESTARTINDEX 1 + +#include + +namespace osg { + +/** + * osg::PrimitiveRestartIndex does nothing if OpenGL 3.1 is not available. +*/ +class OSG_EXPORT PrimitiveRestartIndex : public StateAttribute +{ + public : + + PrimitiveRestartIndex(); + PrimitiveRestartIndex(unsigned int restartIndex); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + PrimitiveRestartIndex(const PrimitiveRestartIndex& primitiveRestartIndex,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + META_StateAttribute(osg, PrimitiveRestartIndex, PRIMITIVERESTARTINDEX) + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + virtual int compare(const StateAttribute& sa) const; + + inline void setRestartIndex(unsigned int restartIndex ) { _restartIndex = restartIndex; } + + inline unsigned int getRestartIndex() const { return _restartIndex; } + + virtual void apply(State& state) const; + + public: + + /** Extensions class which encapsulates the querying of extensions and + * associated function pointers, and provide convenience wrappers to + * check for the extensions or use the associated functions. + */ + class OSG_EXPORT Extensions : public osg::Referenced + { + public: + Extensions(unsigned int contextID); + + Extensions(const Extensions& rhs); + + void lowestCommonDenominator(const Extensions& rhs); + + void setupGLExtensions(unsigned int contextID); + + bool isOpenGL31Supported() const { return _isOpenGL31Supported; } + bool isPrimitiveRestartIndexNVSupported() const { return _isPrimitiveRestartIndexNVSupported; } + + void glPrimitiveRestartIndex( GLuint index ) const; + + protected: + + ~Extensions() {} + + bool _isOpenGL31Supported; + bool _isPrimitiveRestartIndexNVSupported; + + typedef void (GL_APIENTRY * PrimitiveRestartIndex)( GLuint index ); + + PrimitiveRestartIndex _glPrimitiveRestartIndex; + }; + + static Extensions* getExtensions(unsigned int contextID,bool createIfNotInitalized); + + static void setExtensions(unsigned int contextID,Extensions* extensions); + + + protected: + + virtual ~PrimitiveRestartIndex(); + + unsigned int _restartIndex; +}; + +} + +#endif diff --git a/include/osg/StateAttribute b/include/osg/StateAttribute index 977561f4c..7c95997c1 100644 --- a/include/osg/StateAttribute +++ b/include/osg/StateAttribute @@ -165,6 +165,7 @@ class OSG_EXPORT StateAttribute : public Object CLAMPCOLOR, HINT, SAMPLEMASKI, + PRIMITIVERESTARTINDEX, /// osgFX namespace VALIDATOR, diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index 7b991505e..7d180be10 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -128,6 +128,7 @@ SET(TARGET_H ${HEADER_PATH}/Polytope ${HEADER_PATH}/PositionAttitudeTransform ${HEADER_PATH}/PrimitiveSet + ${HEADER_PATH}/PrimitiveRestartIndex ${HEADER_PATH}/Program ${HEADER_PATH}/Projection ${HEADER_PATH}/ProxyNode @@ -315,6 +316,7 @@ SET(TARGET_SRC PolygonStipple.cpp PositionAttitudeTransform.cpp PrimitiveSet.cpp + PrimitiveRestartIndex.cpp Program.cpp Projection.cpp ProxyNode.cpp diff --git a/src/osg/PrimitiveRestartIndex.cpp b/src/osg/PrimitiveRestartIndex.cpp new file mode 100644 index 000000000..6607c40c7 --- /dev/null +++ b/src/osg/PrimitiveRestartIndex.cpp @@ -0,0 +1,141 @@ +/* -*-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; + +PrimitiveRestartIndex::PrimitiveRestartIndex() +{ + _restartIndex = 0; +} + +PrimitiveRestartIndex::PrimitiveRestartIndex(unsigned int restartIndex) +{ + _restartIndex = restartIndex; +} + +PrimitiveRestartIndex::PrimitiveRestartIndex(const PrimitiveRestartIndex& primitiveRestartIndex,const CopyOp& copyop): + StateAttribute(primitiveRestartIndex,copyop) +{ + _restartIndex = primitiveRestartIndex._restartIndex; +} + +PrimitiveRestartIndex::~PrimitiveRestartIndex() +{ +} + +int PrimitiveRestartIndex::compare(const StateAttribute& sa) const +{ + // check the types are equal and then create the rhs variable + // used by the COMPARE_StateAttribute_Parameter macros below. + COMPARE_StateAttribute_Types(PrimitiveRestartIndex,sa) + + COMPARE_StateAttribute_Parameter(_restartIndex) + + return 0; // passed all the above comparison macros, must be equal. +} + +void PrimitiveRestartIndex::apply(State& state) const +{ + // get "per-context" extensions + const unsigned int contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); + + if ( (extensions->isOpenGL31Supported()) || (extensions->isPrimitiveRestartIndexNVSupported()) ) + { + extensions->glPrimitiveRestartIndex( _restartIndex ); + return; + } + + OSG_WARN << "PrimitiveRestartIndex failed as the required graphics capabilities were\n" + " not found (contextID " << contextID << "). OpenGL 3.1 or \n" + " GL_NV_primitive_restart extension is required." << std::endl; +} + + +typedef buffered_value< ref_ptr > BufferedExtensions; +static BufferedExtensions s_extensions; + +PrimitiveRestartIndex::Extensions* PrimitiveRestartIndex::getExtensions(unsigned int contextID,bool createIfNotInitalized) +{ + if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID); + return s_extensions[contextID].get(); +} + +void PrimitiveRestartIndex::setExtensions(unsigned int contextID,Extensions* extensions) +{ + s_extensions[contextID] = extensions; +} + +PrimitiveRestartIndex::Extensions::Extensions(unsigned int contextID) +{ + setupGLExtensions(contextID); +} + +PrimitiveRestartIndex::Extensions::Extensions(const Extensions& rhs): + Referenced() +{ + _isOpenGL31Supported = rhs._isOpenGL31Supported; + _isPrimitiveRestartIndexNVSupported = rhs._isPrimitiveRestartIndexNVSupported; + _glPrimitiveRestartIndex = rhs._glPrimitiveRestartIndex; +} + +void PrimitiveRestartIndex::Extensions::lowestCommonDenominator(const Extensions& rhs) +{ + if (!rhs._isOpenGL31Supported) _isOpenGL31Supported = false; + if (!rhs._isPrimitiveRestartIndexNVSupported) _isPrimitiveRestartIndexNVSupported = false; + if (!rhs._glPrimitiveRestartIndex) _glPrimitiveRestartIndex = NULL; +} + +void PrimitiveRestartIndex::Extensions::setupGLExtensions(unsigned int contextID) +{ + // extension support + _isPrimitiveRestartIndexNVSupported = isGLExtensionSupported(contextID, "GL_NV_primitive_restart"); + _isOpenGL31Supported = getGLVersionNumber() >= 3.1; + _glPrimitiveRestartIndex = NULL; + + // function pointers + if (_isOpenGL31Supported) + setGLExtensionFuncPtr(_glPrimitiveRestartIndex, "glPrimitiveRestartIndex"); + else if (_isPrimitiveRestartIndexNVSupported) + setGLExtensionFuncPtr(_glPrimitiveRestartIndex, "glPrimitiveRestartIndexNV"); + + // protect against buggy drivers (maybe not necessary) + if (!_glPrimitiveRestartIndex) _isPrimitiveRestartIndexNVSupported = false; + + // notify + if( _isOpenGL31Supported ) + { + OSG_INFO << "PrimitiveRestartIndex is going to use OpenGL 3.1 API (contextID " << contextID << ")." << std::endl; + } + else if( _isPrimitiveRestartIndexNVSupported ) + { + OSG_INFO << "PrimitiveRestartIndex is going to use GL_NV_primitive_restart extension (contextID " << contextID << ")." << std::endl; + } + else + { + OSG_INFO << "PrimitiveRestartIndex did not found required graphics capabilities\n" + " (contextID " << contextID << "). OpenGL 3.1 or \n" + " GL_NV_primitive_restart extension is required." << std::endl; + } +} + +void PrimitiveRestartIndex::Extensions::glPrimitiveRestartIndex( GLuint index ) const +{ + _glPrimitiveRestartIndex( index ); +} + diff --git a/src/osgWrappers/serializers/osg/PrimitiveRestartIndex.cpp b/src/osgWrappers/serializers/osg/PrimitiveRestartIndex.cpp new file mode 100644 index 000000000..220cdccc7 --- /dev/null +++ b/src/osgWrappers/serializers/osg/PrimitiveRestartIndex.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +static bool checkRestartIndex( const osg::PrimitiveRestartIndex& ) +{ + return true; +} + +static bool readRestartIndex( osgDB::InputStream& is, osg::PrimitiveRestartIndex& attr ) +{ + if ( is.getFileVersion() > 97 ) + { + unsigned int restartIndex; + is >> restartIndex; + attr.setRestartIndex( restartIndex ); + } + return true; +} + +static bool writeRestartIndex( osgDB::OutputStream& os, const osg::PrimitiveRestartIndex& attr ) +{ + os << attr.getRestartIndex() << std::endl; + return true; +} + +REGISTER_OBJECT_WRAPPER( PrimitiveRestartIndex, + new osg::PrimitiveRestartIndex, + osg::PrimitiveRestartIndex, + "osg::Object osg::StateAttribute osg::PrimitiveRestartIndex" ) +{ + ADD_USER_SERIALIZER( RestartIndex ); +}