2556 lines
95 KiB
C++
2556 lines
95 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.
|
|
*/
|
|
|
|
#ifndef OSG_STATE
|
|
#define OSG_STATE 1
|
|
|
|
#include <osg/Export>
|
|
#include <osg/StateSet>
|
|
#include <osg/Matrix>
|
|
#include <osg/Uniform>
|
|
#include <osg/BufferObject>
|
|
#include <osg/Observer>
|
|
|
|
#include <osg/ShaderComposer>
|
|
#include <osg/FrameStamp>
|
|
#include <osg/DisplaySettings>
|
|
#include <osg/Polytope>
|
|
#include <osg/Viewport>
|
|
#include <osg/GLBeginEndAdapter>
|
|
#include <osg/ArrayDispatchers>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
|
|
#ifndef GL_FOG_COORDINATE_ARRAY
|
|
#ifdef GL_FOG_COORDINATE_ARRAY_EXT
|
|
#define GL_FOG_COORDINATE_ARRAY GL_FOG_COORDINATE_ARRAY_EXT
|
|
#else
|
|
#define GL_FOG_COORDINATE_ARRAY 0x8457
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef GL_SECONDARY_COLOR_ARRAY
|
|
#ifdef GL_SECONDARY_COLOR_ARRAY_EXT
|
|
#define GL_SECONDARY_COLOR_ARRAY GL_SECONDARY_COLOR_ARRAY_EXT
|
|
#else
|
|
#define GL_SECONDARY_COLOR_ARRAY 0x845E
|
|
#endif
|
|
#endif
|
|
|
|
namespace osg {
|
|
|
|
/** macro for use with osg::StateAttribute::apply methods for detecting and
|
|
* reporting OpenGL error messages.*/
|
|
#define OSG_GL_DEBUG(message) \
|
|
if (state.getFineGrainedErrorDetection()) \
|
|
{ \
|
|
GLenum errorNo = glGetError(); \
|
|
if (errorNo!=GL_NO_ERROR) \
|
|
{ \
|
|
osg::notify(WARN)<<"Warning: detected OpenGL error '"<<gluErrorString(errorNo)<<" "<<message<<endl; \
|
|
}\
|
|
}
|
|
|
|
|
|
// forward declare GraphicsContext, View and State
|
|
class GraphicsContext;
|
|
|
|
class VertexAttribAlias
|
|
{
|
|
public:
|
|
VertexAttribAlias():
|
|
_location(0) {}
|
|
|
|
VertexAttribAlias(const VertexAttribAlias& rhs):
|
|
_location(rhs._location),
|
|
_glName(rhs._glName),
|
|
_osgName(rhs._osgName),
|
|
_declaration(rhs._declaration) {}
|
|
|
|
VertexAttribAlias(GLuint location, const std::string glName, const std::string osgName, const std::string& declaration):
|
|
_location(location),
|
|
_glName(glName),
|
|
_osgName(osgName),
|
|
_declaration(declaration) {}
|
|
|
|
GLuint _location;
|
|
std::string _glName;
|
|
std::string _osgName;
|
|
std::string _declaration;
|
|
};
|
|
|
|
|
|
/** Encapsulates the current applied OpenGL modes, attributes and vertex arrays settings,
|
|
* implements lazy state updating and provides accessors for querying the current state.
|
|
* The venerable Red Book says that "OpenGL is a state machine", and this class
|
|
* represents the OpenGL state in OSG. Furthermore, \c State also has other
|
|
* important features:
|
|
* - It works as a stack of states (see \c pushStateSet() and
|
|
* \c popStateSet()). Manipulating this stack of OpenGL states manually is
|
|
* seldom needed, since OSG does this in the most common situations.
|
|
* - It implements lazy state updating. This means that, if one requests a
|
|
* state change and that particular state is already in the requested state,
|
|
* no OpenGL call will be made. This ensures that the OpenGL pipeline is not
|
|
* stalled by unnecessary state changes.
|
|
* - It allows to query the current OpenGL state without calls to \c glGet*(),
|
|
* which typically stall the graphics pipeline (see, for instance,
|
|
* \c captureCurrentState() and \c getModelViewMatrix()).
|
|
*/
|
|
class OSG_EXPORT State : public Referenced, public Observer
|
|
{
|
|
public :
|
|
|
|
State();
|
|
|
|
|
|
/** Set the graphics context associated with that owns this State object.*/
|
|
void setGraphicsContext(GraphicsContext* context) { _graphicsContext = context; }
|
|
|
|
/** Get the graphics context associated with that owns this State object.*/
|
|
GraphicsContext* getGraphicsContext() { return _graphicsContext; }
|
|
|
|
/** Get the const graphics context associated with that owns this State object.*/
|
|
const GraphicsContext* getGraphicsContext() const { return _graphicsContext; }
|
|
|
|
|
|
/** Set the current OpenGL context uniqueID.
|
|
Note, it is the application developers responsibility to
|
|
set up unique ID for each OpenGL context. This value is
|
|
then used by osg::StateAttribute's and osg::Drawable's to
|
|
help manage OpenGL display list and texture binds appropriate
|
|
for each context, the contextID simply acts as an index in local
|
|
arrays that they maintain for the purpose.
|
|
Typical settings for contextID are 0,1,2,3... up to the maximum
|
|
number of graphics contexts you have set up.
|
|
By default contextID is 0.*/
|
|
inline void setContextID(unsigned int contextID) { _contextID=contextID; }
|
|
|
|
/** Get the current OpenGL context unique ID.*/
|
|
inline unsigned int getContextID() const { return _contextID; }
|
|
|
|
|
|
/** Set the ShaderComposor object that implements shader composition.*/
|
|
void setShaderComposer(ShaderComposer* sc) { _shaderComposer = sc; }
|
|
|
|
/** Get the ShaderComposor object.*/
|
|
ShaderComposer* getShaderComposer() { return _shaderComposer.get(); }
|
|
|
|
/** Get the const ShaderComposor object.*/
|
|
const ShaderComposer* getShaderComposer() const { return _shaderComposer.get(); }
|
|
|
|
|
|
/** Push stateset onto state stack.*/
|
|
void pushStateSet(const StateSet* dstate);
|
|
|
|
/** Pop stateset off state stack.*/
|
|
void popStateSet();
|
|
|
|
/** pop all statesets off state stack, ensuring it is empty ready for the next frame.
|
|
* Note, to return OpenGL to default state, one should do any state.popAllStatSets(); state.apply().*/
|
|
void popAllStateSets();
|
|
|
|
/** Insert stateset onto state stack.*/
|
|
void insertStateSet(unsigned int pos,const StateSet* dstate);
|
|
|
|
/** Pop stateset off state stack.*/
|
|
void removeStateSet(unsigned int pos);
|
|
|
|
/** Get the number of StateSet's on the StateSet stack.*/
|
|
unsigned int getStateSetStackSize() { return static_cast<unsigned int>(_stateStateStack.size()); }
|
|
|
|
/** Pop StateSet's for the StateSet stack till its size equals the specified size.*/
|
|
void popStateSetStackToSize(unsigned int size) { while (_stateStateStack.size()>size) popStateSet(); }
|
|
|
|
typedef std::vector<const StateSet*> StateSetStack;
|
|
|
|
/** Get the StateSet stack.*/
|
|
StateSetStack& getStateSetStack() { return _stateStateStack; }
|
|
|
|
|
|
/** Copy the modes and attributes which capture the current state.*/
|
|
void captureCurrentState(StateSet& stateset) const;
|
|
|
|
/** reset the state object to an empty stack.*/
|
|
void reset();
|
|
|
|
|
|
inline const Viewport* getCurrentViewport() const
|
|
{
|
|
return static_cast<const Viewport*>(getLastAppliedAttribute(osg::StateAttribute::VIEWPORT));
|
|
}
|
|
|
|
|
|
void setInitialViewMatrix(const osg::RefMatrix* matrix);
|
|
|
|
inline const osg::Matrix& getInitialViewMatrix() const { return *_initialViewMatrix; }
|
|
inline const osg::Matrix& getInitialInverseViewMatrix() const { return _initialInverseViewMatrix; }
|
|
|
|
void applyProjectionMatrix(const osg::RefMatrix* matrix);
|
|
|
|
inline const osg::Matrix& getProjectionMatrix() const { return *_projection; }
|
|
|
|
void applyModelViewMatrix(const osg::RefMatrix* matrix);
|
|
void applyModelViewMatrix(const osg::Matrix&);
|
|
|
|
const osg::Matrix& getModelViewMatrix() const { return *_modelView; }
|
|
|
|
void setUseModelViewAndProjectionUniforms(bool flag) { _useModelViewAndProjectionUniforms = flag; }
|
|
bool getUseModelViewAndProjectionUniforms() const { return _useModelViewAndProjectionUniforms; }
|
|
|
|
void updateModelViewAndProjectionMatrixUniforms();
|
|
|
|
void applyModelViewAndProjectionUniformsIfRequired();
|
|
|
|
osg::Uniform* getModelViewMatrixUniform() { return _modelViewMatrixUniform.get(); }
|
|
osg::Uniform* getProjectionMatrixUniform() { return _projectionMatrixUniform.get(); }
|
|
osg::Uniform* getModelViewProjectionMatrixUniform() { return _modelViewProjectionMatrixUniform.get(); }
|
|
osg::Uniform* getNormalMatrixUniform() { return _normalMatrixUniform.get(); }
|
|
|
|
|
|
Polytope getViewFrustum() const;
|
|
|
|
|
|
void setUseVertexAttributeAliasing(bool flag) { _useVertexAttributeAliasing = flag; }
|
|
bool getUseVertexAttributeAliasing() const { return _useVertexAttributeAliasing ; }
|
|
|
|
typedef std::vector<VertexAttribAlias> VertexAttribAliasList;
|
|
|
|
const VertexAttribAlias& getVertexAlias() { return _vertexAlias; }
|
|
const VertexAttribAlias& getNormalAlias() { return _normalAlias; }
|
|
const VertexAttribAlias& getColorAlias() { return _colorAlias; }
|
|
const VertexAttribAlias& getSecondaryColorAlias() { return _secondaryColorAlias; }
|
|
const VertexAttribAlias& getFogCoordAlias() { return _fogCoordAlias; }
|
|
const VertexAttribAliasList& getTexCoordAliasList() { return _texCoordAliasList; }
|
|
|
|
|
|
const Program::AttribBindingList& getAttributeBindingList() { return _attributeBindingList; }
|
|
|
|
bool convertVertexShaderSourceToOsgBuiltIns(std::string& source) const;
|
|
|
|
|
|
/** Apply stateset.*/
|
|
void apply(const StateSet* dstate);
|
|
|
|
/** Updates the OpenGL state so that it matches the \c StateSet at the
|
|
* top of the stack of <tt>StateSet</tt>s maintained internally by a
|
|
* \c State.
|
|
*/
|
|
void apply();
|
|
|
|
|
|
/** Set whether a particular OpenGL mode is valid in the current graphics context.
|
|
* Use to disable OpenGL modes that are not supported by current graphics drivers/context.*/
|
|
inline void setModeValidity(StateAttribute::GLMode mode,bool valid)
|
|
{
|
|
ModeStack& ms = _modeMap[mode];
|
|
ms.valid = valid;
|
|
}
|
|
|
|
/** Get whether a particular OpenGL mode is valid in the current graphics context.
|
|
* Use to disable OpenGL modes that are not supported by current graphics drivers/context.*/
|
|
inline bool getModeValidity(StateAttribute::GLMode mode)
|
|
{
|
|
ModeStack& ms = _modeMap[mode];
|
|
return ms.valid;
|
|
}
|
|
|
|
inline void setGlobalDefaultModeValue(StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
ModeStack& ms = _modeMap[mode];
|
|
ms.global_default_value = enabled;
|
|
}
|
|
|
|
inline bool getGlobalDefaultModeValue(StateAttribute::GLMode mode)
|
|
{
|
|
return _modeMap[mode].global_default_value;
|
|
}
|
|
|
|
|
|
/** Apply an OpenGL mode if required. This is a wrapper around
|
|
* \c glEnable() and \c glDisable(), that just actually calls these
|
|
* functions if the \c enabled flag is different than the current
|
|
* state.
|
|
* @return \c true if the state was actually changed. \c false
|
|
* otherwise. Notice that a \c false return does not indicate
|
|
* an error, it just means that the mode was already set to the
|
|
* same value as the \c enabled parameter.
|
|
*/
|
|
inline bool applyMode(StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
ModeStack& ms = _modeMap[mode];
|
|
ms.changed = true;
|
|
return applyMode(mode,enabled,ms);
|
|
}
|
|
|
|
inline void setGlobalDefaultTextureModeValue(unsigned int unit, StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
ModeMap& modeMap = getOrCreateTextureModeMap(unit);
|
|
ModeStack& ms = modeMap[mode];
|
|
ms.global_default_value = enabled;
|
|
}
|
|
|
|
inline bool getGlobalDefaultTextureModeValue(unsigned int unit, StateAttribute::GLMode mode)
|
|
{
|
|
ModeMap& modeMap = getOrCreateTextureModeMap(unit);
|
|
ModeStack& ms = modeMap[mode];
|
|
return ms.global_default_value;
|
|
}
|
|
|
|
inline bool applyTextureMode(unsigned int unit, StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
ModeMap& modeMap = getOrCreateTextureModeMap(unit);
|
|
ModeStack& ms = modeMap[mode];
|
|
ms.changed = true;
|
|
return applyModeOnTexUnit(unit,mode,enabled,ms);
|
|
}
|
|
|
|
inline void setGlobalDefaultAttribute(const StateAttribute* attribute)
|
|
{
|
|
AttributeStack& as = _attributeMap[attribute->getTypeMemberPair()];
|
|
as.global_default_attribute = attribute;
|
|
}
|
|
|
|
inline const StateAttribute* getGlobalDefaultAttribute(StateAttribute::Type type, unsigned int member=0)
|
|
{
|
|
AttributeStack& as = _attributeMap[StateAttribute::TypeMemberPair(type,member)];
|
|
return as.global_default_attribute.get();
|
|
}
|
|
|
|
/** Apply an attribute if required. */
|
|
inline bool applyAttribute(const StateAttribute* attribute)
|
|
{
|
|
AttributeStack& as = _attributeMap[attribute->getTypeMemberPair()];
|
|
as.changed = true;
|
|
return applyAttribute(attribute,as);
|
|
}
|
|
|
|
inline void setGlobalDefaultTextureAttribute(unsigned int unit, const StateAttribute* attribute)
|
|
{
|
|
AttributeMap& attributeMap = getOrCreateTextureAttributeMap(unit);
|
|
AttributeStack& as = attributeMap[attribute->getTypeMemberPair()];
|
|
as.global_default_attribute = attribute;
|
|
}
|
|
|
|
inline const StateAttribute* getGlobalDefaultTextureAttribute(unsigned int unit, StateAttribute::Type type, unsigned int member = 0)
|
|
{
|
|
AttributeMap& attributeMap = getOrCreateTextureAttributeMap(unit);
|
|
AttributeStack& as = attributeMap[StateAttribute::TypeMemberPair(type,member)];
|
|
return as.global_default_attribute.get();
|
|
}
|
|
|
|
|
|
inline bool applyTextureAttribute(unsigned int unit, const StateAttribute* attribute)
|
|
{
|
|
AttributeMap& attributeMap = getOrCreateTextureAttributeMap(unit);
|
|
AttributeStack& as = attributeMap[attribute->getTypeMemberPair()];
|
|
as.changed = true;
|
|
return applyAttributeOnTexUnit(unit,attribute,as);
|
|
}
|
|
|
|
/** Mode has been set externally, update state to reflect this setting.*/
|
|
void haveAppliedMode(StateAttribute::GLMode mode,StateAttribute::GLModeValue value);
|
|
|
|
/** Mode has been set externally, therefore dirty the associated mode in osg::State
|
|
* so it is applied on next call to osg::State::apply(..)*/
|
|
void haveAppliedMode(StateAttribute::GLMode mode);
|
|
|
|
/** Attribute has been applied externally, update state to reflect this setting.*/
|
|
void haveAppliedAttribute(const StateAttribute* attribute);
|
|
|
|
/** Attribute has been applied externally,
|
|
* and therefore this attribute type has been dirtied
|
|
* and will need to be re-applied on next osg::State.apply(..).
|
|
* note, if you have an osg::StateAttribute which you have applied externally
|
|
* then use the have_applied(attribute) method as this will cause the osg::State to
|
|
* track the current state more accurately and enable lazy state updating such
|
|
* that only changed state will be applied.*/
|
|
void haveAppliedAttribute(StateAttribute::Type type, unsigned int member=0);
|
|
|
|
/** Get whether the current specified mode is enabled (true) or disabled (false).*/
|
|
bool getLastAppliedMode(StateAttribute::GLMode mode) const;
|
|
|
|
/** Get the current specified attribute, return NULL if one has not yet been applied.*/
|
|
const StateAttribute* getLastAppliedAttribute(StateAttribute::Type type, unsigned int member=0) const;
|
|
|
|
/** texture Mode has been set externally, update state to reflect this setting.*/
|
|
void haveAppliedTextureMode(unsigned int unit, StateAttribute::GLMode mode,StateAttribute::GLModeValue value);
|
|
|
|
/** texture Mode has been set externally, therefore dirty the associated mode in osg::State
|
|
* so it is applied on next call to osg::State::apply(..)*/
|
|
void haveAppliedTextureMode(unsigned int unit, StateAttribute::GLMode mode);
|
|
|
|
/** texture Attribute has been applied externally, update state to reflect this setting.*/
|
|
void haveAppliedTextureAttribute(unsigned int unit, const StateAttribute* attribute);
|
|
|
|
/** texture Attribute has been applied externally,
|
|
* and therefore this attribute type has been dirtied
|
|
* and will need to be re-applied on next osg::State.apply(..).
|
|
* note, if you have an osg::StateAttribute which you have applied externally
|
|
* then use the have_applied(attribute) method as this will the osg::State to
|
|
* track the current state more accurately and enable lazy state updating such
|
|
* that only changed state will be applied.*/
|
|
void haveAppliedTextureAttribute(unsigned int unit, StateAttribute::Type type, unsigned int member=0);
|
|
|
|
/** Get whether the current specified texture mode is enabled (true) or disabled (false).*/
|
|
bool getLastAppliedTextureMode(unsigned int unit, StateAttribute::GLMode mode) const;
|
|
|
|
/** Get the current specified texture attribute, return NULL if one has not yet been applied.*/
|
|
const StateAttribute* getLastAppliedTextureAttribute(unsigned int unit, StateAttribute::Type type, unsigned int member=0) const;
|
|
|
|
|
|
/** Dirty the modes previously applied in osg::State.*/
|
|
void dirtyAllModes();
|
|
|
|
/** Dirty the modes attributes previously applied in osg::State.*/
|
|
void dirtyAllAttributes();
|
|
|
|
/** disable the vertex, normal, color, tex coords, secondary color, fog coord and index arrays.*/
|
|
void disableAllVertexArrays();
|
|
|
|
/** dirty the vertex, normal, color, tex coords, secondary color, fog coord and index arrays.*/
|
|
void dirtyAllVertexArrays();
|
|
|
|
|
|
void setCurrentVertexBufferObject(osg::GLBufferObject* vbo) { _currentVBO = vbo; }
|
|
const GLBufferObject* getCurrentVertexBufferObject() { return _currentVBO; }
|
|
inline void bindVertexBufferObject(osg::GLBufferObject* vbo)
|
|
{
|
|
if (vbo == _currentVBO) return;
|
|
if (vbo->isDirty()) vbo->compileBuffer();
|
|
else vbo->bindBuffer();
|
|
_currentVBO = vbo;
|
|
}
|
|
|
|
inline void unbindVertexBufferObject()
|
|
{
|
|
if (!_currentVBO) return;
|
|
_glBindBuffer(GL_ARRAY_BUFFER_ARB,0);
|
|
_currentVBO = 0;
|
|
}
|
|
|
|
void setCurrentElementBufferObject(osg::GLBufferObject* ebo) { _currentEBO = ebo; }
|
|
const GLBufferObject* getCurrentElementBufferObject() { return _currentEBO; }
|
|
|
|
inline void bindElementBufferObject(osg::GLBufferObject* ebo)
|
|
{
|
|
if (ebo == _currentEBO) return;
|
|
if (ebo->isDirty()) ebo->compileBuffer();
|
|
else ebo->bindBuffer();
|
|
_currentEBO = ebo;
|
|
}
|
|
|
|
inline void unbindElementBufferObject()
|
|
{
|
|
if (!_currentEBO) return;
|
|
_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
|
|
_currentEBO = 0;
|
|
}
|
|
|
|
void setCurrentPixelBufferObject(osg::GLBufferObject* pbo) { _currentPBO = pbo; }
|
|
const GLBufferObject* getCurrentPixelBufferObject() { return _currentPBO; }
|
|
|
|
inline void bindPixelBufferObject(osg::GLBufferObject* pbo)
|
|
{
|
|
if (pbo == _currentPBO) return;
|
|
|
|
if (pbo->isDirty()) pbo->compileBuffer();
|
|
else pbo->bindBuffer();
|
|
|
|
_currentPBO = pbo;
|
|
}
|
|
|
|
inline void unbindPixelBufferObject()
|
|
{
|
|
if (!_currentPBO) return;
|
|
|
|
_glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB,0);
|
|
_currentPBO = 0;
|
|
}
|
|
|
|
typedef std::vector<GLushort> Indices;
|
|
Indices _quadIndices[6];
|
|
|
|
void drawQuads(GLint first, GLsizei count, GLsizei primCount=0);
|
|
|
|
inline void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
|
|
{
|
|
if (primcount>=1 && _glDrawArraysInstanced!=0) _glDrawArraysInstanced(mode, first, count, primcount);
|
|
else glDrawArrays(mode, first, count);
|
|
}
|
|
|
|
inline void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount )
|
|
{
|
|
if (primcount>=1 && _glDrawElementsInstanced!=0) _glDrawElementsInstanced(mode, count, type, indices, primcount);
|
|
else glDrawElements(mode, count, type, indices);
|
|
}
|
|
|
|
|
|
inline void Vertex(float x, float y, float z, float w=1.0f)
|
|
{
|
|
#if defined(OSG_GL_VERTEX_FUNCS_AVAILABLE) && !defined(OSG_GLES1_AVAILABLE)
|
|
if (_useVertexAttributeAliasing) _glVertexAttrib4f( _vertexAlias._location, x,y,z,w);
|
|
else glVertex4f(x,y,z,w);
|
|
#else
|
|
_glVertexAttrib4f( _vertexAlias._location, x,y,z,w);
|
|
#endif
|
|
}
|
|
|
|
inline void Color(float r, float g, float b, float a=1.0f)
|
|
{
|
|
#ifdef OSG_GL_VERTEX_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing) _glVertexAttrib4f( _colorAlias._location, r,g,b,a);
|
|
else glColor4f(r,g,b,a);
|
|
#else
|
|
_glVertexAttrib4f( _colorAlias._location, r,g,b,a);
|
|
#endif
|
|
}
|
|
|
|
void Normal(float x, float y, float z)
|
|
{
|
|
#ifdef OSG_GL_VERTEX_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing) _glVertexAttrib4f( _normalAlias._location, x,y,z,0.0);
|
|
else glNormal3f(x,y,z);
|
|
#else
|
|
_glVertexAttrib4f( _normalAlias._location, x,y,z,0.0);
|
|
#endif
|
|
}
|
|
|
|
void TexCoord(float x, float y=0.0f, float z=0.0f, float w=1.0f)
|
|
{
|
|
#if !defined(OSG_GLES1_AVAILABLE)
|
|
#ifdef OSG_GL_VERTEX_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing) _glVertexAttrib4f( _texCoordAliasList[0]._location, x,y,z,w);
|
|
else glTexCoord4f(x,y,z,w);
|
|
#else
|
|
_glVertexAttrib4f( _texCoordAliasList[0]._location, x,y,z,w);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void MultiTexCoord(unsigned int unit, float x, float y=0.0f, float z=0.0f, float w=1.0f)
|
|
{
|
|
#if !defined(OSG_GLES1_AVAILABLE)
|
|
#ifdef OSG_GL_VERTEX_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing) _glVertexAttrib4f( _texCoordAliasList[unit]._location, x,y,z,w);
|
|
else _glMultiTexCoord4f(GL_TEXTURE0+unit,x,y,z,w);
|
|
#else
|
|
_glVertexAttrib4f( _texCoordAliasList[unit]._location, x,y,z,w);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void VerteAttrib(unsigned int location, float x, float y=0.0f, float z=0.0f, float w=0.0f)
|
|
{
|
|
_glVertexAttrib4f( location, x,y,z,w);
|
|
}
|
|
|
|
|
|
/** Mark all the vertex attributes as being disabled but leave the disabling till a later call to applyDisablingOfVertexAttributes.*/
|
|
void lazyDisablingOfVertexAttributes();
|
|
|
|
/** Disable all the vertex attributes that have been marked as to be disabled.*/
|
|
void applyDisablingOfVertexAttributes();
|
|
|
|
/** Wrapper around glInterleavedArrays(..).
|
|
* also resets the internal array points and modes within osg::State to keep the other
|
|
* vertex array operations consistent. */
|
|
void setInterleavedArrays( GLenum format, GLsizei stride, const GLvoid* pointer);
|
|
|
|
/** Set the vertex pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setVertexPointer(const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setVertexPointer(array->getDataSize(),array->getDataType(),0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setVertexPointer(array->getDataSize(),array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_VERTEX_ARRAY);glVertexPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setVertexPointer( GLint size, GLenum type,
|
|
GLsizei stride, const GLvoid *ptr )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
setVertexAttribPointer(_vertexAlias._location, size, type, GL_FALSE, stride, ptr);
|
|
}
|
|
else
|
|
{
|
|
if (!_vertexArray._enabled || _vertexArray._dirty)
|
|
{
|
|
_vertexArray._enabled = true;
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
}
|
|
//if (_vertexArray._pointer!=ptr || _vertexArray._dirty)
|
|
{
|
|
_vertexArray._pointer=ptr;
|
|
glVertexPointer( size, type, stride, ptr );
|
|
}
|
|
_vertexArray._lazy_disable = false;
|
|
_vertexArray._dirty = false;
|
|
}
|
|
#else
|
|
setVertexAttribPointer(_vertexAlias._location, size, type, GL_FALSE, stride, ptr);
|
|
#endif
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_VERTEX_ARRAY).
|
|
* note, only updates values that change.*/
|
|
inline void disableVertexPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_vertexAlias._location);
|
|
}
|
|
else
|
|
{
|
|
if (_vertexArray._enabled || _vertexArray._dirty)
|
|
{
|
|
_vertexArray._lazy_disable = false;
|
|
_vertexArray._enabled = false;
|
|
_vertexArray._dirty = false;
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_vertexAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyVertexPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_vertexAlias._location);
|
|
}
|
|
else
|
|
{
|
|
_vertexArray._pointer = 0;
|
|
_vertexArray._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_vertexAlias._location);
|
|
#endif
|
|
}
|
|
|
|
|
|
/** Set the normal pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setNormalPointer(const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setNormalPointer(array->getDataType(),0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setNormalPointer(array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_NORMAL_ARRAY);glNormalPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setNormalPointer( GLenum type, GLsizei stride,
|
|
const GLvoid *ptr )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
setVertexAttribPointer(_normalAlias._location, 3, type, GL_FALSE, stride, ptr);
|
|
}
|
|
else
|
|
{
|
|
if (!_normalArray._enabled || _normalArray._dirty)
|
|
{
|
|
_normalArray._enabled = true;
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
}
|
|
//if (_normalArray._pointer!=ptr || _normalArray._dirty)
|
|
{
|
|
_normalArray._pointer=ptr;
|
|
glNormalPointer( type, stride, ptr );
|
|
}
|
|
_normalArray._lazy_disable = false;
|
|
_normalArray._dirty = false;
|
|
}
|
|
#else
|
|
setVertexAttribPointer(_normalAlias._location, 3, type, GL_FALSE, stride, ptr);
|
|
#endif
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_NORMAL_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableNormalPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_normalAlias._location);
|
|
}
|
|
else
|
|
{
|
|
if (_normalArray._enabled || _normalArray._dirty)
|
|
{
|
|
_normalArray._lazy_disable = false;
|
|
_normalArray._enabled = false;
|
|
_normalArray._dirty = false;
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_normalAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyNormalPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_normalAlias._location);
|
|
}
|
|
else
|
|
{
|
|
_normalArray._pointer = 0;
|
|
_normalArray._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_normalAlias._location);
|
|
#endif
|
|
}
|
|
|
|
/** Set the color pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setColorPointer(const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setColorPointer(array->getDataSize(),array->getDataType(),0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setColorPointer(array->getDataSize(),array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** wrapper around glEnableClientState(GL_COLOR_ARRAY);glColorPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setColorPointer( GLint size, GLenum type,
|
|
GLsizei stride, const GLvoid *ptr )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
setVertexAttribPointer(_colorAlias._location, size, type, GL_FALSE, stride, ptr);
|
|
}
|
|
else
|
|
{
|
|
if (!_colorArray._enabled || _colorArray._dirty)
|
|
{
|
|
_colorArray._enabled = true;
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
}
|
|
//if (_colorArray._pointer!=ptr || _colorArray._dirty)
|
|
{
|
|
_colorArray._pointer=ptr;
|
|
glColorPointer( size, type, stride, ptr );
|
|
}
|
|
_colorArray._lazy_disable = false;
|
|
_colorArray._dirty = false;
|
|
}
|
|
#else
|
|
setVertexAttribPointer(_colorAlias._location, size, type, GL_FALSE, stride, ptr);
|
|
#endif
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_COLOR_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableColorPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_colorAlias._location);
|
|
}
|
|
else
|
|
{
|
|
if (_colorArray._enabled || _colorArray._dirty)
|
|
{
|
|
_colorArray._lazy_disable = false;
|
|
_colorArray._enabled = false;
|
|
_colorArray._dirty = false;
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_colorAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyColorPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_colorAlias._location);
|
|
}
|
|
else
|
|
{
|
|
_colorArray._pointer = 0;
|
|
_colorArray._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_colorAlias._location);
|
|
#endif
|
|
}
|
|
|
|
|
|
inline bool isSecondaryColorSupported() const { return _isSecondaryColorSupportResolved?_isSecondaryColorSupported:computeSecondaryColorSupported(); }
|
|
|
|
|
|
/** Set the secondary color pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setSecondaryColorPointer(const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setSecondaryColorPointer(array->getDataSize(),array->getDataType(),0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setSecondaryColorPointer(array->getDataSize(),array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_SECONDARY_COLOR_ARRAY);glSecondayColorPointer(..);
|
|
* note, only updates values that change.*/
|
|
void setSecondaryColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
|
|
|
|
/** wrapper around glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableSecondaryColorPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_secondaryColorAlias._location);
|
|
}
|
|
else
|
|
{
|
|
if (_secondaryColorArray._enabled || _secondaryColorArray._dirty)
|
|
{
|
|
_secondaryColorArray._lazy_disable = false;
|
|
_secondaryColorArray._enabled = false;
|
|
_secondaryColorArray._dirty = false;
|
|
if (isSecondaryColorSupported()) glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_secondaryColorAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtySecondaryColorPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_secondaryColorAlias._location);
|
|
}
|
|
else
|
|
{
|
|
_secondaryColorArray._pointer = 0;
|
|
_secondaryColorArray._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_secondaryColorAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline bool isFogCoordSupported() const { return _isFogCoordSupportResolved?_isFogCoordSupported:computeFogCoordSupported(); }
|
|
|
|
|
|
/** Set the fog coord pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setFogCoordPointer(const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setFogCoordPointer(array->getDataType(),0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setFogCoordPointer(array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** wrapper around glEnableClientState(GL_FOG_COORDINATE_ARRAY);glFogCoordPointer(..);
|
|
* note, only updates values that change.*/
|
|
void setFogCoordPointer( GLenum type, GLsizei stride, const GLvoid *ptr );
|
|
|
|
/** wrapper around glDisableClientState(GL_FOG_COORDINATE_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableFogCoordPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_fogCoordAlias._location);
|
|
}
|
|
else
|
|
{
|
|
if (_fogArray._enabled || _fogArray._dirty)
|
|
{
|
|
_fogArray._lazy_disable = false;
|
|
_fogArray._enabled = false;
|
|
_fogArray._dirty = false;
|
|
if (isFogCoordSupported()) glDisableClientState(GL_FOG_COORDINATE_ARRAY);
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_fogCoordAlias._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyFogCoordPointer()
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_fogCoordAlias._location);
|
|
}
|
|
else
|
|
{
|
|
_fogArray._pointer = 0;
|
|
_fogArray._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_fogCoordAlias._location);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/** Set the tex coord pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setTexCoordPointer(unsigned int unit, const Array* array)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setTexCoordPointer(unit, array->getDataSize(),array->getDataType(),0, (const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setTexCoordPointer(unit, array->getDataSize(),array->getDataType(),0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_TEXTURE_COORD_ARRAY);glTexCoordPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setTexCoordPointer( unsigned int unit,
|
|
GLint size, GLenum type,
|
|
GLsizei stride, const GLvoid *ptr )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
setVertexAttribPointer(_texCoordAliasList[unit]._location, size, type, GL_FALSE, stride, ptr);
|
|
}
|
|
else
|
|
{
|
|
if (setClientActiveTextureUnit(unit))
|
|
{
|
|
if ( unit >= _texCoordArrayList.size()) _texCoordArrayList.resize(unit+1);
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
|
|
if (!eap._enabled || eap._dirty)
|
|
{
|
|
eap._enabled = true;
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
//if (eap._pointer!=ptr || eap._dirty)
|
|
{
|
|
glTexCoordPointer( size, type, stride, ptr );
|
|
eap._pointer = ptr;
|
|
}
|
|
eap._lazy_disable = false;
|
|
eap._dirty = false;
|
|
}
|
|
}
|
|
#else
|
|
setVertexAttribPointer(_texCoordAliasList[unit]._location, size, type, GL_FALSE, stride, ptr);
|
|
#endif
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableTexCoordPointer( unsigned int unit )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointer(_texCoordAliasList[unit]._location);
|
|
}
|
|
else
|
|
{
|
|
if (setClientActiveTextureUnit(unit))
|
|
{
|
|
if ( unit >= _texCoordArrayList.size()) _texCoordArrayList.resize(unit+1);
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
|
|
if (eap._enabled || eap._dirty)
|
|
{
|
|
eap._lazy_disable = false;
|
|
eap._enabled = false;
|
|
eap._dirty = false;
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointer(_texCoordAliasList[unit]._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyTexCoordPointer( unsigned int unit )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointer(_texCoordAliasList[unit]._location);
|
|
}
|
|
else
|
|
{
|
|
if ( unit >= _texCoordArrayList.size()) return; // _texCoordArrayList.resize(unit+1);
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointer(_texCoordAliasList[unit]._location);
|
|
#endif
|
|
}
|
|
|
|
|
|
inline void disableTexCoordPointersAboveAndIncluding( unsigned int unit )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
disableVertexAttribPointersAboveAndIncluding(_texCoordAliasList[unit]._location);
|
|
}
|
|
else
|
|
{
|
|
while (unit<_texCoordArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
if (eap._enabled || eap._dirty)
|
|
{
|
|
if (setClientActiveTextureUnit(unit))
|
|
{
|
|
eap._lazy_disable = false;
|
|
eap._enabled = false;
|
|
eap._dirty = false;
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
}
|
|
++unit;
|
|
}
|
|
}
|
|
#else
|
|
disableVertexAttribPointersAboveAndIncluding(_texCoordAliasList[unit]._location);
|
|
#endif
|
|
}
|
|
|
|
inline void dirtyTexCoordPointersAboveAndIncluding( unsigned int unit )
|
|
{
|
|
#ifdef OSG_GL_VERTEX_ARRAY_FUNCS_AVAILABLE
|
|
if (_useVertexAttributeAliasing)
|
|
{
|
|
dirtyVertexAttribPointersAboveAndIncluding(_texCoordAliasList[unit]._location);
|
|
}
|
|
else
|
|
{
|
|
while (unit<_texCoordArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
++unit;
|
|
}
|
|
}
|
|
#else
|
|
dirtyVertexAttribPointersAboveAndIncluding(_texCoordAliasList[unit]._location);
|
|
#endif
|
|
}
|
|
|
|
|
|
/** Set the current texture unit, return true if selected,
|
|
* false if selection failed such as when multi texturing is not supported.
|
|
* note, only updates values that change.*/
|
|
inline bool setActiveTextureUnit( unsigned int unit );
|
|
|
|
/** Get the current texture unit.*/
|
|
unsigned int getActiveTextureUnit() const { return _currentActiveTextureUnit; }
|
|
|
|
/** Set the current tex coord array texture unit, return true if selected,
|
|
* false if selection failed such as when multi texturing is not supported.
|
|
* note, only updates values that change.*/
|
|
bool setClientActiveTextureUnit( unsigned int unit );
|
|
|
|
/** Get the current tex coord array texture unit.*/
|
|
unsigned int getClientActiveTextureUnit() const { return _currentClientActiveTextureUnit; }
|
|
|
|
/** Set the vertex attrib pointer using an osg::Array, and manage any VBO that are required.*/
|
|
inline void setVertexAttribPointer(unsigned int unit, const Array* array, GLboolean normalized)
|
|
{
|
|
if (array)
|
|
{
|
|
GLBufferObject* vbo = array->getOrCreateGLBufferObject(_contextID);
|
|
if (vbo)
|
|
{
|
|
bindVertexBufferObject(vbo);
|
|
setVertexAttribPointer(unit, array->getDataSize(),array->getDataType(),normalized,0,(const GLvoid *)(vbo->getOffset(array->getBufferIndex())));
|
|
}
|
|
else
|
|
{
|
|
unbindVertexBufferObject();
|
|
setVertexAttribPointer(unit, array->getDataSize(),array->getDataType(),normalized,0,array->getDataPointer());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** wrapper around glEnableVertexAttribArrayARB(index);glVertexAttribPointerARB(..);
|
|
* note, only updates values that change.*/
|
|
void setVertexAttribPointer( unsigned int index,
|
|
GLint size, GLenum type, GLboolean normalized,
|
|
GLsizei stride, const GLvoid *ptr );
|
|
|
|
/** wrapper around DisableVertexAttribArrayARB(index);
|
|
* note, only updates values that change.*/
|
|
void disableVertexAttribPointer( unsigned int index );
|
|
|
|
void disableVertexAttribPointersAboveAndIncluding( unsigned int index );
|
|
|
|
inline void dirtyVertexAttribPointer( unsigned int index )
|
|
{
|
|
if (index<_vertexAttribArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _vertexAttribArrayList[index];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
}
|
|
}
|
|
|
|
inline void dirtyVertexAttribPointersAboveAndIncluding( unsigned int index )
|
|
{
|
|
while (index<_vertexAttribArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _vertexAttribArrayList[index];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
++index;
|
|
}
|
|
}
|
|
|
|
bool isVertexBufferObjectSupported() const { return _isVertexBufferObjectSupportResolved?_isVertexBufferObjectSupported:computeVertexBufferObjectSupported(); }
|
|
|
|
|
|
inline void setLastAppliedProgramObject(const Program::PerContextProgram* program)
|
|
{
|
|
if (_lastAppliedProgramObject!=program)
|
|
{
|
|
_lastAppliedProgramObject = program;
|
|
if (program && _appliedProgramObjectSet.count(program)==0)
|
|
{
|
|
_appliedProgramObjectSet.insert(program);
|
|
program->addObserver(this);
|
|
}
|
|
}
|
|
}
|
|
inline const Program::PerContextProgram* getLastAppliedProgramObject() const { return _lastAppliedProgramObject; }
|
|
|
|
inline GLint getUniformLocation( const std::string& name ) const { return _lastAppliedProgramObject ? _lastAppliedProgramObject->getUniformLocation(name) : -1; }
|
|
inline GLint getAttribLocation( const std::string& name ) const { return _lastAppliedProgramObject ? _lastAppliedProgramObject->getAttribLocation(name) : -1; }
|
|
|
|
typedef std::pair<const StateAttribute*,StateAttribute::OverrideValue> AttributePair;
|
|
typedef std::vector<AttributePair> AttributeVec;
|
|
|
|
AttributeVec& getAttributeVec( const osg::StateAttribute* attribute )
|
|
{
|
|
AttributeStack& as = _attributeMap[ attribute->getTypeMemberPair() ];
|
|
return as.attributeVec;
|
|
}
|
|
|
|
/** Set the frame stamp for the current frame.*/
|
|
inline void setFrameStamp(FrameStamp* fs) { _frameStamp = fs; }
|
|
|
|
/** Get the frame stamp for the current frame.*/
|
|
inline FrameStamp* getFrameStamp() { return _frameStamp.get(); }
|
|
|
|
/** Get the const frame stamp for the current frame.*/
|
|
inline const FrameStamp* getFrameStamp() const { return _frameStamp.get(); }
|
|
|
|
|
|
/** Set the DisplaySettings. Note, nothing is applied, the visual settings are just
|
|
* used in the State object to pass the current visual settings to Drawables
|
|
* during rendering. */
|
|
inline void setDisplaySettings(DisplaySettings* vs) { _displaySettings = vs; }
|
|
|
|
/** Get the DisplaySettings */
|
|
inline const DisplaySettings* getDisplaySettings() const { return _displaySettings.get(); }
|
|
|
|
|
|
|
|
/** Set flag for early termination of the draw traversal.*/
|
|
void setAbortRenderingPtr(bool* abortPtr) { _abortRenderingPtr = abortPtr; }
|
|
|
|
/** Get flag for early termination of the draw traversal,
|
|
* if true steps should be taken to complete rendering early.*/
|
|
bool getAbortRendering() const { return _abortRenderingPtr!=0?(*_abortRenderingPtr):false; }
|
|
|
|
|
|
struct DynamicObjectRenderingCompletedCallback : public osg::Referenced
|
|
{
|
|
virtual void completed(osg::State*) = 0;
|
|
};
|
|
|
|
/** Set the callback to be called when the dynamic object count hits 0.*/
|
|
void setDynamicObjectRenderingCompletedCallback(DynamicObjectRenderingCompletedCallback* cb){ _completeDynamicObjectRenderingCallback = cb; }
|
|
|
|
/** Get the callback to be called when the dynamic object count hits 0.*/
|
|
DynamicObjectRenderingCompletedCallback* getDynamicObjectRenderingCompletedCallback() { return _completeDynamicObjectRenderingCallback.get(); }
|
|
|
|
/** Set the number of dynamic objects that will be rendered in this graphics context this frame.*/
|
|
void setDynamicObjectCount(unsigned int count, bool callCallbackOnZero = false)
|
|
{
|
|
if (_dynamicObjectCount != count)
|
|
{
|
|
_dynamicObjectCount = count;
|
|
if (_dynamicObjectCount==0 && callCallbackOnZero && _completeDynamicObjectRenderingCallback.valid())
|
|
{
|
|
_completeDynamicObjectRenderingCallback->completed(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Get the number of dynamic objects that will be rendered in this graphics context this frame.*/
|
|
unsigned int getDynamicObjectCount() const { return _dynamicObjectCount; }
|
|
|
|
/** Decrement the number of dynamic objects left to render this frame, and once the count goes to zero call the
|
|
* DynamicObjectRenderingCompletedCallback to inform of completion.*/
|
|
inline void decrementDynamicObjectCount()
|
|
{
|
|
--_dynamicObjectCount;
|
|
if (_dynamicObjectCount==0 && _completeDynamicObjectRenderingCallback.valid())
|
|
{
|
|
_completeDynamicObjectRenderingCallback->completed(this);
|
|
}
|
|
}
|
|
|
|
void setMaxTexturePoolSize(unsigned int size);
|
|
unsigned int getMaxTexturePoolSize() const { return _maxTexturePoolSize; }
|
|
|
|
void setMaxBufferObjectPoolSize(unsigned int size);
|
|
unsigned int getMaxBufferObjectPoolSize() const { return _maxBufferObjectPoolSize; }
|
|
|
|
|
|
enum CheckForGLErrors
|
|
{
|
|
/** NEVER_CHECK_GL_ERRORS hints that OpenGL need not be checked for, this
|
|
is the fastest option since checking for errors does incurr a small overhead.*/
|
|
NEVER_CHECK_GL_ERRORS,
|
|
/** ONCE_PER_FRAME means that OpenGl errors will be checked for once per
|
|
frame, the overhead is still small, but at least OpenGL errors that are occurring
|
|
will be caught, the reporting isn't fine grained enough for debugging purposes.*/
|
|
ONCE_PER_FRAME,
|
|
/** ONCE_PER_ATTRIBUTE means that OpenGL errors will be checked for after
|
|
every attribute is applied, allow errors to be directly associated with
|
|
particular operations which makes debugging much easier.*/
|
|
ONCE_PER_ATTRIBUTE
|
|
};
|
|
|
|
/** Set whether and how often OpenGL errors should be checked for.*/
|
|
void setCheckForGLErrors(CheckForGLErrors check) { _checkGLErrors = check; }
|
|
|
|
/** Get whether and how often OpenGL errors should be checked for.*/
|
|
CheckForGLErrors getCheckForGLErrors() const { return _checkGLErrors; }
|
|
|
|
bool checkGLErrors(const char* str) const;
|
|
bool checkGLErrors(StateAttribute::GLMode mode) const;
|
|
bool checkGLErrors(const StateAttribute* attribute) const;
|
|
|
|
|
|
/** Initialize extension used by osg:::State.*/
|
|
void initializeExtensionProcs();
|
|
|
|
virtual void objectDeleted(void* object);
|
|
|
|
/** get the GL adapter object used to map OpenGL 1.0 glBegin/glEnd usage to vertex arrays.*/
|
|
inline GLBeginEndAdapter& getGLBeginEndAdapter() { return _glBeginEndAdapter; }
|
|
|
|
/** get the helper class for dispatching osg::Arrays as OpenGL attribute data.*/
|
|
inline ArrayDispatchers& getArrayDispatchers() { return _arrayDispatchers; }
|
|
|
|
protected:
|
|
|
|
virtual ~State();
|
|
|
|
GraphicsContext* _graphicsContext;
|
|
unsigned int _contextID;
|
|
|
|
bool _shaderCompositionEnabled;
|
|
bool _shaderCompositionDirty;
|
|
osg::ref_ptr<ShaderComposer> _shaderComposer;
|
|
osg::Program* _currentShaderCompositionProgram;
|
|
|
|
ref_ptr<FrameStamp> _frameStamp;
|
|
|
|
ref_ptr<const RefMatrix> _identity;
|
|
ref_ptr<const RefMatrix> _initialViewMatrix;
|
|
ref_ptr<const RefMatrix> _projection;
|
|
ref_ptr<const RefMatrix> _modelView;
|
|
ref_ptr<RefMatrix> _modelViewCache;
|
|
|
|
bool _useModelViewAndProjectionUniforms;
|
|
ref_ptr<Uniform> _modelViewMatrixUniform;
|
|
ref_ptr<Uniform> _projectionMatrixUniform;
|
|
ref_ptr<Uniform> _modelViewProjectionMatrixUniform;
|
|
ref_ptr<Uniform> _normalMatrixUniform;
|
|
|
|
Matrix _initialInverseViewMatrix;
|
|
|
|
ref_ptr<DisplaySettings> _displaySettings;
|
|
|
|
bool* _abortRenderingPtr;
|
|
CheckForGLErrors _checkGLErrors;
|
|
|
|
|
|
bool _useVertexAttributeAliasing;
|
|
VertexAttribAlias _vertexAlias;
|
|
VertexAttribAlias _normalAlias;
|
|
VertexAttribAlias _colorAlias;
|
|
VertexAttribAlias _secondaryColorAlias;
|
|
VertexAttribAlias _fogCoordAlias;
|
|
VertexAttribAliasList _texCoordAliasList;
|
|
|
|
Program::AttribBindingList _attributeBindingList;
|
|
|
|
void setUpVertexAttribAlias(VertexAttribAlias& alias, GLuint location, const std::string glName, const std::string osgName, const std::string& declaration);
|
|
|
|
|
|
struct ModeStack
|
|
{
|
|
typedef std::vector<StateAttribute::GLModeValue> ValueVec;
|
|
|
|
ModeStack()
|
|
{
|
|
valid = true;
|
|
changed = false;
|
|
last_applied_value = false;
|
|
global_default_value = false;
|
|
}
|
|
|
|
bool valid;
|
|
bool changed;
|
|
bool last_applied_value;
|
|
bool global_default_value;
|
|
ValueVec valueVec;
|
|
};
|
|
|
|
struct AttributeStack
|
|
{
|
|
AttributeStack()
|
|
{
|
|
changed = false;
|
|
last_applied_attribute = 0L;
|
|
last_applied_shadercomponent = 0L;
|
|
global_default_attribute = 0L;
|
|
|
|
}
|
|
|
|
/** apply an attribute if required, passing in attribute and appropriate attribute stack */
|
|
bool changed;
|
|
const StateAttribute* last_applied_attribute;
|
|
const ShaderComponent* last_applied_shadercomponent;
|
|
ref_ptr<const StateAttribute> global_default_attribute;
|
|
AttributeVec attributeVec;
|
|
};
|
|
|
|
|
|
struct UniformStack
|
|
{
|
|
typedef std::pair<const Uniform*,StateAttribute::OverrideValue> UniformPair;
|
|
typedef std::vector<UniformPair> UniformVec;
|
|
|
|
UniformStack() {}
|
|
|
|
UniformVec uniformVec;
|
|
};
|
|
|
|
|
|
/** Apply an OpenGL mode if required, passing in mode, enable flag and
|
|
* appropriate mode stack. This is a wrapper around \c glEnable() and
|
|
* \c glDisable(), that just actually calls these functions if the
|
|
* \c enabled flag is different than the current state.
|
|
* @return \c true if the state was actually changed. \c false
|
|
* otherwise. Notice that a \c false return does not indicate
|
|
* an error, it just means that the mode was already set to the
|
|
* same value as the \c enabled parameter.
|
|
*/
|
|
inline bool applyMode(StateAttribute::GLMode mode,bool enabled,ModeStack& ms)
|
|
{
|
|
if (ms.valid && ms.last_applied_value != enabled)
|
|
{
|
|
ms.last_applied_value = enabled;
|
|
|
|
if (enabled) glEnable(mode);
|
|
else glDisable(mode);
|
|
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(mode);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool applyModeOnTexUnit(unsigned int unit,StateAttribute::GLMode mode,bool enabled,ModeStack& ms)
|
|
{
|
|
if (ms.valid && ms.last_applied_value != enabled)
|
|
{
|
|
if (setActiveTextureUnit(unit))
|
|
{
|
|
ms.last_applied_value = enabled;
|
|
|
|
if (enabled) glEnable(mode);
|
|
else glDisable(mode);
|
|
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(mode);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/** apply an attribute if required, passing in attribute and appropriate attribute stack */
|
|
inline bool applyAttribute(const StateAttribute* attribute,AttributeStack& as)
|
|
{
|
|
if (as.last_applied_attribute != attribute)
|
|
{
|
|
if (!as.global_default_attribute.valid()) as.global_default_attribute = dynamic_cast<StateAttribute*>(attribute->cloneType());
|
|
|
|
as.last_applied_attribute = attribute;
|
|
attribute->apply(*this);
|
|
|
|
const ShaderComponent* sc = attribute->getShaderComponent();
|
|
if (as.last_applied_shadercomponent != sc)
|
|
{
|
|
as.last_applied_shadercomponent = sc;
|
|
_shaderCompositionDirty = true;
|
|
}
|
|
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(attribute);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool applyAttributeOnTexUnit(unsigned int unit,const StateAttribute* attribute,AttributeStack& as)
|
|
{
|
|
if (as.last_applied_attribute != attribute)
|
|
{
|
|
if (setActiveTextureUnit(unit))
|
|
{
|
|
if (!as.global_default_attribute.valid()) as.global_default_attribute = dynamic_cast<StateAttribute*>(attribute->cloneType());
|
|
|
|
as.last_applied_attribute = attribute;
|
|
attribute->apply(*this);
|
|
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(attribute);
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
inline bool applyGlobalDefaultAttribute(AttributeStack& as)
|
|
{
|
|
if (as.last_applied_attribute != as.global_default_attribute.get())
|
|
{
|
|
as.last_applied_attribute = as.global_default_attribute.get();
|
|
if (as.global_default_attribute.valid())
|
|
{
|
|
as.global_default_attribute->apply(*this);
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(as.global_default_attribute.get());
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool applyGlobalDefaultAttributeOnTexUnit(unsigned int unit,AttributeStack& as)
|
|
{
|
|
if (as.last_applied_attribute != as.global_default_attribute.get())
|
|
{
|
|
if (setActiveTextureUnit(unit))
|
|
{
|
|
as.last_applied_attribute = as.global_default_attribute.get();
|
|
if (as.global_default_attribute.valid())
|
|
{
|
|
as.global_default_attribute->apply(*this);
|
|
if (_checkGLErrors==ONCE_PER_ATTRIBUTE) checkGLErrors(as.global_default_attribute.get());
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
typedef std::map<StateAttribute::GLMode,ModeStack> ModeMap;
|
|
typedef std::vector<ModeMap> TextureModeMapList;
|
|
|
|
typedef std::map<StateAttribute::TypeMemberPair,AttributeStack> AttributeMap;
|
|
typedef std::vector<AttributeMap> TextureAttributeMapList;
|
|
|
|
typedef std::map<std::string,UniformStack> UniformMap;
|
|
|
|
typedef std::vector<ref_ptr<const Matrix> > MatrixStack;
|
|
|
|
typedef std::set<const Program::PerContextProgram* > AppliedProgramObjectSet;
|
|
|
|
ModeMap _modeMap;
|
|
AttributeMap _attributeMap;
|
|
UniformMap _uniformMap;
|
|
|
|
TextureModeMapList _textureModeMapList;
|
|
TextureAttributeMapList _textureAttributeMapList;
|
|
|
|
AppliedProgramObjectSet _appliedProgramObjectSet;
|
|
const Program::PerContextProgram* _lastAppliedProgramObject;
|
|
|
|
StateSetStack _stateStateStack;
|
|
|
|
unsigned int _maxTexturePoolSize;
|
|
unsigned int _maxBufferObjectPoolSize;
|
|
|
|
|
|
struct EnabledArrayPair
|
|
{
|
|
EnabledArrayPair():_lazy_disable(false),_dirty(true),_enabled(false),_normalized(0),_pointer(0) {}
|
|
EnabledArrayPair(const EnabledArrayPair& eap):_lazy_disable(eap._lazy_disable),_dirty(eap._dirty), _enabled(eap._enabled),_normalized(eap._normalized),_pointer(eap._pointer) {}
|
|
EnabledArrayPair& operator = (const EnabledArrayPair& eap) { _lazy_disable = eap._lazy_disable;_dirty=eap._dirty; _enabled=eap._enabled; _normalized=eap._normalized;_pointer=eap._pointer; return *this; }
|
|
|
|
bool _lazy_disable;
|
|
bool _dirty;
|
|
bool _enabled;
|
|
GLboolean _normalized;
|
|
const GLvoid* _pointer;
|
|
};
|
|
|
|
typedef std::vector<EnabledArrayPair> EnabledTexCoordArrayList;
|
|
typedef std::vector<EnabledArrayPair> EnabledVertexAttribArrayList;
|
|
|
|
EnabledArrayPair _vertexArray;
|
|
EnabledArrayPair _normalArray;
|
|
EnabledArrayPair _colorArray;
|
|
EnabledArrayPair _secondaryColorArray;
|
|
EnabledArrayPair _fogArray;
|
|
EnabledTexCoordArrayList _texCoordArrayList;
|
|
EnabledVertexAttribArrayList _vertexAttribArrayList;
|
|
|
|
unsigned int _currentActiveTextureUnit;
|
|
unsigned int _currentClientActiveTextureUnit;
|
|
GLBufferObject* _currentVBO;
|
|
GLBufferObject* _currentEBO;
|
|
GLBufferObject* _currentPBO;
|
|
|
|
|
|
inline ModeMap& getOrCreateTextureModeMap(unsigned int unit)
|
|
{
|
|
if (unit>=_textureModeMapList.size()) _textureModeMapList.resize(unit+1);
|
|
return _textureModeMapList[unit];
|
|
}
|
|
|
|
|
|
inline AttributeMap& getOrCreateTextureAttributeMap(unsigned int unit)
|
|
{
|
|
if (unit>=_textureAttributeMapList.size()) _textureAttributeMapList.resize(unit+1);
|
|
return _textureAttributeMapList[unit];
|
|
}
|
|
|
|
inline void pushModeList(ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void pushAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
inline void pushUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList);
|
|
|
|
inline void popModeList(ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void popAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
inline void popUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList);
|
|
|
|
inline void applyModeList(ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void applyAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
inline void applyUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList);
|
|
|
|
inline void applyModeMap(ModeMap& modeMap);
|
|
inline void applyAttributeMap(AttributeMap& attributeMap);
|
|
inline void applyUniformMap(UniformMap& uniformMap);
|
|
|
|
inline void applyModeListOnTexUnit(unsigned int unit,ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void applyAttributeListOnTexUnit(unsigned int unit,AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
|
|
inline void applyModeMapOnTexUnit(unsigned int unit,ModeMap& modeMap);
|
|
inline void applyAttributeMapOnTexUnit(unsigned int unit,AttributeMap& attributeMap);
|
|
|
|
void haveAppliedMode(ModeMap& modeMap,StateAttribute::GLMode mode,StateAttribute::GLModeValue value);
|
|
void haveAppliedMode(ModeMap& modeMap,StateAttribute::GLMode mode);
|
|
void haveAppliedAttribute(AttributeMap& attributeMap,const StateAttribute* attribute);
|
|
void haveAppliedAttribute(AttributeMap& attributeMap,StateAttribute::Type type, unsigned int member);
|
|
bool getLastAppliedMode(const ModeMap& modeMap,StateAttribute::GLMode mode) const;
|
|
const StateAttribute* getLastAppliedAttribute(const AttributeMap& attributeMap,StateAttribute::Type type, unsigned int member) const;
|
|
|
|
void loadModelViewMatrix();
|
|
|
|
|
|
mutable bool _isSecondaryColorSupportResolved;
|
|
mutable bool _isSecondaryColorSupported;
|
|
bool computeSecondaryColorSupported() const;
|
|
|
|
mutable bool _isFogCoordSupportResolved;
|
|
mutable bool _isFogCoordSupported;
|
|
bool computeFogCoordSupported() const;
|
|
|
|
mutable bool _isVertexBufferObjectSupportResolved;
|
|
mutable bool _isVertexBufferObjectSupported;
|
|
bool computeVertexBufferObjectSupported() const;
|
|
|
|
typedef void (GL_APIENTRY * ActiveTextureProc) (GLenum texture);
|
|
typedef void (GL_APIENTRY * FogCoordPointerProc) (GLenum type, GLsizei stride, const GLvoid *pointer);
|
|
typedef void (GL_APIENTRY * SecondaryColorPointerProc) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
|
|
typedef void (GL_APIENTRY * MultiTexCoord4fProc) (GLenum target, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
|
typedef void (GL_APIENTRY * VertexAttrib4fProc)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
|
|
typedef void (GL_APIENTRY * VertexAttrib4fvProc)(GLuint index, const GLfloat *v);
|
|
typedef void (GL_APIENTRY * VertexAttribPointerProc) (unsigned int, GLint, GLenum, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
|
|
typedef void (GL_APIENTRY * EnableVertexAttribProc) (unsigned int);
|
|
typedef void (GL_APIENTRY * DisableVertexAttribProc) (unsigned int);
|
|
typedef void (GL_APIENTRY * BindBufferProc) (GLenum target, GLuint buffer);
|
|
|
|
typedef void (GL_APIENTRY * DrawArraysInstancedProc)( GLenum mode, GLint first, GLsizei count, GLsizei primcount );
|
|
typedef void (GL_APIENTRY * DrawElementsInstancedProc)( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount );
|
|
|
|
bool _extensionProcsInitialized;
|
|
GLint _glMaxTextureCoords;
|
|
GLint _glMaxTextureUnits;
|
|
ActiveTextureProc _glClientActiveTexture;
|
|
ActiveTextureProc _glActiveTexture;
|
|
MultiTexCoord4fProc _glMultiTexCoord4f;
|
|
VertexAttrib4fProc _glVertexAttrib4f;
|
|
VertexAttrib4fvProc _glVertexAttrib4fv;
|
|
FogCoordPointerProc _glFogCoordPointer;
|
|
SecondaryColorPointerProc _glSecondaryColorPointer;
|
|
VertexAttribPointerProc _glVertexAttribPointer;
|
|
EnableVertexAttribProc _glEnableVertexAttribArray;
|
|
DisableVertexAttribProc _glDisableVertexAttribArray;
|
|
BindBufferProc _glBindBuffer;
|
|
DrawArraysInstancedProc _glDrawArraysInstanced;
|
|
DrawElementsInstancedProc _glDrawElementsInstanced;
|
|
|
|
unsigned int _dynamicObjectCount;
|
|
osg::ref_ptr<DynamicObjectRenderingCompletedCallback> _completeDynamicObjectRenderingCallback;
|
|
|
|
GLBeginEndAdapter _glBeginEndAdapter;
|
|
ArrayDispatchers _arrayDispatchers;
|
|
|
|
};
|
|
|
|
inline void State::pushModeList(ModeMap& modeMap,const StateSet::ModeList& modeList)
|
|
{
|
|
for(StateSet::ModeList::const_iterator mitr=modeList.begin();
|
|
mitr!=modeList.end();
|
|
++mitr)
|
|
{
|
|
// get the mode stack for incoming GLmode {mitr->first}.
|
|
ModeStack& ms = modeMap[mitr->first];
|
|
if (ms.valueVec.empty())
|
|
{
|
|
// first pair so simply push incoming pair to back.
|
|
ms.valueVec.push_back(mitr->second);
|
|
}
|
|
else if ((ms.valueVec.back() & StateAttribute::OVERRIDE) && !(mitr->second & StateAttribute::PROTECTED)) // check the existing override flag
|
|
{
|
|
// push existing back since override keeps the previous value.
|
|
ms.valueVec.push_back(ms.valueVec.back());
|
|
}
|
|
else
|
|
{
|
|
// no override on so simply push incoming pair to back.
|
|
ms.valueVec.push_back(mitr->second);
|
|
}
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
inline void State::pushAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList)
|
|
{
|
|
for(StateSet::AttributeList::const_iterator aitr=attributeList.begin();
|
|
aitr!=attributeList.end();
|
|
++aitr)
|
|
{
|
|
// get the attribute stack for incoming type {aitr->first}.
|
|
AttributeStack& as = attributeMap[aitr->first];
|
|
if (as.attributeVec.empty())
|
|
{
|
|
// first pair so simply push incoming pair to back.
|
|
as.attributeVec.push_back(
|
|
AttributePair(aitr->second.first.get(),aitr->second.second));
|
|
}
|
|
else if ((as.attributeVec.back().second & StateAttribute::OVERRIDE) && !(aitr->second.second & StateAttribute::PROTECTED)) // check the existing override flag
|
|
{
|
|
// push existing back since override keeps the previous value.
|
|
as.attributeVec.push_back(as.attributeVec.back());
|
|
}
|
|
else
|
|
{
|
|
// no override on so simply push incoming pair to back.
|
|
as.attributeVec.push_back(
|
|
AttributePair(aitr->second.first.get(),aitr->second.second));
|
|
}
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
|
|
inline void State::pushUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList)
|
|
{
|
|
for(StateSet::UniformList::const_iterator aitr=uniformList.begin();
|
|
aitr!=uniformList.end();
|
|
++aitr)
|
|
{
|
|
// get the attribute stack for incoming type {aitr->first}.
|
|
UniformStack& us = uniformMap[aitr->first];
|
|
if (us.uniformVec.empty())
|
|
{
|
|
// first pair so simply push incoming pair to back.
|
|
us.uniformVec.push_back(
|
|
UniformStack::UniformPair(aitr->second.first.get(),aitr->second.second));
|
|
}
|
|
else if ((us.uniformVec.back().second & StateAttribute::OVERRIDE) && !(aitr->second.second & StateAttribute::PROTECTED)) // check the existing override flag
|
|
{
|
|
// push existing back since override keeps the previous value.
|
|
us.uniformVec.push_back(us.uniformVec.back());
|
|
}
|
|
else
|
|
{
|
|
// no override on so simply push incoming pair to back.
|
|
us.uniformVec.push_back(
|
|
UniformStack::UniformPair(aitr->second.first.get(),aitr->second.second));
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::popModeList(ModeMap& modeMap,const StateSet::ModeList& modeList)
|
|
{
|
|
for(StateSet::ModeList::const_iterator mitr=modeList.begin();
|
|
mitr!=modeList.end();
|
|
++mitr)
|
|
{
|
|
// get the mode stack for incoming GLmode {mitr->first}.
|
|
ModeStack& ms = modeMap[mitr->first];
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
ms.valueVec.pop_back();
|
|
}
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
inline void State::popAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList)
|
|
{
|
|
for(StateSet::AttributeList::const_iterator aitr=attributeList.begin();
|
|
aitr!=attributeList.end();
|
|
++aitr)
|
|
{
|
|
// get the attribute stack for incoming type {aitr->first}.
|
|
AttributeStack& as = attributeMap[aitr->first];
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
as.attributeVec.pop_back();
|
|
}
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
inline void State::popUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList)
|
|
{
|
|
for(StateSet::UniformList::const_iterator aitr=uniformList.begin();
|
|
aitr!=uniformList.end();
|
|
++aitr)
|
|
{
|
|
// get the attribute stack for incoming type {aitr->first}.
|
|
UniformStack& us = uniformMap[aitr->first];
|
|
if (!us.uniformVec.empty())
|
|
{
|
|
us.uniformVec.pop_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::applyModeList(ModeMap& modeMap,const StateSet::ModeList& modeList)
|
|
{
|
|
StateSet::ModeList::const_iterator ds_mitr = modeList.begin();
|
|
ModeMap::iterator this_mitr=modeMap.begin();
|
|
|
|
while (this_mitr!=modeMap.end() && ds_mitr!=modeList.end())
|
|
{
|
|
if (this_mitr->first<ds_mitr->first)
|
|
{
|
|
|
|
// note GLMode = this_mitr->first
|
|
ModeStack& ms = this_mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyMode(this_mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyMode(this_mitr->first,ms.global_default_value,ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++this_mitr;
|
|
|
|
}
|
|
else if (ds_mitr->first<this_mitr->first)
|
|
{
|
|
|
|
// ds_mitr->first is a new mode, therefore
|
|
// need to insert a new mode entry for ds_mistr->first.
|
|
ModeStack& ms = modeMap[ds_mitr->first];
|
|
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
applyMode(ds_mitr->first,new_value,ms);
|
|
|
|
// will need to disable this mode on next apply so set it to changed.
|
|
ms.changed = true;
|
|
|
|
++ds_mitr;
|
|
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same mode, check the override
|
|
// if any otherwise just apply the incoming mode.
|
|
|
|
ModeStack& ms = this_mitr->second;
|
|
|
|
if (!ms.valueVec.empty() && (ms.valueVec.back() & StateAttribute::OVERRIDE) && !(ds_mitr->second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, just treat as a normal apply on modes.
|
|
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyMode(this_mitr->first,new_value,ms);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no override on or no previous entry, therefore consider incoming mode.
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
if (applyMode(ds_mitr->first,new_value,ms))
|
|
{
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
++this_mitr;
|
|
++ds_mitr;
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining state modes to apply any previous changes.
|
|
for(;
|
|
this_mitr!=modeMap.end();
|
|
++this_mitr)
|
|
{
|
|
// note GLMode = this_mitr->first
|
|
ModeStack& ms = this_mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyMode(this_mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyMode(this_mitr->first,ms.global_default_value,ms);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining incoming modes to apply any new mode.
|
|
for(;
|
|
ds_mitr!=modeList.end();
|
|
++ds_mitr)
|
|
{
|
|
ModeStack& ms = modeMap[ds_mitr->first];
|
|
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
applyMode(ds_mitr->first,new_value,ms);
|
|
|
|
// will need to disable this mode on next apply so set it to changed.
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
inline void State::applyModeListOnTexUnit(unsigned int unit,ModeMap& modeMap,const StateSet::ModeList& modeList)
|
|
{
|
|
StateSet::ModeList::const_iterator ds_mitr = modeList.begin();
|
|
ModeMap::iterator this_mitr=modeMap.begin();
|
|
|
|
while (this_mitr!=modeMap.end() && ds_mitr!=modeList.end())
|
|
{
|
|
if (this_mitr->first<ds_mitr->first)
|
|
{
|
|
|
|
// note GLMode = this_mitr->first
|
|
ModeStack& ms = this_mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,this_mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyModeOnTexUnit(unit,this_mitr->first,ms.global_default_value,ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++this_mitr;
|
|
|
|
}
|
|
else if (ds_mitr->first<this_mitr->first)
|
|
{
|
|
|
|
// ds_mitr->first is a new mode, therefore
|
|
// need to insert a new mode entry for ds_mistr->first.
|
|
ModeStack& ms = modeMap[ds_mitr->first];
|
|
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,ds_mitr->first,new_value,ms);
|
|
|
|
// will need to disable this mode on next apply so set it to changed.
|
|
ms.changed = true;
|
|
|
|
++ds_mitr;
|
|
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same mode, check the override
|
|
// if any otherwise just apply the incoming mode.
|
|
|
|
ModeStack& ms = this_mitr->second;
|
|
|
|
if (!ms.valueVec.empty() && (ms.valueVec.back() & StateAttribute::OVERRIDE) && !(ds_mitr->second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, just treat as a normal apply on modes.
|
|
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,this_mitr->first,new_value,ms);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no override on or no previous entry, therefore consider incoming mode.
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
if (applyModeOnTexUnit(unit,ds_mitr->first,new_value,ms))
|
|
{
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
++this_mitr;
|
|
++ds_mitr;
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining state modes to apply any previous changes.
|
|
for(;
|
|
this_mitr!=modeMap.end();
|
|
++this_mitr)
|
|
{
|
|
// note GLMode = this_mitr->first
|
|
ModeStack& ms = this_mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,this_mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyModeOnTexUnit(unit,this_mitr->first,ms.global_default_value,ms);
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining incoming modes to apply any new mode.
|
|
for(;
|
|
ds_mitr!=modeList.end();
|
|
++ds_mitr)
|
|
{
|
|
ModeStack& ms = modeMap[ds_mitr->first];
|
|
|
|
bool new_value = ds_mitr->second & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,ds_mitr->first,new_value,ms);
|
|
|
|
// will need to disable this mode on next apply so set it to changed.
|
|
ms.changed = true;
|
|
}
|
|
}
|
|
|
|
inline void State::applyAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList)
|
|
{
|
|
StateSet::AttributeList::const_iterator ds_aitr=attributeList.begin();
|
|
|
|
AttributeMap::iterator this_aitr=attributeMap.begin();
|
|
|
|
while (this_aitr!=attributeMap.end() && ds_aitr!=attributeList.end())
|
|
{
|
|
if (this_aitr->first<ds_aitr->first)
|
|
{
|
|
|
|
// note attribute type = this_aitr->first
|
|
AttributeStack& as = this_aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttribute(new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttribute(as);
|
|
}
|
|
}
|
|
|
|
++this_aitr;
|
|
|
|
}
|
|
else if (ds_aitr->first<this_aitr->first)
|
|
{
|
|
|
|
// ds_aitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aitr->first.
|
|
AttributeStack& as = attributeMap[ds_aitr->first];
|
|
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
applyAttribute(new_attr,as);
|
|
|
|
as.changed = true;
|
|
|
|
++ds_aitr;
|
|
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same attribute, check the override
|
|
// if any otherwise just apply the incoming attribute
|
|
|
|
AttributeStack& as = this_aitr->second;
|
|
|
|
if (!as.attributeVec.empty() && (as.attributeVec.back().second & StateAttribute::OVERRIDE) && !(ds_aitr->second.second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, just treat as a normal apply on attribute.
|
|
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttribute(new_attr,as);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no override on or no previous entry, therefore consider incoming attribute.
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
if (applyAttribute(new_attr,as))
|
|
{
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
++this_aitr;
|
|
++ds_aitr;
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining state attributes to apply any previous changes.
|
|
for(;
|
|
this_aitr!=attributeMap.end();
|
|
++this_aitr)
|
|
{
|
|
// note attribute type = this_aitr->first
|
|
AttributeStack& as = this_aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttribute(new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttribute(as);
|
|
}
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining incoming attribute to apply any new attribute.
|
|
for(;
|
|
ds_aitr!=attributeList.end();
|
|
++ds_aitr)
|
|
{
|
|
// ds_aitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aitr->first.
|
|
AttributeStack& as = attributeMap[ds_aitr->first];
|
|
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
applyAttribute(new_attr,as);
|
|
|
|
// will need to update this attribute on next apply so set it to changed.
|
|
as.changed = true;
|
|
}
|
|
|
|
}
|
|
|
|
inline void State::applyAttributeListOnTexUnit(unsigned int unit,AttributeMap& attributeMap,const StateSet::AttributeList& attributeList)
|
|
{
|
|
StateSet::AttributeList::const_iterator ds_aitr=attributeList.begin();
|
|
|
|
AttributeMap::iterator this_aitr=attributeMap.begin();
|
|
|
|
while (this_aitr!=attributeMap.end() && ds_aitr!=attributeList.end())
|
|
{
|
|
if (this_aitr->first<ds_aitr->first)
|
|
{
|
|
|
|
// note attribute type = this_aitr->first
|
|
AttributeStack& as = this_aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttributeOnTexUnit(unit,as);
|
|
}
|
|
}
|
|
|
|
++this_aitr;
|
|
|
|
}
|
|
else if (ds_aitr->first<this_aitr->first)
|
|
{
|
|
|
|
// ds_aitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aitr->first.
|
|
AttributeStack& as = attributeMap[ds_aitr->first];
|
|
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
|
|
as.changed = true;
|
|
|
|
++ds_aitr;
|
|
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same attribute, check the override
|
|
// if any otherwise just apply the incoming attribute
|
|
|
|
AttributeStack& as = this_aitr->second;
|
|
|
|
if (!as.attributeVec.empty() && (as.attributeVec.back().second & StateAttribute::OVERRIDE) && !(ds_aitr->second.second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, just treat as a normal apply on attribute.
|
|
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no override on or no previous entry, therefore consider incoming attribute.
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
if (applyAttributeOnTexUnit(unit,new_attr,as))
|
|
{
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
++this_aitr;
|
|
++ds_aitr;
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining state attributes to apply any previous changes.
|
|
for(;
|
|
this_aitr!=attributeMap.end();
|
|
++this_aitr)
|
|
{
|
|
// note attribute type = this_aitr->first
|
|
AttributeStack& as = this_aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttributeOnTexUnit(unit,as);
|
|
}
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining incoming attribute to apply any new attribute.
|
|
for(;
|
|
ds_aitr!=attributeList.end();
|
|
++ds_aitr)
|
|
{
|
|
// ds_aitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aitr->first.
|
|
AttributeStack& as = attributeMap[ds_aitr->first];
|
|
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
|
|
// will need to update this attribute on next apply so set it to changed.
|
|
as.changed = true;
|
|
}
|
|
|
|
}
|
|
|
|
inline void State::applyUniformList(UniformMap& uniformMap,const StateSet::UniformList& uniformList)
|
|
{
|
|
if (!_lastAppliedProgramObject) return;
|
|
|
|
StateSet::UniformList::const_iterator ds_aitr=uniformList.begin();
|
|
|
|
UniformMap::iterator this_aitr=uniformMap.begin();
|
|
|
|
while (this_aitr!=uniformMap.end() && ds_aitr!=uniformList.end())
|
|
{
|
|
if (this_aitr->first<ds_aitr->first)
|
|
{
|
|
// note attribute type = this_aitr->first
|
|
UniformStack& as = this_aitr->second;
|
|
if (!as.uniformVec.empty())
|
|
{
|
|
_lastAppliedProgramObject->apply(*as.uniformVec.back().first);
|
|
}
|
|
|
|
++this_aitr;
|
|
|
|
}
|
|
else if (ds_aitr->first<this_aitr->first)
|
|
{
|
|
_lastAppliedProgramObject->apply(*(ds_aitr->second.first.get()));
|
|
|
|
++ds_aitr;
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same attribute, check the override
|
|
// if any otherwise just apply the incoming attribute
|
|
|
|
UniformStack& as = this_aitr->second;
|
|
|
|
if (!as.uniformVec.empty() && (as.uniformVec.back().second & StateAttribute::OVERRIDE) && !(ds_aitr->second.second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, just treat as a normal apply on uniform.
|
|
_lastAppliedProgramObject->apply(*as.uniformVec.back().first);
|
|
}
|
|
else
|
|
{
|
|
// no override on or no previous entry, therefore consider incoming attribute.
|
|
_lastAppliedProgramObject->apply(*(ds_aitr->second.first.get()));
|
|
}
|
|
|
|
++this_aitr;
|
|
++ds_aitr;
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining state attributes to apply any previous changes.
|
|
for(;
|
|
this_aitr!=uniformMap.end();
|
|
++this_aitr)
|
|
{
|
|
// note attribute type = this_aitr->first
|
|
UniformStack& as = this_aitr->second;
|
|
if (!as.uniformVec.empty())
|
|
{
|
|
_lastAppliedProgramObject->apply(*as.uniformVec.back().first);
|
|
}
|
|
}
|
|
|
|
// iterator over the remaining incoming attribute to apply any new attribute.
|
|
for(;
|
|
ds_aitr!=uniformList.end();
|
|
++ds_aitr)
|
|
{
|
|
_lastAppliedProgramObject->apply(*(ds_aitr->second.first.get()));
|
|
}
|
|
|
|
}
|
|
|
|
inline void State::applyModeMap(ModeMap& modeMap)
|
|
{
|
|
for(ModeMap::iterator mitr=modeMap.begin();
|
|
mitr!=modeMap.end();
|
|
++mitr)
|
|
{
|
|
// note GLMode = mitr->first
|
|
ModeStack& ms = mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyMode(mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyMode(mitr->first,ms.global_default_value,ms);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::applyModeMapOnTexUnit(unsigned int unit,ModeMap& modeMap)
|
|
{
|
|
for(ModeMap::iterator mitr=modeMap.begin();
|
|
mitr!=modeMap.end();
|
|
++mitr)
|
|
{
|
|
// note GLMode = mitr->first
|
|
ModeStack& ms = mitr->second;
|
|
if (ms.changed)
|
|
{
|
|
ms.changed = false;
|
|
if (!ms.valueVec.empty())
|
|
{
|
|
bool new_value = ms.valueVec.back() & StateAttribute::ON;
|
|
applyModeOnTexUnit(unit,mitr->first,new_value,ms);
|
|
}
|
|
else
|
|
{
|
|
// assume default of disabled.
|
|
applyModeOnTexUnit(unit,mitr->first,ms.global_default_value,ms);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::applyAttributeMap(AttributeMap& attributeMap)
|
|
{
|
|
for(AttributeMap::iterator aitr=attributeMap.begin();
|
|
aitr!=attributeMap.end();
|
|
++aitr)
|
|
{
|
|
AttributeStack& as = aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttribute(new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttribute(as);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::applyAttributeMapOnTexUnit(unsigned int unit,AttributeMap& attributeMap)
|
|
{
|
|
for(AttributeMap::iterator aitr=attributeMap.begin();
|
|
aitr!=attributeMap.end();
|
|
++aitr)
|
|
{
|
|
AttributeStack& as = aitr->second;
|
|
if (as.changed)
|
|
{
|
|
as.changed = false;
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
const StateAttribute* new_attr = as.attributeVec.back().first;
|
|
applyAttributeOnTexUnit(unit,new_attr,as);
|
|
}
|
|
else
|
|
{
|
|
applyGlobalDefaultAttributeOnTexUnit(unit,as);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void State::applyUniformMap(UniformMap& uniformMap)
|
|
{
|
|
if (!_lastAppliedProgramObject) return;
|
|
|
|
for(UniformMap::iterator aitr=uniformMap.begin();
|
|
aitr!=uniformMap.end();
|
|
++aitr)
|
|
{
|
|
UniformStack& as = aitr->second;
|
|
if (!as.uniformVec.empty())
|
|
{
|
|
_lastAppliedProgramObject->apply(*as.uniformVec.back().first);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool State::setActiveTextureUnit( unsigned int unit )
|
|
{
|
|
if (unit!=_currentActiveTextureUnit)
|
|
{
|
|
if (_glActiveTexture && unit < (unsigned int)(maximum(_glMaxTextureCoords,_glMaxTextureUnits)) )
|
|
{
|
|
_glActiveTexture(GL_TEXTURE0+unit);
|
|
_currentActiveTextureUnit = unit;
|
|
}
|
|
else
|
|
{
|
|
return unit==0;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|