From 23d0601d824603c4cfa9bdc14d9e4e33111680ee Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 25 Aug 2009 16:01:11 +0200 Subject: [PATCH] Add support for blend functions and alpha test functions in effects --- simgear/scene/material/Effect.cxx | 209 +++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 7 deletions(-) diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 3bd14cc3..5562c63b 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -36,9 +36,12 @@ #include #include +#include +#include #include #include #include +#include #include #include #include @@ -240,8 +243,10 @@ struct CullFaceBuilder : PassAttributeBuilder const osgDB::ReaderWriter::Options* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); - if (!realProp) + if (!realProp) { + pass->setMode(GL_CULL_FACE, StateAttribute::OFF); return; + } StateAttributeFactory *attrFact = StateAttributeFactory::instance(); string propVal = realProp->getStringValue(); if (propVal == "front") @@ -250,6 +255,8 @@ struct CullFaceBuilder : PassAttributeBuilder pass->setAttributeAndModes(attrFact->getCullFaceBack()); else if (propVal == "front-back") pass->setAttributeAndModes(new CullFace(CullFace::FRONT_AND_BACK)); + else if (propVal == "off") + pass->setMode(GL_CULL_FACE, StateAttribute::OFF); else SG_LOG(SG_INPUT, SG_ALERT, "invalid cull face property " << propVal); @@ -365,33 +372,166 @@ void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass, InstallAttributeBuilder installMaterial("material"); +EffectNameValue blendFuncModesInit[] = +{ + {"dst-alpha", BlendFunc::DST_ALPHA}, + {"dst-color", BlendFunc::DST_COLOR}, + {"one", BlendFunc::ONE}, + {"one-minus-dst-alpha", BlendFunc::ONE_MINUS_DST_ALPHA}, + {"one-minus-dst-color", BlendFunc::ONE_MINUS_DST_COLOR}, + {"one-minus-src-alpha", BlendFunc::ONE_MINUS_SRC_ALPHA}, + {"one-minus-src-color", BlendFunc::ONE_MINUS_SRC_COLOR}, + {"src-alpha", BlendFunc::SRC_ALPHA}, + {"src-alpha-saturate", BlendFunc::SRC_ALPHA_SATURATE}, + {"src-color", BlendFunc::SRC_COLOR}, + {"constant-color", BlendFunc::CONSTANT_COLOR}, + {"one-minus-constant-color", BlendFunc::ONE_MINUS_CONSTANT_COLOR}, + {"constant-alpha", BlendFunc::CONSTANT_ALPHA}, + {"one-minus-constant-alpha", BlendFunc::ONE_MINUS_CONSTANT_ALPHA}, + {"zero", BlendFunc::ZERO} +}; +EffectPropertyMap blendFuncModes(blendFuncModesInit); + struct BlendBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, const osgDB::ReaderWriter::Options* options) { + // XXX Compatibility with early syntax; should go away + // before a release const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) return; - pass->setMode(GL_BLEND, (realProp->getBoolValue() - ? StateAttribute::ON - : StateAttribute::OFF)); + if (realProp->nChildren() == 0) { + pass->setMode(GL_BLEND, (realProp->getBoolValue() + ? StateAttribute::ON + : StateAttribute::OFF)); + return; + } + + const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop, + "mode"); + // XXX When dynamic parameters are supported, this code should + // create the blend function even if the mode is off. + if (pmode && !pmode->getValue()) { + pass->setMode(GL_BLEND, StateAttribute::OFF); + return; + } + const SGPropertyNode* psource = getEffectPropertyChild(effect, prop, + "source"); + const SGPropertyNode* pdestination + = getEffectPropertyChild(effect, prop, "destination"); + const SGPropertyNode* psourceRGB + = getEffectPropertyChild(effect, prop, "source-rgb"); + const SGPropertyNode* psourceAlpha + = getEffectPropertyChild(effect, prop, "source-alpha"); + const SGPropertyNode* pdestRGB + = getEffectPropertyChild(effect, prop, "destination-rgb"); + const SGPropertyNode* pdestAlpha + = getEffectPropertyChild(effect, prop, "destination-alpha"); + BlendFunc::BlendFuncMode sourceMode = BlendFunc::ONE; + BlendFunc::BlendFuncMode destMode = BlendFunc::ZERO; + if (psource) + findAttr(blendFuncModes, psource, sourceMode); + if (pdestination) + findAttr(blendFuncModes, pdestination, destMode); + if (psource && pdestination + && !(psourceRGB || psourceAlpha || pdestRGB || pdestAlpha) + && sourceMode == BlendFunc::SRC_ALPHA + && destMode == BlendFunc::ONE_MINUS_SRC_ALPHA) { + pass->setAttributeAndModes(StateAttributeFactory::instance() + ->getStandardBlendFunc()); + return; + } + BlendFunc* blendFunc = new BlendFunc; + if (psource) + blendFunc->setSource(sourceMode); + if (pdestination) + blendFunc->setDestination(destMode); + if (psourceRGB) { + BlendFunc::BlendFuncMode sourceRGBMode; + findAttr(blendFuncModes, psourceRGB, sourceRGBMode); + blendFunc->setSourceRGB(sourceRGBMode); + } + if (pdestRGB) { + BlendFunc::BlendFuncMode destRGBMode; + findAttr(blendFuncModes, pdestRGB, destRGBMode); + blendFunc->setDestinationRGB(destRGBMode); + } + if (psourceAlpha) { + BlendFunc::BlendFuncMode sourceAlphaMode; + findAttr(blendFuncModes, psourceAlpha, sourceAlphaMode); + blendFunc->setSourceAlpha(sourceAlphaMode); + } + if (pdestAlpha) { + BlendFunc::BlendFuncMode destAlphaMode; + findAttr(blendFuncModes, pdestAlpha, destAlphaMode); + blendFunc->setDestinationAlpha(destAlphaMode); + } + pass->setAttributeAndModes(blendFunc); } }; InstallAttributeBuilder installBlend("blend"); +EffectNameValue alphaComparisonInit[] = +{ + {"never", AlphaFunc::NEVER}, + {"less", AlphaFunc::LESS}, + {"equal", AlphaFunc::EQUAL}, + {"lequal", AlphaFunc::LEQUAL}, + {"greater", AlphaFunc::GREATER}, + {"notequal", AlphaFunc::NOTEQUAL}, + {"gequal", AlphaFunc::GEQUAL}, + {"always", AlphaFunc::ALWAYS} +}; +EffectPropertyMap +alphaComparison(alphaComparisonInit); + struct AlphaTestBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, const osgDB::ReaderWriter::Options* options) { + // XXX Compatibility with early syntax; should go away + // before a release const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) return; - pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue() - ? StateAttribute::ON - : StateAttribute::OFF)); + if (realProp->nChildren() == 0) { + pass->setMode(GL_ALPHA_TEST, (realProp->getBoolValue() + ? StateAttribute::ON + : StateAttribute::OFF)); + return; + } + + const SGPropertyNode* pmode = getEffectPropertyChild(effect, prop, + "mode"); + // XXX When dynamic parameters are supported, this code should + // create the blend function even if the mode is off. + if (pmode && !pmode->getValue()) { + pass->setMode(GL_ALPHA_TEST, StateAttribute::OFF); + return; + } + const SGPropertyNode* pComp = getEffectPropertyChild(effect, prop, + "comparison"); + const SGPropertyNode* pRef = getEffectPropertyChild(effect, prop, + "reference"); + AlphaFunc::ComparisonFunction func = AlphaFunc::ALWAYS; + float refValue = 1.0f; + if (pComp) + findAttr(alphaComparison, pComp, func); + if (pRef) + refValue = pRef->getValue(); + if (func == AlphaFunc::GREATER && osg::equivalent(refValue, 1.0f)) { + pass->setAttributeAndModes(StateAttributeFactory::instance() + ->getStandardAlphaFunc()); + } else { + AlphaFunc* alphaFunc = new AlphaFunc; + alphaFunc->setFunction(func); + alphaFunc->setReferenceValue(refValue); + pass->setAttributeAndModes(alphaFunc); + } } }; @@ -735,6 +875,61 @@ void buildTechnique(Effect* effect, const SGPropertyNode* prop, } } +// Specifically for .ac files... +bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss) +{ + SGPropertyNode* matNode = paramRoot->getChild("material", 0, true); + Vec4f ambVal, difVal, specVal, emisVal; + float shininess = 0.0f; + const Material* mat + = static_cast(ss->getAttribute(StateAttribute + ::MATERIAL)); + if (mat) { + ambVal = mat->getAmbient(Material::FRONT_AND_BACK); + difVal = mat->getDiffuse(Material::FRONT_AND_BACK); + specVal = mat->getSpecular(Material::FRONT_AND_BACK); + emisVal = mat->getEmission(Material::FRONT_AND_BACK); + shininess = mat->getShininess(Material::FRONT_AND_BACK); + } + matNode->getChild("ambient", 0, true)->setValue(toVec4d(toSG(ambVal))); + matNode->getChild("diffuse", 0, true)->setValue(toVec4d(toSG(difVal))); + matNode->getChild("specular", 0, true)->setValue(toVec4d(toSG(specVal))); + matNode->getChild("emissive", 0, true)->setValue(toVec4d(toSG(emisVal))); + matNode->getChild("shininess", 0, true)->setValue(shininess); + matNode->getChild("color-mode", 0, true)->setStringValue("diffuse"); + const ShadeModel* sm + = static_cast(ss->getAttribute(StateAttribute + ::SHADEMODEL)); + string shadeModelString("smooth"); + if (sm) { + ShadeModel::Mode smMode = sm->getMode(); + if (smMode == ShadeModel::FLAT) + shadeModelString = "flat"; + } + paramRoot->getChild("shade-model", 0, true) + ->setStringValue(shadeModelString); + string cullFaceString("off"); + const CullFace* cullFace + = static_cast(ss->getAttribute(StateAttribute + ::CULLFACE)); + if (cullFace) { + switch (cullFace->getMode()) { + case CullFace::FRONT: + cullFaceString = "front"; + break; + case CullFace::BACK: + cullFaceString = "back"; + break; + case CullFace::FRONT_AND_BACK: + cullFaceString = "front-back"; + break; + default: + break; + } + } + paramRoot->getChild("cull-face", 0, true)->setStringValue(cullFaceString); +} + // Walk the techniques property tree, building techniques and // passes. bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options) -- 2.39.5