From a9439d58c718c264edad865c378e3ea0729bc021 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 13 Jan 2009 12:50:47 +0100 Subject: [PATCH 1/2] SGMaterialAnimation: factor out update of osg::Material --- simgear/scene/model/SGMaterialAnimation.cxx | 117 ++++++++++++-------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/simgear/scene/model/SGMaterialAnimation.cxx b/simgear/scene/model/SGMaterialAnimation.cxx index 47397fdb..cce40c62 100644 --- a/simgear/scene/model/SGMaterialAnimation.cxx +++ b/simgear/scene/model/SGMaterialAnimation.cxx @@ -245,20 +245,78 @@ public: osg::Vec4 ambientDiffuse; }; +class MaterialPropertyAdapter +{ +public: + MaterialPropertyAdapter(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : + _ambient(configNode->getChild("ambient"), modelRoot), + _diffuse(configNode->getChild("diffuse"), modelRoot), + _specular(configNode->getChild("specular"), modelRoot), + _emission(configNode->getChild("emission"), modelRoot), + _shininess("shininess", "shininess-prop", + configNode/*->getChild("shininess")*/, modelRoot), + _transparency("alpha", "alpha-prop", + configNode->getChild("transparency"), modelRoot) + { + _shininess.max = 128; + _isAnimated = (_ambient.live() || _diffuse.live() || _specular.live() + || _emission.live() || _shininess.live() + || _transparency.live()); + } + bool isAnimated() { return _isAnimated; } + // This takes a StateSet argument because the rendering bin will + // be changed if there is transparency. + void setMaterialValues(osg::StateSet* stateSet) + { + osg::StateAttribute* stateAttribute + = stateSet->getAttribute(osg::StateAttribute::MATERIAL); + osg::Material* material = dynamic_cast(stateAttribute); + if (material) { + if (_ambient.live() || _ambient.dirty()) + material->setAmbient(osg::Material::FRONT_AND_BACK, + _ambient.rgbaVec4()); + if (_diffuse.live() || _diffuse.dirty()) + material->setDiffuse(osg::Material::FRONT_AND_BACK, + _diffuse.rgbaVec4()); + if (_specular.live() || _specular.dirty()) + material->setSpecular(osg::Material::FRONT_AND_BACK, + _specular.rgbaVec4()); + if (_emission.live() || _emission.dirty()) + material->setEmission(osg::Material::FRONT_AND_BACK, + _emission.rgbaVec4()); + if (_shininess.live() || _shininess.dirty()) + material->setShininess(osg::Material::FRONT_AND_BACK, + _shininess.getValue()); + if (_transparency.live() || _transparency.dirty()) { + float alpha = _transparency.getValue(); + material->setAlpha(osg::Material::FRONT_AND_BACK, alpha); + if (alpha < 1.0f) { + stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); + } else { + stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN); + } + } + } + } + ColorSpec _ambient; + ColorSpec _diffuse; + ColorSpec _specular; + ColorSpec _emission; + PropSpec _shininess; + PropSpec _transparency; + bool _isAnimated; + +}; + class UpdateCallback : public osg::NodeCallback { public: UpdateCallback(const osgDB::FilePathList& texturePathList, const SGCondition* condition, const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : _condition(condition), - _ambient(configNode->getChild("ambient"), modelRoot), - _diffuse(configNode->getChild("diffuse"), modelRoot), - _specular(configNode->getChild("specular"), modelRoot), - _emission(configNode->getChild("emission"), modelRoot), - _shininess("shininess", "shininess-prop", - configNode/*->getChild("shininess")*/, modelRoot), - _transparency("alpha", "alpha-prop", - configNode->getChild("transparency"), modelRoot), + _materialProps(configNode, modelRoot), _texturePathList(texturePathList), _prevState(false) { @@ -270,7 +328,6 @@ public: node = configNode->getChild("texture-prop"); if (node) _textureProp = modelRoot->getNode(node->getStringValue(), true); - _shininess.max = 128; } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -302,40 +359,13 @@ public: osg::StateSet* stateSet = node->getOrCreateStateSet(); osg::StateAttribute* stateAttribute; stateAttribute = stateSet->getAttribute(osg::StateAttribute::ALPHAFUNC); - osg::AlphaFunc* alphaFunc = dynamic_cast(stateAttribute); + osg::AlphaFunc* alphaFunc + = dynamic_cast(stateAttribute); assert(alphaFunc); alphaFunc->setReferenceValue(_thresholdProp->getFloatValue()); } - osg::StateAttribute* stateAttribute - = stateSet->getAttribute(osg::StateAttribute::MATERIAL); - osg::Material* material = dynamic_cast(stateAttribute); - if (material) { - if (_ambient.live() || (!_prevState && _ambient.dirty())) - material->setAmbient(osg::Material::FRONT_AND_BACK, - _ambient.rgbaVec4()); - if (_diffuse.live() || (!_prevState && _diffuse.dirty())) - material->setDiffuse(osg::Material::FRONT_AND_BACK, - _diffuse.rgbaVec4()); - if (_specular.live() || (!_prevState && _specular.dirty())) - material->setSpecular(osg::Material::FRONT_AND_BACK, - _specular.rgbaVec4()); - if (_emission.live() || (!_prevState && _emission.dirty())) - material->setEmission(osg::Material::FRONT_AND_BACK, - _emission.rgbaVec4()); - if (_shininess.live() || (!_prevState && _shininess.dirty())) - material->setShininess(osg::Material::FRONT_AND_BACK, - _shininess.getValue()); - if (_transparency.live() || (!_prevState && _transparency.dirty())) { - float alpha = _transparency.getValue(); - material->setAlpha(osg::Material::FRONT_AND_BACK, alpha); - if (alpha < 1.0f) { - stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); - } else { - stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN); - } - } - } + if (_materialProps.isAnimated() || !_prevState) + _materialProps.setMaterialValues(stateSet); _prevState = true; } else { _prevState = false; @@ -347,12 +377,7 @@ private: SGSharedPtr _textureProp; SGSharedPtr _thresholdProp; std::string _textureName; - ColorSpec _ambient; - ColorSpec _diffuse; - ColorSpec _specular; - ColorSpec _emission; - PropSpec _shininess; - PropSpec _transparency; + MaterialPropertyAdapter _materialProps; osgDB::FilePathList _texturePathList; bool _prevState; }; From 55e9d8d944d5dc0ba59b159b801af11d6e39923b Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 13 Jan 2009 14:10:15 +0100 Subject: [PATCH 2/2] SGMaterialAnimation: Don't install an update callback if values are static --- simgear/scene/model/SGMaterialAnimation.cxx | 160 ++++++++++---------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/simgear/scene/model/SGMaterialAnimation.cxx b/simgear/scene/model/SGMaterialAnimation.cxx index cce40c62..72df88e5 100644 --- a/simgear/scene/model/SGMaterialAnimation.cxx +++ b/simgear/scene/model/SGMaterialAnimation.cxx @@ -406,16 +406,12 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent) 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, @@ -430,7 +426,6 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent) } 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); @@ -452,83 +447,92 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent) 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 { - mat = new osg::Material; - mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + // The animation overrides the glColor color. + mat->setColorMode(osg::Material::OFF); } - 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 { - // No overlap between the animation and color mode, so leave - // the color mode alone. - } - 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, + getCondition(), + getConfig(), inputRoot)); + } else { + stateSet->setDataVariance(osg::Object::STATIC); } - group->setUpdateCallback(new UpdateCallback(texturePathList, - getCondition(), - getConfig(), inputRoot)); parent.addChild(group); return group; }