/* -*-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 #include #include #include #include #include #include #include #include #include #include #include #include using namespace osg; unsigned int Drawable::s_numberDrawablesReusedLastInLastFrame = 0; unsigned int Drawable::s_numberNewDrawablesInLastFrame = 0; unsigned int Drawable::s_numberDeletedDrawablesInLastFrame = 0; // static cache of deleted display lists which can only // by completely deleted once the appropriate OpenGL context // is set. Used osg::Drawable::deleteDisplayList(..) and flushDeletedDisplayLists(..) below. typedef std::multimap DisplayListMap; typedef osg::buffered_object DeletedDisplayListCache; static OpenThreads::Mutex s_mutex_deletedDisplayListCache; static DeletedDisplayListCache s_deletedDisplayListCache; GLuint Drawable::generateDisplayList(unsigned int contextID, unsigned int sizeHint) { #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE OpenThreads::ScopedLock lock(s_mutex_deletedDisplayListCache); DisplayListMap& dll = s_deletedDisplayListCache[contextID]; if (dll.empty()) { ++s_numberNewDrawablesInLastFrame; return glGenLists( 1 ); } else { DisplayListMap::iterator itr = dll.lower_bound(sizeHint); if (itr!=dll.end()) { // OSG_NOTICE<<"Reusing a display list of size = "<first<<" for requested size = "<second; dll.erase(itr); return globj; } else { // OSG_NOTICE<<"Creating a new display list of size = "< lock(s_mutex_deletedDisplayListCache); // insert the globj into the cache for the appropriate context. s_deletedDisplayListCache[contextID].insert(DisplayListMap::value_type(sizeHint,globj)); } #else OSG_NOTICE<<"Warning: Drawable::deleteDisplayList(..) - not supported."< lock(s_mutex_deletedDisplayListCache); DisplayListMap& dll = s_deletedDisplayListCache[contextID]; for(DisplayListMap::iterator ditr=dll.begin(); ditr!=dll.end(); ++ditr) { glDeleteLists(ditr->second,1); } dll.clear(); #else OSG_NOTICE<<"Warning: Drawable::deleteDisplayList(..) - not supported."< lock(s_mutex_deletedDisplayListCache); DisplayListMap& dll = s_deletedDisplayListCache[contextID]; dll.clear(); } void Drawable::flushDeletedDisplayLists(unsigned int contextID, double& availableTime) { #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // if no time available don't try to flush objects. if (availableTime<=0.0) return; const osg::Timer& timer = *osg::Timer::instance(); osg::Timer_t start_tick = timer.tick(); double elapsedTime = 0.0; unsigned int noDeleted = 0; { OpenThreads::ScopedLock lock(s_mutex_deletedDisplayListCache); DisplayListMap& dll = s_deletedDisplayListCache[contextID]; bool trimFromFront = true; if (trimFromFront) { unsigned int prev_size = dll.size(); DisplayListMap::iterator ditr=dll.begin(); unsigned int maxNumToDelete = (dll.size() > s_minimumNumberOfDisplayListsToRetainInCache) ? dll.size()-s_minimumNumberOfDisplayListsToRetainInCache : 0; for(; ditr!=dll.end() && elapsedTimesecond,1); elapsedTime = timer.delta_s(start_tick,timer.tick()); ++noDeleted; ++Drawable::s_numberDeletedDrawablesInLastFrame; } if (ditr!=dll.begin()) dll.erase(dll.begin(),ditr); if (noDeleted+dll.size() != prev_size) { OSG_WARN<<"Error in delete"< s_minimumNumberOfDisplayListsToRetainInCache) ? dll.size()-s_minimumNumberOfDisplayListsToRetainInCache : 0; for(; ditr!=dll.rend() && elapsedTimesecond,1); elapsedTime = timer.delta_s(start_tick,timer.tick()); ++noDeleted; ++Drawable::s_numberDeletedDrawablesInLastFrame; } if (ditr!=dll.rbegin()) dll.erase(ditr.base(),dll.end()); if (noDeleted+dll.size() != prev_size) { OSG_WARN<<"Error in delete"<getWorldMatrices(haltTraversalAtNode); matrices.insert(matrices.end(), localMatrices.begin(), localMatrices.end()); } return matrices; } void Drawable::computeDataVariance() { if (getDataVariance() != UNSPECIFIED) return; bool dynamic = false; if (getUpdateCallback() || getEventCallback() || getCullCallback()) { dynamic = true; } setDataVariance(dynamic ? DYNAMIC : STATIC); } void Drawable::addParent(osg::Node* node) { OpenThreads::ScopedPointerLock lock(getRefMutex()); _parents.push_back(node); } void Drawable::removeParent(osg::Node* node) { OpenThreads::ScopedPointerLock lock(getRefMutex()); ParentList::iterator pitr = std::find(_parents.begin(),_parents.end(),node); if (pitr!=_parents.end()) _parents.erase(pitr); } void Drawable::setStateSet(osg::StateSet* stateset) { // do nothing if nothing changed. if (_stateset==stateset) return; // track whether we need to account for the need to do a update or event traversal. int delta_update = 0; int delta_event = 0; // remove this node from the current statesets parent list if (_stateset.valid()) { _stateset->removeParent(this); if (_stateset->requiresUpdateTraversal()) --delta_update; if (_stateset->requiresEventTraversal()) --delta_event; } // set the stateset. _stateset = stateset; // add this node to the new stateset to the parent list. if (_stateset.valid()) { _stateset->addParent(this); if (_stateset->requiresUpdateTraversal()) ++delta_update; if (_stateset->requiresEventTraversal()) ++delta_event; } // only inform parents if change occurs and drawable doesn't already have an update callback if (delta_update!=0 && !_updateCallback) { for(ParentList::iterator itr=_parents.begin(); itr!=_parents.end(); ++itr) { (*itr)->setNumChildrenRequiringUpdateTraversal( (*itr)->getNumChildrenRequiringUpdateTraversal()+delta_update ); } } // only inform parents if change occurs and drawable doesn't already have an event callback if (delta_event!=0 && !_eventCallback) { for(ParentList::iterator itr=_parents.begin(); itr!=_parents.end(); ++itr) { (*itr)->setNumChildrenRequiringEventTraversal( (*itr)->getNumChildrenRequiringEventTraversal()+delta_event ); } } } void Drawable::setNumChildrenRequiringUpdateTraversal(unsigned int num) { // if no changes just return. if (_numChildrenRequiringUpdateTraversal==num) return; // note, if _updateCallback is set then the // parents won't be affected by any changes to // _numChildrenRequiringUpdateTraversal so no need to inform them. if (!_updateCallback && !_parents.empty()) { // need to pass on changes to parents. int delta = 0; if (_numChildrenRequiringUpdateTraversal>0) --delta; if (num>0) ++delta; if (delta!=0) { // the number of callbacks has changed, need to pass this // on to parents so they know whether app traversal is // required on this subgraph. for(ParentList::iterator itr =_parents.begin(); itr != _parents.end(); ++itr) { (*itr)->setNumChildrenRequiringUpdateTraversal( (*itr)->getNumChildrenRequiringUpdateTraversal()+delta ); } } } // finally update this objects value. _numChildrenRequiringUpdateTraversal=num; } void Drawable::setNumChildrenRequiringEventTraversal(unsigned int num) { // if no changes just return. if (_numChildrenRequiringEventTraversal==num) return; // note, if _eventCallback is set then the // parents won't be affected by any changes to // _numChildrenRequiringEventTraversal so no need to inform them. if (!_eventCallback && !_parents.empty()) { // need to pass on changes to parents. int delta = 0; if (_numChildrenRequiringEventTraversal>0) --delta; if (num>0) ++delta; if (delta!=0) { // the number of callbacks has changed, need to pass this // on to parents so they know whether app traversal is // required on this subgraph. for(ParentList::iterator itr =_parents.begin(); itr != _parents.end(); ++itr) { (*itr)->setNumChildrenRequiringEventTraversal( (*itr)->getNumChildrenRequiringEventTraversal()+delta ); } } } // finally Event this objects value. _numChildrenRequiringEventTraversal=num; } osg::StateSet* Drawable::getOrCreateStateSet() { if (!_stateset) setStateSet(new StateSet); return _stateset.get(); } void Drawable::dirtyBound() { if (_boundingBoxComputed) { _boundingBoxComputed = false; // dirty parent bounding sphere's to ensure that all are valid. for(ParentList::iterator itr=_parents.begin(); itr!=_parents.end(); ++itr) { (*itr)->dirtyBound(); } } } void Drawable::compileGLObjects(RenderInfo& renderInfo) const { if (!_useDisplayList) return; #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. unsigned int contextID = renderInfo.getContextID(); // get the globj for the current contextID. GLuint& globj = _globjList[contextID]; // call the globj if already set otherwise compile and execute. if( globj != 0 ) { glDeleteLists( globj, 1 ); } globj = generateDisplayList(contextID, getGLObjectSizeHint()); glNewList( globj, GL_COMPILE ); if (_drawCallback.valid()) _drawCallback->drawImplementation(renderInfo,this); else drawImplementation(renderInfo); glEndList(); #else OSG_NOTICE<<"Warning: Drawable::compileGLObjects(RenderInfo&) - not supported."<setThreadSafeRefUnref(threadSafe); if (_updateCallback.valid()) _updateCallback->setThreadSafeRefUnref(threadSafe); if (_eventCallback.valid()) _eventCallback->setThreadSafeRefUnref(threadSafe); if (_cullCallback.valid()) _cullCallback->setThreadSafeRefUnref(threadSafe); if (_drawCallback.valid()) _drawCallback->setThreadSafeRefUnref(threadSafe); if (_userData.valid()) _userData->setThreadSafeRefUnref(threadSafe); } void Drawable::resizeGLObjectBuffers(unsigned int maxSize) { if (_stateset.valid()) _stateset->resizeGLObjectBuffers(maxSize); if (_drawCallback.valid()) _drawCallback->resizeGLObjectBuffers(maxSize); _globjList.resize(maxSize); } void Drawable::releaseGLObjects(State* state) const { if (_stateset.valid()) _stateset->releaseGLObjects(state); if (_drawCallback.valid()) _drawCallback->releaseGLObjects(state); if (!_useDisplayList) return; if (state) { // get the contextID (user defined ID of 0 upwards) for the // current OpenGL context. unsigned int contextID = state->getContextID(); // get the globj for the current contextID. GLuint& globj = _globjList[contextID]; // call the globj if already set otherwise compile and execute. if( globj != 0 ) { Drawable::deleteDisplayList(contextID,globj, getGLObjectSizeHint()); globj = 0; } } else { const_cast(this)->dirtyDisplayList(); } } void Drawable::setSupportsDisplayList(bool flag) { // if value unchanged simply return. if (_supportsDisplayList==flag) return; #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // if previously set to true then need to check about display lists. if (_supportsDisplayList) { if (_useDisplayList) { // used to support display lists and display lists switched // on so now delete them and turn useDisplayList off. dirtyDisplayList(); _useDisplayList = false; } } // set with new value. _supportsDisplayList=flag; #else _supportsDisplayList=false; #endif } void Drawable::setUseDisplayList(bool flag) { // if value unchanged simply return. if (_useDisplayList==flag) return; #ifdef OSG_GL_DISPLAYLISTS_AVAILABLE // if was previously set to true, remove display list. if (_useDisplayList) { dirtyDisplayList(); } if (_supportsDisplayList) { // set with new value. _useDisplayList = flag; } else // does not support display lists. { if (flag) { OSG_WARN<<"Warning: attempt to setUseDisplayList(true) on a drawable with does not support display lists."<requiresUpdateTraversal())) { for(ParentList::iterator itr=_parents.begin(); itr!=_parents.end(); ++itr) { (*itr)->setNumChildrenRequiringUpdateTraversal((*itr)->getNumChildrenRequiringUpdateTraversal()+delta); } } } void Drawable::setEventCallback(EventCallback* ac) { if (_eventCallback==ac) return; int delta = 0; if (_eventCallback.valid()) --delta; if (ac) ++delta; _eventCallback = ac; if (delta!=0 && !(_stateset.valid() && _stateset->requiresEventTraversal())) { for(ParentList::iterator itr=_parents.begin(); itr!=_parents.end(); ++itr) { (*itr)->setNumChildrenRequiringEventTraversal( (*itr)->getNumChildrenRequiringEventTraversal()+delta ); } } } struct ComputeBound : public PrimitiveFunctor { ComputeBound() { _vertices2f = 0; _vertices3f = 0; _vertices4f = 0; _vertices2d = 0; _vertices3d = 0; _vertices4d = 0; } virtual void setVertexArray(unsigned int,const Vec2* vertices) { _vertices2f = vertices; } virtual void setVertexArray(unsigned int,const Vec3* vertices) { _vertices3f = vertices; } virtual void setVertexArray(unsigned int,const Vec4* vertices) { _vertices4f = vertices; } virtual void setVertexArray(unsigned int,const Vec2d* vertices) { _vertices2d = vertices; } virtual void setVertexArray(unsigned int,const Vec3d* vertices) { _vertices3d = vertices; } virtual void setVertexArray(unsigned int,const Vec4d* vertices) { _vertices4d = vertices; } template void _drawArrays(T* vert, T* end) { for(;vert void _drawElements(T* vert, I* indices, I* end) { for(;indices(this); non_const_this->accept(cb); #if 0 OSG_NOTICE<<"computeBound() "< > BufferedExtensions; static BufferedExtensions s_extensions; Drawable::Extensions* Drawable::getExtensions(unsigned int contextID,bool createIfNotInitalized) { if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Drawable::Extensions(contextID); return s_extensions[contextID].get(); } void Drawable::setExtensions(unsigned int contextID,Extensions* extensions) { s_extensions[contextID] = extensions; } Drawable::Extensions::Extensions(unsigned int contextID) { setupGLExtensions(contextID); } Drawable::Extensions::Extensions(const Extensions& rhs): Referenced() { _isVertexProgramSupported = rhs._isVertexProgramSupported; _isSecondaryColorSupported = rhs._isSecondaryColorSupported; _isFogCoordSupported = rhs._isFogCoordSupported; _isMultiTexSupported = rhs._isMultiTexSupported; _isOcclusionQuerySupported = rhs._isOcclusionQuerySupported; _isTimerQuerySupported = rhs._isTimerQuerySupported; _glFogCoordfv = rhs._glFogCoordfv; _glSecondaryColor3ubv = rhs._glSecondaryColor3ubv; _glSecondaryColor3fv = rhs._glSecondaryColor3fv; _glMultiTexCoord1f = rhs._glMultiTexCoord1f; _glMultiTexCoord2fv = rhs._glMultiTexCoord2fv; _glMultiTexCoord3fv = rhs._glMultiTexCoord3fv; _glMultiTexCoord4fv = rhs._glMultiTexCoord4fv; _glVertexAttrib1s = rhs._glVertexAttrib1s; _glVertexAttrib1f = rhs._glVertexAttrib1f; _glVertexAttrib2fv = rhs._glVertexAttrib2fv; _glVertexAttrib3fv = rhs._glVertexAttrib3fv; _glVertexAttrib4fv = rhs._glVertexAttrib4fv; _glVertexAttrib4ubv = rhs._glVertexAttrib4ubv; _glVertexAttrib4Nubv = rhs._glVertexAttrib4Nubv; _glGenBuffers = rhs._glGenBuffers; _glBindBuffer = rhs._glBindBuffer; _glBufferData = rhs._glBufferData; _glBufferSubData = rhs._glBufferSubData; _glDeleteBuffers = rhs._glDeleteBuffers; _glGenOcclusionQueries = rhs._glGenOcclusionQueries; _glDeleteOcclusionQueries = rhs._glDeleteOcclusionQueries; _glIsOcclusionQuery = rhs._glIsOcclusionQuery; _glBeginOcclusionQuery = rhs._glBeginOcclusionQuery; _glEndOcclusionQuery = rhs._glEndOcclusionQuery; _glGetOcclusionQueryiv = rhs._glGetOcclusionQueryiv; _glGetOcclusionQueryuiv = rhs._glGetOcclusionQueryuiv; _gl_gen_queries_arb = rhs._gl_gen_queries_arb; _gl_delete_queries_arb = rhs._gl_delete_queries_arb; _gl_is_query_arb = rhs._gl_is_query_arb; _gl_begin_query_arb = rhs._gl_begin_query_arb; _gl_end_query_arb = rhs._gl_end_query_arb; _gl_get_queryiv_arb = rhs._gl_get_queryiv_arb; _gl_get_query_objectiv_arb = rhs._gl_get_query_objectiv_arb; _gl_get_query_objectuiv_arb = rhs._gl_get_query_objectuiv_arb; _gl_get_query_objectui64v = rhs._gl_get_query_objectui64v; } void Drawable::Extensions::lowestCommonDenominator(const Extensions& rhs) { if (!rhs._isVertexProgramSupported) _isVertexProgramSupported = false; if (!rhs._isSecondaryColorSupported) _isSecondaryColorSupported = false; if (!rhs._isFogCoordSupported) _isFogCoordSupported = false; if (!rhs._isMultiTexSupported) _isMultiTexSupported = false; if (!rhs._isOcclusionQuerySupported) _isOcclusionQuerySupported = false; if (!rhs._isARBOcclusionQuerySupported) _isARBOcclusionQuerySupported = false; if (!rhs._isTimerQuerySupported) _isTimerQuerySupported = false; if (!rhs._glFogCoordfv) _glFogCoordfv = 0; if (!rhs._glSecondaryColor3ubv) _glSecondaryColor3ubv = 0; if (!rhs._glSecondaryColor3fv) _glSecondaryColor3fv = 0; if (!rhs._glMultiTexCoord1f) _glMultiTexCoord1f = 0; if (!rhs._glMultiTexCoord2fv) _glMultiTexCoord2fv = 0; if (!rhs._glMultiTexCoord3fv) _glMultiTexCoord3fv = 0; if (!rhs._glMultiTexCoord4fv) _glMultiTexCoord4fv = 0; if (!rhs._glVertexAttrib1s) _glVertexAttrib1s = 0; if (!rhs._glVertexAttrib1f) _glVertexAttrib1f = 0; if (!rhs._glVertexAttrib2fv) _glVertexAttrib2fv = 0; if (!rhs._glVertexAttrib3fv) _glVertexAttrib3fv = 0; if (!rhs._glVertexAttrib4fv) _glVertexAttrib4fv = 0; if (!rhs._glVertexAttrib4ubv) _glVertexAttrib4ubv = 0; if (!rhs._glVertexAttrib4Nubv) _glVertexAttrib4Nubv = 0; if (!rhs._glGenBuffers) _glGenBuffers = 0; if (!rhs._glBindBuffer) _glBindBuffer = 0; if (!rhs._glBufferData) _glBufferData = 0; if (!rhs._glBufferSubData) _glBufferSubData = 0; if (!rhs._glDeleteBuffers) _glDeleteBuffers = 0; if (!rhs._glIsBuffer) _glIsBuffer = 0; if (!rhs._glGetBufferSubData) _glGetBufferSubData = 0; if (!rhs._glMapBuffer) _glMapBuffer = 0; if (!rhs._glUnmapBuffer) _glUnmapBuffer = 0; if (!rhs._glGetBufferParameteriv) _glGetBufferParameteriv = 0; if (!rhs._glGetBufferPointerv) _glGetBufferPointerv = 0; if (!rhs._glGenOcclusionQueries) _glGenOcclusionQueries = 0; if (!rhs._glDeleteOcclusionQueries) _glDeleteOcclusionQueries = 0; if (!rhs._glIsOcclusionQuery) _glIsOcclusionQuery = 0; if (!rhs._glBeginOcclusionQuery) _glBeginOcclusionQuery = 0; if (!rhs._glEndOcclusionQuery) _glEndOcclusionQuery = 0; if (!rhs._glGetOcclusionQueryiv) _glGetOcclusionQueryiv = 0; if (!rhs._glGetOcclusionQueryuiv) _glGetOcclusionQueryuiv = 0; if (!rhs._gl_gen_queries_arb) _gl_gen_queries_arb = 0; if (!rhs._gl_delete_queries_arb) _gl_delete_queries_arb = 0; if (!rhs._gl_is_query_arb) _gl_is_query_arb = 0; if (!rhs._gl_begin_query_arb) _gl_begin_query_arb = 0; if (!rhs._gl_end_query_arb) _gl_end_query_arb = 0; if (!rhs._gl_get_queryiv_arb) _gl_get_queryiv_arb = 0; if (!rhs._gl_get_query_objectiv_arb) _gl_get_query_objectiv_arb = 0; if (!rhs._gl_get_query_objectuiv_arb) _gl_get_query_objectuiv_arb = 0; if (!rhs._gl_get_query_objectui64v) _gl_get_query_objectui64v = 0; } void Drawable::Extensions::setupGLExtensions(unsigned int contextID) { _isVertexProgramSupported = isGLExtensionSupported(contextID,"GL_ARB_vertex_program"); _isSecondaryColorSupported = isGLExtensionSupported(contextID,"GL_EXT_secondary_color"); _isFogCoordSupported = isGLExtensionSupported(contextID,"GL_EXT_fog_coord"); _isMultiTexSupported = isGLExtensionSupported(contextID,"GL_ARB_multitexture"); _isOcclusionQuerySupported = osg::isGLExtensionSupported(contextID, "GL_NV_occlusion_query" ); _isARBOcclusionQuerySupported = OSG_GL3_FEATURES || osg::isGLExtensionSupported(contextID, "GL_ARB_occlusion_query" ); _isTimerQuerySupported = osg::isGLExtensionSupported(contextID, "GL_EXT_timer_query" );; setGLExtensionFuncPtr(_glFogCoordfv, "glFogCoordfv","glFogCoordfvEXT"); setGLExtensionFuncPtr(_glSecondaryColor3ubv, "glSecondaryColor3ubv","glSecondaryColor3ubvEXT"); setGLExtensionFuncPtr(_glSecondaryColor3fv, "glSecondaryColor3fv","glSecondaryColor3fvEXT"); setGLExtensionFuncPtr(_glMultiTexCoord1f, "glMultiTexCoord1f","glMultiTexCoord1fARB"); setGLExtensionFuncPtr(_glMultiTexCoord1fv, "glMultiTexCoord1fv","glMultiTexCoord1fvARB"); setGLExtensionFuncPtr(_glMultiTexCoord2fv, "glMultiTexCoord2fv","glMultiTexCoord2fvARB"); setGLExtensionFuncPtr(_glMultiTexCoord3fv, "glMultiTexCoord3fv","glMultiTexCoord3fvARB"); setGLExtensionFuncPtr(_glMultiTexCoord4fv, "glMultiTexCoord4fv","glMultiTexCoord4fvARB"); setGLExtensionFuncPtr(_glMultiTexCoord1d, "glMultiTexCoord1d","glMultiTexCoorddfARB"); setGLExtensionFuncPtr(_glMultiTexCoord2dv, "glMultiTexCoord2dv","glMultiTexCoord2dvARB"); setGLExtensionFuncPtr(_glMultiTexCoord3dv, "glMultiTexCoord3dv","glMultiTexCoord3dvARB"); setGLExtensionFuncPtr(_glMultiTexCoord4dv, "glMultiTexCoord4dv","glMultiTexCoord4dvARB"); setGLExtensionFuncPtr(_glVertexAttrib1s, "glVertexAttrib1s","glVertexAttrib1sARB"); setGLExtensionFuncPtr(_glVertexAttrib1f, "glVertexAttrib1f","glVertexAttrib1fARB"); setGLExtensionFuncPtr(_glVertexAttrib1d, "glVertexAttrib1d","glVertexAttrib1dARB"); setGLExtensionFuncPtr(_glVertexAttrib1fv, "glVertexAttrib1fv","glVertexAttrib1fvARB"); setGLExtensionFuncPtr(_glVertexAttrib2fv, "glVertexAttrib2fv","glVertexAttrib2fvARB"); setGLExtensionFuncPtr(_glVertexAttrib3fv, "glVertexAttrib3fv","glVertexAttrib3fvARB"); setGLExtensionFuncPtr(_glVertexAttrib4fv, "glVertexAttrib4fv","glVertexAttrib4fvARB"); setGLExtensionFuncPtr(_glVertexAttrib2dv, "glVertexAttrib2dv","glVertexAttrib2dvARB"); setGLExtensionFuncPtr(_glVertexAttrib3dv, "glVertexAttrib3dv","glVertexAttrib3dvARB"); setGLExtensionFuncPtr(_glVertexAttrib4dv, "glVertexAttrib4dv","glVertexAttrib4dvARB"); setGLExtensionFuncPtr(_glVertexAttrib4ubv, "glVertexAttrib4ubv","glVertexAttrib4ubvARB"); setGLExtensionFuncPtr(_glVertexAttrib4Nubv, "glVertexAttrib4Nubv","glVertexAttrib4NubvARB"); setGLExtensionFuncPtr(_glGenBuffers, "glGenBuffers","glGenBuffersARB"); setGLExtensionFuncPtr(_glBindBuffer, "glBindBuffer","glBindBufferARB"); setGLExtensionFuncPtr(_glBufferData, "glBufferData","glBufferDataARB"); setGLExtensionFuncPtr(_glBufferSubData, "glBufferSubData","glBufferSubDataARB"); setGLExtensionFuncPtr(_glDeleteBuffers, "glDeleteBuffers","glDeleteBuffersARB"); setGLExtensionFuncPtr(_glIsBuffer, "glIsBuffer","glIsBufferARB"); setGLExtensionFuncPtr(_glGetBufferSubData, "glGetBufferSubData","glGetBufferSubDataARB"); setGLExtensionFuncPtr(_glMapBuffer, "glMapBuffer","glMapBufferARB"); setGLExtensionFuncPtr(_glUnmapBuffer, "glUnmapBuffer","glUnmapBufferARB"); setGLExtensionFuncPtr(_glGetBufferParameteriv, "glGetBufferParameteriv","glGetBufferParameterivARB"); setGLExtensionFuncPtr(_glGetBufferPointerv, "glGetBufferPointerv","glGetBufferPointervARB"); setGLExtensionFuncPtr(_glGenOcclusionQueries, "glGenOcclusionQueries","glGenOcclusionQueriesNV"); setGLExtensionFuncPtr(_glDeleteOcclusionQueries, "glDeleteOcclusionQueries","glDeleteOcclusionQueriesNV"); setGLExtensionFuncPtr(_glIsOcclusionQuery, "glIsOcclusionQuery","_glIsOcclusionQueryNV"); setGLExtensionFuncPtr(_glBeginOcclusionQuery, "glBeginOcclusionQuery","glBeginOcclusionQueryNV"); setGLExtensionFuncPtr(_glEndOcclusionQuery, "glEndOcclusionQuery","glEndOcclusionQueryNV"); setGLExtensionFuncPtr(_glGetOcclusionQueryiv, "glGetOcclusionQueryiv","glGetOcclusionQueryivNV"); setGLExtensionFuncPtr(_glGetOcclusionQueryuiv, "glGetOcclusionQueryuiv","glGetOcclusionQueryuivNV"); setGLExtensionFuncPtr(_gl_gen_queries_arb, "glGenQueries", "glGenQueriesARB"); setGLExtensionFuncPtr(_gl_delete_queries_arb, "glDeleteQueries", "glDeleteQueriesARB"); setGLExtensionFuncPtr(_gl_is_query_arb, "glIsQuery", "glIsQueryARB"); setGLExtensionFuncPtr(_gl_begin_query_arb, "glBeginQuery", "glBeginQueryARB"); setGLExtensionFuncPtr(_gl_end_query_arb, "glEndQuery", "glEndQueryARB"); setGLExtensionFuncPtr(_gl_get_queryiv_arb, "glGetQueryiv", "glGetQueryivARB"); setGLExtensionFuncPtr(_gl_get_query_objectiv_arb, "glGetQueryObjectiv","glGetQueryObjectivARB"); setGLExtensionFuncPtr(_gl_get_query_objectuiv_arb, "glGetQueryObjectuiv","glGetQueryObjectuivARB"); setGLExtensionFuncPtr(_gl_get_query_objectui64v, "glGetQueryObjectui64v","glGetQueryObjectui64vEXT"); } void Drawable::Extensions::glFogCoordfv(const GLfloat* coord) const { if (_glFogCoordfv) { _glFogCoordfv(coord); } else { OSG_WARN<<"Error: glFogCoordfv not supported by OpenGL driver"<