1187 lines
42 KiB
C++
1187 lines
42 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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/FrameStamp>
|
|
#include <osg/DisplaySettings>
|
|
#include <osg/Polytope>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
namespace osg {
|
|
|
|
#ifndef GL_TEXTURE0
|
|
#define GL_TEXTURE0 0x84C0
|
|
#endif
|
|
|
|
#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
|
|
|
|
/** macro for use with osg::StateAttrbiute::apply methods for detected 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; \
|
|
}\
|
|
}
|
|
|
|
/** State class for managing a state stack.
|
|
* Lazy state updating is used to minimize state changes.
|
|
*/
|
|
class SG_EXPORT State : public Referenced
|
|
{
|
|
public :
|
|
|
|
State();
|
|
|
|
/** push stateset onto state stack.*/
|
|
void pushStateSet(const StateSet* dstate);
|
|
|
|
/** pop drawstate off state stack.*/
|
|
void popStateSet();
|
|
|
|
/** copy the modes and attributes which captures the current state.*/
|
|
void captureCurrentState(StateSet& stateset) const;
|
|
|
|
/** reset the state object to an empty stack.*/
|
|
void reset();
|
|
|
|
inline void applyProjectionMatrix(const osg::RefMatrix* matrix)
|
|
{
|
|
if (_projection!=matrix)
|
|
{
|
|
glMatrixMode( GL_PROJECTION );
|
|
if (matrix)
|
|
{
|
|
_projection=matrix;
|
|
glLoadMatrixf(matrix->ptr());
|
|
}
|
|
else
|
|
{
|
|
_projection=_identity;
|
|
glLoadIdentity();
|
|
}
|
|
glMatrixMode( GL_MODELVIEW );
|
|
}
|
|
}
|
|
|
|
const osg::Matrix& getProjectionMatrix() const
|
|
{
|
|
return *_projection;
|
|
}
|
|
|
|
inline void applyModelViewMatrix(const osg::RefMatrix* matrix)
|
|
{
|
|
if (_modelView!=matrix)
|
|
{
|
|
if (matrix)
|
|
{
|
|
_modelView=matrix;
|
|
glLoadMatrixf(matrix->ptr());
|
|
}
|
|
else
|
|
{
|
|
_modelView=_identity;
|
|
glLoadIdentity();
|
|
}
|
|
}
|
|
}
|
|
|
|
const osg::Matrix& getModelViewMatrix() const
|
|
{
|
|
return *_modelView;
|
|
}
|
|
|
|
|
|
Polytope getViewFrustum() const;
|
|
|
|
|
|
/** Apply stateset.*/
|
|
void apply(const StateSet* dstate);
|
|
|
|
/** Apply the state.*/
|
|
void apply();
|
|
|
|
|
|
/** Apply an OpenGL mode if required. */
|
|
inline bool applyMode(StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
ModeStack& ms = _modeMap[mode];
|
|
ms.changed = true;
|
|
return applyMode(mode,enabled,ms);
|
|
}
|
|
|
|
inline bool applyTextureMode(unsigned int unit, StateAttribute::GLMode mode,bool enabled)
|
|
{
|
|
if (setActiveTextureUnit(unit))
|
|
{
|
|
ModeMap& modeMap = getOrCreateTextureModeMap(unit);
|
|
ModeStack& ms = modeMap[mode];
|
|
ms.changed = true;
|
|
return applyMode(mode,enabled,ms);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/** Apply an attribute if required. */
|
|
inline bool applyAttribute(const StateAttribute* attribute)
|
|
{
|
|
AttributeStack& as = _attributeMap[attribute->getType()];
|
|
as.changed = true;
|
|
return applyAttribute(attribute,as);
|
|
}
|
|
|
|
inline bool applyTextureAttribute(unsigned int unit, const StateAttribute* attribute)
|
|
{
|
|
if (setActiveTextureUnit(unit))
|
|
{
|
|
AttributeMap& attributeMap = getOrCreateTextureAttributeMap(unit);
|
|
AttributeStack& as = attributeMap[attribute->getType()];
|
|
as.changed = true;
|
|
return applyAttribute(attribute,as);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/** 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-appplied 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 accuratly and enable lazy state updating such
|
|
* that only changed state will be applied.*/
|
|
void haveAppliedAttribute(StateAttribute::Type type);
|
|
|
|
/** 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 is one has not yet been applied.*/
|
|
const StateAttribute* getLastAppliedAttribute(StateAttribute::Type type) 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-appplied 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 accuratly and enable lazy state updating such
|
|
* that only changed state will be applied.*/
|
|
void haveAppliedTextureAttribute(unsigned int unit, StateAttribute::Type type);
|
|
|
|
/** 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 is one has not yet been applied.*/
|
|
const StateAttribute* getLastAppliedTextureAttribute(unsigned int unit, StateAttribute::Type type) 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, secenday color, fog coord and index arrays.*/
|
|
void disableAllVertexArrays();
|
|
|
|
/** dirty the vertex, normal, color, tex coords, secenday color, fog coord and index arrays.*/
|
|
void dirtyAllVertexArrays();
|
|
|
|
|
|
/** 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);
|
|
|
|
|
|
/** 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 )
|
|
{
|
|
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._dirty = false;
|
|
}
|
|
|
|
/** wrapper glDisableClientState(GL_VERTEX_ARRAY).
|
|
* note, only updates values that change.*/
|
|
inline void disableVertexPointer()
|
|
{
|
|
if (_vertexArray._enabled || _vertexArray._dirty)
|
|
{
|
|
_vertexArray._enabled = false;
|
|
_vertexArray._dirty = false;
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtyVertexPointer()
|
|
{
|
|
_vertexArray._pointer = 0;
|
|
_vertexArray._dirty = true;
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_NORMAL_ARRAY);glNormalPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setNormalPointer( GLenum type, GLsizei stride,
|
|
const GLvoid *ptr )
|
|
{
|
|
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._dirty = false;
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_NORMAL_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableNormalPointer()
|
|
{
|
|
if (_normalArray._enabled || _normalArray._dirty)
|
|
{
|
|
_normalArray._enabled = false;
|
|
_normalArray._dirty = false;
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtyNormalPointer()
|
|
{
|
|
_normalArray._pointer = 0;
|
|
_normalArray._dirty = true;
|
|
}
|
|
|
|
/** 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 )
|
|
{
|
|
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._dirty = false;
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_COLOR_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableColorPointer()
|
|
{
|
|
if (_colorArray._enabled || _colorArray._dirty)
|
|
{
|
|
_colorArray._enabled = false;
|
|
_colorArray._dirty = false;
|
|
glDisableClientState(GL_COLOR_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtyColorPointer()
|
|
{
|
|
_colorArray._pointer = 0;
|
|
_colorArray._dirty = true;
|
|
}
|
|
|
|
|
|
inline bool isSecondaryColorSupported() const { return _isSecondColorSupportResolved?_isSecondColorSupported:computeSecondaryColorSupported(); }
|
|
|
|
/** 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()
|
|
{
|
|
if (_secondaryColorArray._enabled || _secondaryColorArray._dirty)
|
|
{
|
|
_secondaryColorArray._enabled = false;
|
|
_secondaryColorArray._dirty = false;
|
|
if (isSecondaryColorSupported()) glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtySecondaryColorPointer()
|
|
{
|
|
_secondaryColorArray._pointer = 0;
|
|
_secondaryColorArray._dirty = true;
|
|
}
|
|
|
|
/** wrapper around glEnableClientState(GL_INDEX_ARRAY);glIndexPointer(..);
|
|
* note, only updates values that change.*/
|
|
inline void setIndexPointer( GLenum type, GLsizei stride,
|
|
const GLvoid *ptr )
|
|
{
|
|
if (!_indexArray._enabled || _indexArray._dirty)
|
|
{
|
|
_indexArray._enabled = true;
|
|
glEnableClientState(GL_INDEX_ARRAY);
|
|
}
|
|
if (_indexArray._pointer!=ptr || _indexArray._dirty)
|
|
{
|
|
_indexArray._pointer=ptr;
|
|
glIndexPointer( type, stride, ptr );
|
|
}
|
|
_indexArray._dirty = false;
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_INDEX_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableIndexPointer()
|
|
{
|
|
if (_indexArray._enabled || _indexArray._dirty)
|
|
{
|
|
_indexArray._enabled = false;
|
|
_indexArray._dirty = false;
|
|
glDisableClientState(GL_INDEX_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtyIndexPointer()
|
|
{
|
|
_indexArray._pointer = 0;
|
|
_indexArray._dirty = true;
|
|
}
|
|
|
|
|
|
inline bool isFogCoordSupported() const { return _isFogCoordSupportResolved?_isFogCoordSupported:computeFogCoordSupported(); }
|
|
|
|
/** 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()
|
|
{
|
|
if (_fogArray._enabled || _fogArray._dirty)
|
|
{
|
|
_fogArray._enabled = false;
|
|
_fogArray._dirty = false;
|
|
if (isFogCoordSupported()) glDisableClientState(GL_FOG_COORDINATE_ARRAY);
|
|
}
|
|
}
|
|
|
|
inline void dirtyFogCoordPointer()
|
|
{
|
|
_fogArray._pointer = 0;
|
|
_fogArray._dirty = true;
|
|
}
|
|
|
|
|
|
/** 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 )
|
|
{
|
|
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._dirty = false;
|
|
}
|
|
}
|
|
|
|
/** wrapper around glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
* note, only updates values that change.*/
|
|
inline void disableTexCoordPointer( unsigned int unit )
|
|
{
|
|
if (setClientActiveTextureUnit(unit))
|
|
{
|
|
if ( unit >= _texCoordArrayList.size()) _texCoordArrayList.resize(unit+1);
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
|
|
if (eap._enabled || eap._dirty)
|
|
{
|
|
eap._enabled = false;
|
|
eap._dirty = false;
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void dirtyTexCoordPointer( unsigned int unit )
|
|
{
|
|
if ( unit >= _texCoordArrayList.size()) return; // _texCoordArrayList.resize(unit+1);
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
}
|
|
|
|
|
|
inline void disableTexCoordPointersAboveAndIncluding( unsigned int unit )
|
|
{
|
|
while (unit<_texCoordArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
if (eap._enabled || eap._dirty)
|
|
{
|
|
if (setClientActiveTextureUnit(unit))
|
|
{
|
|
eap._enabled = false;
|
|
eap._dirty = false;
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
}
|
|
++unit;
|
|
}
|
|
}
|
|
|
|
inline void dirtyTexCoordPointersAboveAndIncluding( unsigned int unit )
|
|
{
|
|
while (unit<_texCoordArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _texCoordArrayList[unit];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
++unit;
|
|
}
|
|
}
|
|
|
|
/** set the current tex coord array texture unit, return true if selected, false if selection failed such as when multitexturing is not supported.
|
|
* note, only updates values that change.*/
|
|
bool setClientActiveTextureUnit( unsigned int unit );
|
|
|
|
|
|
/** set the current texture unit, return true if selected, false if selection failed such as when multitexturing is not supported.
|
|
* note, only updates values that change.*/
|
|
bool setActiveTextureUnit( unsigned int unit );
|
|
|
|
/** 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 dirtyVertexAttribPointersAboveAndIncluding( unsigned int index )
|
|
{
|
|
while (index<_vertexAttribArrayList.size())
|
|
{
|
|
EnabledArrayPair& eap = _vertexAttribArrayList[index];
|
|
eap._pointer = 0;
|
|
eap._dirty = true;
|
|
++index;
|
|
}
|
|
}
|
|
|
|
|
|
/** 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::StateAttribure'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 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 setup.
|
|
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 frame stamp for the current frame.*/
|
|
inline void setFrameStamp(FrameStamp* fs) { _frameStamp = fs; }
|
|
|
|
/** Set the 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
|
|
* 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(); }
|
|
|
|
typedef std::pair<const StateAttribute*,StateAttribute::OverrideValue> AttributePair;
|
|
typedef std::vector<AttributePair> AttributeVec;
|
|
typedef std::vector<StateAttribute::GLModeValue> ValueVec;
|
|
|
|
|
|
/** 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; }
|
|
|
|
|
|
void setReportGLErrors(bool flag) { _reportGLErrors = flag; }
|
|
bool getReportGLErrors() const { return _reportGLErrors; }
|
|
|
|
bool checkGLErrors(const char* str) const;
|
|
bool checkGLErrors(StateAttribute::GLMode mode) const;
|
|
bool checkGLErrors(const StateAttribute* attribute) const;
|
|
|
|
|
|
protected:
|
|
|
|
virtual ~State();
|
|
|
|
unsigned int _contextID;
|
|
ref_ptr<FrameStamp> _frameStamp;
|
|
|
|
ref_ptr<const RefMatrix> _identity;
|
|
ref_ptr<const RefMatrix> _projection;
|
|
ref_ptr<const RefMatrix> _modelView;
|
|
|
|
ref_ptr<DisplaySettings> _displaySettings;
|
|
|
|
bool* _abortRenderingPtr;
|
|
bool _reportGLErrors;
|
|
|
|
struct ModeStack
|
|
{
|
|
ModeStack()
|
|
{
|
|
changed = false;
|
|
last_applied_value = false;
|
|
global_default_value = false;
|
|
}
|
|
|
|
bool changed;
|
|
bool last_applied_value;
|
|
bool global_default_value;
|
|
ValueVec valueVec;
|
|
};
|
|
|
|
|
|
|
|
struct AttributeStack
|
|
{
|
|
AttributeStack()
|
|
{
|
|
changed = false;
|
|
last_applied_attribute = 0L;
|
|
global_default_attribute = 0L;
|
|
}
|
|
|
|
/** apply an attribute if required, passing in attribute and appropriate attribute stack */
|
|
bool changed;
|
|
const StateAttribute* last_applied_attribute;
|
|
ref_ptr<StateAttribute> global_default_attribute;
|
|
AttributeVec attributeVec;
|
|
};
|
|
|
|
|
|
/** apply an OpenGL mode if required, passing in mode, enable flag and appropriate mode stack */
|
|
inline bool applyMode(StateAttribute::GLMode mode,bool enabled,ModeStack& ms)
|
|
{
|
|
if (ms.last_applied_value != enabled)
|
|
{
|
|
ms.last_applied_value = enabled;
|
|
|
|
if (enabled) glEnable(mode);
|
|
else glDisable(mode);
|
|
|
|
if (_reportGLErrors) checkGLErrors(mode);
|
|
|
|
return true;
|
|
}
|
|
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);
|
|
|
|
if (_reportGLErrors) checkGLErrors(attribute);
|
|
|
|
return true;
|
|
}
|
|
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 (_reportGLErrors) checkGLErrors(as.global_default_attribute.get());
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
typedef std::map<StateAttribute::GLMode,ModeStack> ModeMap;
|
|
typedef std::vector<ModeMap> TextureModeMapList;
|
|
|
|
typedef std::map<StateAttribute::Type,AttributeStack> AttributeMap;
|
|
typedef std::vector<AttributeMap> TextureAttributeMapList;
|
|
|
|
typedef std::vector<const StateSet*> StateSetStack;
|
|
typedef std::vector<ref_ptr<const Matrix> > MatrixStack;
|
|
|
|
ModeMap _modeMap;
|
|
AttributeMap _attributeMap;
|
|
|
|
TextureModeMapList _textureModeMapList;
|
|
TextureAttributeMapList _textureAttributeMapList;
|
|
|
|
StateSetStack _drawStateStack;
|
|
|
|
struct EnabledArrayPair
|
|
{
|
|
EnabledArrayPair():_dirty(true),_enabled(false),_normalized(0),_pointer(0) {}
|
|
EnabledArrayPair(const EnabledArrayPair& eap):_dirty(eap._dirty), _enabled(eap._enabled),_normalized(eap._normalized),_pointer(eap._pointer) {}
|
|
EnabledArrayPair& operator = (const EnabledArrayPair& eap) { _dirty=eap._dirty; _enabled=eap._enabled; _normalized=eap._normalized;_pointer=eap._pointer; return *this; }
|
|
|
|
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 _indexArray;
|
|
EnabledArrayPair _fogArray;
|
|
EnabledTexCoordArrayList _texCoordArrayList;
|
|
EnabledVertexAttribArrayList _vertexAttribArrayList;
|
|
|
|
unsigned int _currentActiveTextureUnit;
|
|
unsigned int _currentClientActiveTextureUnit;
|
|
|
|
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 popModeList(ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void popAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
|
|
inline void applyModeList(ModeMap& modeMap,const StateSet::ModeList& modeList);
|
|
inline void applyAttributeList(AttributeMap& attributeMap,const StateSet::AttributeList& attributeList);
|
|
|
|
inline void applyModeMap(ModeMap& modeMap);
|
|
inline void applyAttributeMap(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);
|
|
bool getLastAppliedMode(const ModeMap& modeMap,StateAttribute::GLMode mode) const;
|
|
const StateAttribute* getLastAppliedAttribute(const AttributeMap& attributeMap,StateAttribute::Type type) const;
|
|
|
|
|
|
mutable bool _isSecondColorSupportResolved;
|
|
mutable bool _isSecondColorSupported;
|
|
bool computeSecondaryColorSupported() const;
|
|
|
|
mutable bool _isFogCoordSupportResolved;
|
|
mutable bool _isFogCoordSupported;
|
|
bool computeFogCoordSupported() const;
|
|
};
|
|
|
|
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 incomming GLmode {mitr->first}.
|
|
ModeStack& ms = modeMap[mitr->first];
|
|
if (ms.valueVec.empty())
|
|
{
|
|
// first pair so simply push incomming 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 previoius value.
|
|
ms.valueVec.push_back(ms.valueVec.back());
|
|
}
|
|
else
|
|
{
|
|
// no override on so simply push incomming 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 incomming type {aitr->first}.
|
|
AttributeStack& as = attributeMap[aitr->first];
|
|
if (as.attributeVec.empty())
|
|
{
|
|
// first pair so simply push incomming 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 previoius value.
|
|
as.attributeVec.push_back(as.attributeVec.back());
|
|
}
|
|
else
|
|
{
|
|
// no override on so simply push incomming pair to back.
|
|
as.attributeVec.push_back(
|
|
AttributePair(aitr->second.first.get(),aitr->second.second));
|
|
}
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
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 incomming 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 incomming type {aitr->first}.
|
|
AttributeStack& as = attributeMap[aitr->first];
|
|
if (!as.attributeVec.empty())
|
|
{
|
|
as.attributeVec.pop_back();
|
|
}
|
|
as.changed = true;
|
|
}
|
|
}
|
|
|
|
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 overide
|
|
// if any otherwise just apply the incomming mode.
|
|
|
|
ModeStack& ms = this_mitr->second;
|
|
|
|
if (!ms.valueVec.empty() && (ms.valueVec.back() & StateAttribute::OVERRIDE) && !(ds_mitr->second & StateAttribute::PROTECTED))
|
|
{
|
|
// override is on, there 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 incomming 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 incomming 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::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_mitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aistr->first.
|
|
AttributeStack& as = attributeMap[ds_aitr->first];
|
|
|
|
const StateAttribute* new_attr = ds_aitr->second.first.get();
|
|
applyAttribute(new_attr,as);
|
|
|
|
// will need to disable this mode on next apply so set it to changed.
|
|
as.changed = true;
|
|
|
|
++ds_aitr;
|
|
|
|
}
|
|
else
|
|
{
|
|
// this_mitr & ds_mitr refer to the same attribute, check the overide
|
|
// if any otherwise just apply the incomming 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, there just treat as a normal apply on modes.
|
|
|
|
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 incomming mode.
|
|
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 modes 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 incomming modes to apply any new mode.
|
|
for(;
|
|
ds_aitr!=attributeList.end();
|
|
++ds_aitr)
|
|
{
|
|
// ds_mitr->first is a new attribute, therefore
|
|
// need to insert a new attribute entry for ds_aistr->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::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::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);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|