X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmaterial%2FEffect.cxx;h=b4c010f497b66d1b5265f2c9e944714a7de7aece;hb=0d419aba8a1ea9c67b1982f4d68fe1fe7bd79033;hp=1cff2323f42ff86f034544bf69a05c62ee6970c8;hpb=5991195062dad2bd11962eb52a49127e5a636b10;p=simgear.git diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 1cff2323..b4c010f4 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2008 - 2009 Tim Moore timoore@redhat.com +// Copyright (C) 2008 - 2010 Tim Moore timoore33@gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -30,14 +30,18 @@ #include #include #include +#include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -47,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +66,7 @@ #include #include +#include #include #include #include @@ -92,6 +98,8 @@ Effect::Effect(const Effect& rhs, const CopyOp& copyop) itr != end; ++itr) techniques.push_back(static_cast(copyop(itr->get()))); + + generator = rhs.generator; } // Assume that the last technique is always valid. @@ -104,6 +112,13 @@ StateSet* Effect::getDefaultStateSet() return pass; } +int Effect::getGenerator(Effect::Generator what) const +{ + std::map::const_iterator it = generator.find(what); + if(it == generator.end()) return -1; + else return it->second; +} + // There should always be a valid technique in an effect. Technique* Effect::chooseTechnique(RenderInfo* info) @@ -138,7 +153,7 @@ Effect::~Effect() } void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { Pass* pass = new Pass; tniq->passes.push_back(pass); @@ -154,6 +169,10 @@ void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop, } } +// Default names for vector property components +const char* vec3Names[] = {"x", "y", "z"}; +const char* vec4Names[] = {"x", "y", "z", "w"}; + osg::Vec4f getColor(const SGPropertyNode* prop) { if (prop->nChildren() == 0) { @@ -183,12 +202,12 @@ osg::Vec4f getColor(const SGPropertyNode* prop) struct LightingBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; void LightingBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -202,7 +221,7 @@ InstallAttributeBuilder installLighting("lighting"); struct ShadeModelBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -224,7 +243,7 @@ InstallAttributeBuilder installShadeModel("shade-model"); struct CullFaceBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) { @@ -249,6 +268,24 @@ struct CullFaceBuilder : PassAttributeBuilder InstallAttributeBuilder installCullFace("cull-face"); +struct ColorMaskBuilder : PassAttributeBuilder +{ + void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) + { + const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); + if (!realProp) + return; + + ColorMask *mask = new ColorMask; + Vec4 m = getColor(realProp); + mask->setMask(m.r(), m.g(), m.b(), m.a()); + pass->setAttributeAndModes(mask); + } +}; + +InstallAttributeBuilder installColorMask("color-mask"); + EffectNameValue renderingHintInit[] = { { "default", StateSet::DEFAULT_BIN }, @@ -261,7 +298,7 @@ EffectPropertyMap renderingHints(renderingHintInit); struct HintBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -277,7 +314,7 @@ InstallAttributeBuilder installHint("rendering-hint"); struct RenderBinBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -304,7 +341,7 @@ InstallAttributeBuilder installRenderBin("render-bin"); struct MaterialBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; EffectNameValue colorModeInit[] = @@ -320,7 +357,7 @@ EffectPropertyMap colorModes(colorModeInit); void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -390,7 +427,7 @@ EffectPropertyMap blendFuncModes(blendFuncModesInit); struct BlendBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -471,6 +508,99 @@ struct BlendBuilder : public PassAttributeBuilder InstallAttributeBuilder installBlend("blend"); + +EffectNameValue stencilFunctionInit[] = +{ + {"never", Stencil::NEVER }, + {"less", Stencil::LESS}, + {"equal", Stencil::EQUAL}, + {"less-or-equal", Stencil::LEQUAL}, + {"greater", Stencil::GREATER}, + {"not-equal", Stencil::NOTEQUAL}, + {"greater-or-equal", Stencil::GEQUAL}, + {"always", Stencil::ALWAYS} +}; + +EffectPropertyMap stencilFunction(stencilFunctionInit); + +EffectNameValue stencilOperationInit[] = +{ + {"keep", Stencil::KEEP}, + {"zero", Stencil::ZERO}, + {"replace", Stencil::REPLACE}, + {"increase", Stencil::INCR}, + {"decrease", Stencil::DECR}, + {"invert", Stencil::INVERT}, + {"increase-wrap", Stencil::INCR_WRAP}, + {"decrease-wrap", Stencil::DECR_WRAP} +}; + +EffectPropertyMap stencilOperation(stencilOperationInit); + +struct StencilBuilder : public PassAttributeBuilder +{ + void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) + { + if (!isAttributeActive(effect, prop)) + return; + + const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop, + "mode"); + if (pmode && !pmode->getValue()) { + pass->setMode(GL_STENCIL, StateAttribute::OFF); + return; + } + const SGPropertyNode* pfunction + = getEffectPropertyChild(effect, prop, "function"); + const SGPropertyNode* pvalue + = getEffectPropertyChild(effect, prop, "value"); + const SGPropertyNode* pmask + = getEffectPropertyChild(effect, prop, "mask"); + const SGPropertyNode* psfail + = getEffectPropertyChild(effect, prop, "stencil-fail"); + const SGPropertyNode* pzfail + = getEffectPropertyChild(effect, prop, "z-fail"); + const SGPropertyNode* ppass + = getEffectPropertyChild(effect, prop, "pass"); + + Stencil::Function func = Stencil::ALWAYS; // Always pass + int ref = 0; + unsigned int mask = ~0u; // All bits on + Stencil::Operation sfailop = Stencil::KEEP; // Keep the old values as default + Stencil::Operation zfailop = Stencil::KEEP; + Stencil::Operation passop = Stencil::KEEP; + + ref_ptr stencilFunc = new Stencil; + + if (pfunction) + findAttr(stencilFunction, pfunction, func); + if (pvalue) + ref = pvalue->getIntValue(); + if (pmask) + mask = pmask->getIntValue(); + + if (psfail) + findAttr(stencilOperation, psfail, sfailop); + if (pzfail) + findAttr(stencilOperation, pzfail, zfailop); + if (ppass) + findAttr(stencilOperation, ppass, passop); + + // Set the stencil operation + stencilFunc->setFunction(func, ref, mask); + + // Set the operation, s-fail, s-pass/z-fail, s-pass/z-pass + stencilFunc->setOperation(sfailop, zfailop, passop); + + // Add the operation to pass + pass->setAttributeAndModes(stencilFunc.get()); + } +}; + +InstallAttributeBuilder installStencil("stencil"); + + EffectNameValue alphaComparisonInit[] = { {"never", AlphaFunc::NEVER}, @@ -488,7 +618,7 @@ alphaComparison(alphaComparisonInit); struct AlphaTestBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -538,10 +668,50 @@ InstallAttributeBuilder installAlphaTest("alpha-test"); InstallAttributeBuilder textureUnitBuilder("texture-unit"); -typedef map > ProgramMap; +// Shader key, used both for shaders with relative and absolute names +typedef pair ShaderKey; + +struct ProgramKey +{ + typedef pair AttribKey; + osgDB::FilePathList paths; + vector shaders; + vector attributes; + struct EqualTo + { + bool operator()(const ProgramKey& lhs, const ProgramKey& rhs) const + { + return (lhs.paths.size() == rhs.paths.size() + && equal(lhs.paths.begin(), lhs.paths.end(), + rhs.paths.begin()) + && lhs.shaders.size() == rhs.shaders.size() + && equal (lhs.shaders.begin(), lhs.shaders.end(), + rhs.shaders.begin()) + && lhs.attributes.size() == rhs.attributes.size() + && equal(lhs.attributes.begin(), lhs.attributes.end(), + rhs.attributes.begin())); + } + }; +}; + +size_t hash_value(const ProgramKey& key) +{ + size_t seed = 0; + boost::hash_range(seed, key.paths.begin(), key.paths.end()); + boost::hash_range(seed, key.shaders.begin(), key.shaders.end()); + boost::hash_range(seed, key.attributes.begin(), key.attributes.end()); + return seed; +} + +// XXX Should these be protected by a mutex? Probably + +typedef tr1::unordered_map, + boost::hash, ProgramKey::EqualTo> +ProgramMap; ProgramMap programMap; -typedef map > ShaderMap; +typedef tr1::unordered_map, boost::hash > +ShaderMap; ShaderMap shaderMap; void reload_shaders() @@ -549,7 +719,7 @@ void reload_shaders() for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr) { Shader *shader = sitr->second.get(); - string fileName = osgDB::findDataFile(sitr->first); + string fileName = osgDB::findDataFile(sitr->first.first); if (!fileName.empty()) { shader->loadShaderSourceFromFile(fileName); } @@ -559,68 +729,137 @@ void reload_shaders() struct ShaderProgramBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; + +EffectNameValue geometryInputTypeInit[] = +{ + {"points", GL_POINTS}, + {"lines", GL_LINES}, + {"lines-adjacency", GL_LINES_ADJACENCY_EXT}, + {"triangles", GL_TRIANGLES}, + {"triangles-adjacency", GL_TRIANGLES_ADJACENCY_EXT}, +}; +EffectPropertyMap +geometryInputType(geometryInputTypeInit); + + +EffectNameValue geometryOutputTypeInit[] = +{ + {"points", GL_POINTS}, + {"line-strip", GL_LINE_STRIP}, + {"triangle-strip", GL_TRIANGLE_STRIP} +}; +EffectPropertyMap +geometryOutputType(geometryOutputTypeInit); + void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* + const SGReaderWriterXMLOptions* options) { + using namespace boost; if (!isAttributeActive(effect, prop)) return; PropertyList pVertShaders = prop->getChildren("vertex-shader"); + PropertyList pGeomShaders = prop->getChildren("geometry-shader"); PropertyList pFragShaders = prop->getChildren("fragment-shader"); - string programKey; + PropertyList pAttributes = prop->getChildren("attribute"); + ProgramKey prgKey; for (PropertyList::iterator itr = pVertShaders.begin(), e = pVertShaders.end(); itr != e; ++itr) - { - programKey += (*itr)->getStringValue(); - programKey += ";"; - } + prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(), + Shader::VERTEX)); + for (PropertyList::iterator itr = pGeomShaders.begin(), + e = pGeomShaders.end(); + itr != e; + ++itr) + prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(), + Shader::GEOMETRY)); for (PropertyList::iterator itr = pFragShaders.begin(), e = pFragShaders.end(); itr != e; ++itr) - { - programKey += (*itr)->getStringValue(); - programKey += ";"; + prgKey.shaders.push_back(ShaderKey((*itr)->getStringValue(), + Shader::FRAGMENT)); + for (PropertyList::iterator itr = pAttributes.begin(), + e = pAttributes.end(); + itr != e; + ++itr) { + const SGPropertyNode* pName = getEffectPropertyChild(effect, *itr, + "name"); + const SGPropertyNode* pIndex = getEffectPropertyChild(effect, *itr, + "index"); + if (!pName || ! pIndex) + throw BuilderException("malformed attribute property"); + prgKey.attributes + .push_back(ProgramKey::AttribKey(pName->getStringValue(), + pIndex->getValue())); } + if (options) + prgKey.paths = options->getDatabasePathList(); Program* program = 0; - ProgramMap::iterator pitr = programMap.find(programKey); + ProgramMap::iterator pitr = programMap.find(prgKey); if (pitr != programMap.end()) { program = pitr->second.get(); } else { program = new Program; - program->setName(programKey); // Add vertex shaders, then fragment shaders PropertyList& pvec = pVertShaders; Shader::Type stype = Shader::VERTEX; - for (int i = 0; i < 2; ++i) { + for (int i = 0; i < 3; ++i) { for (PropertyList::iterator nameItr = pvec.begin(), e = pvec.end(); nameItr != e; ++nameItr) { string shaderName = (*nameItr)->getStringValue(); - ShaderMap::iterator sitr = shaderMap.find(shaderName); + string fileName = osgDB::findDataFile(shaderName, options); + if (fileName.empty()) + throw BuilderException(string("couldn't find shader ") + + shaderName); + ShaderKey skey(fileName, stype); + ShaderMap::iterator sitr = shaderMap.find(skey); if (sitr != shaderMap.end()) { program->addShader(sitr->second.get()); } else { - string fileName = osgDB::findDataFile(shaderName, options); - if (!fileName.empty()) { - ref_ptr shader = new Shader(stype); - if (shader->loadShaderSourceFromFile(fileName)) { - program->addShader(shader.get()); - shaderMap.insert(make_pair(shaderName, shader)); - } + ref_ptr shader = new Shader(stype); + if (shader->loadShaderSourceFromFile(fileName)) { + program->addShader(shader.get()); + shaderMap.insert(ShaderMap::value_type(skey, shader)); } } } - pvec = pFragShaders; - stype = Shader::FRAGMENT; + if (i == 0) { + pvec = pGeomShaders; + stype = Shader::GEOMETRY; + } else { + pvec = pFragShaders; + stype = Shader::FRAGMENT; + } + } + BOOST_FOREACH(const ProgramKey::AttribKey& key, prgKey.attributes) { + program->addBindAttribLocation(key.first, key.second); } - programMap.insert(make_pair(programKey, program)); + const SGPropertyNode* pGeometryVerticesOut = getEffectPropertyChild(effect, prop, "geometry-vertices-out"); + if ( pGeometryVerticesOut ) { + program->setParameter( GL_GEOMETRY_VERTICES_OUT_EXT, pGeometryVerticesOut->getIntValue() ); + } + const SGPropertyNode* pGeometryInputType = getEffectPropertyChild(effect, prop, "geometry-input-type"); + if ( pGeometryInputType ) { + GLint type; + findAttr( geometryInputType, pGeometryInputType->getStringValue(), type ); + program->setParameter( GL_GEOMETRY_INPUT_TYPE_EXT, type ); + } + const SGPropertyNode* pGeometryOutputType = getEffectPropertyChild(effect, prop, "geometry-output-type"); + if ( pGeometryOutputType ) { + GLint type; + findAttr( geometryOutputType, pGeometryOutputType->getStringValue(), type ); + program->setParameter( GL_GEOMETRY_OUTPUT_TYPE_EXT, type ); + } + + programMap.insert(ProgramMap::value_type(prgKey, program)); } pass->setAttributeAndModes(program); } @@ -629,26 +868,30 @@ InstallAttributeBuilder installShaderProgram("program"); EffectNameValue uniformTypesInit[] = { + {"bool", Uniform::BOOL}, + {"int", Uniform::INT}, {"float", Uniform::FLOAT}, {"float-vec3", Uniform::FLOAT_VEC3}, {"float-vec4", Uniform::FLOAT_VEC4}, {"sampler-1d", Uniform::SAMPLER_1D}, + {"sampler-1d-shadow", Uniform::SAMPLER_1D_SHADOW}, {"sampler-2d", Uniform::SAMPLER_2D}, - {"sampler-3d", Uniform::SAMPLER_3D} + {"sampler-2d-shadow", Uniform::SAMPLER_2D_SHADOW}, + {"sampler-3d", Uniform::SAMPLER_3D}, + {"sampler-cube", Uniform::SAMPLER_CUBE} }; EffectPropertyMap uniformTypes(uniformTypesInit); struct UniformBuilder :public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; const SGPropertyNode* nameProp = prop->getChild("name"); const SGPropertyNode* typeProp = prop->getChild("type"); - const SGPropertyNode* valProp - = getEffectPropertyChild(effect, prop, "value"); + const SGPropertyNode* valProp = prop->getChild("value"); string name; Uniform::Type uniformType = Uniform::FLOAT; if (nameProp) { @@ -665,6 +908,12 @@ struct UniformBuilder :public PassAttributeBuilder if (!typeProp) { props::Type propType = valProp->getType(); switch (propType) { + case props::BOOL: + uniformType = Uniform::BOOL; + break; + case props::INT: + uniformType = Uniform::INT; + break; case props::FLOAT: case props::DOUBLE: break; // default float type; @@ -687,18 +936,29 @@ struct UniformBuilder :public PassAttributeBuilder uniform->setType(uniformType); switch (uniformType) { case Uniform::FLOAT: - uniform->set(valProp->getValue()); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + options); break; case Uniform::FLOAT_VEC3: - uniform->set(toOsg(valProp->getValue())); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + vec3Names, options); break; case Uniform::FLOAT_VEC4: - uniform->set(toOsg(valProp->getValue())); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + vec4Names, options); break; case Uniform::SAMPLER_1D: case Uniform::SAMPLER_2D: case Uniform::SAMPLER_3D: - uniform->set(valProp->getValue()); + case Uniform::SAMPLER_1D_SHADOW: + case Uniform::SAMPLER_2D_SHADOW: + case Uniform::SAMPLER_CUBE: + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + options); break; default: // avoid compiler warning break; @@ -715,7 +975,7 @@ InstallAttributeBuilder installUniform("uniform"); struct NameBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { // name can't use string name = prop->getStringValue(); @@ -737,7 +997,7 @@ EffectPropertyMap polygonModeModes(polygonModeModesInit); struct PolygonModeBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -761,8 +1021,89 @@ struct PolygonModeBuilder : public PassAttributeBuilder }; InstallAttributeBuilder installPolygonMode("polygon-mode"); + +struct VertexProgramTwoSideBuilder : public PassAttributeBuilder +{ + void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) + { + const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); + if (!realProp) + return; + pass->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, + (realProp->getValue() + ? StateAttribute::ON : StateAttribute::OFF)); + } +}; + +InstallAttributeBuilder +installTwoSide("vertex-program-two-side"); + +struct VertexProgramPointSizeBuilder : public PassAttributeBuilder +{ + void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) + { + const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); + if (!realProp) + return; + pass->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, + (realProp->getValue() + ? StateAttribute::ON : StateAttribute::OFF)); + } +}; + +InstallAttributeBuilder +installPointSize("vertex-program-point-size"); + +EffectNameValue depthFunctionInit[] = +{ + {"never", Depth::NEVER}, + {"less", Depth::LESS}, + {"equal", Depth::EQUAL}, + {"lequal", Depth::LEQUAL}, + {"greater", Depth::GREATER}, + {"notequal", Depth::NOTEQUAL}, + {"gequal", Depth::GEQUAL}, + {"always", Depth::ALWAYS} +}; +EffectPropertyMap depthFunction(depthFunctionInit); + +struct DepthBuilder : public PassAttributeBuilder +{ + void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) + { + if (!isAttributeActive(effect, prop)) + return; + ref_ptr depth = new Depth; + const SGPropertyNode* pfunc + = getEffectPropertyChild(effect, prop, "function"); + if (pfunc) { + Depth::Function func = Depth::LESS; + findAttr(depthFunction, pfunc, func); + depth->setFunction(func); + } + const SGPropertyNode* pnear + = getEffectPropertyChild(effect, prop, "near"); + if (pnear) + depth->setZNear(pnear->getValue()); + const SGPropertyNode* pfar + = getEffectPropertyChild(effect, prop, "far"); + if (pfar) + depth->setZFar(pnear->getValue()); + const SGPropertyNode* pmask + = getEffectPropertyChild(effect, prop, "write-mask"); + if (pmask) + depth->setWriteMask(pmask->getValue()); + pass->setAttribute(depth.get()); + } +}; + +InstallAttributeBuilder installDepth("depth"); + void buildTechnique(Effect* effect, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { Technique* tniq = new Technique; effect->techniques.push_back(tniq); @@ -848,6 +1189,9 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss) } } makeChild(paramRoot, "cull-face")->setStringValue(cullFaceString); + // Macintosh ATI workaround + bool vertexTwoSide = cullFaceString == "off"; + makeChild(paramRoot, "vertex-program-two-side")->setValue(vertexTwoSide); const BlendFunc* blendFunc = getStateAttribute(ss); SGPropertyNode* blendNode = makeChild(paramRoot, "blend"); if (blendFunc) { @@ -868,7 +1212,7 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss) // Walk the techniques property tree, building techniques and // passes. -bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options) +bool Effect::realizeTechniques(const SGReaderWriterXMLOptions* options) { if (_isRealized) return true; @@ -907,13 +1251,17 @@ bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs, if (lhs.paths.size() != rhs.paths.size() || !equal(lhs.paths.begin(), lhs.paths.end(), rhs.paths.begin())) return false; - return props::Compare()(lhs.unmerged, rhs.unmerged); + if (lhs.unmerged.valid() && rhs.unmerged.valid()) + return props::Compare()(lhs.unmerged, rhs.unmerged); + else + return lhs.unmerged == rhs.unmerged; } size_t hash_value(const Effect::Key& key) { size_t seed = 0; - boost::hash_combine(seed, *key.unmerged); + if (key.unmerged.valid()) + boost::hash_combine(seed, *key.unmerged); boost::hash_range(seed, key.paths.begin(), key.paths.end()); return seed; } @@ -942,14 +1290,15 @@ osgDB::RegisterDotOsgWrapperProxy effectProxy } // Property expressions for technique predicates -class PropertyExpression : public SGExpression +template +class PropertyExpression : public SGExpression { public: PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {} - void eval(bool& value, const expression::Binding*) const + void eval(T& value, const expression::Binding*) const { - value = _pnode->getValue(); + value = _pnode->getValue(); } protected: SGPropertyNode_ptr _pnode; @@ -968,12 +1317,13 @@ protected: osg::ref_ptr _tniq; }; +template Expression* propertyExpressionParser(const SGPropertyNode* exp, expression::Parser* parser) { SGPropertyNode_ptr pnode = getPropertyRoot()->getNode(exp->getStringValue(), true); - PropertyExpression* pexp = new PropertyExpression(pnode); + PropertyExpression* pexp = new PropertyExpression(pnode); TechniquePredParser* predParser = dynamic_cast(parser); if (predParser) @@ -983,6 +1333,9 @@ Expression* propertyExpressionParser(const SGPropertyNode* exp, } expression::ExpParserRegistrar propertyRegistrar("property", - propertyExpressionParser); + propertyExpressionParser); + +expression::ExpParserRegistrar propvalueRegistrar("float-property", + propertyExpressionParser); }