#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/Pass.hxx>
+#include <simgear/scene/material/Technique.hxx>
#include <simgear/scene/model/model.hxx>
+#include <simgear/scene/model/ConditionNode.hxx>
+
+using namespace std;
+using namespace simgear;
namespace {
/**
return v;
}
- osg::Vec4& rgbaVec4()
+ osg::Vec4 rgbaVec4()
{
- return rgba().osg();
+ return toOsg(rgba());
}
SGVec4f &initialRgba() {
virtual void apply(osg::Geode& node)
{
- maybeGetMaterialValues(node.getStateSet());
+ using namespace simgear;
+ EffectGeode* eg = dynamic_cast<EffectGeode*>(&node);
+ if (eg) {
+ const Effect* effect = eg->getEffect();
+ if (effect)
+ for (vector<osg::ref_ptr<Technique> >::const_iterator itr
+ = effect->techniques.begin(), end = effect->techniques.end();
+ itr != end;
+ ++itr) {
+ const Technique* tniq = itr->get();
+ for (vector<osg::ref_ptr<Pass> >::const_iterator pitr
+ = tniq->passes.begin(), pend = tniq->passes.end();
+ pitr != pend;
+ ++pitr)
+ maybeGetMaterialValues(pitr->get());
+ }
+ } else {
+ maybeGetMaterialValues(node.getStateSet());
+ }
int numDrawables = node.getNumDrawables();
for (int i = 0; i < numDrawables; i++) {
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
}
}
- void maybeGetMaterialValues(osg::StateSet* stateSet)
+ void maybeGetMaterialValues(const osg::StateSet* stateSet)
{
if (!stateSet)
return;
- osg::Material* nodeMat
- = dynamic_cast<osg::Material*>(stateSet->getAttribute(osg::StateAttribute::MATERIAL));
+ const osg::Material* nodeMat
+ = dynamic_cast<const osg::Material*>(stateSet
+ ->getAttribute(osg::StateAttribute
+ ::MATERIAL));
if (!nodeMat)
return;
material = nodeMat;
}
- osg::ref_ptr<osg::Material> material;
+ osg::ref_ptr<const osg::Material> material;
osg::Vec4 ambientDiffuse;
};
class UpdateCallback : public osg::NodeCallback {
public:
UpdateCallback(const osgDB::FilePathList& texturePathList,
- const SGCondition* condition,
const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
- _condition(condition),
_materialProps(configNode, modelRoot),
_texturePathList(texturePathList),
_prevState(false)
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osg::StateSet* stateSet = node->getStateSet();
- if ((!_condition || _condition->test()) && stateSet) {
+ if (stateSet) {
if (_textureProp) {
std::string textureName = _textureProp->getStringValue();
if (_textureName != textureName) {
traverse(node, nv);
}
private:
- SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGPropertyNode> _textureProp;
SGSharedPtr<const SGPropertyNode> _thresholdProp;
std::string _textureName;
const SGPropertyNode* node = getConfig()->getChild("property-base");
if (node)
inputRoot = getModelRoot()->getNode(node->getStringValue(), true);
- if (getConfig()->hasChild("texture-prop")) {
- osg::StateSet* stateSet = group->getOrCreateStateSet();
- stateSet->setDataVariance(osg::Object::DYNAMIC);
- }
+ osg::StateSet* stateSet = group->getOrCreateStateSet();
if (getConfig()->hasChild("texture")) {
std::string textureName = getConfig()->getStringValue("texture");
std::string textureFile;
textureFile = osgDB::findFileInPath(textureName, texturePathList);
if (!textureFile.empty()) {
- osg::StateSet* stateSet = group->getOrCreateStateSet();
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
if (texture2D) {
stateSet->setTextureAttribute(0, texture2D,
}
if (getConfig()->hasChild("threshold-prop") ||
getConfig()->hasChild("threshold")) {
- osg::StateSet* stateSet = group->getOrCreateStateSet();
osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
alphaFunc->setFunction(osg::AlphaFunc::GREATER);
float threshold = getConfig()->getFloatValue("threshold", 0);
suppliedColors |= SHININESS;
if (getConfig()->hasChild("transparency"))
suppliedColors |= TRANSPARENCY;
-
+ osg::Material* mat = 0;
if (suppliedColors != 0) {
- osg::StateSet* stateSet = group->getOrCreateStateSet();
- osg::Material* mat;
+ if (defaultMaterial.valid()) {
+ mat = defaultMaterial.get();
- if (defaultMaterial.valid()) {
- mat = defaultMaterial.get();
-
- } else {
- mat = new osg::Material;
- mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
- }
- mat->setDataVariance(osg::Object::DYNAMIC);
- unsigned defaultColorModeMask = 0;
- mat->setUpdateCallback(0); // Just to make sure.
- switch (mat->getColorMode()) {
- case osg::Material::OFF:
- defaultColorModeMask = 0;
- break;
- case osg::Material::AMBIENT:
- defaultColorModeMask = AMBIENT;
- break;
- case osg::Material::DIFFUSE:
- defaultColorModeMask = DIFFUSE;
- break;
- case osg::Material::AMBIENT_AND_DIFFUSE:
- defaultColorModeMask = AMBIENT | DIFFUSE;
- break;
- case osg::Material::SPECULAR:
- defaultColorModeMask = SPECULAR;
- break;
- case osg::Material::EMISSION:
- defaultColorModeMask = EMISSION;
- break;
- }
- // Copy the color found by traversing geometry into the material
- // in case we need to specify it (e.g., transparency) and it is
- // not specified by the animation.
- if (defaultAmbientDiffuse.x() >= 0) {
- if (defaultColorModeMask & AMBIENT)
- mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
- if (defaultColorModeMask & DIFFUSE)
- mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
- }
- // Compute which colors in the animation override colors set via
- // colorMode / glColor, and set the colorMode for the animation's
- // material accordingly.
- if (suppliedColors & TRANSPARENCY) {
- // All colors will be affected by the material. Hope all the
- // defaults are fine, if needed.
- mat->setColorMode(osg::Material::OFF);
- } else if ((suppliedColors & defaultColorModeMask) != 0) {
- // First deal with the complicated AMBIENT/DIFFUSE case.
- if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
- // glColor can supply colors not specified by the animation.
- unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
- & AMBIENT_DIFFUSE);
- if ((matColorModeMask & DIFFUSE) != 0)
- mat->setColorMode(osg::Material::DIFFUSE);
- else if ((matColorModeMask & AMBIENT) != 0)
- mat->setColorMode(osg::Material::AMBIENT);
- else
- mat->setColorMode(osg::Material::OFF);
- } else {
- // The animation overrides the glColor color.
- mat->setColorMode(osg::Material::OFF);
- }
+ } else {
+ mat = new osg::Material;
+ mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
+ }
+ mat->setDataVariance(osg::Object::DYNAMIC);
+ unsigned defaultColorModeMask = 0;
+ mat->setUpdateCallback(0); // Just to make sure.
+ // XXX This should probably go away, as ac3d models always have a
+ // DIFFUSE color mode.
+ switch (mat->getColorMode()) {
+ case osg::Material::OFF:
+ defaultColorModeMask = 0;
+ break;
+ case osg::Material::AMBIENT:
+ defaultColorModeMask = AMBIENT;
+ break;
+ case osg::Material::DIFFUSE:
+ defaultColorModeMask = DIFFUSE;
+ break;
+ case osg::Material::AMBIENT_AND_DIFFUSE:
+ defaultColorModeMask = AMBIENT | DIFFUSE;
+ break;
+ case osg::Material::SPECULAR:
+ defaultColorModeMask = SPECULAR;
+ break;
+ case osg::Material::EMISSION:
+ defaultColorModeMask = EMISSION;
+ break;
+ }
+ // Copy the color found by traversing geometry into the material
+ // in case we need to specify it (e.g., transparency) and it is
+ // not specified by the animation.
+ if (defaultAmbientDiffuse.x() >= 0) {
+ if (defaultColorModeMask & AMBIENT)
+ mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
+ if (defaultColorModeMask & DIFFUSE)
+ mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
+ }
+ // Compute which colors in the animation override colors set via
+ // colorMode / glColor, and set the colorMode for the animation's
+ // material accordingly.
+ if (suppliedColors & TRANSPARENCY) {
+ // All colors will be affected by the material. Hope all the
+ // defaults are fine, if needed.
+ mat->setColorMode(osg::Material::OFF);
+ } else if ((suppliedColors & defaultColorModeMask) != 0) {
+ // First deal with the complicated AMBIENT/DIFFUSE case.
+ if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
+ // glColor can supply colors not specified by the animation.
+ unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
+ & AMBIENT_DIFFUSE);
+ if ((matColorModeMask & DIFFUSE) != 0)
+ mat->setColorMode(osg::Material::DIFFUSE);
+ else if ((matColorModeMask & AMBIENT) != 0)
+ mat->setColorMode(osg::Material::AMBIENT);
+ else
+ mat->setColorMode(osg::Material::OFF);
} else {
- // No overlap between the animation and color mode, so leave
- // the color mode alone.
+ // The animation overrides the glColor color.
+ mat->setColorMode(osg::Material::OFF);
}
- stateSet->setAttribute(mat,(osg::StateAttribute::ON
- | osg::StateAttribute::OVERRIDE));
+ } else {
+ // No overlap between the animation and color mode, so leave
+ // the color mode alone.
+ }
+ stateSet->setAttribute(mat,(osg::StateAttribute::ON
+ | osg::StateAttribute::OVERRIDE));
+ }
+ bool matAnimated = false;
+ if (mat) {
+ MaterialPropertyAdapter adapter(getConfig(), inputRoot);
+ adapter.setMaterialValues(stateSet);
+ matAnimated = adapter.isAnimated();
+ }
+ if (matAnimated || getConfig()->hasChild("texture-prop")
+ || getConfig()->hasChild("threshold-prop") || getCondition()) {
+ stateSet->setDataVariance(osg::Object::DYNAMIC);
+ group->setUpdateCallback(new UpdateCallback(texturePathList,
+ getConfig(), inputRoot));
+ } else {
+ stateSet->setDataVariance(osg::Object::STATIC);
+ }
+ if (getCondition()) {
+ ConditionNode* cn = new ConditionNode;
+ cn->setCondition(getCondition());
+ osg::Group* modelGroup = new osg::Group;
+ group->addChild(modelGroup);
+ cn->addChild(group);
+ cn->addChild(modelGroup);
+ parent.addChild(cn);
+ return modelGroup;
+ } else {
+ parent.addChild(group);
+ return group;
}
- group->setUpdateCallback(new UpdateCallback(texturePathList,
- getCondition(),
- getConfig(), inputRoot));
- parent.addChild(group);
- return group;
}
void
}
defaultAmbientDiffuse = defaultsVisitor.ambientDiffuse;
}
+
+const char* colorNames[] =
+{
+ "ambient",
+ "diffuse",
+ "specular",
+ "emission"
+};
+
+// Build an effect which mimics the material color mode in a
+// shader. The OpenGL material values will be overridden by the
+// material animation's material.
+//
+// This is a hack to get the effect to respect the values set in the
+// material, set up by the animation, which overrides the values in
+// the effect's material attributes. Things will be different when
+// material animations are implemented purely by manipulating effects.
+
+SGPropertyNode_ptr
+SGMaterialAnimation::makeEffectProperties(const SGPropertyNode* animProp)
+{
+ SGPropertyNode_ptr eRoot = new SGPropertyNode;
+ SGPropertyNode* inherit = makeNode(eRoot, "inherits-from");
+ if (animProp->hasChild("diffuse") || animProp->hasChild("transparency"))
+ inherit->setStringValue("Effects/material-off");
+ else
+ inherit->setStringValue("Effects/material-diffuse");
+ return eRoot;
+}