diff --git a/include/osg/Program b/include/osg/Program index b88bc17f9..aed54ecb7 100644 --- a/include/osg/Program +++ b/include/osg/Program @@ -12,21 +12,15 @@ */ /* file: include/osg/Program - * author: Mike Weiblen 2005-03-23 + * author: Mike Weiblen 2005-03-30 */ -// NOTICE: This code is CLOSED during construction and/or renovation! -// It is in active development, so DO NOT yet use in application code. -// This notice will be removed when the code is open for business. -// For development plan and status see: -// http://www.openscenegraph.org/index.php?page=Community.DevelopmentWork - - #ifndef OSG_PROGRAM #define OSG_PROGRAM 1 #include #include +#include #include #include @@ -180,6 +174,7 @@ class SG_EXPORT GL2Extensions : public osg::Referenced GLuint getCurrentProgram() const; bool getProgramInfoLog( GLuint program, std::string& result ) const; bool getShaderInfoLog( GLuint shader, std::string& result ) const; + bool getAttribLocation( const char* attribName, GLuint& slot ) const; protected: ~GL2Extensions() {} @@ -339,8 +334,10 @@ class SG_EXPORT Program : public osg::StateAttribute * Mark Program as needing relink. Return true for success */ bool removeShader( Shader* shader ); - /** */ + /** Add an attribute location binding. */ void bindAttribLocation( GLuint index, const char* name ); + typedef std::map AttribBindingList; + const AttribBindingList& getAttribBindingList() const { return _attribBindingList; } /** Return true if this Program represents "fixed-functionality" rendering */ bool isFixedFunction() const; @@ -353,12 +350,6 @@ class SG_EXPORT Program : public osg::StateAttribute void setName( const char* name ) { _name = name; } const std::string& getName() const { return _name; } - /** should Uniform values be tested to avoid redundant setting? */ - void setAvoidRedundantUniformSetting( bool flag ) { _avoidRedundantUniformSetting = flag; } - bool getAvoidRedundantUniformSetting() const { return _avoidRedundantUniformSetting; } - - // TODO glBindAttribLocation - /** Mark internal glProgram for deletion. * Deletion requests are queued until they can be executed * in the proper GL context. */ @@ -370,23 +361,22 @@ class SG_EXPORT Program : public osg::StateAttribute protected: - /** An OSG-internal encapsulation of glProgram's active uniforms */ - class ActiveUniform : public osg::Referenced + class ActiveUniform : public osg::Uniform { public: - ActiveUniform( const GLchar* name, GLenum type ); + ActiveUniform( const char* name, GLenum type, GLint loc ); + void applyData( const GL2Extensions* ext, GLuint prog ); protected: virtual ~ActiveUniform() {} - - Uniform::Value _value; - GLint _location; + const GLint _location; private: ActiveUniform(); // disallowed + ActiveUniform(ActiveUniform&); // disallowed + ActiveUniform& operator=(ActiveUniform&); // disallowed }; - typedef osg::ref_ptr< ActiveUniform > ActiveUniformPtr; - typedef std::vector< ActiveUniformPtr > ActiveUniformList; + typedef std::vector< osg::ref_ptr > ActiveUniformList; protected: @@ -405,9 +395,11 @@ class SG_EXPORT Program : public osg::StateAttribute void getInfoLog( std::string& infoLog ) const; void useProgram() const; - void applyUniforms( osg::State& state ) const; + GLint getUniformLocation( const char* name ) const; + GLint getAttribLocation( const char* name ) const; + protected: /*methods*/ ~PerContextProgram(); @@ -438,11 +430,13 @@ class SG_EXPORT Program : public osg::StateAttribute PerContextProgram* getPCP(unsigned int contextID) const; protected: /*data*/ - bool _avoidRedundantUniformSetting; std::string _name; + mutable osg::buffered_value< osg::ref_ptr > _pcpList; + AttribBindingList _attribBindingList; + typedef std::vector< ref_ptr > ShaderList; ShaderList _shaderList; - mutable osg::buffered_value< osg::ref_ptr > _pcpList; + private: Program& operator=(const Program&); // disallowed diff --git a/include/osg/Shader b/include/osg/Shader index 4e822bc05..d69f0e024 100644 --- a/include/osg/Shader +++ b/include/osg/Shader @@ -12,16 +12,9 @@ */ /* file: include/osg/Shader - * author: Mike Weiblen 2005-03-23 + * author: Mike Weiblen 2005-03-30 */ -// NOTICE: This code is CLOSED during construction and/or renovation! -// It is in active development, so DO NOT yet use in application code. -// This notice will be removed when the code is open for business. -// For development plan and status see: -// http://www.openscenegraph.org/index.php?page=Community.DevelopmentWork - - #ifndef OSG_SHADER #define OSG_SHADER 1 diff --git a/include/osg/State b/include/osg/State index e0c2f0909..0a8642571 100644 --- a/include/osg/State +++ b/include/osg/State @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include +#include #ifndef GL_TEXTURE0 #define GL_TEXTURE0 0x84C0 @@ -710,6 +712,13 @@ class SG_EXPORT State : public Referenced bool checkGLErrors(StateAttribute::GLMode mode) const; bool checkGLErrors(const StateAttribute* attribute) const; + typedef std::map< std::string,ref_ptr > UniformMap; + const Uniform* findUniform( const std::string& name ) + { + UniformMap::const_iterator itr = _uniformMap.find( name ); + return (itr != _uniformMap.end()) ? itr->second.get() : 0; + } + protected: virtual ~State(); @@ -840,6 +849,8 @@ class SG_EXPORT State : public Referenced TextureModeMapList _textureModeMapList; TextureAttributeMapList _textureAttributeMapList; + UniformMap _uniformMap; + StateSetStack _drawStateStack; struct EnabledArrayPair diff --git a/include/osg/Uniform b/include/osg/Uniform index e96f5a406..764928a9d 100644 --- a/include/osg/Uniform +++ b/include/osg/Uniform @@ -11,7 +11,7 @@ */ /* file: include/osg/Uniform - * author: Mike Weiblen 2005-03-23 + * author: Mike Weiblen 2005-03-29 */ // NOTICE: This code is CLOSED during construction and/or renovation! @@ -33,8 +33,9 @@ #include -#ifndef GL_VERSION_2_0 +#ifndef GL_VERSION_2_0 //[ #define GL_VERSION_2_0 1 +typedef char GLchar; #define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 @@ -119,116 +120,60 @@ #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 - -typedef char GLchar; - -#endif +#endif //] namespace osg { /////////////////////////////////////////////////////////////////////////// /** Uniform encapsulates glUniform values */ +class GL2Extensions; + class SG_EXPORT Uniform : public Object { public: - class Value - { - public: - enum Type { - FLOAT = GL_FLOAT, - FLOAT_VEC2 = GL_FLOAT_VEC2, - FLOAT_VEC3 = GL_FLOAT_VEC3, - FLOAT_VEC4 = GL_FLOAT_VEC4, - INT = GL_INT, - INT_VEC2 = GL_INT_VEC2, - INT_VEC3 = GL_INT_VEC3, - INT_VEC4 = GL_INT_VEC4, - BOOL = GL_BOOL, - BOOL_VEC2 = GL_BOOL_VEC2, - BOOL_VEC3 = GL_BOOL_VEC3, - BOOL_VEC4 = GL_BOOL_VEC4, - FLOAT_MAT2 = GL_FLOAT_MAT2, - FLOAT_MAT3 = GL_FLOAT_MAT3, - FLOAT_MAT4 = GL_FLOAT_MAT4, - SAMPLER_1D = GL_SAMPLER_1D, - SAMPLER_2D = GL_SAMPLER_2D, - SAMPLER_3D = GL_SAMPLER_3D, - SAMPLER_CUBE = GL_SAMPLER_CUBE, - SAMPLER_1D_SHADOW = GL_SAMPLER_1D_SHADOW, - SAMPLER_2D_SHADOW = GL_SAMPLER_2D_SHADOW, - UNDEFINED = -1, - }; - - Value( const char* name, Type type ); - Value( const Value& rhs ); - - - /** Get the name of glUniform. */ - const std::string& getName() const { return _name; } - - /** Get the type of glUniform as enum. */ - const Type getType() const { return _type; } - - /** Return the name of a type as string. */ - static const char* getTypename(Type t); - - /** Does this Value contain real data? */ - bool isValid() const { return _isValid; } - - /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ - int compare(const Value& rhs) const; - - bool isCompatibleType( Type t ) const; - - /** assignment */ - void set( float f ); - void set( const osg::Vec2& v2 ); - void set( const osg::Vec3& v3 ); - void set( const osg::Vec4& v4 ); - //TODO void set( const osg::Matrix2& m2 ); - //TODO void set( const osg::Matrix3& m3 ); - void set( const osg::Matrix& m4 ); - void set( int i ); - void set( int i0, int i1 ); - void set( int i0, int i1, int i2 ); - void set( int i0, int i1, int i2, int i3 ); - void set( bool b ); - void set( bool b0, bool b1 ); - void set( bool b0, bool b1, bool b2 ); - void set( bool b0, bool b1, bool b2, bool b3 ); - - - protected: - /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ - int compareData(const Value& rhs) const; - void copyData(const Value& rhs); - - protected: - const std::string _name; - const Type _type; - bool _isValid; // is _data valid? - union { - GLfloat f1; // float - GLfloat f2[2]; // vec2 - GLfloat f3[3]; // vec3 - GLfloat f4[4]; // vec4, mat2 - GLfloat f9[9]; // mat3 - GLfloat f16[16]; // mat4 - GLint i1; // int, bool, sampler* - GLint i2[2]; // ivec2, bvec2 - GLint i3[3]; // ivec3, bvec3 - GLint i4[4]; // ivec4, bvec4 - } _data; - - private: - Value(); // disallowed + enum Type { + FLOAT = GL_FLOAT, + FLOAT_VEC2 = GL_FLOAT_VEC2, + FLOAT_VEC3 = GL_FLOAT_VEC3, + FLOAT_VEC4 = GL_FLOAT_VEC4, + INT = GL_INT, + INT_VEC2 = GL_INT_VEC2, + INT_VEC3 = GL_INT_VEC3, + INT_VEC4 = GL_INT_VEC4, + BOOL = GL_BOOL, + BOOL_VEC2 = GL_BOOL_VEC2, + BOOL_VEC3 = GL_BOOL_VEC3, + BOOL_VEC4 = GL_BOOL_VEC4, + FLOAT_MAT2 = GL_FLOAT_MAT2, + FLOAT_MAT3 = GL_FLOAT_MAT3, + FLOAT_MAT4 = GL_FLOAT_MAT4, + SAMPLER_1D = GL_SAMPLER_1D, + SAMPLER_2D = GL_SAMPLER_2D, + SAMPLER_3D = GL_SAMPLER_3D, + SAMPLER_CUBE = GL_SAMPLER_CUBE, + SAMPLER_1D_SHADOW = GL_SAMPLER_1D_SHADOW, + SAMPLER_2D_SHADOW = GL_SAMPLER_2D_SHADOW, + UNDEFINED = -1, }; - public: - Uniform(); - Uniform( const char* name, Value::Type type ); + Uniform( const char* name, Type type ); + + /** Copy constructor using CopyOp to manage deep vs shallow copy. */ + Uniform(const Uniform& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + META_Object(osg, Uniform); + + + /** Get the name of glUniform. */ + const std::string& getName() const { return _name; } + + /** Get the type of glUniform as enum. */ + const Type getType() const { return _type; } + + /** Return the name of a type as string. */ + static const char* getTypename( Type t ); /** convenient construction w/ assignment */ explicit Uniform( const char* name, float f ); @@ -247,26 +192,15 @@ class SG_EXPORT Uniform : public Object Uniform( const char* name, bool b0, bool b1, bool b2 ); Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 ); - /** Copy constructor using CopyOp to manage deep vs shallow copy. */ - Uniform(const Uniform& gu,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ + virtual int compare(const Uniform& rhs) const; + virtual int compareData(const Uniform& rhs) const; - META_Object(osg, Uniform); + virtual bool operator < (const Uniform& rhs) const { return (compare(rhs) == -1); } - /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ - virtual int compare(const Uniform& rhs) const - { - return _value.compare( rhs._value ); - } + void copyData( const Uniform& rhs ); - bool operator < (const Uniform& rhs) const - { - if (_value.getName() #include @@ -35,12 +28,14 @@ #include #include #include +#include #include #include using namespace osg; + /////////////////////////////////////////////////////////////////////////// // Extension function pointers for OpenGL v2.0 @@ -286,16 +281,12 @@ void GL2Extensions::setupGL2Extensions() if( isGlslSupported() ) { // If glGetString raises an error, assume initial release "1.00" - glGetError(); // reset error flag + while(glGetError() != GL_NO_ERROR) {} // reset error flag const char* langVerStr = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - const GLenum errorNum = glGetError(); - if( (errorNum != GL_NO_ERROR) || (langVerStr == 0) ) - { - langVerStr = "1.00 (default)"; - } - osg::notify(osg::INFO) << "GL_SHADING_LANGUAGE_VERSION: \"" << langVerStr << "\"" << std::endl; - - _glslLanguageVersion = atof( langVerStr ); + if( (glGetError() == GL_NO_ERROR) && langVerStr ) + _glslLanguageVersion = atof( langVerStr ); + else + _glslLanguageVersion = 1.0f; } osg::notify(osg::INFO) @@ -1787,14 +1778,14 @@ void GL2Extensions::glVertexAttribPointer(GLuint index, GLint size, GLenum type, /////////////////////////////////////////////////////////////////////////// -// convenience methods +// C++-friendly convenience methods GLuint GL2Extensions::getCurrentProgram() const { if( _glVersion >= 2.0f ) { // GLSL as GL v2.0 core functionality - GLint result; + GLint result = 0; glGetIntegerv( GL_CURRENT_PROGRAM, &result ); return static_cast(result); } @@ -1817,8 +1808,8 @@ GLuint GL2Extensions::getCurrentProgram() const bool GL2Extensions::getProgramInfoLog( GLuint program, std::string& result ) const { - GLint bufLen = 0; // length of buffer to allocate - GLint strLen = 0; // strlen GL actually wrote to buffer + GLsizei bufLen = 0; // length of buffer to allocate + GLsizei strLen = 0; // strlen GL actually wrote to buffer glGetProgramiv( program, GL_INFO_LOG_LENGTH, &bufLen ); if( bufLen > 1 ) @@ -1834,8 +1825,8 @@ bool GL2Extensions::getProgramInfoLog( GLuint program, std::string& result ) con bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const { - GLint bufLen = 0; // length of buffer to allocate - GLint strLen = 0; // strlen GL actually wrote to buffer + GLsizei bufLen = 0; // length of buffer to allocate + GLsizei strLen = 0; // strlen GL actually wrote to buffer glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &bufLen ); if( bufLen > 1 ) @@ -1848,6 +1839,27 @@ bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const return (strLen > 0); } + +bool GL2Extensions::getAttribLocation( const char* attribName, GLuint& location ) const +{ + // is there an active GLSL program? + GLuint program = getCurrentProgram(); + if( glIsProgram(program) == GL_FALSE ) return false; + + // has that program been successfully linked? + GLint linked = GL_FALSE; + glGetProgramiv( program, GL_LINK_STATUS, &linked ); + if( linked == GL_FALSE ) return false; + + // is there such a named attribute? + GLint loc = glGetAttribLocation( program, attribName ); + if( loc < 0 ) return false; + + location = loc; + return true; +} + + /////////////////////////////////////////////////////////////////////////// // static cache of glPrograms flagged for deletion, which will actually // be deleted in the correct GL context. @@ -1909,7 +1921,6 @@ void Program::flushDeletedGlPrograms(unsigned int contextID,double /*currentTime Program::Program() { - _avoidRedundantUniformSetting = true; } @@ -1952,9 +1963,6 @@ int Program::compare(const osg::StateAttribute& sa) const if (result!=0) return result; } - // TODO should Program comparison depend on the values of - // its uniforms? I'd assert not. - return 0; // passed all the above comparison macro's, must be equal. } @@ -2024,7 +2032,7 @@ bool Program::removeShader( Shader* shader ) void Program::bindAttribLocation( GLuint index, const char* name ) { - // TODO add to binding list + _attribBindingList[name] = index; dirtyProgram(); } @@ -2091,11 +2099,64 @@ void Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) cons // osg::Program::ActiveUniform /////////////////////////////////////////////////////////////////////////// -Program::ActiveUniform::ActiveUniform( const GLchar* name, GLenum type ) : - _value( name, static_cast< Uniform::Value::Type >(type) ) +Program::ActiveUniform::ActiveUniform( const char* name, GLenum type, GLint loc ) : + Uniform(name, static_cast(type)), _location(loc) { } +void Program::ActiveUniform::applyData( const GL2Extensions* ext, GLuint prog ) +{ + switch( repType(getType()) ) + { + case FLOAT: + ext->glUniform1f( _location, _data.f1 ); + break; + + case FLOAT_VEC2: + ext->glUniform2fv( _location, 1, _data.f2 ); + break; + + case FLOAT_VEC3: + ext->glUniform3fv( _location, 1, _data.f3 ); + break; + + case FLOAT_VEC4: + ext->glUniform4fv( _location, 1, _data.f4 ); + break; + + case FLOAT_MAT2: + ext->glUniformMatrix2fv( _location, 1, GL_FALSE, _data.f4 ); + break; + + case FLOAT_MAT3: + ext->glUniformMatrix3fv( _location, 1, GL_FALSE, _data.f9 ); + break; + + case FLOAT_MAT4: + ext->glUniformMatrix4fv( _location, 1, GL_FALSE, _data.f16 ); + break; + + case INT: + ext->glUniform1i( _location, _data.i1 ); + break; + + case INT_VEC2: + ext->glUniform2iv( _location, 1, _data.i2 ); + break; + + case INT_VEC3: + ext->glUniform3iv( _location, 1, _data.i3 ); + break; + + case INT_VEC4: + ext->glUniform4iv( _location, 1, _data.i4 ); + break; + + default: + osg::notify(osg::FATAL) << "how got here?" << std::endl; + break; + } +} /////////////////////////////////////////////////////////////////////////// // osg::Program::PerContextProgram @@ -2130,15 +2191,20 @@ void Program::PerContextProgram::linkProgram() if( ! _needsLink ) return; _needsLink = false; - // TODO for( each itr in binding list ) - // { - // _extensions->glBindAttribLocation( _glProgramHandle, index, name ); - // } + _activeUniformList.clear(); - GLint linked; + // set any explicit vertex attribute bindings + const AttribBindingList& bindlist = _program->getAttribBindingList(); + for( AttribBindingList::const_iterator itr = bindlist.begin(); + itr != bindlist.end(); ++itr ) + { + _extensions->glBindAttribLocation( _glProgramHandle, itr->second, itr->first.c_str() ); + } + + // link the glProgram + GLint linked = GL_FALSE; _extensions->glLinkProgram( _glProgramHandle ); _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked ); - _isLinked = (linked == GL_TRUE); if( ! _isLinked ) { @@ -2146,6 +2212,32 @@ void Program::PerContextProgram::linkProgram() std::string infoLog; getInfoLog( infoLog ); osg::notify(osg::WARN) << "glLinkProgram FAILED:\n" << infoLog << std::endl; + return; + } + + // build ActiveUniformList + GLint numUniforms = 0; + GLsizei maxLen = 0; + _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORMS, &numUniforms ); + _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen ); + if( (numUniforms > 0) && (maxLen > 1) ) + { + GLint size = 0; + GLenum type = 0; + GLchar* name = new GLchar[maxLen]; + + for( GLint i = 0; i < numUniforms; ++i ) + { + _extensions->glGetActiveUniform( _glProgramHandle, + i, maxLen, 0, &size, &type, name ); + GLint loc = getUniformLocation( name ); + + if( loc != -1 ) + { + _activeUniformList.push_back( new ActiveUniform( name, type, loc ) ); + } + } + delete [] name; } } @@ -2159,23 +2251,36 @@ void Program::PerContextProgram::useProgram() const _extensions->glUseProgram( _glProgramHandle ); } - -void Program::PerContextProgram::applyUniforms( osg::State& /*state*/ ) const +GLint Program::PerContextProgram::getUniformLocation( const char* name ) const { - bool uniformDoesNeedSetting = true; + return _extensions->glGetUniformLocation( _glProgramHandle, name ); +} - if( _program->getAvoidRedundantUniformSetting() ) - { - // TODO - calling glUniform*() can be expensive. - // so this will query osg::Program state to determine if - // the uniform already has the requested value, and if so, - // will set uniformNeedsSetting=false to prevent redundant - // re-setting of the uniform. - } +GLint Program::PerContextProgram::getAttribLocation( const char* name ) const +{ + return _extensions->glGetAttribLocation( _glProgramHandle, name ); +} - if( uniformDoesNeedSetting ) + +void Program::PerContextProgram::applyUniforms( osg::State& state ) const +{ + for( ActiveUniformList::const_iterator itr = _activeUniformList.begin(); + itr != _activeUniformList.end(); ++itr ) { - // TODO set the uniform value on the currently active glProgram. + ActiveUniform* au = const_cast( itr->get() ); + + // use name of active uniform to find a value uniform + const osg::Uniform* vu = state.findUniform( au->getName() ); + if( ! vu ) continue; + + // skip if types are not identical + if( au->getType() != vu->getType() ) continue; + + // skip if values are already identical + if( au->compareData( *vu ) == 0 ) continue; + + au->copyData( *vu ); + au->applyData( _extensions.get(), _glProgramHandle ); } } diff --git a/src/osg/Shader.cpp b/src/osg/Shader.cpp index f4059fd9a..3c01ed634 100644 --- a/src/osg/Shader.cpp +++ b/src/osg/Shader.cpp @@ -13,16 +13,9 @@ */ /* file: src/osg/Shader.cpp - * author: Mike Weiblen 2005-03-23 + * author: Mike Weiblen 2005-03-30 */ -// NOTICE: This code is CLOSED during construction and/or renovation! -// It is in active development, so DO NOT yet use in application code. -// This notice will be removed when the code is open for business. -// For development plan and status see: -// http://www.openscenegraph.org/index.php?page=Community.DevelopmentWork - - #include #include @@ -290,7 +283,7 @@ void Shader::PerContextShader::compileShader() if( ! _needsCompile ) return; _needsCompile = false; - GLint compiled; + GLint compiled = GL_FALSE; const char* sourceText = _shader->getShaderSource().c_str(); _extensions->glShaderSource( _glShaderHandle, 1, &sourceText, NULL ); _extensions->glCompileShader( _glShaderHandle ); diff --git a/src/osg/Uniform.cpp b/src/osg/Uniform.cpp index 94e48a23b..d6f9424cb 100644 --- a/src/osg/Uniform.cpp +++ b/src/osg/Uniform.cpp @@ -11,7 +11,7 @@ */ /* file: src/osg/Uniform.cpp - * author: Mike Weiblen 2005-03-23 + * author: Mike Weiblen 2005-03-30 */ // NOTICE: This code is CLOSED during construction and/or renovation! @@ -23,27 +23,241 @@ #include #include +#include using namespace osg; - /////////////////////////////////////////////////////////////////////////// -// osg::Uniform::Value +// osg::Uniform /////////////////////////////////////////////////////////////////////////// -Uniform::Value::Value( const char* name, Type type ) : - _name(name), _type(type), _isValid(false) -{} - - -Uniform::Value::Value( const Value& rhs ) : - _name(rhs._name), _type(rhs._type), _isValid(false) +Uniform::Uniform() : + _name(""), _type(UNDEFINED) { - if( rhs._isValid ) copyData(rhs); + // do not use this constructor in application code. + // it exists only because META_Object requires a trivial + // default constructor, but that is concept is meaningless for Uniform. + osg::notify(osg::FATAL) << "how got here?" << std::endl; } -const char* Uniform::Value::getTypename( Type t ) +Uniform::Uniform( const char* name, Type type ) : + _name(name), _type(type) +{ + switch( _type ) + { + case FLOAT: set( 0.0f ); break; + case FLOAT_VEC2: set( osg::Vec2() ); break; + case FLOAT_VEC3: set( osg::Vec3() ); break; + case FLOAT_VEC4: set( osg::Vec4() ); break; + case INT: set( 0 ); break; + case INT_VEC2: set( 0, 0 ); break; + case INT_VEC3: set( 0, 0, 0 ); break; + case INT_VEC4: set( 0, 0, 0, 0 ); break; + case BOOL: set( false ); break; + case BOOL_VEC2: set( false, false ); break; + case BOOL_VEC3: set( false, false, false ); break; + case BOOL_VEC4: set( false, false, false, false ); break; + // TODO case FLOAT_MAT2: + // TODO case FLOAT_MAT3: + case FLOAT_MAT4: set( osg::Matrix() ); break; + case SAMPLER_1D: set( 0 ); break; + case SAMPLER_2D: set( 0 ); break; + case SAMPLER_3D: set( 0 ); break; + case SAMPLER_CUBE: set( 0 ); break; + case SAMPLER_1D_SHADOW: set( 0 ); break; + case SAMPLER_2D_SHADOW: set( 0 ); break; + default: + osg::notify(osg::WARN) << "unhandled Uniform type" << std::endl; + break; + } +} + +Uniform::Uniform( const Uniform& rhs, const CopyOp& copyop ) : + Object(rhs,copyop), _name(rhs._name), _type(rhs._type) +{ + copyData( rhs ); +} + +/////////////////////////////////////////////////////////////////////////// + +int Uniform::compare(const Uniform& rhs) const +{ + if( this == &rhs ) return 0; + + if( _type < rhs._type ) return -1; + if( rhs._type < _type ) return 1; + + if( _name < rhs._name ) return -1; + if( rhs._name < _name ) return 1; + + return compareData( rhs ); +} + +int Uniform::compareData(const Uniform& rhs) const +{ + // caller must ensure that _type==rhs._type + + switch( repType(getType()) ) + { + case FLOAT: + if( _data.f1 < rhs._data.f1 ) return -1; + if( _data.f1 > rhs._data.f1 ) return 1; + return 0; + + case FLOAT_VEC2: + if( _data.f2[0] < rhs._data.f2[0] ) return -1; + if( _data.f2[0] > rhs._data.f2[0] ) return 1; + if( _data.f2[1] < rhs._data.f2[1] ) return -1; + if( _data.f2[1] > rhs._data.f2[1] ) return 1; + return 0; + + case FLOAT_VEC3: + if( _data.f3[0] < rhs._data.f3[0] ) return -1; + if( _data.f3[0] > rhs._data.f3[0] ) return 1; + if( _data.f3[1] < rhs._data.f3[1] ) return -1; + if( _data.f3[1] > rhs._data.f3[1] ) return 1; + if( _data.f3[2] < rhs._data.f3[2] ) return -1; + if( _data.f3[2] > rhs._data.f3[2] ) return 1; + return 0; + + case FLOAT_VEC4: + case FLOAT_MAT2: + if( _data.f4[0] < rhs._data.f4[0] ) return -1; + if( _data.f4[0] > rhs._data.f4[0] ) return 1; + if( _data.f4[1] < rhs._data.f4[1] ) return -1; + if( _data.f4[1] > rhs._data.f4[1] ) return 1; + if( _data.f4[2] < rhs._data.f4[2] ) return -1; + if( _data.f4[2] > rhs._data.f4[2] ) return 1; + if( _data.f4[3] < rhs._data.f4[3] ) return -1; + if( _data.f4[3] > rhs._data.f4[3] ) return 1; + return 0; + + case FLOAT_MAT3: + return memcmp(_data.f9, rhs._data.f9, sizeof(_data.f9)); + + case FLOAT_MAT4: + return memcmp(_data.f16, rhs._data.f16, sizeof(_data.f16)); + + case INT: + if( _data.i1 < rhs._data.i1 ) return -1; + if( _data.i1 > rhs._data.i1 ) return 1; + return 0; + + case INT_VEC2: + if( _data.i2[0] < rhs._data.i2[0] ) return -1; + if( _data.i2[0] > rhs._data.i2[0] ) return 1; + if( _data.i2[1] < rhs._data.i2[1] ) return -1; + if( _data.i2[1] > rhs._data.i2[1] ) return 1; + return 0; + + case INT_VEC3: + if( _data.i3[0] < rhs._data.i3[0] ) return -1; + if( _data.i3[0] > rhs._data.i3[0] ) return 1; + if( _data.i3[1] < rhs._data.i3[1] ) return -1; + if( _data.i3[1] > rhs._data.i3[1] ) return 1; + if( _data.i3[2] < rhs._data.i3[2] ) return -1; + if( _data.i3[2] > rhs._data.i3[2] ) return 1; + return 0; + + case INT_VEC4: + if( _data.i4[0] < rhs._data.i4[0] ) return -1; + if( _data.i4[0] > rhs._data.i4[0] ) return 1; + if( _data.i4[1] < rhs._data.i4[1] ) return -1; + if( _data.i4[1] > rhs._data.i4[1] ) return 1; + if( _data.i4[2] < rhs._data.i4[2] ) return -1; + if( _data.i4[2] > rhs._data.i4[2] ) return 1; + if( _data.i4[3] < rhs._data.i4[3] ) return -1; + if( _data.i4[3] > rhs._data.i4[3] ) return 1; + return 0; + + default: + osg::notify(osg::FATAL) << "how got here?" << std::endl; + return 0; + } +} + +void Uniform::copyData(const Uniform& rhs) +{ + // caller must ensure that _type==rhs._type + + int i; + switch( repType(getType()) ) + { + case FLOAT: + _data.f1 = rhs._data.f1; + break; + + case FLOAT_VEC2: + _data.f2[0] = rhs._data.f2[0]; + _data.f2[1] = rhs._data.f2[1]; + break; + + case FLOAT_VEC3: + _data.f3[0] = rhs._data.f3[0]; + _data.f3[1] = rhs._data.f3[1]; + _data.f3[2] = rhs._data.f3[2]; + break; + + case FLOAT_VEC4: + case FLOAT_MAT2: + _data.f4[0] = rhs._data.f4[0]; + _data.f4[1] = rhs._data.f4[1]; + _data.f4[2] = rhs._data.f4[2]; + _data.f4[3] = rhs._data.f4[3]; + break; + + case FLOAT_MAT3: + for(i=0;i<9;++i) _data.f9[i]=rhs._data.f9[i]; + break; + + case FLOAT_MAT4: + for(i=0;i<16;++i) _data.f16[i]=rhs._data.f16[i]; + break; + + case INT: + _data.i1 = rhs._data.i1; + break; + + case INT_VEC2: + _data.i2[0] = rhs._data.i2[0]; + _data.i2[1] = rhs._data.i2[1]; + break; + + case INT_VEC3: + _data.i3[0] = rhs._data.i3[0]; + _data.i3[1] = rhs._data.i3[1]; + _data.i3[2] = rhs._data.i3[2]; + break; + + case INT_VEC4: + _data.i4[0] = rhs._data.i4[0]; + _data.i4[1] = rhs._data.i4[1]; + _data.i4[2] = rhs._data.i4[2]; + _data.i4[3] = rhs._data.i4[3]; + break; + + default: + osg::notify(osg::FATAL) << "how got here?" << std::endl; + break; + } +} + +bool Uniform::isCompatibleType( Type t ) const +{ + if( t == getType() ) return true; + if( repType(t) == repType(getType()) ) return true; + + osg::notify(osg::WARN) + << "Cannot assign between Uniform types " << getTypename(t) + << " and " << getTypename(getType()) << std::endl; + return false; +} + +/////////////////////////////////////////////////////////////////////////// +// static methods + +const char* Uniform::getTypename( Type t ) { switch( t ) { @@ -72,150 +286,10 @@ const char* Uniform::Value::getTypename( Type t ) } } - -int Uniform::Value::compare(const Value& rhs) const +Uniform::Type Uniform::repType( Type t ) { - if( this == &rhs ) return 0; - - if( _type < rhs._type ) return -1; - if( rhs._type < _type ) return 1; - - // consider invalid values "less than" valid values - if( !_isValid && rhs._isValid ) return -1; - if( _isValid && !rhs._isValid ) return 1; - - if( _name < rhs._name ) return -1; - if( rhs._name < _name ) return 1; - - if( isValid() ) return compareData( rhs ); - - return 0; -} - - - -void Uniform::Value:: set( float f ) -{ - _data.f1 = f; - _isValid = true; -} - -void Uniform::Value:: set( const osg::Vec2& v2 ) -{ - _data.f2[0] = v2.x(); - _data.f2[1] = v2.y(); - _isValid = true; -} - -void Uniform::Value:: set( const osg::Vec3& v3 ) -{ - _data.f3[0] = v3.x(); - _data.f3[1] = v3.y(); - _data.f3[2] = v3.z(); - _isValid = true; -} - -void Uniform::Value:: set( const osg::Vec4& v4 ) -{ - _data.f4[0] = v4.x(); - _data.f4[1] = v4.y(); - _data.f4[2] = v4.z(); - _data.f4[3] = v4.w(); - _isValid = true; -} - -//TODO void Uniform::Value:: set( const osg::Matrix2& m2 ) - -//TODO void Uniform::Value:: set( const osg::Matrix3& m3 ) - -void Uniform::Value:: set( const osg::Matrix& m4 ) -{ // TODO verify if needs to be transposed - int n = 0; - for(int row=0; row<4; ++row) + switch( t ) { - for(int col=0; col<4; ++col) - { - _data.f16[n++] = m4(row,col); - } - } - _isValid = true; -} - -void Uniform::Value:: set( int i ) -{ - _data.i1 = i; - _isValid = true; -} - -//TODO void Uniform::Value:: set( int i0, int i1 ) - -//TODO void Uniform::Value:: set( int i0, int i1, int i2 ) - -//TODO void Uniform::Value:: set( int i0, int i1, int i2, int i3 ) - -//TODO void Uniform::Value:: set( bool b ) - -//TODO void Uniform::Value:: set( bool b0, bool b1 ) - -//TODO void Uniform::Value:: set( bool b0, bool b1, bool b2 ) - -//TODO void Uniform::Value:: set( bool b0, bool b1, bool b2, bool b3 ) - - - -int Uniform::Value::compareData(const Value& rhs) const -{ - // caller is responsible for ensuring that - // _type==rhs._type && _isValid && rhs._isValid - - switch( getType() ) - { - case FLOAT: - { - if( _data.f1 < rhs._data.f1 ) return -1; - if( _data.f1 > rhs._data.f1 ) return 1; - return 0; - } - - case FLOAT_VEC2: - { - if( _data.f2[0] < rhs._data.f2[0] ) return -1; - if( _data.f2[0] > rhs._data.f2[0] ) return 1; - if( _data.f2[1] < rhs._data.f2[1] ) return -1; - if( _data.f2[1] > rhs._data.f2[1] ) return 1; - return 0; - } - - case FLOAT_VEC3: - { - if( _data.f3[0] < rhs._data.f3[0] ) return -1; - if( _data.f3[0] > rhs._data.f3[0] ) return 1; - if( _data.f3[1] < rhs._data.f3[1] ) return -1; - if( _data.f3[1] > rhs._data.f3[1] ) return 1; - if( _data.f3[2] < rhs._data.f3[2] ) return -1; - if( _data.f3[2] > rhs._data.f3[2] ) return 1; - return 0; - } - - case FLOAT_VEC4: - case FLOAT_MAT2: - { - if( _data.f4[0] < rhs._data.f4[0] ) return -1; - if( _data.f4[0] > rhs._data.f4[0] ) return 1; - if( _data.f4[1] < rhs._data.f4[1] ) return -1; - if( _data.f4[1] > rhs._data.f4[1] ) return 1; - if( _data.f4[2] < rhs._data.f4[2] ) return -1; - if( _data.f4[2] > rhs._data.f4[2] ) return 1; - if( _data.f4[3] < rhs._data.f4[3] ) return -1; - if( _data.f4[3] > rhs._data.f4[3] ) return 1; - return 0; - } - - case FLOAT_MAT3: return memcmp(_data.f9, rhs._data.f9, sizeof(_data.f9)); - - case FLOAT_MAT4: return memcmp(_data.f16, rhs._data.f16, sizeof(_data.f16)); - - case INT: case BOOL: case SAMPLER_1D: case SAMPLER_2D: @@ -223,238 +297,142 @@ int Uniform::Value::compareData(const Value& rhs) const case SAMPLER_CUBE: case SAMPLER_1D_SHADOW: case SAMPLER_2D_SHADOW: - { - if( _data.i1 < rhs._data.i1 ) return -1; - if( _data.i1 > rhs._data.i1 ) return 1; - return 0; - } + return INT; - case INT_VEC2: case BOOL_VEC2: - { - if( _data.i2[0] < rhs._data.i2[0] ) return -1; - if( _data.i2[0] > rhs._data.i2[0] ) return 1; - if( _data.i2[1] < rhs._data.i2[1] ) return -1; - if( _data.i2[1] > rhs._data.i2[1] ) return 1; - return 0; - } + return INT_VEC2; - case INT_VEC3: case BOOL_VEC3: - { - if( _data.i3[0] < rhs._data.i3[0] ) return -1; - if( _data.i3[0] > rhs._data.i3[0] ) return 1; - if( _data.i3[1] < rhs._data.i3[1] ) return -1; - if( _data.i3[1] > rhs._data.i3[1] ) return 1; - if( _data.i3[2] < rhs._data.i3[2] ) return -1; - if( _data.i3[2] > rhs._data.i3[2] ) return 1; - return 0; - } + return INT_VEC3; - case INT_VEC4: case BOOL_VEC4: - { - if( _data.i4[0] < rhs._data.i4[0] ) return -1; - if( _data.i4[0] > rhs._data.i4[0] ) return 1; - if( _data.i4[1] < rhs._data.i4[1] ) return -1; - if( _data.i4[1] > rhs._data.i4[1] ) return 1; - if( _data.i4[2] < rhs._data.i4[2] ) return -1; - if( _data.i4[2] > rhs._data.i4[2] ) return 1; - if( _data.i4[3] < rhs._data.i4[3] ) return -1; - if( _data.i4[3] > rhs._data.i4[3] ) return 1; - return 0; - } + return INT_VEC4; default: - osg::notify(osg::INFO) << "how got here?" << std::endl; - return 0; - } -} - - -void Uniform::Value::copyData(const Value& rhs) -{ - // caller is responsible for ensuring that - // _type==rhs._type && rhs._isValid - - _isValid = true; - switch( getType() ) - { - case FLOAT: - _data.f1 = rhs._data.f1; - break; - - case FLOAT_VEC2: - _data.f2[0] = rhs._data.f2[0]; - _data.f2[1] = rhs._data.f2[1]; - break; - - case FLOAT_VEC3: - _data.f3[0] = rhs._data.f3[0]; - _data.f3[1] = rhs._data.f3[1]; - _data.f3[2] = rhs._data.f3[2]; - break; - - case FLOAT_VEC4: - case FLOAT_MAT2: - _data.f4[0] = rhs._data.f4[0]; - _data.f4[1] = rhs._data.f4[1]; - _data.f4[2] = rhs._data.f4[2]; - _data.f4[3] = rhs._data.f4[3]; - break; - - case FLOAT_MAT3: - for(int i=0;i<9;++i) _data.f9[i]=rhs._data.f9[i]; - break; - - case FLOAT_MAT4: - for(int i=0;i<16;++i) _data.f16[i]=rhs._data.f16[i]; - break; - - case INT: - case BOOL: - case SAMPLER_1D: - case SAMPLER_2D: - case SAMPLER_3D: - case SAMPLER_CUBE: - case SAMPLER_1D_SHADOW: - case SAMPLER_2D_SHADOW: - _data.i1 = rhs._data.i1; - break; - - case INT_VEC2: - case BOOL_VEC2: - _data.i2[0] = rhs._data.i2[0]; - _data.i2[1] = rhs._data.i2[1]; - break; - - case INT_VEC3: - case BOOL_VEC3: - _data.i3[0] = rhs._data.i3[0]; - _data.i3[1] = rhs._data.i3[1]; - _data.i3[2] = rhs._data.i3[2]; - break; - - case INT_VEC4: - case BOOL_VEC4: - _data.i4[0] = rhs._data.i4[0]; - _data.i4[1] = rhs._data.i4[1]; - _data.i4[2] = rhs._data.i4[2]; - _data.i4[3] = rhs._data.i4[3]; - break; - - default: - osg::notify(osg::INFO) << "how got here?" << std::endl; - break; + return t; } } /////////////////////////////////////////////////////////////////////////// -// osg::Uniform -/////////////////////////////////////////////////////////////////////////// - -Uniform::Uniform() : - _value( "", Value::UNDEFINED ) -{ - // do not use this constructor in application code! - // it exists only because StateAttribute _requires_ a trivial default - // constructor, but that is concept is meaningless for Uniform. -} - - -Uniform::Uniform( const char* name, Value::Type type ) : - _value( name, type ) -{} - - -Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) : - Object(gu,copyop), - _value( gu._value ) -{ -} - +// value constructors Uniform::Uniform( const char* name, float f ) : - _value( name, Value::FLOAT ) + _name(name), _type(FLOAT) { - _value.set( f ); + set( f ); } Uniform::Uniform( const char* name, const osg::Vec2& v2 ) : - _value( name, Value::FLOAT_VEC2 ) + _name(name), _type(FLOAT_VEC2) { - _value.set( v2 ); + set( v2 ); } Uniform::Uniform( const char* name, const osg::Vec3& v3 ) : - _value( name, Value::FLOAT_VEC3 ) + _name(name), _type(FLOAT_VEC3) { - _value.set( v3 ); + set( v3 ); } Uniform::Uniform( const char* name, const osg::Vec4& v4 ) : - _value( name, Value::FLOAT_VEC4 ) + _name(name), _type(FLOAT_VEC4) { - _value.set( v4 ); + set( v4 ); } -//TODO Uniform::Uniform( const char* name, const osg::Matrix2& m2 ) +//Uniform::Uniform( const char* name, const osg::Matrix2& m2 ) -//TODO Uniform::Uniform( const char* name, const osg::Matrix3& m3 ) +//Uniform::Uniform( const char* name, const osg::Matrix3& m3 ) Uniform::Uniform( const char* name, const osg::Matrix& m4 ) : - _value( name, Value::FLOAT_MAT4 ) + _name(name), _type(FLOAT_MAT4) { - _value.set( m4 ); + set( m4 ); } Uniform::Uniform( const char* name, int i ) : - _value( name, Value::INT ) + _name(name), _type(INT) { - _value.set( i ); + set( i ); } -//TODO Uniform::Uniform( const char* name, int i0, int i1 ) +Uniform::Uniform( const char* name, int i0, int i1 ) : + _name(name), _type(INT_VEC2) +{ + set( i0, i1 ); +} -//TODO Uniform::Uniform( const char* name, int i0, int i1, int i2 ) +Uniform::Uniform( const char* name, int i0, int i1, int i2 ) : + _name(name), _type(INT_VEC3) +{ + set( i0, i1, i2 ); +} -//TODO Uniform::Uniform( const char* name, int i0, int i1, int i2, int i3 ) +Uniform::Uniform( const char* name, int i0, int i1, int i2, int i3 ) : + _name(name), _type(INT_VEC4) +{ + set( i0, i1, i2, i3 ); +} -//TODO Uniform::Uniform( const char* name, bool b ) +Uniform::Uniform( const char* name, bool b ) : + _name(name), _type(BOOL) +{ + set( b ); +} -//TODO Uniform::Uniform( const char* name, bool b0, bool b1 ) +Uniform::Uniform( const char* name, bool b0, bool b1 ) : + _name(name), _type(BOOL_VEC2) +{ + set( b0, b1 ); +} -//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2 ) +Uniform::Uniform( const char* name, bool b0, bool b1, bool b2 ) : + _name(name), _type(BOOL_VEC3) +{ + set( b0, b1, b2 ); +} -//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 ) +Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 ) : + _name(name), _type(BOOL_VEC4) +{ + set( b0, b1, b2, b3 ); +} +/////////////////////////////////////////////////////////////////////////// +// value assignment bool Uniform::set( float f ) { - if( ! isCompatibleType( Value::FLOAT ) ) return false; - _value.set( f ); + if( ! isCompatibleType(FLOAT) ) return false; + _data.f1 = f; return true; } bool Uniform::set( const osg::Vec2& v2 ) { - if( ! isCompatibleType( Value::FLOAT_VEC2 ) ) return false; - _value.set( v2 ); + if( ! isCompatibleType(FLOAT_VEC2) ) return false; + _data.f2[0] = v2.x(); + _data.f2[1] = v2.y(); return true; } bool Uniform::set( const osg::Vec3& v3 ) { - if( ! isCompatibleType( Value::FLOAT_VEC3 ) ) return false; - _value.set( v3 ); + if( ! isCompatibleType(FLOAT_VEC3) ) return false; + _data.f3[0] = v3.x(); + _data.f3[1] = v3.y(); + _data.f3[2] = v3.z(); return true; } bool Uniform::set( const osg::Vec4& v4 ) { - if( ! isCompatibleType( Value::FLOAT_VEC4 ) ) return false; - _value.set( v4 ); + if( ! isCompatibleType(FLOAT_VEC4) ) return false; + _data.f4[0] = v4.x(); + _data.f4[1] = v4.y(); + _data.f4[2] = v4.z(); + _data.f4[3] = v4.w(); return true; } @@ -464,43 +442,207 @@ bool Uniform::set( const osg::Vec4& v4 ) bool Uniform::set( const osg::Matrix& m4 ) { - if( ! isCompatibleType( Value::FLOAT_MAT4 ) ) return false; - _value.set( m4 ); + if( ! isCompatibleType(FLOAT_MAT4) ) return false; + int n = 0; + for(int row=0; row<4; ++row) + { + for(int col=0; col<4; ++col) + { + _data.f16[n++] = m4(row,col); + } + } return true; } bool Uniform::set( int i ) { - if( ! isCompatibleType( Value::INT ) ) return false; - _value.set( i ); + if( ! isCompatibleType(INT) ) return false; + _data.i1 = i; return true; } -//TODO bool Uniform::set( int i0, int i1 ) - -//TODO bool Uniform::set( int i0, int i1, int i2 ) - -//TODO bool Uniform::set( int i0, int i1, int i2, int i3 ) - -//TODO bool Uniform::set( bool b ) - -//TODO bool Uniform::set( bool b0, bool b1 ); - -//TODO bool Uniform::set( bool b0, bool b1, bool b2 ) - -//TODO bool Uniform::set( bool b0, bool b1, bool b2, bool b3 ) - - -bool Uniform::isCompatibleType( Value::Type t ) const +bool Uniform::set( int i0, int i1 ) { - if( t == _value.getType() ) return true; + if( ! isCompatibleType(INT_VEC2) ) return false; + _data.i2[0] = i0; + _data.i2[1] = i1; + return true; +} - osg::notify(osg::WARN) << - "Cannot assign " << _value.getTypename(t) << - " to Uniform \"" << _value.getName() << - "\" of type " << _value.getTypename( _value.getType() ) << - std::endl; - return false; +bool Uniform::set( int i0, int i1, int i2 ) +{ + if( ! isCompatibleType(INT_VEC3) ) return false; + _data.i3[0] = i0; + _data.i3[1] = i1; + _data.i3[2] = i2; + return true; +} + +bool Uniform::set( int i0, int i1, int i2, int i3 ) +{ + if( ! isCompatibleType(INT_VEC4) ) return false; + _data.i4[0] = i0; + _data.i4[1] = i1; + _data.i4[2] = i2; + _data.i4[3] = i3; + return true; +} + +bool Uniform::set( bool b ) +{ + if( ! isCompatibleType(BOOL) ) return false; + _data.i1 = b; + return true; +} + +bool Uniform::set( bool b0, bool b1 ) +{ + if( ! isCompatibleType(BOOL_VEC2) ) return false; + _data.i2[0] = b0; + _data.i2[1] = b1; + return true; +} + +bool Uniform::set( bool b0, bool b1, bool b2 ) +{ + if( ! isCompatibleType(BOOL_VEC3) ) return false; + _data.i3[0] = b0; + _data.i3[1] = b1; + _data.i3[2] = b2; + return true; +} + +bool Uniform::set( bool b0, bool b1, bool b2, bool b3 ) +{ + if( ! isCompatibleType(BOOL_VEC4) ) return false; + _data.i4[0] = b0; + _data.i4[1] = b1; + _data.i4[2] = b2; + _data.i4[3] = b3; + return true; +} + +/////////////////////////////////////////////////////////////////////////// +// value query + +bool Uniform::get( float& f ) const +{ + if( ! isCompatibleType(FLOAT) ) return false; + f = _data.f1; + return true; +} + +bool Uniform::get( osg::Vec2& v2 ) const +{ + if( ! isCompatibleType(FLOAT_VEC2) ) return false; + v2.x() = _data.f2[0]; + v2.y() = _data.f2[1]; + return true; +} + +bool Uniform::get( osg::Vec3& v3 ) const +{ + if( ! isCompatibleType(FLOAT_VEC3) ) return false; + v3.x() = _data.f3[0]; + v3.y() = _data.f3[1]; + v3.z() = _data.f3[2]; + return true; +} + +bool Uniform::get( osg::Vec4& v4 ) const +{ + if( ! isCompatibleType(FLOAT_VEC4) ) return false; + v4.x() = _data.f4[0]; + v4.y() = _data.f4[1]; + v4.z() = _data.f4[2]; + v4.w() = _data.f4[3]; + return true; +} + +//TODO bool Uniform::get( osg::Matrix2& m2 ) const + +//TODO bool Uniform::get( osg::Matrix3& m3 ) const + +bool Uniform::get( osg::Matrix& m4 ) const +{ + if( ! isCompatibleType(FLOAT_MAT4) ) return false; + int n = 0; + for(int row=0; row<4; ++row) + { + for(int col=0; col<4; ++col) + { + m4(row,col) = _data.f16[n++]; + } + } + return true; +} + +bool Uniform::get( int& i ) const +{ + if( ! isCompatibleType(INT) ) return false; + i = _data.i1; + return true; +} + +bool Uniform::get( int& i0, int& i1 ) const +{ + if( ! isCompatibleType(INT_VEC2) ) return false; + i0 = _data.i2[0]; + i1 = _data.i2[1]; + return true; +} + +bool Uniform::get( int& i0, int& i1, int& i2 ) const +{ + if( ! isCompatibleType(INT_VEC3) ) return false; + i0 = _data.i3[0]; + i1 = _data.i3[1]; + i2 = _data.i3[2]; + return true; +} + +bool Uniform::get( int& i0, int& i1, int& i2, int& i3 ) const +{ + if( ! isCompatibleType(INT_VEC4) ) return false; + i0 = _data.i4[0]; + i1 = _data.i4[1]; + i2 = _data.i4[2]; + i3 = _data.i4[3]; + return true; +} + +bool Uniform::get( bool& b ) const +{ + if( ! isCompatibleType(BOOL) ) return false; + b = (_data.i1 != 0); + return true; +} + +bool Uniform::get( bool& b0, bool& b1 ) const +{ + if( ! isCompatibleType(BOOL_VEC2) ) return false; + b0 = (_data.i2[0] != 0); + b1 = (_data.i2[1] != 0); + return true; +} + +bool Uniform::get( bool& b0, bool& b1, bool& b2 ) const +{ + if( ! isCompatibleType(BOOL_VEC3) ) return false; + b0 = (_data.i3[0] != 0); + b1 = (_data.i3[1] != 0); + b2 = (_data.i3[2] != 0); + return true; +} + +bool Uniform::get( bool& b0, bool& b1, bool& b2, bool& b3 ) const +{ + if( ! isCompatibleType(BOOL_VEC4) ) return false; + b0 = (_data.i4[0] != 0); + b1 = (_data.i4[1] != 0); + b2 = (_data.i4[2] != 0); + b3 = (_data.i4[3] != 0); + return true; } /*EOF*/