From 5fbb1f11cdb92c8107a10601a5de18dbd38fb7a4 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 24 Feb 2005 13:33:35 +0000 Subject: [PATCH] From Mike Weiblen, adding prelimimnary GL Shader Language support into core OSG lib. with renaming and reordering by Robert Osfield, --- VisualStudio/osg/osg.dsp | 24 + include/osg/Program | 447 ++++++++ include/osg/Shader | 152 +++ include/osg/StateAttribute | 9 +- include/osg/Uniform | 299 +++++ src/osg/GNUmakefile | 5 +- src/osg/Program.cpp | 2163 ++++++++++++++++++++++++++++++++++++ src/osg/Shader.cpp | 239 ++++ src/osg/Uniform.cpp | 527 +++++++++ 9 files changed, 3861 insertions(+), 4 deletions(-) create mode 100644 include/osg/Program create mode 100644 include/osg/Shader create mode 100644 include/osg/Uniform create mode 100644 src/osg/Program.cpp create mode 100644 src/osg/Shader.cpp create mode 100644 src/osg/Uniform.cpp diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index d118d7987..be32d03a7 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -380,6 +380,10 @@ SOURCE=..\..\src\osg\PrimitiveSet.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\Program.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Projection.cpp # End Source File # Begin Source File @@ -400,6 +404,10 @@ SOURCE=..\..\src\osg\ShadeModel.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\Shader.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\ShadowVolumeOccluder.cpp # End Source File # Begin Source File @@ -484,6 +492,10 @@ SOURCE=..\..\src\osg\Transform.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\Uniform.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\UnitTestFramework.cpp # End Source File # Begin Source File @@ -837,6 +849,10 @@ SOURCE=..\..\Include\Osg\Projection # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\Program +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Quat # End Source File # Begin Source File @@ -857,6 +873,10 @@ SOURCE=..\..\Include\Osg\ShadeModel # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\Shader +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\ShadowVolumeOccluder # End Source File # Begin Source File @@ -949,6 +969,10 @@ SOURCE=..\..\Include\Osg\TriangleFunctor # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\Uniform +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\UnitTestFramework # End Source File # Begin Source File diff --git a/include/osg/Program b/include/osg/Program new file mode 100644 index 000000000..8d585c8bd --- /dev/null +++ b/include/osg/Program @@ -0,0 +1,447 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. +*/ + +/* file: include/osg/Program + * author: Mike Weiblen 2005-02-20 +*/ + +// 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 +#include +#include +#include +#include +#include + +#include +#include + + +namespace osg { + +class SG_EXPORT GL2Extensions : public osg::Referenced +{ + public: + GL2Extensions(); + GL2Extensions(const GL2Extensions& rhs); + + void lowestCommonDenominator(const GL2Extensions& rhs); + + void setupGL2Extensions(); + + /** Does the GL driver support OpenGL Shading Language? */ + bool isGlslSupported() const; + + float getGlVersion() const { return _glVersion; } + float getLanguageVersion() const { return _glslLanguageVersion; } + + void setShaderObjectsSupported(bool flag) { _isShaderObjectsSupported = flag; } + bool isShaderObjectsSupported() const { return _isShaderObjectsSupported; } + + void setVertexShaderSupported(bool flag) { _isVertexShaderSupported = flag; } + bool isVertexShaderSupported() const { return _isVertexShaderSupported; } + + void setFragmentShaderSupported(bool flag) { _isFragmentShaderSupported = flag; } + bool isFragmentShaderSupported() const { return _isFragmentShaderSupported; } + + void setLanguage100Supported(bool flag) { _isLanguage100Supported = flag; } + bool isLanguage100Supported() const { return _isLanguage100Supported; } + + /** Function to call to get the extension of a specified context. + * If the Exentsion object for that context has not yet been created then + * and the 'createIfNotInitalized' flag been set to false then returns NULL. + * If 'createIfNotInitalized' is true then the Extensions object is + * automatically created. However, in this case the extension object + * only be created with the graphics context associated with ContextID..*/ + static GL2Extensions* Get(unsigned int contextID,bool createIfNotInitalized); + + /** allows users to override the extensions across graphics contexts. + * typically used when you have different extensions supported across graphics pipes + * but need to ensure that they all use the same low common denominator extensions.*/ + static void Set(unsigned int contextID, GL2Extensions* extensions); + + + void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) const; + void glDrawBuffers(GLsizei n, const GLenum *bufs) const; + void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) const; + void glStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) const; + void glStencilMaskSeparate(GLenum face, GLuint mask) const; + void glAttachShader(GLuint program, GLuint shader) const; + void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) const; + void glCompileShader(GLuint shader) const; + GLuint glCreateProgram(void) const; + GLuint glCreateShader(GLenum type) const; + void glDeleteProgram(GLuint program) const; + void glDeleteShader(GLuint shader) const; + void glDetachShader(GLuint program, GLuint shader) const; + void glDisableVertexAttribArray(GLuint index) const; + void glEnableVertexAttribArray(GLuint index) const; + void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; + void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; + void glGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj) const; + GLint glGetAttribLocation(GLuint program, const GLchar *name) const; + void glGetProgramiv(GLuint program, GLenum pname, GLint *params) const; + void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const; + void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) const; + void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const; + void glGetShaderSource(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) const; + GLint glGetUniformLocation(GLuint program, const GLchar *name) const; + void glGetUniformfv(GLuint program, GLint location, GLfloat *params) const; + void glGetUniformiv(GLuint program, GLint location, GLint *params) const; + void glGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params) const; + void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) const; + void glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) const; + void glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid* *pointer) const; + GLboolean glIsProgram(GLuint program) const; + GLboolean glIsShader(GLuint shader) const; + void glLinkProgram(GLuint program) const; + void glShaderSource(GLuint shader, GLsizei count, const GLchar* *string, const GLint *length) const; + void glUseProgram(GLuint program) const; + void glUniform1f(GLint location, GLfloat v0) const; + void glUniform2f(GLint location, GLfloat v0, GLfloat v1) const; + void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) const; + void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) const; + void glUniform1i(GLint location, GLint v0) const; + void glUniform2i(GLint location, GLint v0, GLint v1) const; + void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) const; + void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) const; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform1iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) const; + void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; + void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; + void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; + void glValidateProgram(GLuint program) const; + void glVertexAttrib1d(GLuint index, GLdouble x) const; + void glVertexAttrib1dv(GLuint index, const GLdouble *v) const; + void glVertexAttrib1f(GLuint index, GLfloat x) const; + void glVertexAttrib1fv(GLuint index, const GLfloat *v) const; + void glVertexAttrib1s(GLuint index, GLshort x) const; + void glVertexAttrib1sv(GLuint index, const GLshort *v) const; + void glVertexAttrib2d(GLuint index, GLdouble x, GLdouble y) const; + void glVertexAttrib2dv(GLuint index, const GLdouble *v) const; + void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) const; + void glVertexAttrib2fv(GLuint index, const GLfloat *v) const; + void glVertexAttrib2s(GLuint index, GLshort x, GLshort y) const; + void glVertexAttrib2sv(GLuint index, const GLshort *v) const; + void glVertexAttrib3d(GLuint index, GLdouble x, GLdouble y, GLdouble z) const; + void glVertexAttrib3dv(GLuint index, const GLdouble *v) const; + void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) const; + void glVertexAttrib3fv(GLuint index, const GLfloat *v) const; + void glVertexAttrib3s(GLuint index, GLshort x, GLshort y, GLshort z) const; + void glVertexAttrib3sv(GLuint index, const GLshort *v) const; + void glVertexAttrib4Nbv(GLuint index, const GLbyte *v) const; + void glVertexAttrib4Niv(GLuint index, const GLint *v) const; + void glVertexAttrib4Nsv(GLuint index, const GLshort *v) const; + void glVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) const; + void glVertexAttrib4Nubv(GLuint index, const GLubyte *v) const; + void glVertexAttrib4Nuiv(GLuint index, const GLuint *v) const; + void glVertexAttrib4Nusv(GLuint index, const GLushort *v) const; + void glVertexAttrib4bv(GLuint index, const GLbyte *v) const; + void glVertexAttrib4d(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) const; + void glVertexAttrib4dv(GLuint index, const GLdouble *v) const; + void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) const; + void glVertexAttrib4fv(GLuint index, const GLfloat *v) const; + void glVertexAttrib4iv(GLuint index, const GLint *v) const; + void glVertexAttrib4s(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) const; + void glVertexAttrib4sv(GLuint index, const GLshort *v) const; + void glVertexAttrib4ubv(GLuint index, const GLubyte *v) const; + void glVertexAttrib4uiv(GLuint index, const GLuint *v) const; + void glVertexAttrib4usv(GLuint index, const GLushort *v) const; + void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) const; + + // C++-friendly convenience wrapper methods + GLuint getCurrentProgram() const; + bool getProgramInfoLog( GLuint program, std::string& result ) const; + bool getShaderInfoLog( GLuint shader, std::string& result ) const; + + protected: + ~GL2Extensions() {} + + float _glVersion; + float _glslLanguageVersion; + + bool _isShaderObjectsSupported; + bool _isVertexShaderSupported; + bool _isFragmentShaderSupported; + bool _isLanguage100Supported; + + void* _glBlendEquationSeparate; + void* _glDrawBuffers; + void* _glStencilOpSeparate; + void* _glStencilFuncSeparate; + void* _glStencilMaskSeparate; + void* _glAttachShader; + void* _glBindAttribLocation; + void* _glCompileShader; + void* _glCreateProgram; + void* _glCreateShader; + void* _glDeleteProgram; + void* _glDeleteShader; + void* _glDetachShader; + void* _glDisableVertexAttribArray; + void* _glEnableVertexAttribArray; + void* _glGetActiveAttrib; + void* _glGetActiveUniform; + void* _glGetAttachedShaders; + void* _glGetAttribLocation; + void* _glGetProgramiv; + void* _glGetProgramInfoLog; + void* _glGetShaderiv; + void* _glGetShaderInfoLog; + void* _glGetShaderSource; + void* _glGetUniformLocation; + void* _glGetUniformfv; + void* _glGetUniformiv; + void* _glGetVertexAttribdv; + void* _glGetVertexAttribfv; + void* _glGetVertexAttribiv; + void* _glGetVertexAttribPointerv; + void* _glIsProgram; + void* _glIsShader; + void* _glLinkProgram; + void* _glShaderSource; + void* _glUseProgram; + void* _glUniform1f; + void* _glUniform2f; + void* _glUniform3f; + void* _glUniform4f; + void* _glUniform1i; + void* _glUniform2i; + void* _glUniform3i; + void* _glUniform4i; + void* _glUniform1fv; + void* _glUniform2fv; + void* _glUniform3fv; + void* _glUniform4fv; + void* _glUniform1iv; + void* _glUniform2iv; + void* _glUniform3iv; + void* _glUniform4iv; + void* _glUniformMatrix2fv; + void* _glUniformMatrix3fv; + void* _glUniformMatrix4fv; + void* _glValidateProgram; + void* _glVertexAttrib1d; + void* _glVertexAttrib1dv; + void* _glVertexAttrib1f; + void* _glVertexAttrib1fv; + void* _glVertexAttrib1s; + void* _glVertexAttrib1sv; + void* _glVertexAttrib2d; + void* _glVertexAttrib2dv; + void* _glVertexAttrib2f; + void* _glVertexAttrib2fv; + void* _glVertexAttrib2s; + void* _glVertexAttrib2sv; + void* _glVertexAttrib3d; + void* _glVertexAttrib3dv; + void* _glVertexAttrib3f; + void* _glVertexAttrib3fv; + void* _glVertexAttrib3s; + void* _glVertexAttrib3sv; + void* _glVertexAttrib4Nbv; + void* _glVertexAttrib4Niv; + void* _glVertexAttrib4Nsv; + void* _glVertexAttrib4Nub; + void* _glVertexAttrib4Nubv; + void* _glVertexAttrib4Nuiv; + void* _glVertexAttrib4Nusv; + void* _glVertexAttrib4bv; + void* _glVertexAttrib4d; + void* _glVertexAttrib4dv; + void* _glVertexAttrib4f; + void* _glVertexAttrib4fv; + void* _glVertexAttrib4iv; + void* _glVertexAttrib4s; + void* _glVertexAttrib4sv; + void* _glVertexAttrib4ubv; + void* _glVertexAttrib4uiv; + void* _glVertexAttrib4usv; + void* _glVertexAttribPointer; + + void* _glGetInfoLogARB; + void* _glGetObjectParameterivARB; + void* _glDeleteObjectARB; + void* _glGetHandleARB; +}; + +class Program; +typedef osg::ref_ptr ProgramPtr; + +class Shader; +typedef osg::ref_ptr ShaderPtr; +typedef std::vector< ShaderPtr > ShaderList; + +/////////////////////////////////////////////////////////////////////////// +/** osg::Program is an application-level abstraction of an OpenGL glProgram. + * It is an osg::StateAttribute that, when applied, will activate a + * glProgram for subsequent rendering. + * osg::Shaders containing the actual shader source code are + * attached to a Program, which will then manage the compilation, + * linking, and activation of the GLSL program. + * Program will automatically manage per-context instancing of the + * OpenGL objects, if that is necessary for a particular display + * configuration. + */ + +class SG_EXPORT Program : public osg::StateAttribute +{ + public: + Program(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + Program(const Program& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_StateAttribute(osg, Program, PROGRAM); + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + virtual int compare(const osg::StateAttribute& sa) const; + + /** If enabled, activate our program in the GL pipeline, + * performing any rebuild operations that might be pending. */ + virtual void apply(osg::State& state) const; + + virtual void compileGLObjects(osg::State& state) const; + + /** release OpenGL objects in specified graphics context if State + object is passed, otherwise release OpenGL objects for all graphics context if + State object pointer NULL.*/ + virtual void releaseGLObjects(osg::State* state=0) const; + + // data access methods. + + /** Mark us as "dirty" and in need of relinking. */ + void dirtyProgram(); + + /** Mark our attached Shaders as "dirty" and in need of recompilation. */ + void dirtyShaders(); + + /** Attach a Shader to this Program */ + void addShader( Shader* shader ); + + /** Mark internal GL glProgram for deletion. + * Deletion requests are queued until they can be executed + * in the proper GL context. */ + static void deleteProgram(unsigned int contextID, GLuint program); + + /** flush all the cached glPrograms which need to be deleted + * in the OpenGL context related to contextID.*/ + static void flushDeletedGlslObjects(unsigned int contextID,double currentTime, double& availableTime); + + /** An annotation/comment for use by the application */ + void setComment( const std::string& comment ) { _comment = comment; } + void setComment( const char* comment ) { _comment = comment; } + const std::string& getComment() const { return _comment; } + + /** should Uniform values be tested to avoid redundant setting? */ + void setAvoidRedundantUniformSetting( bool flag ) { _avoidRedundantUniformSetting = flag; } + bool getAvoidRedundantUniformSetting() const { return _avoidRedundantUniformSetting; } + + // TODO glBindAttribLocation + + + protected: + /** An OSG-internal encapsulation of glProgram's active uniforms */ + class ActiveUniform : public osg::Referenced + { + public: + ActiveUniform( const GLchar* name, GLenum type ); + + protected: + virtual ~ActiveUniform() {} + + Uniform::Value _value; + GLint _location; + + private: + ActiveUniform(); // disallowed + }; + typedef osg::ref_ptr< ActiveUniform > ActiveUniformPtr; + typedef std::vector< ActiveUniformPtr > ActiveUniformList; + + + protected: + /** PCPO is an OSG-internal encapsulation of glPrograms per-GL context. */ + class PerContextProgObj : public osg::Referenced + { + public: + PerContextProgObj(const Program* program, unsigned int contextID); + PerContextProgObj(const PerContextProgObj& rhs); + + const GLuint getHandle() {return _glProgramHandle;} + + bool isDirty() const {return _dirty;} + void markAsDirty(); + void linkProgram(); + void useProgram() const; + + void applyUniforms( osg::State& state ) const; + + protected: /*methods*/ + PerContextProgObj(); + ~PerContextProgObj(); + + protected: /*data*/ + /** Pointer to our parent Program */ + const Program* _program; + /** Pointer to this context's extension functions */ + osg::ref_ptr _extensions; + /** Handle to the actual OpenGL glProgram */ + GLuint _glProgramHandle; + /** Do we need to be linked? */ + bool _dirty; + /** Queue of UniformValues awaiting assignment */ + const unsigned int _contextID; + /** List of PCPO's active uniforms */ + ActiveUniformList _activeUniformList; + }; + + protected: /*methods*/ + virtual ~Program(); + /** Get the PCPO for a particular GL context */ + PerContextProgObj* getPCPO(unsigned int contextID) const; + + protected: /*data*/ + bool _avoidRedundantUniformSetting; + std::string _comment; + ShaderList _shaderList; + mutable osg::buffered_value< osg::ref_ptr > _pcpoList; + + private: + const Program& operator=(const Program&); +}; + + +} + +#endif + +/*EOF*/ diff --git a/include/osg/Shader b/include/osg/Shader new file mode 100644 index 000000000..08c69da7a --- /dev/null +++ b/include/osg/Shader @@ -0,0 +1,152 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. +*/ + +/* file: include/osg/Program + * author: Mike Weiblen 2005-02-20 +*/ + +// 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 + +#include + +namespace osg { + +/////////////////////////////////////////////////////////////////////////// +/** osg::Shader is an application-level abstraction of an OpenGL glShader. + * It is a container to load the shader source code text and manage its + * compilation. + * A Shader may be attached to more than one osg::Program. + * Shader will automatically manage per-context instancing of the + * internal objects, if that is necessary for a particular display + * configuration. + */ + +class SG_EXPORT Shader : public osg::Referenced +{ + public: + + enum Type { + VERTEX = GL_VERTEX_SHADER, + FRAGMENT = GL_FRAGMENT_SHADER, + }; + + Shader( Type type, const char* sourceText = 0 ); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + Shader(const Shader& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + int compare(const Shader& rhs) const; + + // data access methods. + + /** Load the Shader's source code text from a string. */ + void setShaderSource( const char* sourceText ); + + /** Load the Shader's source code text from a file. */ + bool loadShaderSourceFromFile( const char* fileName ); + + /** Query the shader's source code text */ + inline const std::string& getShaderSource() const { return _shaderSource; } + + /** Get the Shader type as an enum. */ + inline Type getType() const { return _type; } + + /** Get the Shader type as a descriptive string. */ + const char* getTypename() const; + + /** Mark us as "dirty" and in need of recompilation */ + void dirtyShader(); + + /** Mark internal GL glShader for deletion. + * Deletion requests are queued until they can be executed + * in the proper GL context. */ + static void deleteShader(unsigned int contextID, GLuint shader); + + /** Perform a recompilation of all our PCSOs */ + void compileShader(unsigned int contextID) const; + + /** For a given GL context, attach a glShader to a glProgram */ + void attachShader(unsigned int contextID, GLuint program) const; + + /** An annotation/comment for use by the application */ + void setComment( const std::string& comment ) { _comment = comment; } + void setComment( const char* comment ) { _comment = comment; } + const std::string& getComment() const { return _comment; }; + + + protected: + /** PCSO is an OSG-internal encapsulation of glShader per-GL context. */ + class PerContextShaderObj : public osg::Referenced + { + public: + PerContextShaderObj(const Shader* shader, unsigned int contextID); + PerContextShaderObj(const PerContextShaderObj& rhs); + + const GLuint getHandle() {return _glShaderHandle;} + + bool isDirty() const {return _dirty;} + void markAsDirty() {_dirty = true; } + void compileShader(); + + /** Attach our glShader to a glProgram */ + void attachShader(GLuint program) const; + + protected: /*methods*/ + PerContextShaderObj(); + ~PerContextShaderObj(); + + protected: /*data*/ + /** Pointer to our parent Shader */ + const Shader* _shader; + /** Pointer to this context's extension functions. */ + osg::ref_ptr _extensions; + /** Handle to the actual glShader. */ + GLuint _glShaderHandle; + /** Do we need to be recompiled? */ + bool _dirty; + const unsigned int _contextID; + }; + + protected: /*methods*/ + virtual ~Shader(); + PerContextShaderObj* getPCSO(unsigned int contextID) const; + + friend void Program::addShader( Shader* shader ); // to access addProgObjRef() + void addProgObjRef( Program* program ); + + protected: /*data*/ + const Type _type; + std::string _comment; + std::string _shaderSource; + /** list of Programs that this Shader is attached to */ + std::vector< ProgramPtr > _programList; + mutable osg::buffered_value< osg::ref_ptr > _pcsoList; + + private: + Shader(); // disallowed + Shader& operator=(const Shader&); // disallowed +}; + + +} + +#endif + +/*EOF*/ diff --git a/include/osg/StateAttribute b/include/osg/StateAttribute index 98ae40957..8f036aaf8 100644 --- a/include/osg/StateAttribute +++ b/include/osg/StateAttribute @@ -1,4 +1,4 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 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 @@ -175,8 +175,11 @@ class SG_EXPORT StateAttribute : public Object VERTEX_PROGRAM, REGISTER_COMBINERS, // osgNVParse - PROGRAM, - PROGRAM_PARSER + PROGRAM_PARSER, + + /// core GLSL + PROGRAM, + UNIFORM, }; /** Simple pairing between an attribute type and the member within that attribute type group.*/ diff --git a/include/osg/Uniform b/include/osg/Uniform new file mode 100644 index 000000000..fb1b3d912 --- /dev/null +++ b/include/osg/Uniform @@ -0,0 +1,299 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. +*/ + +/* file: include/osg/Uniform + * author: Mike Weiblen 2005-02-20 +*/ + +// 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_UNIFORM +#define OSG_UNIFORM 1 + +#include +#include +#include +#include +#include +#include + +#include + +#ifndef GL_VERSION_2_0 +#define GL_VERSION_2_0 1 +#define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 +#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_POINT_SPRITE 0x8861 +#define GL_COORD_REPLACE 0x8862 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_MAX_TEXTURE_COORDS 0x8871 +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_VARYING_FLOATS 0x8B4B +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_SHADER_TYPE 0x8B4F +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_1D 0x8B5D +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SAMPLER_1D_SHADOW 0x8B61 +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 +#define GL_LOWER_LEFT 0x8CA1 +#define GL_UPPER_LEFT 0x8CA2 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 + +typedef char GLchar; + +#endif + +namespace osg { + +/////////////////////////////////////////////////////////////////////////// +/** Uniform is an osg::StateAttribute to encapsulate glUniform values */ + +class SG_EXPORT Uniform : public StateAttribute +{ + 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 ); + //TODO void set( int i0, int i1 ); + //TODO void set( int i0, int i1, int i2 ); + //TODO void set( int i0, int i1, int i2, int i3 ); + //TODO void set( bool b ); + //TODO void set( bool b0, bool b1 ); + //TODO void set( bool b0, bool b1, bool b2 ); + //TODO 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 + }; + + + public: + Uniform(); + Uniform( const char* name, Value::Type type ); + + /** convenient construction w/ assignment */ + Uniform( const char* name, float f ); + Uniform( const char* name, const osg::Vec2& v2 ); + Uniform( const char* name, const osg::Vec3& v3 ); + Uniform( const char* name, const osg::Vec4& v4 ); + //TODO Uniform( const char* name, const osg::Matrix2& m2 ); + //TODO Uniform( const char* name, const osg::Matrix3& m3 ); + Uniform( const char* name, const osg::Matrix& m4 ); + Uniform( const char* name, int i ); + //TODO Uniform( const char* name, int i0, int i1 ); + //TODO Uniform( const char* name, int i0, int i1, int i2 ); + //TODO Uniform( const char* name, int i0, int i1, int i2, int i3 ); + //TODO Uniform( const char* name, bool b ); + //TODO Uniform( const char* name, bool b0, bool b1 ); + //TODO Uniform( const char* name, bool b0, bool b1, bool b2 ); + //TODO 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); + + META_StateAttribute(osg, Uniform, UNIFORM); + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */ + virtual int compare(const StateAttribute& sa) const + { + // check if the types are equal and then create the rhs variable + // used by the COMPARE_StateAttribute_Parameter macros below. + COMPARE_StateAttribute_Types(Uniform,sa) + + return _value.compare( rhs._value ); + } + + virtual void apply( State& state ) const; + + /** assignment */ + bool set( float f ); + bool set( const osg::Vec2& v2 ); + bool set( const osg::Vec3& v3 ); + bool set( const osg::Vec4& v4 ); + //TODO bool set( const osg::Matrix2& m2 ); + //TODO bool set( const osg::Matrix3& m3 ); + bool set( const osg::Matrix& m4 ); + bool set( int i ); + //TODO bool set( int i0, int i1 ); + //TODO bool set( int i0, int i1, int i2 ); + //TODO bool set( int i0, int i1, int i2, int i3 ); + //TODO bool set( bool b ); + //TODO bool set( bool b0, bool b1 ); + //TODO bool set( bool b0, bool b1, bool b2 ); + //TODO bool set( bool b0, bool b1, bool b2, bool b3 ); + + protected: + virtual ~Uniform() {} + + bool isCompatibleType( Value::Type t ) const; + + protected: + Value _value; + + private: + Uniform& operator=(const Uniform&); // disallowed +}; + +} + +#endif + +/*EOF*/ diff --git a/src/osg/GNUmakefile b/src/osg/GNUmakefile index 10531b65f..ee4fcb430 100644 --- a/src/osg/GNUmakefile +++ b/src/osg/GNUmakefile @@ -39,8 +39,10 @@ CXXFILES =\ FrameStamp.cpp\ FrontFace.cpp\ GLExtensions.cpp\ - Geometry.cpp\ Geode.cpp\ + Geometry.cpp\ + Program.cpp\ + Uniform.cpp\ Group.cpp\ dxtctool.cpp\ Image.cpp\ @@ -78,6 +80,7 @@ CXXFILES =\ Quat.cpp\ Referenced.cpp\ Sequence.cpp\ + Shader.cpp\ ShadeModel.cpp\ ShadowVolumeOccluder.cpp\ Shape.cpp\ diff --git a/src/osg/Program.cpp b/src/osg/Program.cpp new file mode 100644 index 000000000..2dd9fa353 --- /dev/null +++ b/src/osg/Program.cpp @@ -0,0 +1,2163 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. + * +*/ + +/* file: src/osg/Program.cpp + * author: Mike Weiblen 2005-02-20 +*/ + +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace osg; + +/////////////////////////////////////////////////////////////////////////// +// static cache of GL objects flagged for deletion, which will actually +// be deleted in the correct GL context. + +typedef std::list GlProgramHandleList; +typedef std::map DeletedGlProgramCache; + +static OpenThreads::Mutex s_mutex_deletedGL2ObjectCache; +static DeletedGlProgramCache s_deletedGlProgramCache; + + +GL2Extensions::GL2Extensions() +{ + setupGL2Extensions(); +} + + +GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced() +{ + _glVersion = rhs._glVersion; + _glslLanguageVersion = rhs._glslLanguageVersion; + + _isShaderObjectsSupported = rhs._isShaderObjectsSupported; + _isVertexShaderSupported = rhs._isVertexShaderSupported; + _isFragmentShaderSupported = rhs._isFragmentShaderSupported; + _isLanguage100Supported = rhs._isLanguage100Supported; + + _glBlendEquationSeparate = rhs._glBlendEquationSeparate; + _glDrawBuffers = rhs._glDrawBuffers; + _glStencilOpSeparate = rhs._glStencilOpSeparate; + _glStencilFuncSeparate = rhs._glStencilFuncSeparate; + _glStencilMaskSeparate = rhs._glStencilMaskSeparate; + _glAttachShader = rhs._glAttachShader; + _glBindAttribLocation = rhs._glBindAttribLocation; + _glCompileShader = rhs._glCompileShader; + _glCreateProgram = rhs._glCreateProgram; + _glCreateShader = rhs._glCreateShader; + _glDeleteProgram = rhs._glDeleteProgram; + _glDeleteShader = rhs._glDeleteShader; + _glDetachShader = rhs._glDetachShader; + _glDisableVertexAttribArray = rhs._glDisableVertexAttribArray; + _glEnableVertexAttribArray = rhs._glEnableVertexAttribArray; + _glGetActiveAttrib = rhs._glGetActiveAttrib; + _glGetActiveUniform = rhs._glGetActiveUniform; + _glGetAttachedShaders = rhs._glGetAttachedShaders; + _glGetAttribLocation = rhs._glGetAttribLocation; + _glGetProgramiv = rhs._glGetProgramiv; + _glGetProgramInfoLog = rhs._glGetProgramInfoLog; + _glGetShaderiv = rhs._glGetShaderiv; + _glGetShaderInfoLog = rhs._glGetShaderInfoLog; + _glGetShaderSource = rhs._glGetShaderSource; + _glGetUniformLocation = rhs._glGetUniformLocation; + _glGetUniformfv = rhs._glGetUniformfv; + _glGetUniformiv = rhs._glGetUniformiv; + _glGetVertexAttribdv = rhs._glGetVertexAttribdv; + _glGetVertexAttribfv = rhs._glGetVertexAttribfv; + _glGetVertexAttribiv = rhs._glGetVertexAttribiv; + _glGetVertexAttribPointerv = rhs._glGetVertexAttribPointerv; + _glIsProgram = rhs._glIsProgram; + _glIsShader = rhs._glIsShader; + _glLinkProgram = rhs._glLinkProgram; + _glShaderSource = rhs._glShaderSource; + _glUseProgram = rhs._glUseProgram; + _glUniform1f = rhs._glUniform1f; + _glUniform2f = rhs._glUniform2f; + _glUniform3f = rhs._glUniform3f; + _glUniform4f = rhs._glUniform4f; + _glUniform1i = rhs._glUniform1i; + _glUniform2i = rhs._glUniform2i; + _glUniform3i = rhs._glUniform3i; + _glUniform4i = rhs._glUniform4i; + _glUniform1fv = rhs._glUniform1fv; + _glUniform2fv = rhs._glUniform2fv; + _glUniform3fv = rhs._glUniform3fv; + _glUniform4fv = rhs._glUniform4fv; + _glUniform1iv = rhs._glUniform1iv; + _glUniform2iv = rhs._glUniform2iv; + _glUniform3iv = rhs._glUniform3iv; + _glUniform4iv = rhs._glUniform4iv; + _glUniformMatrix2fv = rhs._glUniformMatrix2fv; + _glUniformMatrix3fv = rhs._glUniformMatrix3fv; + _glUniformMatrix4fv = rhs._glUniformMatrix4fv; + _glValidateProgram = rhs._glValidateProgram; + _glVertexAttrib1d = rhs._glVertexAttrib1d; + _glVertexAttrib1dv = rhs._glVertexAttrib1dv; + _glVertexAttrib1f = rhs._glVertexAttrib1f; + _glVertexAttrib1fv = rhs._glVertexAttrib1fv; + _glVertexAttrib1s = rhs._glVertexAttrib1s; + _glVertexAttrib1sv = rhs._glVertexAttrib1sv; + _glVertexAttrib2d = rhs._glVertexAttrib2d; + _glVertexAttrib2dv = rhs._glVertexAttrib2dv; + _glVertexAttrib2f = rhs._glVertexAttrib2f; + _glVertexAttrib2fv = rhs._glVertexAttrib2fv; + _glVertexAttrib2s = rhs._glVertexAttrib2s; + _glVertexAttrib2sv = rhs._glVertexAttrib2sv; + _glVertexAttrib3d = rhs._glVertexAttrib3d; + _glVertexAttrib3dv = rhs._glVertexAttrib3dv; + _glVertexAttrib3f = rhs._glVertexAttrib3f; + _glVertexAttrib3fv = rhs._glVertexAttrib3fv; + _glVertexAttrib3s = rhs._glVertexAttrib3s; + _glVertexAttrib3sv = rhs._glVertexAttrib3sv; + _glVertexAttrib4Nbv = rhs._glVertexAttrib4Nbv; + _glVertexAttrib4Niv = rhs._glVertexAttrib4Niv; + _glVertexAttrib4Nsv = rhs._glVertexAttrib4Nsv; + _glVertexAttrib4Nub = rhs._glVertexAttrib4Nub; + _glVertexAttrib4Nubv = rhs._glVertexAttrib4Nubv; + _glVertexAttrib4Nuiv = rhs._glVertexAttrib4Nuiv; + _glVertexAttrib4Nusv = rhs._glVertexAttrib4Nusv; + _glVertexAttrib4bv = rhs._glVertexAttrib4bv; + _glVertexAttrib4d = rhs._glVertexAttrib4d; + _glVertexAttrib4dv = rhs._glVertexAttrib4dv; + _glVertexAttrib4f = rhs._glVertexAttrib4f; + _glVertexAttrib4fv = rhs._glVertexAttrib4fv; + _glVertexAttrib4iv = rhs._glVertexAttrib4iv; + _glVertexAttrib4s = rhs._glVertexAttrib4s; + _glVertexAttrib4sv = rhs._glVertexAttrib4sv; + _glVertexAttrib4ubv = rhs._glVertexAttrib4ubv; + _glVertexAttrib4uiv = rhs._glVertexAttrib4uiv; + _glVertexAttrib4usv = rhs._glVertexAttrib4usv; + _glVertexAttribPointer = rhs._glVertexAttribPointer; + + _glGetInfoLogARB = rhs._glGetInfoLogARB; + _glGetObjectParameterivARB = rhs._glGetObjectParameterivARB; + _glDeleteObjectARB = rhs._glDeleteObjectARB; + _glGetHandleARB = rhs._glGetHandleARB; +} + + +void GL2Extensions::lowestCommonDenominator(const GL2Extensions& rhs) +{ + if (rhs._glVersion < _glVersion) _glVersion = rhs._glVersion; + if (rhs._glslLanguageVersion < _glslLanguageVersion) + _glslLanguageVersion = rhs._glslLanguageVersion; + + if (!rhs._isShaderObjectsSupported) _isShaderObjectsSupported = false; + if (!rhs._isVertexShaderSupported) _isVertexShaderSupported = false; + if (!rhs._isFragmentShaderSupported) _isFragmentShaderSupported = false; + if (!rhs._isLanguage100Supported) _isLanguage100Supported = false; + + if (!rhs._glBlendEquationSeparate) _glBlendEquationSeparate = 0; + if (!rhs._glDrawBuffers) _glDrawBuffers = 0; + if (!rhs._glStencilOpSeparate) _glStencilOpSeparate = 0; + if (!rhs._glStencilFuncSeparate) _glStencilFuncSeparate = 0; + if (!rhs._glStencilMaskSeparate) _glStencilMaskSeparate = 0; + if (!rhs._glAttachShader) _glAttachShader = 0; + if (!rhs._glBindAttribLocation) _glBindAttribLocation = 0; + if (!rhs._glCompileShader) _glCompileShader = 0; + if (!rhs._glCreateProgram) _glCreateProgram = 0; + if (!rhs._glCreateShader) _glCreateShader = 0; + if (!rhs._glDeleteProgram) _glDeleteProgram = 0; + if (!rhs._glDeleteShader) _glDeleteShader = 0; + if (!rhs._glDetachShader) _glDetachShader = 0; + if (!rhs._glDisableVertexAttribArray) _glDisableVertexAttribArray = 0; + if (!rhs._glEnableVertexAttribArray) _glEnableVertexAttribArray = 0; + if (!rhs._glGetActiveAttrib) _glGetActiveAttrib = 0; + if (!rhs._glGetActiveUniform) _glGetActiveUniform = 0; + if (!rhs._glGetAttachedShaders) _glGetAttachedShaders = 0; + if (!rhs._glGetAttribLocation) _glGetAttribLocation = 0; + if (!rhs._glGetProgramiv) _glGetProgramiv = 0; + if (!rhs._glGetProgramInfoLog) _glGetProgramInfoLog = 0; + if (!rhs._glGetShaderiv) _glGetShaderiv = 0; + if (!rhs._glGetShaderInfoLog) _glGetShaderInfoLog = 0; + if (!rhs._glGetShaderSource) _glGetShaderSource = 0; + if (!rhs._glGetUniformLocation) _glGetUniformLocation = 0; + if (!rhs._glGetUniformfv) _glGetUniformfv = 0; + if (!rhs._glGetUniformiv) _glGetUniformiv = 0; + if (!rhs._glGetVertexAttribdv) _glGetVertexAttribdv = 0; + if (!rhs._glGetVertexAttribfv) _glGetVertexAttribfv = 0; + if (!rhs._glGetVertexAttribiv) _glGetVertexAttribiv = 0; + if (!rhs._glGetVertexAttribPointerv) _glGetVertexAttribPointerv = 0; + if (!rhs._glIsProgram) _glIsProgram = 0; + if (!rhs._glIsShader) _glIsShader = 0; + if (!rhs._glLinkProgram) _glLinkProgram = 0; + if (!rhs._glShaderSource) _glShaderSource = 0; + if (!rhs._glUseProgram) _glUseProgram = 0; + if (!rhs._glUniform1f) _glUniform1f = 0; + if (!rhs._glUniform2f) _glUniform2f = 0; + if (!rhs._glUniform3f) _glUniform3f = 0; + if (!rhs._glUniform4f) _glUniform4f = 0; + if (!rhs._glUniform1i) _glUniform1i = 0; + if (!rhs._glUniform2i) _glUniform2i = 0; + if (!rhs._glUniform3i) _glUniform3i = 0; + if (!rhs._glUniform4i) _glUniform4i = 0; + if (!rhs._glUniform1fv) _glUniform1fv = 0; + if (!rhs._glUniform2fv) _glUniform2fv = 0; + if (!rhs._glUniform3fv) _glUniform3fv = 0; + if (!rhs._glUniform4fv) _glUniform4fv = 0; + if (!rhs._glUniform1iv) _glUniform1iv = 0; + if (!rhs._glUniform2iv) _glUniform2iv = 0; + if (!rhs._glUniform3iv) _glUniform3iv = 0; + if (!rhs._glUniform4iv) _glUniform4iv = 0; + if (!rhs._glUniformMatrix2fv) _glUniformMatrix2fv = 0; + if (!rhs._glUniformMatrix3fv) _glUniformMatrix3fv = 0; + if (!rhs._glUniformMatrix4fv) _glUniformMatrix4fv = 0; + if (!rhs._glValidateProgram) _glValidateProgram = 0; + if (!rhs._glVertexAttrib1d) _glVertexAttrib1d = 0; + if (!rhs._glVertexAttrib1dv) _glVertexAttrib1dv = 0; + if (!rhs._glVertexAttrib1f) _glVertexAttrib1f = 0; + if (!rhs._glVertexAttrib1fv) _glVertexAttrib1fv = 0; + if (!rhs._glVertexAttrib1s) _glVertexAttrib1s = 0; + if (!rhs._glVertexAttrib1sv) _glVertexAttrib1sv = 0; + if (!rhs._glVertexAttrib2d) _glVertexAttrib2d = 0; + if (!rhs._glVertexAttrib2dv) _glVertexAttrib2dv = 0; + if (!rhs._glVertexAttrib2f) _glVertexAttrib2f = 0; + if (!rhs._glVertexAttrib2fv) _glVertexAttrib2fv = 0; + if (!rhs._glVertexAttrib2s) _glVertexAttrib2s = 0; + if (!rhs._glVertexAttrib2sv) _glVertexAttrib2sv = 0; + if (!rhs._glVertexAttrib3d) _glVertexAttrib3d = 0; + if (!rhs._glVertexAttrib3dv) _glVertexAttrib3dv = 0; + if (!rhs._glVertexAttrib3f) _glVertexAttrib3f = 0; + if (!rhs._glVertexAttrib3fv) _glVertexAttrib3fv = 0; + if (!rhs._glVertexAttrib3s) _glVertexAttrib3s = 0; + if (!rhs._glVertexAttrib3sv) _glVertexAttrib3sv = 0; + if (!rhs._glVertexAttrib4Nbv) _glVertexAttrib4Nbv = 0; + if (!rhs._glVertexAttrib4Niv) _glVertexAttrib4Niv = 0; + if (!rhs._glVertexAttrib4Nsv) _glVertexAttrib4Nsv = 0; + if (!rhs._glVertexAttrib4Nub) _glVertexAttrib4Nub = 0; + if (!rhs._glVertexAttrib4Nubv) _glVertexAttrib4Nubv = 0; + if (!rhs._glVertexAttrib4Nuiv) _glVertexAttrib4Nuiv = 0; + if (!rhs._glVertexAttrib4Nusv) _glVertexAttrib4Nusv = 0; + if (!rhs._glVertexAttrib4bv) _glVertexAttrib4bv = 0; + if (!rhs._glVertexAttrib4d) _glVertexAttrib4d = 0; + if (!rhs._glVertexAttrib4dv) _glVertexAttrib4dv = 0; + if (!rhs._glVertexAttrib4f) _glVertexAttrib4f = 0; + if (!rhs._glVertexAttrib4fv) _glVertexAttrib4fv = 0; + if (!rhs._glVertexAttrib4iv) _glVertexAttrib4iv = 0; + if (!rhs._glVertexAttrib4s) _glVertexAttrib4s = 0; + if (!rhs._glVertexAttrib4sv) _glVertexAttrib4sv = 0; + if (!rhs._glVertexAttrib4ubv) _glVertexAttrib4ubv = 0; + if (!rhs._glVertexAttrib4uiv) _glVertexAttrib4uiv = 0; + if (!rhs._glVertexAttrib4usv) _glVertexAttrib4usv = 0; + if (!rhs._glVertexAttribPointer) _glVertexAttribPointer = 0; + + if (!rhs._glGetInfoLogARB) _glGetInfoLogARB = 0; + if (!rhs._glGetObjectParameterivARB) _glGetObjectParameterivARB = 0; + if (!rhs._glDeleteObjectARB) _glDeleteObjectARB = 0; + if (!rhs._glGetHandleARB) _glGetHandleARB = 0; +} + + +void GL2Extensions::setupGL2Extensions() +{ + _glVersion = atof( (const char*)glGetString( GL_VERSION ) ); + _glslLanguageVersion = 0.0f; + + _isShaderObjectsSupported = osg::isGLExtensionSupported("GL_ARB_shader_objects"); + _isVertexShaderSupported = osg::isGLExtensionSupported("GL_ARB_vertex_shader"); + _isFragmentShaderSupported = osg::isGLExtensionSupported("GL_ARB_fragment_shader"); + _isLanguage100Supported = osg::isGLExtensionSupported("GL_ARB_shading_language_100"); + + if( isGlslSupported() ) + { + // If glGetString raises an error, assume initial release "1.00" + glGetError(); // 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 ); + } + + osg::notify(osg::INFO) + << "glVersion=" << getGlVersion() << ", " + << "isGlslSupported=" << (isGlslSupported() ? "YES" : "NO") << ", " + << "glslLanguageVersion=" << getLanguageVersion() + << std::endl; + + + _glBlendEquationSeparate = osg::getGLExtensionFuncPtr("glBlendEquationSeparate"); + _glDrawBuffers = osg::getGLExtensionFuncPtr("glDrawBuffers", "glDrawBuffersARB"); + _glStencilOpSeparate = osg::getGLExtensionFuncPtr("glStencilOpSeparate"); + _glStencilFuncSeparate = osg::getGLExtensionFuncPtr("glStencilFuncSeparate"); + _glStencilMaskSeparate = osg::getGLExtensionFuncPtr("glStencilMaskSeparate"); + _glAttachShader = osg::getGLExtensionFuncPtr("glAttachShader", "glAttachObjectARB"); + _glBindAttribLocation = osg::getGLExtensionFuncPtr("glBindAttribLocation", "glBindAttribLocationARB"); + _glCompileShader = osg::getGLExtensionFuncPtr("glCompileShader", "glCompileShaderARB"); + _glCreateProgram = osg::getGLExtensionFuncPtr("glCreateProgram", "glCreateProgramObjectARB"); + _glCreateShader = osg::getGLExtensionFuncPtr("glCreateShader", "glCreateShaderObjectARB"); + _glDeleteProgram = osg::getGLExtensionFuncPtr("glDeleteProgram"); + _glDeleteShader = osg::getGLExtensionFuncPtr("glDeleteShader"); + _glDetachShader = osg::getGLExtensionFuncPtr("glDetachShader", "glDetachObjectARB"); + _glDisableVertexAttribArray = osg::getGLExtensionFuncPtr("glDisableVertexAttribArray"); + _glEnableVertexAttribArray = osg::getGLExtensionFuncPtr("glEnableVertexAttribArray"); + _glGetActiveAttrib = osg::getGLExtensionFuncPtr("glGetActiveAttrib", "glGetActiveAttribARB"); + _glGetActiveUniform = osg::getGLExtensionFuncPtr("glGetActiveUniform", "glGetActiveUniformARB"); + _glGetAttachedShaders = osg::getGLExtensionFuncPtr("glGetAttachedShaders", "glGetAttachedObjectsARB"); + _glGetAttribLocation = osg::getGLExtensionFuncPtr("glGetAttribLocation", "glGetAttribLocationARB"); + _glGetProgramiv = osg::getGLExtensionFuncPtr("glGetProgramiv"); + _glGetProgramInfoLog = osg::getGLExtensionFuncPtr("glGetProgramInfoLog"); + _glGetShaderiv = osg::getGLExtensionFuncPtr("glGetShaderiv"); + _glGetShaderInfoLog = osg::getGLExtensionFuncPtr("glGetShaderInfoLog"); + _glGetShaderSource = osg::getGLExtensionFuncPtr("glGetShaderSource", "glGetShaderSourceARB"); + _glGetUniformLocation = osg::getGLExtensionFuncPtr("glGetUniformLocation", "glGetUniformLocationARB"); + _glGetUniformfv = osg::getGLExtensionFuncPtr("glGetUniformfv", "glGetUniformfvARB"); + _glGetUniformiv = osg::getGLExtensionFuncPtr("glGetUniformiv", "glGetUniformivARB"); + _glGetVertexAttribdv = osg::getGLExtensionFuncPtr("glGetVertexAttribdv"); + _glGetVertexAttribfv = osg::getGLExtensionFuncPtr("glGetVertexAttribfv"); + _glGetVertexAttribiv = osg::getGLExtensionFuncPtr("glGetVertexAttribiv"); + _glGetVertexAttribPointerv = osg::getGLExtensionFuncPtr("glGetVertexAttribPointerv"); + _glIsProgram = osg::getGLExtensionFuncPtr("glIsProgram"); + _glIsShader = osg::getGLExtensionFuncPtr("glIsShader"); + _glLinkProgram = osg::getGLExtensionFuncPtr("glLinkProgram", "glLinkProgramARB"); + _glShaderSource = osg::getGLExtensionFuncPtr("glShaderSource", "glShaderSourceARB"); + _glUseProgram = osg::getGLExtensionFuncPtr("glUseProgram", "glUseProgramObjectARB"); + _glUniform1f = osg::getGLExtensionFuncPtr("glUniform1f", "glUniform1fARB"); + _glUniform2f = osg::getGLExtensionFuncPtr("glUniform2f", "glUniform2fARB"); + _glUniform3f = osg::getGLExtensionFuncPtr("glUniform3f", "glUniform3fARB"); + _glUniform4f = osg::getGLExtensionFuncPtr("glUniform4f", "glUniform4fARB"); + _glUniform1i = osg::getGLExtensionFuncPtr("glUniform1i", "glUniform1iARB"); + _glUniform2i = osg::getGLExtensionFuncPtr("glUniform2i", "glUniform2iARB"); + _glUniform3i = osg::getGLExtensionFuncPtr("glUniform3i", "glUniform3iARB"); + _glUniform4i = osg::getGLExtensionFuncPtr("glUniform4i", "glUniform4iARB"); + _glUniform1fv = osg::getGLExtensionFuncPtr("glUniform1fv", "glUniform1fvARB"); + _glUniform2fv = osg::getGLExtensionFuncPtr("glUniform2fv", "glUniform2fvARB"); + _glUniform3fv = osg::getGLExtensionFuncPtr("glUniform3fv", "glUniform3fvARB"); + _glUniform4fv = osg::getGLExtensionFuncPtr("glUniform4fv", "glUniform4fvARB"); + _glUniform1iv = osg::getGLExtensionFuncPtr("glUniform1iv", "glUniform1ivARB"); + _glUniform2iv = osg::getGLExtensionFuncPtr("glUniform2iv", "glUniform2ivARB"); + _glUniform3iv = osg::getGLExtensionFuncPtr("glUniform3iv", "glUniform3ivARB"); + _glUniform4iv = osg::getGLExtensionFuncPtr("glUniform4iv", "glUniform4ivARB"); + _glUniformMatrix2fv = osg::getGLExtensionFuncPtr("glUniformMatrix2fv", "glUniformMatrix2fvARB"); + _glUniformMatrix3fv = osg::getGLExtensionFuncPtr("glUniformMatrix3fv", "glUniformMatrix3fvARB"); + _glUniformMatrix4fv = osg::getGLExtensionFuncPtr("glUniformMatrix4fv", "glUniformMatrix4fvARB"); + _glValidateProgram = osg::getGLExtensionFuncPtr("glValidateProgram", "glValidateProgramARB"); + _glVertexAttrib1d = osg::getGLExtensionFuncPtr("glVertexAttrib1d"); + _glVertexAttrib1dv = osg::getGLExtensionFuncPtr("glVertexAttrib1dv"); + _glVertexAttrib1f = osg::getGLExtensionFuncPtr("glVertexAttrib1f"); + _glVertexAttrib1fv = osg::getGLExtensionFuncPtr("glVertexAttrib1fv"); + _glVertexAttrib1s = osg::getGLExtensionFuncPtr("glVertexAttrib1s"); + _glVertexAttrib1sv = osg::getGLExtensionFuncPtr("glVertexAttrib1sv"); + _glVertexAttrib2d = osg::getGLExtensionFuncPtr("glVertexAttrib2d"); + _glVertexAttrib2dv = osg::getGLExtensionFuncPtr("glVertexAttrib2dv"); + _glVertexAttrib2f = osg::getGLExtensionFuncPtr("glVertexAttrib2f"); + _glVertexAttrib2fv = osg::getGLExtensionFuncPtr("glVertexAttrib2fv"); + _glVertexAttrib2s = osg::getGLExtensionFuncPtr("glVertexAttrib2s"); + _glVertexAttrib2sv = osg::getGLExtensionFuncPtr("glVertexAttrib2sv"); + _glVertexAttrib3d = osg::getGLExtensionFuncPtr("glVertexAttrib3d"); + _glVertexAttrib3dv = osg::getGLExtensionFuncPtr("glVertexAttrib3dv"); + _glVertexAttrib3f = osg::getGLExtensionFuncPtr("glVertexAttrib3f"); + _glVertexAttrib3fv = osg::getGLExtensionFuncPtr("glVertexAttrib3fv"); + _glVertexAttrib3s = osg::getGLExtensionFuncPtr("glVertexAttrib3s"); + _glVertexAttrib3sv = osg::getGLExtensionFuncPtr("glVertexAttrib3sv"); + _glVertexAttrib4Nbv = osg::getGLExtensionFuncPtr("glVertexAttrib4Nbv"); + _glVertexAttrib4Niv = osg::getGLExtensionFuncPtr("glVertexAttrib4Niv"); + _glVertexAttrib4Nsv = osg::getGLExtensionFuncPtr("glVertexAttrib4Nsv"); + _glVertexAttrib4Nub = osg::getGLExtensionFuncPtr("glVertexAttrib4Nub"); + _glVertexAttrib4Nubv = osg::getGLExtensionFuncPtr("glVertexAttrib4Nubv"); + _glVertexAttrib4Nuiv = osg::getGLExtensionFuncPtr("glVertexAttrib4Nuiv"); + _glVertexAttrib4Nusv = osg::getGLExtensionFuncPtr("glVertexAttrib4Nusv"); + _glVertexAttrib4bv = osg::getGLExtensionFuncPtr("glVertexAttrib4bv"); + _glVertexAttrib4d = osg::getGLExtensionFuncPtr("glVertexAttrib4d"); + _glVertexAttrib4dv = osg::getGLExtensionFuncPtr("glVertexAttrib4dv"); + _glVertexAttrib4f = osg::getGLExtensionFuncPtr("glVertexAttrib4f"); + _glVertexAttrib4fv = osg::getGLExtensionFuncPtr("glVertexAttrib4fv"); + _glVertexAttrib4iv = osg::getGLExtensionFuncPtr("glVertexAttrib4iv"); + _glVertexAttrib4s = osg::getGLExtensionFuncPtr("glVertexAttrib4s"); + _glVertexAttrib4sv = osg::getGLExtensionFuncPtr("glVertexAttrib4sv"); + _glVertexAttrib4ubv = osg::getGLExtensionFuncPtr("glVertexAttrib4ubv"); + _glVertexAttrib4uiv = osg::getGLExtensionFuncPtr("glVertexAttrib4uiv"); + _glVertexAttrib4usv = osg::getGLExtensionFuncPtr("glVertexAttrib4usv"); + _glVertexAttribPointer = osg::getGLExtensionFuncPtr("glVertexAttribPointer"); + + // v1.5-only ARB entry points, in case they're needed for fallback + _glGetInfoLogARB = osg::getGLExtensionFuncPtr("glGetInfoLogARB"); + _glGetObjectParameterivARB = osg::getGLExtensionFuncPtr("glGetObjectParameterivARB"); + _glDeleteObjectARB = osg::getGLExtensionFuncPtr("glDeleteObjectARB"); + _glGetHandleARB = osg::getGLExtensionFuncPtr("glGetHandleARB"); +} + + +bool GL2Extensions::isGlslSupported() const +{ + return ( _glVersion >= 2.0f ) || + ( _isShaderObjectsSupported && + _isVertexShaderSupported && + _isFragmentShaderSupported && + _isLanguage100Supported ); +} + + +/////////////////////////////////////////////////////////////////////////// +// Static array of per-context osg::GL2Extensions instances + +typedef osg::buffered_value< osg::ref_ptr > BufferedExtensions; +static BufferedExtensions s_extensions; + +GL2Extensions* +GL2Extensions::Get(unsigned int contextID, bool createIfNotInitalized) +{ + if (!s_extensions[contextID] && createIfNotInitalized) + s_extensions[contextID] = new GL2Extensions; + + return s_extensions[contextID].get(); +} + +void GL2Extensions::Set(unsigned int contextID, GL2Extensions* extensions) +{ + s_extensions[contextID] = extensions; +} + + +/////////////////////////////////////////////////////////////////////////// + +static void NotSupported( const char* funcName ) +{ + osg::notify(osg::WARN) + <<"Error: "<= 2.0f ) + { + // GLSL as GL v2.0 core functionality + GLint result; + glGetIntegerv( GL_CURRENT_PROGRAM, &result ); + return static_cast(result); + } + else if (_glGetHandleARB) + { + // fallback for GLSL as GL v1.5 ARB extension +#ifndef GL_PROGRAM_OBJECT_ARB +#define GL_PROGRAM_OBJECT_ARB 0x8B40 +#endif + typedef GLuint (APIENTRY * GetHandleProc) (GLenum pname); + return ((GetHandleProc)_glGetHandleARB)( GL_PROGRAM_OBJECT_ARB ); + } + else + { + NotSupported( "getCurrentProgram" ); + return 0; + } +} + + +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 + + glGetProgramiv( program, GL_INFO_LOG_LENGTH, &bufLen ); + if( bufLen > 1 ) + { + GLchar* infoLog = new GLchar[bufLen]; + glGetProgramInfoLog( program, bufLen, &strLen, infoLog ); + if( strLen > 0 ) result = infoLog; + delete [] infoLog; + } + return (strLen > 0); +} + + +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 + + glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &bufLen ); + if( bufLen > 1 ) + { + GLchar* infoLog = new GLchar[bufLen]; + glGetShaderInfoLog( shader, bufLen, &strLen, infoLog ); + if( strLen > 0 ) result = infoLog; + delete [] infoLog; + } + return (strLen > 0); +} + + +void Program::deleteProgram(unsigned int contextID, GLuint program) +{ + if( program ) + { + OpenThreads::ScopedLock lock(s_mutex_deletedGL2ObjectCache); + + // add program to the cache for the appropriate context. + s_deletedGlProgramCache[contextID].push_back(program); + } +} + +void Program::flushDeletedGlslObjects(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 lock(s_mutex_deletedGL2ObjectCache); + + DeletedGlProgramCache::iterator citr = s_deletedGlProgramCache.find(contextID); + if( citr != s_deletedGlProgramCache.end() ) + { + GlProgramHandleList& pList = citr->second; + for(GlProgramHandleList::iterator titr=pList.begin(); + titr!=pList.end() && elapsedTimeglDeleteProgram( *titr ); + titr = pList.erase( titr ); + elapsedTime = timer.delta_s(start_tick,timer.tick()); + } + } + } + + availableTime -= elapsedTime; +} + + +/////////////////////////////////////////////////////////////////////////// +// osg::Program +/////////////////////////////////////////////////////////////////////////// + +Program::Program() +{ + _avoidRedundantUniformSetting = true; +} + + +Program::Program(const Program& rhs, const osg::CopyOp& copyop): + osg::StateAttribute(rhs, copyop) +{ + osg::notify(osg::FATAL) << "how got here?" << std::endl; +} + + +Program::~Program() +{ + for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt ) + { + if( ! _pcpoList[cxt] ) continue; + + PerContextProgObj* pcpo = _pcpoList[cxt].get(); + + deleteProgram( cxt, pcpo->getHandle() ); + // TODO add shader objects to delete list. + _pcpoList[cxt] = 0; + } +} + +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. + COMPARE_StateAttribute_Types(Program,sa) + + 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; + + ShaderList::const_iterator litr=_shaderList.begin(); + ShaderList::const_iterator ritr=rhs._shaderList.begin(); + for(; + litr!=_shaderList.end(); + ++litr,++ritr) + { + int result = (*litr)->compare(*(*ritr)); + if (result!=0) return result; + } + + return 0; // passed all the above comparison macro's, must be equal. +} + + +void Program::compileGLObjects( osg::State& state ) const +{ + if( _shaderList.empty() ) 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 ) + { + _shaderList[i]->compileShader( contextID ); + } + pcpo->linkProgram(); + + // TODO pcpo->releaseActiveUniformList(); + // TODO pcpo->buildActiveUniformList; + + // TODO regenerate pcpo->_activeAttribList; +} + + +void Program::dirtyProgram() +{ + // mark all PCPOs as needing a relink + for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt ) + { + if( ! _pcpoList[cxt] ) continue; + + PerContextProgObj* pcpo = _pcpoList[cxt].get(); + pcpo->markAsDirty(); + } +} + + +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(this)->dirtyShaders(); + else + { + unsigned int contextID = state->getContextID(); + const_cast(this)->_shaderList[contextID]->dirtyShader(); + } +} + + +void Program::addShader( Shader* shader ) +{ + _shaderList.push_back( shader ); + shader->addProgObjRef( this ); + dirtyProgram(); +} + + +void Program::apply( osg::State& state ) const +{ + const unsigned int contextID = state.getContextID(); + 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() ) + { + extensions->glUseProgram( 0 ); + return; + } + + PerContextProgObj* pcpo = getPCPO( contextID ); + if( pcpo->isDirty() ) compileGLObjects( state ); + + if( pcpo->isDirty() ) + { + // _still_ dirty, something went wrong + extensions->glUseProgram( 0 ); + } + else + { + pcpo->useProgram(); + pcpo->applyUniforms( state ); + } +} + + +Program::PerContextProgObj* Program::getPCPO(unsigned int contextID) const +{ + if( ! _pcpoList[contextID].valid() ) + { + _pcpoList[contextID] = new PerContextProgObj( this, contextID ); + + // attach all PCSOs to this new PCPO + for( unsigned int i=0; i < _shaderList.size() ; ++i ) + { + _shaderList[i]->attachShader( contextID, _pcpoList[contextID]->getHandle() ); + } + } + return _pcpoList[contextID].get(); +} + + +/////////////////////////////////////////////////////////////////////////// +// osg::Program::ActiveUniform +/////////////////////////////////////////////////////////////////////////// + +Program::ActiveUniform::ActiveUniform( const GLchar* name, GLenum type ) : + _value( name, static_cast< Uniform::Value::Type >(type) ) +{ +} + + +/////////////////////////////////////////////////////////////////////////// +// osg::Program::PerContextProgObj +// PCPO is an OSG abstraction of the per-context glProgram +/////////////////////////////////////////////////////////////////////////// + +Program::PerContextProgObj::PerContextProgObj(const Program* program, unsigned int contextID ) : + osg::Referenced(), + _contextID( contextID ) +{ + _program = program; + _extensions = GL2Extensions::Get( _contextID, true ); + _glProgramHandle = _extensions->glCreateProgram(); + markAsDirty(); +} + +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() +{ +} + + +void Program::PerContextProgObj::markAsDirty() +{ + // TODO releaseActiveUniformList(); + _dirty = true; +} + + +void Program::PerContextProgObj::linkProgram() +{ + GLint linked; + + _extensions->glLinkProgram( _glProgramHandle ); + _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked ); + _dirty = (linked == 0); + + if( _dirty ) + { + // _still_ dirty, something went wrong + std::string infoLog; + _extensions->getProgramInfoLog( _glProgramHandle, infoLog ); + osg::notify(osg::WARN) << "glLinkProgram FAILED:\n" << infoLog << std::endl; + } +} + + +void Program::PerContextProgObj::useProgram() const +{ + _extensions->glUseProgram( _glProgramHandle ); +} + + +void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const +{ + bool uniformDoesNeedSetting = true; + + 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. + } + + if( uniformDoesNeedSetting ) + { + // TODO set the uniform value on the currently active glProgram. + } +} diff --git a/src/osg/Shader.cpp b/src/osg/Shader.cpp new file mode 100644 index 000000000..a93c25273 --- /dev/null +++ b/src/osg/Shader.cpp @@ -0,0 +1,239 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. + * +*/ + +/* file: src/osg/Program.cpp + * author: Mike Weiblen 2005-02-20 +*/ + +// 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace osg; + +typedef std::list GlShaderHandleList; +typedef std::map DeletedGlShaderCache; + +static OpenThreads::Mutex s_mutex_deletedGL2ShaderCache; +static DeletedGlShaderCache s_deletedGlShaderCache; + +/////////////////////////////////////////////////////////////////////////// +// osg::Shader +/////////////////////////////////////////////////////////////////////////// + +Shader::Shader(Type type, const char* sourceText) : + _type(type) +{ + setShaderSource( sourceText ); +} + +Shader::Shader(const Shader& rhs, const osg::CopyOp& /*copyop*/): + Referenced( rhs ), + _type(rhs._type) +{ + /*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( 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; + + sourceFile.open(fileName, std::ios::binary); + if(!sourceFile) + { + osg::notify(osg::WARN)<<"Error: can't open file \""<isDirty() ) pcso->compileShader(); +} + + +Shader::PerContextShaderObj* Shader::getPCSO(unsigned int contextID) const +{ + if( ! _pcsoList[contextID].valid() ) + { + _pcsoList[contextID] = new PerContextShaderObj( this, contextID ); + } + return _pcsoList[contextID].get(); +} + + +void Shader::attachShader(unsigned int contextID, GLuint program) const +{ + getPCSO( contextID )->attachShader( program ); +} + + +void Shader::addProgObjRef( Program* program ) +{ + _programList.push_back( program ); +} + + +void Shader::deleteShader(unsigned int contextID, GLuint shader) +{ + if( shader ) + { + OpenThreads::ScopedLock lock(s_mutex_deletedGL2ShaderCache); + + // add shader to the cache for the appropriate context. + s_deletedGlShaderCache[contextID].push_back(shader); + } +} + + +/////////////////////////////////////////////////////////////////////////// +// osg::Shader::PerContextShaderObj +// PCSO is the OSG abstraction of the per-context glShader +/////////////////////////////////////////////////////////////////////////// + +Shader::PerContextShaderObj::PerContextShaderObj(const Shader* shader, unsigned int contextID) : + osg::Referenced(), + _contextID( contextID ) +{ + _shader = shader; + _extensions = GL2Extensions::Get( _contextID, true ); + _glShaderHandle = _extensions->glCreateShader( shader->getType() ); + markAsDirty(); +} + +Shader::PerContextShaderObj::PerContextShaderObj(const PerContextShaderObj& rhs) : + osg::Referenced(), + _contextID( rhs._contextID ) +{ + _shader = rhs._shader; + _extensions = rhs._extensions; + _glShaderHandle = rhs._glShaderHandle; + _dirty = rhs._dirty; +} + +Shader::PerContextShaderObj::~PerContextShaderObj() +{ +} + +void Shader::PerContextShaderObj::compileShader() +{ + 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 ) + { + // _still_ dirty, something went wrong + std::string infoLog; + _extensions->getShaderInfoLog( _glShaderHandle, infoLog ); + osg::notify(osg::WARN) << _shader->getTypename() << + " glCompileShader FAILED:\n" << infoLog << std::endl; + } +} + +void Shader::PerContextShaderObj::attachShader(GLuint program) const +{ + _extensions->glAttachShader( program, _glShaderHandle ); +} + +/*EOF*/ diff --git a/src/osg/Uniform.cpp b/src/osg/Uniform.cpp new file mode 100644 index 000000000..140d008ff --- /dev/null +++ b/src/osg/Uniform.cpp @@ -0,0 +1,527 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield + * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application 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. +*/ + +/* file: src/osg/Uniform.cpp + * author: Mike Weiblen 2005-02-20 +*/ + +// 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 + +using namespace osg; + + +/////////////////////////////////////////////////////////////////////////// +// osg::Uniform::Value +/////////////////////////////////////////////////////////////////////////// + +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) +{ + if( rhs._isValid ) copyData(rhs); +} + + +const char* Uniform::Value::getTypename( Type t ) +{ + switch( t ) + { + case FLOAT: return "float"; + case FLOAT_VEC2: return "vec2"; + case FLOAT_VEC3: return "vec3"; + case FLOAT_VEC4: return "vec4"; + case INT: return "int"; + case INT_VEC2: return "ivec2"; + case INT_VEC3: return "ivec3"; + case INT_VEC4: return "ivec4"; + case BOOL: return "bool"; + case BOOL_VEC2: return "bvec2"; + case BOOL_VEC3: return "bvec3"; + case BOOL_VEC4: return "bvec4"; + case FLOAT_MAT2: return "mat2"; + case FLOAT_MAT3: return "mat3"; + case FLOAT_MAT4: return "mat4"; + case SAMPLER_1D: return "sampler1D"; + case SAMPLER_2D: return "sampler2D"; + case SAMPLER_3D: return "sampler3D"; + case SAMPLER_CUBE: return "samplerCube"; + case SAMPLER_1D_SHADOW: return "sampler1DShadow"; + case SAMPLER_2D_SHADOW: return "sampler2DShadow"; + default: return "UNDEFINED"; + } +} + + +int Uniform::Value::compare(const Value& rhs) const +{ + 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) + { + 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: + case SAMPLER_3D: + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } +} + + +/////////////////////////////////////////////////////////////////////////// +// 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 char* name, float f ) : + _value( name, Value::FLOAT ) +{ + _value.set( f ); +} + +Uniform::Uniform( const char* name, const osg::Vec2& v2 ) : + _value( name, Value::FLOAT_VEC2 ) +{ + _value.set( v2 ); +} + +Uniform::Uniform( const char* name, const osg::Vec3& v3 ) : + _value( name, Value::FLOAT_VEC3 ) +{ + _value.set( v3 ); +} + +Uniform::Uniform( const char* name, const osg::Vec4& v4 ) : + _value( name, Value::FLOAT_VEC4 ) +{ + _value.set( v4 ); +} + +//TODO 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::Matrix& m4 ) : + _value( name, Value::FLOAT_MAT4 ) +{ + _value.set( m4 ); +} + +Uniform::Uniform( const char* name, int i ) : + _value( name, Value::INT ) +{ + _value.set( i ); +} + +//TODO Uniform::Uniform( const char* name, int i0, int i1 ) + +//TODO Uniform::Uniform( const char* name, int i0, int i1, int i2 ) + +//TODO Uniform::Uniform( const char* name, int i0, int i1, int i2, int i3 ) + +//TODO Uniform::Uniform( const char* name, bool b ) + +//TODO Uniform::Uniform( const char* name, bool b0, bool b1 ) + +//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2 ) + +//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 ) + + +Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) : + StateAttribute(gu,copyop), + _value( gu._value ) +{ +} + + +void Uniform::apply( State& /*state*/ ) const +{ + // The definition of apply() for Uniforms is unique among + // osg::StateAttributes... + // If a Program is not active, then cannot apply the uniform value, + // but must wait for a Program to do that itself later when it + // does become active. + // If a Program is active, then the Uniform may be applied + // immediately. + // something like... + // + // Program* program = state->getActiveProgram(); + // if( program ) + // { + // program->applyUniform( this ); + // } +} + + + +bool Uniform::set( float f ) +{ + if( ! isCompatibleType( Value::FLOAT ) ) return false; + _value.set( f ); + return true; +} + +bool Uniform::set( const osg::Vec2& v2 ) +{ + if( ! isCompatibleType( Value::FLOAT_VEC2 ) ) return false; + _value.set( v2 ); + return true; +} + +bool Uniform::set( const osg::Vec3& v3 ) +{ + if( ! isCompatibleType( Value::FLOAT_VEC3 ) ) return false; + _value.set( v3 ); + return true; +} + +bool Uniform::set( const osg::Vec4& v4 ) +{ + if( ! isCompatibleType( Value::FLOAT_VEC4 ) ) return false; + _value.set( v4 ); + return true; +} + +//TODO bool Uniform::set( const osg::Matrix2& m2 ) + +//TODO bool Uniform::set( const osg::Matrix3& m3 ) + +bool Uniform::set( const osg::Matrix& m4 ) +{ + if( ! isCompatibleType( Value::FLOAT_MAT4 ) ) return false; + _value.set( m4 ); + return true; +} + +bool Uniform::set( int i ) +{ + if( ! isCompatibleType( Value::INT ) ) return false; + _value.set( 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 +{ + if( t == _value.getType() ) 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; +} + + +/*EOF*/