From Mike Weiblen,

"updates for GLSL core integration:
Code compiles and runs on win32.
Basic functionality of Program and Shader in place.
Program derived from StateAttribute.
Uniform value propagation is not yet functional (in development)
Includes some patches by Nathan Cournia.
includes example testcase to demo use of new classes."
This commit is contained in:
Robert Osfield
2005-03-24 09:37:45 +00:00
parent 2ab78cfe38
commit 7883574d28
9 changed files with 492 additions and 314 deletions

View File

@@ -1,5 +1,6 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
* Copyright (C) 2003-2005 3Dlabs Inc. Ltd.
* Copyright (C) 2004-2005 Nathan Cournia
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial
@@ -12,7 +13,7 @@
*/
/* file: src/osg/Program.cpp
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -28,11 +29,11 @@
#include <osg/Notify>
#include <osg/State>
#include <osg/Timer>
#include <osg/FrameStamp>
#include <osg/buffered_value>
#include <osg/ref_ptr>
#include <osg/Program>
#include <osg/Shader>
#include <osg/Uniform>
#include <osg/GLExtensions>
#include <OpenThreads/ScopedLock>
@@ -41,15 +42,7 @@
using namespace osg;
///////////////////////////////////////////////////////////////////////////
// static cache of GL objects flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std::list<GLuint> GlProgramHandleList;
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
static OpenThreads::Mutex s_mutex_deletedGL2ObjectCache;
static DeletedGlProgramCache s_deletedGlProgramCache;
// Extension function pointers for OpenGL v2.0
GL2Extensions::GL2Extensions()
{
@@ -1855,19 +1848,28 @@ bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const
return (strLen > 0);
}
///////////////////////////////////////////////////////////////////////////
// static cache of glPrograms flagged for deletion, which will actually
// be deleted in the correct GL context.
void Program::deleteProgram(unsigned int contextID, GLuint program)
typedef std::list<GLuint> GlProgramHandleList;
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
static OpenThreads::Mutex s_mutex_deletedGlProgramCache;
static DeletedGlProgramCache s_deletedGlProgramCache;
void Program::deleteGlProgram(unsigned int contextID, GLuint program)
{
if( program )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
// add program to the cache for the appropriate context.
// add glProgram to the cache for the appropriate context.
s_deletedGlProgramCache[contextID].push_back(program);
}
}
void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTime*/, double& availableTime)
void Program::flushDeletedGlPrograms(unsigned int contextID,double /*currentTime*/, double& availableTime)
{
// if no time available don't try to flush objects.
if (availableTime<=0.0) return;
@@ -1880,7 +1882,7 @@ void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTim
double elapsedTime = 0.0;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
DeletedGlProgramCache::iterator citr = s_deletedGlProgramCache.find(contextID);
if( citr != s_deletedGlProgramCache.end() )
@@ -1912,7 +1914,7 @@ Program::Program()
Program::Program(const Program& rhs, const osg::CopyOp& copyop):
osg::Object(rhs, copyop)
osg::StateAttribute(rhs, copyop)
{
osg::notify(osg::FATAL) << "how got here?" << std::endl;
}
@@ -1920,19 +1922,15 @@ Program::Program(const Program& rhs, const osg::CopyOp& copyop):
Program::~Program()
{
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
// inform any attached Shaders that we're going away
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
if( ! _pcpoList[cxt] ) continue;
PerContextProgObj* pcpo = _pcpoList[cxt].get();
deleteProgram( cxt, pcpo->getHandle() );
// TODO add shader objects to delete list.
_pcpoList[cxt] = 0;
_shaderList[i]->removeProgramRef( this );
}
}
int Program::compare(const osg::Program& sa) const
int Program::compare(const osg::StateAttribute& sa) const
{
// check the types are equal and then create the rhs variable
// used by the COMPARE_StateAttribute_Paramter macro's below.
@@ -1941,8 +1939,8 @@ int Program::compare(const osg::Program& sa) const
if( _shaderList.size() < rhs._shaderList.size() ) return -1;
if( rhs._shaderList.size() < _shaderList.size() ) return 1;
if( getComment() < rhs.getComment() ) return -1;
if( rhs.getComment() < getComment() ) return 1;
if( getName() < rhs.getName() ) return -1;
if( rhs.getName() < getName() ) return 1;
ShaderList::const_iterator litr=_shaderList.begin();
ShaderList::const_iterator ritr=rhs._shaderList.begin();
@@ -1954,73 +1952,79 @@ int Program::compare(const osg::Program& 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.
}
void Program::compileGLObjects( osg::State& state ) const
{
if( _shaderList.empty() ) return;
if( isFixedFunction() ) return;
const unsigned int contextID = state.getContextID();
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
if( ! extensions->isGlslSupported() )
{
osg::notify(osg::WARN) << "GLSL not supported by OpenGL driver" << std::endl;
return;
}
PerContextProgObj* pcpo = getPCPO( contextID );
for( unsigned int i=0; i < _shaderList.size() ; ++i )
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
_shaderList[i]->compileShader( contextID );
}
pcpo->linkProgram();
// TODO pcpo->releaseActiveUniformList();
// TODO pcpo->buildActiveUniformList;
// TODO regenerate pcpo->_activeAttribList;
getPCP( contextID )->linkProgram();
}
void Program::dirtyProgram()
{
// mark all PCPOs as needing a relink
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
// mark our PCPs as needing relink
for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
{
if( ! _pcpoList[cxt] ) continue;
PerContextProgObj* pcpo = _pcpoList[cxt].get();
pcpo->markAsDirty();
if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
}
}
void Program::dirtyShaders()
{
// mark all attached Shaders as needing a rebuild
for( unsigned int i=0; i < _shaderList.size() ; ++i )
{
_shaderList[i]->dirtyShader();
}
}
void Program::releaseGLObjects(osg::State* state) const
{
if (!state) const_cast<Program*>(this)->dirtyShaders();
else
{
unsigned int contextID = state->getContextID();
const_cast<Program*>(this)->_shaderList[contextID]->dirtyShader();
}
// TODO
}
void Program::addShader( Shader* shader )
bool Program::addShader( Shader* shader )
{
// Shader can only be added once to a Program
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
if( shader == _shaderList[i].get() ) return false;
}
shader->addProgramRef( this );
_shaderList.push_back( shader );
shader->addProgObjRef( this );
dirtyProgram();
return true;
}
bool Program::removeShader( Shader* shader )
{
// Shader must exist to be removed.
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
if( shader == _shaderList[i].get() )
{
shader->removeProgramRef( this );
_shaderList[i] = 0;
dirtyProgram();
return true;
}
}
return false;
}
void Program::bindAttribLocation( GLuint index, const char* name )
{
// TODO add to binding list
dirtyProgram();
}
@@ -2031,44 +2035,55 @@ void Program::apply( osg::State& state ) const
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
if( ! extensions->isGlslSupported() ) return;
// A Program object having no attached Shaders is a special
// case: it indicates that programmable shading is to be disabled,
// and thus use GL 1.x "fixed functionality" rendering.
if( _shaderList.empty() )
if( isFixedFunction() )
{
extensions->glUseProgram( 0 );
return;
}
PerContextProgObj* pcpo = getPCPO( contextID );
if( pcpo->isDirty() ) compileGLObjects( state );
if( pcpo->isDirty() )
PerContextProgram* pcp = getPCP( contextID );
if( pcp->needsLink() ) compileGLObjects( state );
if( pcp->isLinked() )
{
// _still_ dirty, something went wrong
extensions->glUseProgram( 0 );
pcp->useProgram();
pcp->applyUniforms( state );
}
else
{
pcpo->useProgram();
pcpo->applyUniforms( state );
// program not usable, fallback to fixed function.
extensions->glUseProgram( 0 );
}
}
Program::PerContextProgObj* Program::getPCPO(unsigned int contextID) const
Program::PerContextProgram* Program::getPCP(unsigned int contextID) const
{
if( ! _pcpoList[contextID].valid() )
if( ! _pcpList[contextID].valid() )
{
_pcpoList[contextID] = new PerContextProgObj( this, contextID );
_pcpList[contextID] = new PerContextProgram( this, contextID );
// attach all PCSOs to this new PCPO
for( unsigned int i=0; i < _shaderList.size() ; ++i )
// attach all PCSs to this new PCP
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
_shaderList[i]->attachShader( contextID, _pcpoList[contextID]->getHandle() );
_shaderList[i]->attachShader( contextID, _pcpList[contextID]->getHandle() );
}
}
return _pcpoList[contextID].get();
return _pcpList[contextID].get();
}
bool Program::isFixedFunction() const
{
// A Program object having no attached Shaders is a special case:
// it indicates that programmable shading is to be disabled,
// and thus use GL 1.x "fixed functionality" rendering.
return _shaderList.empty();
}
void Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
{
getPCP( contextID )->getInfoLog( log );
}
@@ -2083,67 +2098,69 @@ Program::ActiveUniform::ActiveUniform( const GLchar* name, GLenum type ) :
///////////////////////////////////////////////////////////////////////////
// osg::Program::PerContextProgObj
// PCPO is an OSG abstraction of the per-context glProgram
// osg::Program::PerContextProgram
// PCP is an OSG abstraction of the per-context glProgram
///////////////////////////////////////////////////////////////////////////
Program::PerContextProgObj::PerContextProgObj(const Program* program, unsigned int contextID ) :
Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID ) :
osg::Referenced(),
_contextID( contextID )
{
_program = program;
_extensions = GL2Extensions::Get( _contextID, true );
_glProgramHandle = _extensions->glCreateProgram();
markAsDirty();
requestLink();
}
Program::PerContextProgObj::PerContextProgObj(const PerContextProgObj& rhs) :
osg::Referenced(),
_contextID( rhs._contextID )
{
_program = rhs._program;
_extensions = rhs._extensions;
_glProgramHandle = rhs._glProgramHandle ;
_dirty = rhs._dirty;
}
Program::PerContextProgObj::~PerContextProgObj()
Program::PerContextProgram::~PerContextProgram()
{
Program::deleteGlProgram( _contextID, _glProgramHandle );
}
void Program::PerContextProgObj::markAsDirty()
void Program::PerContextProgram::requestLink()
{
// TODO releaseActiveUniformList();
_dirty = true;
_needsLink = true;
_isLinked = false;
}
void Program::PerContextProgObj::linkProgram()
void Program::PerContextProgram::linkProgram()
{
if( ! _needsLink ) return;
_needsLink = false;
// TODO for( each itr in binding list )
// {
// _extensions->glBindAttribLocation( _glProgramHandle, index, name );
// }
GLint linked;
_extensions->glLinkProgram( _glProgramHandle );
_extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
_dirty = (linked == 0);
if( _dirty )
_isLinked = (linked == GL_TRUE);
if( ! _isLinked )
{
// _still_ dirty, something went wrong
// link failed
std::string infoLog;
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
getInfoLog( infoLog );
osg::notify(osg::WARN) << "glLinkProgram FAILED:\n" << infoLog << std::endl;
}
}
void Program::PerContextProgram::getInfoLog( std::string& infoLog ) const
{
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
}
void Program::PerContextProgObj::useProgram() const
void Program::PerContextProgram::useProgram() const
{
_extensions->glUseProgram( _glProgramHandle );
}
void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
void Program::PerContextProgram::applyUniforms( osg::State& /*state*/ ) const
{
bool uniformDoesNeedSetting = true;
@@ -2161,3 +2178,5 @@ void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
// TODO set the uniform value on the currently active glProgram.
}
}
/*EOF*/

