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.
"
This commit is contained in:
Robert Osfield 2013-06-28 13:43:46 +00:00
parent b2c838033d
commit 353b18b27b
5 changed files with 271 additions and 0 deletions

View File

@ -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 <osg/StateAttribute>
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

View File

@ -165,6 +165,7 @@ class OSG_EXPORT StateAttribute : public Object
CLAMPCOLOR, CLAMPCOLOR,
HINT, HINT,
SAMPLEMASKI, SAMPLEMASKI,
PRIMITIVERESTARTINDEX,
/// osgFX namespace /// osgFX namespace
VALIDATOR, VALIDATOR,

View File

@ -128,6 +128,7 @@ SET(TARGET_H
${HEADER_PATH}/Polytope ${HEADER_PATH}/Polytope
${HEADER_PATH}/PositionAttitudeTransform ${HEADER_PATH}/PositionAttitudeTransform
${HEADER_PATH}/PrimitiveSet ${HEADER_PATH}/PrimitiveSet
${HEADER_PATH}/PrimitiveRestartIndex
${HEADER_PATH}/Program ${HEADER_PATH}/Program
${HEADER_PATH}/Projection ${HEADER_PATH}/Projection
${HEADER_PATH}/ProxyNode ${HEADER_PATH}/ProxyNode
@ -315,6 +316,7 @@ SET(TARGET_SRC
PolygonStipple.cpp PolygonStipple.cpp
PositionAttitudeTransform.cpp PositionAttitudeTransform.cpp
PrimitiveSet.cpp PrimitiveSet.cpp
PrimitiveRestartIndex.cpp
Program.cpp Program.cpp
Projection.cpp Projection.cpp
ProxyNode.cpp ProxyNode.cpp

View File

@ -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 <osg/PrimitiveRestartIndex>
#include <osg/State>
#include <osg/GLExtensions>
#include <osg/Notify>
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<PrimitiveRestartIndex::Extensions> > 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 );
}

View File

@ -0,0 +1,34 @@
#include <osg/PrimitiveRestartIndex>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>
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 );
}