Add support for blend functions and alpha test functions in effects

This commit is contained in:
Tim Moore 2009-08-25 16:01:11 +02:00
parent 6db9138eeb
commit 23d0601d82

View File

@ -36,9 +36,12 @@
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <osg/AlphaFunc>
#include <osg/BlendFunc>
#include <osg/CullFace>
#include <osg/Drawable>
#include <osg/Material>
#include <osg/Math>
#include <osg/PolygonMode>
#include <osg/Program>
#include <osg/Referenced>
@ -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<MaterialBuilder> installMaterial("material");
EffectNameValue<BlendFunc::BlendFuncMode> 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<BlendFunc::BlendFuncMode> blendFuncModes(blendFuncModesInit);
struct BlendBuilder : public PassAttributeBuilder
{
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
// XXX Compatibility with early <blend> 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<bool>()) {
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<BlendBuilder> installBlend("blend");
EffectNameValue<AlphaFunc::ComparisonFunction> 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<AlphaFunc::ComparisonFunction>
alphaComparison(alphaComparisonInit);
struct AlphaTestBuilder : public PassAttributeBuilder
{
void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
const osgDB::ReaderWriter::Options* options)
{
// XXX Compatibility with early <alpha-test> 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<bool>()) {
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<float>();
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<const Material*>(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<const ShadeModel*>(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<const CullFace*>(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)