bool ShaderGenerator::processText(const osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement) { // do nothing if there's no GLSL support if ( !_active ) return false; // Capture the active current state: osg::ref_ptr<osg::StateSet> current = static_cast<StateEx*>(_state.get())->capture(); // check for a real osg::Program. If it exists, bail out so that OSG // can use the program already in the graph osg::StateAttribute* program = current->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // New state set. We never modify existing statesets. replacement = ss ? osg::clone(ss, osg::CopyOp::SHALLOW_COPY) : new osg::StateSet(); // new VP: osg::ref_ptr<VirtualProgram> vp = VirtualProgram::cloneOrCreate(replacement.get()); // give the VP a name if it needs one. if ( vp->getName().empty() ) { vp->setName( _name ); } std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertexVIEW)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" //INDENT MEDIUMP "vec4 texel = texture2DLod(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy, 0.0);\n" INDENT "color.a *= texel.a; \n" "}\n"; vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_MODEL, 0.5f ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING, 0.5f ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
bool ShaderGenerator::processText(const osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement) { // do nothing if there's no GLSL support if ( !_active ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program. If it exists, bail out so that OSG // can use the program already in the graph osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // new state set: replacement = ss ? osg::clone(ss, osg::CopyOp::SHALLOW_COPY) : new osg::StateSet(); // new VP: VirtualProgram* vp = 0L; if ( VirtualProgram::get(replacement.get()) ) vp = osg::clone(VirtualProgram::get(replacement.get()), osg::CopyOp::DEEP_COPY_ALL); else vp = VirtualProgram::getOrCreate(replacement.get()); if ( vp->referenceCount() == 1 ) vp->setName( _name ); std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertexVIEW)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" INDENT "color.a *= texel.a; \n" "}\n"; vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
bool ShaderGenerator::processText( osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement ) { // do nothing if there's no GLSL support if ( !Registry::capabilities().supportsGLSL() ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program. If it exists, bail out so that OSG // can use the program already in the graph osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // see if the current state set contains a VirtualProgram already. If so, // we will add to it if necessary. VirtualProgram* vp = dynamic_cast<VirtualProgram*>( ss->getAttribute(VirtualProgram::SA_TYPE) ); replacement = osg::clone(ss, osg::CopyOp::SHALLOW_COPY); //replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); std::string vertSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " VERTEX_FUNCTION "(inout vec4 vertex_view)\n" "{ \n" INDENT TEX_COORD_TEXT " = gl_MultiTexCoord0;\n" "} \n"; std::string fragSrc = "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION "\n" "uniform sampler2D " SAMPLER_TEXT ";\n" "varying " MEDIUMP "vec4 " TEX_COORD_TEXT ";\n" "void " FRAGMENT_FUNCTION "(inout vec4 color)\n" "{ \n" INDENT MEDIUMP "vec4 texel = texture2D(" SAMPLER_TEXT ", " TEX_COORD_TEXT ".xy);\n" INDENT "color.a *= texel.a; \n" "}\n"; if ( !vp ) vp = osg::clone( _defaultVP.get() ); replacement->setAttributeAndModes( vp, osg::StateAttribute::ON ); vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); replacement->getOrCreateUniform( SAMPLER_TEXT, osg::Uniform::SAMPLER_2D )->set( 0 ); return replacement.valid(); }
bool ShaderGenerator::processGeometry( osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement ) { // do nothing if there's no GLSL support if ( !Registry::capabilities().supportsGLSL() ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program in the whole state stack. If it exists, bail out // so that OSG can use the program already in the graph. We never override a // full Program. osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // see if the current state set contains a VirtualProgram already. If so, // we will add to it if necessary. osg::ref_ptr<VirtualProgram> vp = dynamic_cast<VirtualProgram*>( ss->getAttribute(VirtualProgram::SA_TYPE) ); // Check whether the lighting state has changed and install a mode uniform. if ( ss->getMode(GL_LIGHTING) != osg::StateAttribute::INHERIT ) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::SHALLOW_COPY); //if ( !replacement.valid() ) // replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); osg::StateAttribute::GLModeValue value = state->getMode(GL_LIGHTING); // from the state, not the ss. replacement->addUniform( Registry::shaderFactory()->createUniformForGLMode(GL_LIGHTING, value) ); } // if the stateset changes any texture attributes, we need a new virtual program: if (ss->getTextureAttributeList().size() > 0) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::SHALLOW_COPY); //if ( !replacement.valid() ) // replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); // work off the state's accumulated texture attribute set: int texCount = state->getNumTextureAttributes(); if ( !vp ) { vp = osg::clone( _defaultVP.get() ); replacement->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // start generating the shader source. std::stringstream vertHead, vertBody, fragHead, fragBody; // compatibility strings make it work in GL or GLES. vertHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; fragHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; // function declarations: vertBody << "void " VERTEX_FUNCTION "(inout vec4 vertex_view)\n{\n"; fragBody << "void " FRAGMENT_FUNCTION "(inout vec4 color)\n{\n"; for( int t = 0; t < texCount; ++t ) { if (t == 0) { fragBody << INDENT << MEDIUMP "vec4 texel; \n"; } osg::StateAttribute* tex = state->getTextureAttribute( t, osg::StateAttribute::TEXTURE ); if ( tex ) { // see if we have a texenv; if so get its blending mode. osg::TexEnv::Mode blendingMode = osg::TexEnv::MODULATE; osg::TexEnv* env = dynamic_cast<osg::TexEnv*>(state->getTextureAttribute(t, osg::StateAttribute::TEXENV) ); if ( env ) { blendingMode = env->getMode(); if ( blendingMode == osg::TexEnv::BLEND ) { replacement->getOrCreateUniform( Stringify() << TEXENV_COLOR << t, osg::Uniform::FLOAT_VEC4 )->set( env->getColor() ); } } osg::TexGen::Mode texGenMode = osg::TexGen::OBJECT_LINEAR; osg::TexGen* texGen = dynamic_cast<osg::TexGen*>(state->getTextureAttribute(t, osg::StateAttribute::TEXGEN)); if ( texGen ) { texGenMode = texGen->getMode(); } vertHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; fragHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; // handle different TexGen modes. switch(texGenMode) { case osg::TexGen::SPHERE_MAP: vertBody //todo: consolidate. << INDENT "{\n" // scope it in case there are > 1 << INDENT "vec3 v = normalize(vec3(vertex_view));\n" << INDENT "vec3 n = normalize(gl_NormalMatrix * gl_Normal);\n" << INDENT "vec3 r = reflect(v, n);\n" << INDENT "float m = 2.0 * sqrt(r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0));\n" << INDENT TEX_COORD << t << ".s = r.x/m + 0.5;\n" << INDENT TEX_COORD << t << ".t = r.y/m + 0.5;\n" << INDENT "}\n"; break; default: vertBody << INDENT << TEX_COORD << t << " = gl_MultiTexCoord" << t << ";\n"; break; } if ( dynamic_cast<osg::Texture1D*>(tex) ) { fragHead << "uniform sampler1D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture1D(" SAMPLER << t << ", " TEX_COORD << t << ".x);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_1D )->set( t ); } #if 1 else if ( dynamic_cast<osg::Texture2D*>(tex) ) { fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2D(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } #else // embosser else if ( dynamic_cast<osg::Texture2D*>(tex) ) { fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "{\n" << INDENT "float bs = 1.0/256.0;\n" << INDENT "vec4 bm = vec4(0.0);\n" << INDENT "float u = " TEX_COORD << t << ".x;\n" << INDENT "float v = " TEX_COORD << t << ".y;\n" << INDENT "texel = texture2D(" SAMPLER << t << ", vec2(u, v)); \n" << INDENT "bm = texture2D(" SAMPLER << t << ", vec2(u-bs, v-bs)) + \n" << INDENT " texture2D(" SAMPLER << t << ", vec2(u-bs, v-bs)) - \n" << INDENT " texel - \n" << INDENT " texture2D(" SAMPLER << t << ", vec2(u+bs, v+bs)); \n" << INDENT "texel *= vec4( 2.0*(bm.rgb+vec3(0.5,0.5,0.5)),1.0 );\n" << INDENT "}\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } #endif #if 0 // works, but requires a higher version of GL? else if ( dynamic_cast<osg::TextureRectangle*>(tex) ) { fragHead << "uniform sampler2Drect " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2Drect(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D_RECT )->set( t ); } #endif // doesn't work. why? else if ( dynamic_cast<osg::TextureRectangle*>(tex) ) { osg::Image* image = static_cast<osg::TextureRectangle*>(tex)->getImage(); vertBody << INDENT << TEX_COORD << t << ".x /= " << (image->s()-1) << ".0;\n" << INDENT << TEX_COORD << t << ".y /= " << (image->t()-1) << ".0;\n"; fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2D(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } else if ( dynamic_cast<osg::Texture3D*>(tex) ) { fragHead << "uniform sampler3D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture3D(" SAMPLER << t << ", " TEX_COORD << t << ".xyz);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_3D )->set( t ); } // See http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml switch( blendingMode ) { case osg::TexEnv::REPLACE: fragBody << INDENT "color = texel; \n"; break; case osg::TexEnv::MODULATE: fragBody << INDENT "color = color * texel; \n"; break; case osg::TexEnv::DECAL: fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.a) + (texel.rgb * texel.a); \n"; break; case osg::TexEnv::BLEND: fragHead << "uniform " MEDIUMP "vec4 " TEXENV_COLOR << t << "\n;"; fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.rgb) + (" << TEXENV_COLOR << t << ".rgb * texel.rgb); \n" << INDENT "color.a = color.a * texel.a; \n"; break; case osg::TexEnv::ADD: default: fragBody << INDENT "color.rgb = color.rgb + texel.rgb; \n" << INDENT "color.a = color.a * texel.a; \n"; } } } // close out functions: vertBody << "}\n"; fragBody << "}\n"; // Extract the shader source strings (win compat method) std::string vertBodySrc, vertSrc, fragBodySrc, fragSrc; vertBodySrc = vertBody.str(); vertHead << vertBodySrc; vertSrc = vertHead.str(); fragBodySrc = fragBody.str(); fragHead << fragBodySrc; fragSrc = fragHead.str(); // inject the shaders: vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_VIEW ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_COLORING ); } return replacement.valid(); }
bool ShaderGenerator::processGeometry( osg::StateSet* ss, osg::ref_ptr<osg::StateSet>& replacement ) { // do nothing if there's no GLSL support if ( !Registry::capabilities().supportsGLSL() ) return false; // State object with extra accessors: StateEx* state = static_cast<StateEx*>(_state.get()); // check for a real osg::Program in the whole state stack. If it exists, bail out // so that OSG can use the program already in the graph. We never override a // full Program. osg::StateAttribute* program = state->getAttribute(osg::StateAttribute::PROGRAM); if ( dynamic_cast<osg::Program*>(program) != 0L ) return false; // see if the current state set contains a VirtualProgram already. If so, // we will add to it if necessary. VirtualProgram* vp = dynamic_cast<VirtualProgram*>( ss->getAttribute(VirtualProgram::SA_TYPE) ); // Check whether the lighting state has changed and install a mode uniform. if ( ss->getMode(GL_LIGHTING) != osg::StateAttribute::INHERIT ) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); ShaderFactory* sf = Registry::instance()->getShaderFactory(); osg::StateAttribute::GLModeValue value = state->getMode(GL_LIGHTING); // from the state, not the ss. replacement->addUniform( sf->createUniformForGLMode(GL_LIGHTING, value) ); } // if the stateset changes any texture attributes, we need a new virtual program: if (ss->getTextureAttributeList().size() > 0) { if ( !replacement.valid() ) replacement = osg::clone(ss, osg::CopyOp::DEEP_COPY_ALL); // work off the state's accumulated texture attribute set: int texCount = state->getNumTextureAttributes(); if ( !vp ) { vp = osg::clone( _defaultVP.get() ); replacement->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // start generating the shader source. std::stringstream vertHead, vertBody, fragHead, fragBody; // compatibility strings make it work in GL or GLES. vertHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; fragHead << "#version " GLSL_VERSION_STR "\n" GLSL_PRECISION; // function declarations: vertBody << "void " VERTEX_FUNCTION "()\n{\n"; fragBody << "void " FRAGMENT_FUNCTION "(inout vec4 color)\n{\n"; for( int t = 0; t < texCount; ++t ) { if (t == 0) { fragBody << INDENT << MEDIUMP "vec4 texel; \n"; } osg::StateAttribute* tex = state->getTextureAttribute( t, osg::StateAttribute::TEXTURE ); if ( tex ) { // see if we have a texenv; if so get its blending mode. osg::TexEnv::Mode blendingMode = osg::TexEnv::MODULATE; osg::TexEnv* env = dynamic_cast<osg::TexEnv*>(state->getTextureAttribute(t, osg::StateAttribute::TEXENV) ); if ( env ) { blendingMode = env->getMode(); if ( blendingMode == osg::TexEnv::BLEND ) { replacement->getOrCreateUniform( Stringify() << TEXENV_COLOR << t, osg::Uniform::FLOAT_VEC4 )->set( env->getColor() ); } } vertHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; vertBody << INDENT << TEX_COORD << t << " = gl_MultiTexCoord" << t << ";\n"; fragHead << "varying " MEDIUMP "vec4 " TEX_COORD << t << ";\n"; if ( dynamic_cast<osg::Texture1D*>(tex) ) { fragHead << "uniform sampler1D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture1D(" SAMPLER << t << ", " TEX_COORD << t << ".x);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_1D )->set( t ); } else if ( dynamic_cast<osg::Texture2D*>(tex) ) { fragHead << "uniform sampler2D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture2D(" SAMPLER << t << ", " TEX_COORD << t << ".xy);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_2D )->set( t ); } else if ( dynamic_cast<osg::Texture3D*>(tex) ) { fragHead << "uniform sampler3D " SAMPLER << t << ";\n"; fragBody << INDENT "texel = texture3D(" SAMPLER << t << ", " TEX_COORD << t << ".xyz);\n"; replacement->getOrCreateUniform( Stringify() << SAMPLER << t, osg::Uniform::SAMPLER_3D )->set( t ); } // See http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml switch( blendingMode ) { case osg::TexEnv::REPLACE: fragBody << INDENT "color = texel; \n"; break; case osg::TexEnv::MODULATE: fragBody << INDENT "color = color * texel; \n"; break; case osg::TexEnv::DECAL: fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.a) + (texel.rgb * texel.a); \n"; break; case osg::TexEnv::BLEND: fragHead << "uniform " MEDIUMP "vec4 " TEXENV_COLOR << t << "\n;"; fragBody << INDENT "color.rgb = color.rgb * (1.0 - texel.rgb) + (" << TEXENV_COLOR << t << ".rgb * texel.rgb); \n" << INDENT "color.a = color.a * texel.a; \n"; break; case osg::TexEnv::ADD: default: fragBody << INDENT "color.rgb = color.rgb + texel.rgb; \n" << INDENT "color.a = color.a * texel.a; \n"; } } } // close out functions: vertBody << "}\n"; fragBody << "}\n"; // Extract the shader source strings (win compat method) std::string vertBodySrc, vertSrc, fragBodySrc, fragSrc; vertBodySrc = vertBody.str(); vertHead << vertBodySrc; vertSrc = vertHead.str(); fragBodySrc = fragBody.str(); fragHead << fragBodySrc; fragSrc = fragHead.str(); // inject the shaders: vp->setFunction( VERTEX_FUNCTION, vertSrc, ShaderComp::LOCATION_VERTEX_PRE_LIGHTING ); vp->setFunction( FRAGMENT_FUNCTION, fragSrc, ShaderComp::LOCATION_FRAGMENT_PRE_LIGHTING ); } return replacement.valid(); }