View File

@@ -1,5 +1,6 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
* Copyright (C) 2003-2005 3Dlabs Inc. Ltd.
* Copyright (C) 2004-2005 Nathan Cournia
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial
@@ -11,8 +12,8 @@
*
*/
/* file: src/osg/Program.cpp
* author: Mike Weiblen 2005-02-20
/* file: src/osg/Shader.cpp
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -39,12 +40,61 @@
using namespace osg;
///////////////////////////////////////////////////////////////////////////
// static cache of glShaders flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std::list<GLuint> GlShaderHandleList;
typedef std::map<unsigned int, GlShaderHandleList> DeletedGlShaderCache;
static OpenThreads::Mutex s_mutex_deletedGL2ShaderCache;
static OpenThreads::Mutex s_mutex_deletedGlShaderCache;
static DeletedGlShaderCache s_deletedGlShaderCache;
void Shader::deleteGlShader(unsigned int contextID, GLuint shader)
{
if( shader )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
// add glShader to the cache for the appropriate context.
s_deletedGlShaderCache[contextID].push_back(shader);
}
}
void Shader::flushDeletedGlShaders(unsigned int contextID,double /*currentTime*/, double& availableTime)
{
// if no time available don't try to flush objects.
if (availableTime<=0.0) return;
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
if( ! extensions->isGlslSupported() ) return;
const osg::Timer& timer = *osg::Timer::instance();
osg::Timer_t start_tick = timer.tick();
double elapsedTime = 0.0;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
DeletedGlShaderCache::iterator citr = s_deletedGlShaderCache.find(contextID);
if( citr != s_deletedGlShaderCache.end() )
{
GlShaderHandleList& pList = citr->second;
for(GlShaderHandleList::iterator titr=pList.begin();
titr!=pList.end() && elapsedTime<availableTime;
)
{
extensions->glDeleteShader( *titr );
titr = pList.erase( titr );
elapsedTime = timer.delta_s(start_tick,timer.tick());
}
}
}
availableTime -= elapsedTime;
}
///////////////////////////////////////////////////////////////////////////
// osg::Shader
///////////////////////////////////////////////////////////////////////////
@@ -55,54 +105,49 @@ Shader::Shader(Type type, const char* sourceText) :
setShaderSource( sourceText );
}
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
Object( rhs, copyop ),
_type(rhs._type)
Shader::Shader() :
_type(VERTEX)
{
// TODO this default constructor is inappropriate for the Shader class.
// It exists for now because it is required by META_OBject
osg::notify(osg::FATAL) << "how got here?" << std::endl;
}
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
osg::Object( rhs, copyop ),
_type(rhs._type),
_name(rhs._name),
_shaderSource(rhs._shaderSource)
{
/*TODO*/
}
Shader::~Shader()
{
/*TODO*/
}
int Shader::compare(const Shader& rhs) const
{
if( this == &rhs ) return 0;
if( getComment() < rhs.getComment() ) return -1;
if( rhs.getComment() < getComment() ) return 1;
if( getType() < rhs.getType() ) return -1;
if( rhs.getType() < getType() ) return 1;
if( getName() < rhs.getName() ) return -1;
if( rhs.getName() < getName() ) return 1;
if( getShaderSource() < rhs.getShaderSource() ) return -1;
if( rhs.getShaderSource() < getShaderSource() ) return 1;
return 0;
}
void Shader::dirtyShader()
{
// mark each PCSO as needing a recompile
for( unsigned int cxt=0; cxt < _pcsoList.size(); ++cxt )
{
if( ! _pcsoList[cxt] ) continue;
PerContextShaderObj* pcso = _pcsoList[cxt].get();
pcso->markAsDirty();
}
// also mark-as-dirty the Programs we're attach to
for( unsigned int i=0; i < _programList.size(); ++i )
{
_programList[i]->dirtyProgram();
}
}
void Shader::setShaderSource( const char* sourceText )
{
_shaderSource = ( sourceText ? sourceText : "" );
dirtyShader();
}
bool Shader::loadShaderSourceFromFile( const char* fileName )
{
std::ifstream sourceFile;
@@ -143,97 +188,138 @@ const char* Shader::getTypename() const
void Shader::compileShader( unsigned int contextID ) const
{
PerContextShaderObj* pcso = getPCSO( contextID );
if( pcso->isDirty() ) pcso->compileShader();
getPCS( contextID )->compileShader();
}
Shader::PerContextShaderObj* Shader::getPCSO(unsigned int contextID) const
Shader::PerContextShader* Shader::getPCS(unsigned int contextID) const
{
if( ! _pcsoList[contextID].valid() )
if( ! _pcsList[contextID].valid() )
{
_pcsoList[contextID] = new PerContextShaderObj( this, contextID );
_pcsList[contextID] = new PerContextShader( this, contextID );
}
return _pcsoList[contextID].get();
return _pcsList[contextID].get();
}
void Shader::attachShader(unsigned int contextID, GLuint program) const
{
getPCSO( contextID )->attachShader( program );
getPCS( contextID )->attachShader( program );
}
void Shader::addProgObjRef( Program* program )
void Shader::getGlShaderInfoLog(unsigned int contextID, std::string& log) const
{
_programList.push_back( program );
getPCS( contextID )->getInfoLog( log );
}
void Shader::deleteShader(unsigned int contextID, GLuint shader)
/////////////////////////////////////////////////////////////////////////
// A Shader stores pointers to the osg::Programs to which it is attached,
// so that if the Shader is marked for recompilation with
// Shader::dirtyShader(), the upstream Program can be marked for relinking.
// _programSet does not use ref_ptrs, as that would cause a cyclical
// dependency, and neither the Program nor the Shader would be deleted.
bool Shader::addProgramRef( Program* program )
{
if( shader )
ProgramSet::iterator itr = _programSet.find(program);
if( itr != _programSet.end() ) return false;
_programSet.insert( program );
return true;
}
bool Shader::removeProgramRef( Program* program )
{
ProgramSet::iterator itr = _programSet.find(program);
if( itr == _programSet.end() ) return false;
_programSet.erase( itr );
return true;
}
void Shader::dirtyShader()
{
// Mark our PCSs as needing recompilation.
for( unsigned int cxt=0; cxt < _pcsList.size(); ++cxt )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ShaderCache);
if( _pcsList[cxt].valid() ) _pcsList[cxt]->requestCompile();
}
// add shader to the cache for the appropriate context.
s_deletedGlShaderCache[contextID].push_back(shader);
// Also mark Programs that depend on us as needing relink.
for( ProgramSet::iterator itr = _programSet.begin();
itr != _programSet.end(); ++itr )
{
(*itr)->dirtyProgram();
}
}
///////////////////////////////////////////////////////////////////////////
// osg::Shader::PerContextShaderObj
// PCSO is the OSG abstraction of the per-context glShader
/////////////////////////////////////////////////////////////////////////
// osg::Shader::PerContextShader
// PCS is the OSG abstraction of the per-context glShader
///////////////////////////////////////////////////////////////////////////
Shader::PerContextShaderObj::PerContextShaderObj(const Shader* shader, unsigned int contextID) :
Shader::PerContextShader::PerContextShader(const Shader* shader, unsigned int contextID) :
osg::Referenced(),
_contextID( contextID )
{
_shader = shader;
_extensions = GL2Extensions::Get( _contextID, true );
_glShaderHandle = _extensions->glCreateShader( shader->getType() );
markAsDirty();
requestCompile();
}
Shader::PerContextShaderObj::PerContextShaderObj(const PerContextShaderObj& rhs) :
osg::Referenced(),
_contextID( rhs._contextID )
Shader::PerContextShader::~PerContextShader()
{
_shader = rhs._shader;
_extensions = rhs._extensions;
_glShaderHandle = rhs._glShaderHandle;
_dirty = rhs._dirty;
Shader::deleteGlShader( _contextID, _glShaderHandle );
}
Shader::PerContextShaderObj::~PerContextShaderObj()
void Shader::PerContextShader::requestCompile()
{
_needsCompile = true;
_isCompiled = false;
}
void Shader::PerContextShaderObj::compileShader()
void Shader::PerContextShader::compileShader()
{
if( ! _needsCompile ) return;
_needsCompile = false;
GLint compiled;
const char* sourceText = _shader->getShaderSource().c_str();
_extensions->glShaderSource( _glShaderHandle, 1, &sourceText, NULL );
_extensions->glCompileShader( _glShaderHandle );
_extensions->glGetShaderiv( _glShaderHandle, GL_COMPILE_STATUS, &compiled );
_dirty = (compiled == 0);
if( _dirty )
_isCompiled = (compiled == GL_TRUE);
if( ! _isCompiled )
{
// _still_ dirty, something went wrong
// compile failed
std::string infoLog;
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
getInfoLog( infoLog );
osg::notify(osg::WARN) << _shader->getTypename() <<
" glCompileShader FAILED:\n" << infoLog << std::endl;
}
}
void Shader::PerContextShaderObj::attachShader(GLuint program) const
void Shader::PerContextShader::getInfoLog( std::string& infoLog ) const
{
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
}
void Shader::PerContextShader::attachShader(GLuint program) const
{
_extensions->glAttachShader( program, _glShaderHandle );
}
void Shader::PerContextShader::detachShader(GLuint program) const
{
_extensions->glDetachShader( program, _glShaderHandle );
}
/*EOF*/

