Files
OpenSceneGraph/src/osg/VertexArrayState.cpp

632 lines
23 KiB
C++

/* -*-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/VertexArrayState>
#include <osg/State>
#include <osg/ContextData>
using namespace osg;
#if 1
#define VAS_NOTICE OSG_INFO
#else
#define VAS_NOTICE OSG_NOTICE
#endif
class VertexArrayStateManager : public GraphicsObjectManager
{
public:
VertexArrayStateManager(unsigned int contextID):
GraphicsObjectManager("VertexArrayStateManager", contextID)
{
}
virtual void flushDeletedGLObjects(double, double& availableTime)
{
// if no time available don't try to flush objects.
if (availableTime<=0.0) return;
VAS_NOTICE<<"VertexArrayStateManager::flushDeletedGLObjects()"<<std::endl;
const osg::Timer& timer = *osg::Timer::instance();
osg::Timer_t start_tick = timer.tick();
double elapsedTime = 0.0;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex_vertexArrayStateList);
// trim from front
VertexArrayStateList::iterator ditr=_vertexArrayStateList.begin();
for(;
ditr!=_vertexArrayStateList.end() && elapsedTime<availableTime;
++ditr)
{
VertexArrayState* vas = ditr->get();
vas->deleteVertexArrayObject();
elapsedTime = timer.delta_s(start_tick,timer.tick());
}
if (ditr!=_vertexArrayStateList.begin()) _vertexArrayStateList.erase(_vertexArrayStateList.begin(),ditr);
}
elapsedTime = timer.delta_s(start_tick,timer.tick());
availableTime -= elapsedTime;
}
virtual void flushAllDeletedGLObjects()
{
VAS_NOTICE<<"VertexArrayStateManager::flushAllDeletedGLObjects()"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex_vertexArrayStateList);
for(VertexArrayStateList::iterator itr = _vertexArrayStateList.begin();
itr != _vertexArrayStateList.end();
++itr)
{
VertexArrayState* vas = itr->get();
vas->deleteVertexArrayObject();
}
_vertexArrayStateList.clear();
}
virtual void deleteAllGLObjects()
{
OSG_INFO<<"VertexArrayStateManager::deleteAllGLObjects() Not currently implementated"<<std::endl;
}
virtual void discardAllGLObjects()
{
VAS_NOTICE<<"VertexArrayStateManager::flushAllDeletedGLObjects()"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex_vertexArrayStateList);
_vertexArrayStateList.clear();
}
void release(VertexArrayState* vas)
{
VAS_NOTICE<<"VertexArrayStateManager::release("<<this<<")"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex_vertexArrayStateList);
_vertexArrayStateList.push_back(vas);
}
protected:
typedef std::list< osg::ref_ptr<VertexArrayState> > VertexArrayStateList;
OpenThreads::Mutex _mutex_vertexArrayStateList;
VertexArrayStateList _vertexArrayStateList;
};
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
///////////////////////////////////////////////////////////////////////////////////
//
// VertexArrayDispatch
//
struct VertexArrayDispatch : public VertexArrayState::ArrayDispatch
{
VertexArrayDispatch() {}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array)
{
VAS_NOTICE<<" VertexArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" VertexArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<")"<<std::endl;
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
VAS_NOTICE<<" VertexArrayDispatch::dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glVertexPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" VertexArrayDispatch::dispatch("<<new_array->getNumElements()<<", vbo"<<vbo<<")"<<std::endl;
glVertexPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
VAS_NOTICE<<" VertexArrayDispatch::disable()"<<std::endl;
glDisableClientState(GL_VERTEX_ARRAY);
}
};
///////////////////////////////////////////////////////////////////////////////////
//
// ColorArrayDispatch
//
struct ColorArrayDispatch : public VertexArrayState::ArrayDispatch
{
ColorArrayDispatch() {}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array)
{
VAS_NOTICE<<" ColorArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" ColorArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<")"<<std::endl;
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
VAS_NOTICE<<" ColorArrayDispatch::dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" ColorArrayDispatch::dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<")"<<std::endl;
glColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
VAS_NOTICE<<" ColorArrayDispatch::disable()"<<std::endl;
glDisableClientState(GL_COLOR_ARRAY);
}
};
///////////////////////////////////////////////////////////////////////////////////
//
// NormalArrayDispatch
//
struct NormalArrayDispatch : public VertexArrayState::ArrayDispatch
{
NormalArrayDispatch() {}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array)
{
VAS_NOTICE<<" NormalArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State&, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" NormalArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<")"<<std::endl;
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
VAS_NOTICE<<" NormalArrayDispatch::dispatch("<<new_array->getNumElements()<<")"<<std::endl;
glNormalPointer(new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" NormalArrayDispatch::dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<")"<<std::endl;
glNormalPointer(new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
VAS_NOTICE<<" NormalArrayDispatch::disable()"<<std::endl;
glDisableClientState(GL_NORMAL_ARRAY);
}
};
///////////////////////////////////////////////////////////////////////////////////
//
// SecondaryColorArrayDispatch
//
struct SecondaryColorArrayDispatch : public VertexArrayState::ArrayDispatch
{
SecondaryColorArrayDispatch() {}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array)
{
glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
state.get<GLExtensions>()->glSecondaryColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
state.get<GLExtensions>()->glSecondaryColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
state.get<GLExtensions>()->glSecondaryColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
state.get<GLExtensions>()->glSecondaryColorPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
}
};
///////////////////////////////////////////////////////////////////////////////////
//
// FogCoordArrayDispatch
//
struct FogCoordArrayDispatch : public VertexArrayState::ArrayDispatch
{
FogCoordArrayDispatch() {}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array)
{
glEnableClientState(GL_FOG_COORD_ARRAY);
state.get<GLExtensions>()->glFogCoordPointer(new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
glEnableClientState(GL_FOG_COORD_ARRAY);
state.get<GLExtensions>()->glFogCoordPointer(new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
state.get<GLExtensions>()->glFogCoordPointer(new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
state.get<GLExtensions>()->glFogCoordPointer(new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
glDisableClientState(GL_FOG_COORD_ARRAY);
}
};
///////////////////////////////////////////////////////////////////////////////////
//
// TexCoordArrayDispatch
//
struct TexCoordArrayDispatch : public VertexArrayState::ArrayDispatch
{
TexCoordArrayDispatch(unsigned int in_unit) : unit(in_unit) {}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array)
{
VAS_NOTICE<<" TexCoordArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<") unit="<<unit<<std::endl;
glClientActiveTexture(static_cast<GLenum>(GL_TEXTURE0+unit));
//state.setClientActiveTextureUnit(unit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" TexCoordArrayDispatch::enable_and_dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<") unit="<<unit<<std::endl;
//glClientActiveTexture(static_cast<GLenum>(GL_TEXTURE0+unit));
state.setClientActiveTextureUnit(unit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
VAS_NOTICE<<" TexCoordArrayDispatch::dispatch("<<new_array->getNumElements()<<") unit="<<unit<<std::endl;
//glClientActiveTexture(static_cast<GLenum>(GL_TEXTURE0+unit));
state.setClientActiveTextureUnit(unit);
glTexCoordPointer(new_array->getDataSize(), new_array->getDataType(), 0, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
VAS_NOTICE<<" TexCoordArrayDispatch::dispatch("<<new_array->getNumElements()<<", vbo="<<vbo<<") unit="<<unit<<std::endl;
//glClientActiveTexture(static_cast<GLenum>(GL_TEXTURE0+unit));
state.setClientActiveTextureUnit(unit);
glTexCoordPointer(new_array->getDataSize(), new_array->getDataType(), 0, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
VAS_NOTICE<<" TexCoordArrayDispatch::disable() unit="<<unit<<std::endl;
//state.glClientActiveTexture(static_cast<GLenum>(GL_TEXTURE0+unit));
state.setClientActiveTextureUnit(unit);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
unsigned int unit;
};
#endif
///////////////////////////////////////////////////////////////////////////////////
//
// VertexAttribArrayDispatch
//
struct VertexAttribArrayDispatch : public VertexArrayState::ArrayDispatch
{
VertexAttribArrayDispatch(unsigned int in_unit) : unit(in_unit) {}
inline void callVertexAttribPointer(GLExtensions* ext, const osg::Array* new_array, const GLvoid * ptr)
{
if (new_array->getDataType()==GL_FLOAT)
ext->glVertexAttribPointer(static_cast<GLuint>(unit), new_array->getDataSize(), new_array->getDataType(), new_array->getNormalize(), 0, ptr);
else if (array->getDataType()==GL_DOUBLE)
ext->glVertexAttribLPointer(static_cast<GLuint>(unit), new_array->getDataSize(), new_array->getDataType(), 0, ptr);
else
ext->glVertexAttribIPointer(static_cast<GLuint>(unit), new_array->getDataSize(), new_array->getDataType(), 0, ptr);
}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array)
{
GLExtensions* ext = state.get<GLExtensions>();
ext->glEnableVertexAttribArray( unit );
callVertexAttribPointer(ext, new_array, new_array->getDataPointer());
}
virtual void enable_and_dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
GLExtensions* ext = state.get<GLExtensions>();
ext->glEnableVertexAttribArray( unit );
callVertexAttribPointer(ext, new_array, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void dispatch(osg::State& state, const osg::Array* new_array)
{
GLExtensions* ext = state.get<GLExtensions>();
callVertexAttribPointer(ext, new_array, new_array->getDataPointer());
}
virtual void dispatch(osg::State& state, const osg::Array* new_array, const osg::GLBufferObject* vbo)
{
GLExtensions* ext = state.get<GLExtensions>();
callVertexAttribPointer(ext, new_array, (const GLvoid *)(vbo->getOffset(new_array->getBufferIndex())));
}
virtual void disable(osg::State& state)
{
GLExtensions* ext = state.get<GLExtensions>();
ext->glDisableVertexAttribArray( unit );
}
unsigned int unit;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// VertexArrayState
//
VertexArrayState::VertexArrayState(osg::State* state):
_state(state),
_vertexArrayObject(0),
_currentVBO(0),
_currentEBO(0),
_requiresSetArrays(true)
{
_ext = _state->get<GLExtensions>();
}
void VertexArrayState::generateVretexArrayObject()
{
_ext->glGenVertexArrays(1, &_vertexArrayObject);
}
void VertexArrayState::deleteVertexArrayObject()
{
if (_vertexArrayObject)
{
VAS_NOTICE<<" VertexArrayState::deleteVertexArrayObject() "<<_vertexArrayObject<<std::endl;
_ext->glDeleteVertexArrays(1, &_vertexArrayObject);
_vertexArrayObject = 0;
}
}
void VertexArrayState::assignVertexArrayDispatcher()
{
OSG_NOTICE<<"VertexArrayState::assignVertexArrayDispatcher() _state->getUseVertexAttributeAliasing()="<<_state->getUseVertexAttributeAliasing()<<std::endl;
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_vertexArray = new VertexArrayDispatch();
}
else
#endif
{
VAS_NOTICE<<"VertexArrayState::assignNormalArrayDispatcher() _state->getVertexAlias()._location="<<_state->getVertexAlias()._location<<std::endl;
_vertexArray = new VertexAttribArrayDispatch(_state->getVertexAlias()._location);
}
}
void VertexArrayState::assignNormalArrayDispatcher()
{
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_normalArray = new NormalArrayDispatch();
}
else
#endif
{
VAS_NOTICE<<"VertexArrayState::assignNormalArrayDispatcher() _state->getNormalAlias()._location="<<_state->getNormalAlias()._location<<std::endl;
_normalArray = new VertexAttribArrayDispatch(_state->getNormalAlias()._location);
}
}
void VertexArrayState::assignColorArrayDispatcher()
{
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_colorArray = new ColorArrayDispatch();
}
else
#endif
{
VAS_NOTICE<<"VertexArrayState::assignColorArrayDispatcher() _state->getColorAlias()._location="<<_state->getColorAlias()._location<<std::endl;
_colorArray = new VertexAttribArrayDispatch(_state->getColorAlias()._location);
}
}
void VertexArrayState::assignSecondaryColorArrayDispatcher()
{
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_secondaryColorArray = new SecondaryColorArrayDispatch();
}
else
#endif
{
_secondaryColorArray = new VertexAttribArrayDispatch(_state->getSecondaryColorAlias()._location);
}
}
void VertexArrayState::assignFogCoordArrayDispatcher()
{
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_fogCoordArray = new FogCoordArrayDispatch();
}
else
#endif
{
_fogCoordArray = new VertexAttribArrayDispatch(_state->getFogCoordAlias()._location);
}
}
void VertexArrayState::assignTexCoordArrayDispatcher(unsigned int numUnits)
{
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
if (!_state->getUseVertexAttributeAliasing())
{
_texCoordArrays.clear();
for(unsigned int i=0; i<numUnits; ++i)
{
_texCoordArrays.push_back( new TexCoordArrayDispatch(i) );
}
}
else
#endif
{
_texCoordArrays.clear();
for(unsigned int i=0; i<numUnits; ++i)
{
VAS_NOTICE<<"VertexArrayState::VertexArrayState::assignTexCoordArrayDispatcher() _state->getTexCoordAliasList()[i]._location="<<_state->getTexCoordAliasList()[i]._location<<std::endl;
_texCoordArrays.push_back( new VertexAttribArrayDispatch(_state->getTexCoordAliasList()[i]._location) );
}
}
}
void VertexArrayState::assignVertexAttribArrayDispatcher(unsigned int numUnits)
{
_vertexAttribArrays.clear();
for(unsigned int i=0; i<numUnits; ++i)
{
_vertexAttribArrays.push_back( new VertexAttribArrayDispatch(i) );
}
}
void VertexArrayState::assignAllDispatchers()
{
unsigned int numUnits = 8;
unsigned int numVertexAttrib = 16;
assignVertexArrayDispatcher();
assignNormalArrayDispatcher();
assignColorArrayDispatcher();
assignSecondaryColorArrayDispatcher();
assignFogCoordArrayDispatcher();
assignTexCoordArrayDispatcher(numUnits);
assignVertexAttribArrayDispatcher(numVertexAttrib);
}
void VertexArrayState::release()
{
VAS_NOTICE<<"VertexArrayState::release() "<<this<<std::endl;
osg::get<VertexArrayStateManager>(_ext->contextID)->release(this);
}
void VertexArrayState::setArray(ArrayDispatch* vad, osg::State& state, const osg::Array* new_array)
{
if (new_array)
{
if (!vad->active)
{
vad->active = true;
_activeDispatchers.push_back(vad);
}
if (vad->array==0)
{
GLBufferObject* vbo = isVertexBufferObjectSupported() ? new_array->getOrCreateGLBufferObject(state.getContextID()) : 0;
if (vbo)
{
bindVertexBufferObject(vbo);
vad->enable_and_dispatch(state, new_array, vbo);
}
else
{
unbindVertexBufferObject();
vad->enable_and_dispatch(state, new_array);
}
}
else if (new_array!=vad->array || new_array->getModifiedCount()!=vad->modifiedCount)
{
GLBufferObject* vbo = isVertexBufferObjectSupported() ? new_array->getOrCreateGLBufferObject(state.getContextID()) : 0;
if (vbo)
{
bindVertexBufferObject(vbo);
vad->dispatch(state, new_array, vbo);
}
else
{
unbindVertexBufferObject();
vad->dispatch(state, new_array);
}
}
vad->array = new_array;
vad->modifiedCount = new_array->getModifiedCount();
}
else if (vad->array)
{
disable(vad, state);
}
}