View File

@@ -29,7 +29,6 @@
#include <set>
using namespace osg;
// local class to help porting from OSG0.8.x to 0.9.x
@@ -113,7 +112,22 @@ StateSet::StateSet(const StateSet& rhs,const CopyOp& copyop):Object(rhs,copyop)
if (attr) lhs_attributeList[typemember]=RefAttributePair(attr,rap.second);
}
}
#if 0 //[ TODO
// copy uniform values
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
rhs_uitr != rhs._uniformList.end();
++rhs_uitr)
{
const std::string& name = rhs_uitr->first;
const RefUniformPair& rup = rhs_uitr->second;
Uniform* uni = copyop(rup.first.get());
if( uni ) _uniformList[name] = RefUniformPair(uni, rup.second);
}
Program* prog = copyop( rhs._program );
if( prog ) _program = prog;
#endif //]
_renderingHint = rhs._renderingHint;
@@ -410,6 +424,9 @@ void StateSet::clear()
_textureModeList.clear();
_textureAttributeList.clear();
_uniformList.clear();
_program = 0;
}
@@ -521,6 +538,29 @@ void StateSet::merge(const StateSet& rhs)
}
}
// merge the uniforms of rhs into this,
// this overrides rhs if OVERRIDE defined in this.
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
rhs_uitr != rhs._uniformList.end();
++rhs_uitr)
{
UniformList::iterator lhs_uitr = _uniformList.find(rhs_uitr->first);
if (lhs_uitr!=_uniformList.end())
{
if (!(lhs_uitr->second.second & StateAttribute::OVERRIDE))
{
// override isn't on in rhs, so overrite it with incomming
// value.
lhs_uitr->second = rhs_uitr->second;
}
}
else
{
// entry doesn't exist so insert it.
_uniformList.insert(*rhs_uitr);
}
}
// need to merge rendering hints
// but will need to think how best to do this first
// RO, Nov. 2001.
@@ -662,7 +702,7 @@ const StateSet::RefAttributePair* StateSet::getAttributePair(StateAttribute::Typ
return getAttributePair(_attributeList,type,member);
}
void StateSet::setUniform(Uniform* uniform, StateAttribute::OverrideValue value)
void StateSet::addUniform(Uniform* uniform, StateAttribute::OverrideValue value)
{
if (uniform)
{

View File

@@ -11,7 +11,7 @@
*/
/* file: src/osg/Uniform.cpp
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -368,6 +368,13 @@ Uniform::Uniform( const char* name, Value::Type type ) :
{}
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
Object(gu,copyop),
_value( gu._value )
{
}
Uniform::Uniform( const char* name, float f ) :
_value( name, Value::FLOAT )
{
@@ -423,13 +430,6 @@ Uniform::Uniform( const char* name, int i ) :
//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 )
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
Object(gu,copyop),
_value( gu._value )
{
}
bool Uniform::set( float f )
{
if( ! isCompatibleType( Value::FLOAT ) ) return false;
@@ -503,5 +503,4 @@ bool Uniform::isCompatibleType( Value::Type t ) const
return false;
}
/*EOF*/