From 3ce0c1723753ca3a76489bc750f6da538ccca454 Mon Sep 17 00:00:00 2001 From: ehofman Date: Tue, 22 Mar 2005 13:12:51 +0000 Subject: [PATCH] Melchior FRANZ: here is the promised material animation. It looks a bit longish, but that wasn't avoidable -- there are simply too many parameters to consider. I tried hard, though, to make the animation fast by only doing the necessary stuff. It doesn't affect the frame rate here with my test model. The animation is heavily based on Jim's "material-emission" animation. * implementation of the "material" animation (this required to make the texture path available) + documentation update ($FG_ROOT/Docs/) * fix some more return values (texture animations, and select) for the shadow problem (and some in anticipation of other problems :-) * fix compiler warning --- simgear/scene/model/animation.cxx | 363 ++++++++++++++++++++++++------ simgear/scene/model/animation.hxx | 92 ++++++-- simgear/scene/model/model.cxx | 8 +- simgear/scene/model/model.hxx | 2 + 4 files changed, 371 insertions(+), 94 deletions(-) diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 641331d1..dc991c26 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -339,7 +339,7 @@ SGSelectAnimation::update() ((ssgSelector *)_branch)->select(0xffff); else ((ssgSelector *)_branch)->select(0x0000); - return 1; + return 2; } @@ -905,7 +905,7 @@ SGTexRotateAnimation::update() } set_rotation(_matrix, _position_deg, _center, _axis); ((ssgTexTrans *)_branch)->setTransform(_matrix); - return 1; + return 2; } @@ -953,7 +953,7 @@ SGTexTranslateAnimation::update() } set_translation(_matrix, _position, _axis); ((ssgTexTrans *)_branch)->setTransform(_matrix); - return 1; + return 2; } @@ -1070,7 +1070,7 @@ SGTexMultipleAnimation::update() } } ((ssgTexTrans *)_branch)->setTransform(tmatrix); - return 1; + return 2; } @@ -1112,95 +1112,308 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp) //////////////////////////////////////////////////////////////////////// -// Implementation of SGEmissionAnimation +// Implementation of SGMaterialAnimation //////////////////////////////////////////////////////////////////////// -SGEmissionAnimation::SGEmissionAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props) - : SGAnimation(props, new ssgBranch), - _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)), - _color0(props->getFloatValue("emiss-red", 0.0)), - _color1(props->getFloatValue("emiss-green", 0.0)), - _color2(props->getFloatValue("emiss-blue", 0.0)), - _old_brightness(0.0), - _cached_material(0), - _cloned_material(0) -{ -} - -SGEmissionAnimation::~SGEmissionAnimation () -{ -} +SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root, + SGPropertyNode_ptr props, const SGPath &texture_path) + : SGAnimation(props, new ssgBranch), + _base_dir(texture_path), + _cached_material(0), + _cloned_material(0), + _read(0), + _update(0), + _global(props->getBoolValue("global", false)) +{ + _diff.red = props->getFloatValue("diffuse-red", -1.0); + _diff.green = props->getFloatValue("diffuse-green", -1.0); + _diff.blue = props->getFloatValue("diffuse-blue", -1.0); + _diff.factor = props->getFloatValue("diffuse-factor", 1.0); + _diff.offset = props->getFloatValue("diffuse-offset", 0.0); + if (_diff.dirty()) + _update |= DIFFUSE; + + _amb.red = props->getFloatValue("ambient-red", -1.0); + _amb.green = props->getFloatValue("ambient-green", -1.0); + _amb.blue = props->getFloatValue("ambient-blue", -1.0); + _amb.factor = props->getFloatValue("ambient-factor", 1.0); + _amb.offset = props->getFloatValue("ambient-offset", 0.0); + if (_amb.dirty()) + _update |= AMBIENT; + + _spec.red = props->getFloatValue("specular-red", -1.0); + _spec.green = props->getFloatValue("specular-green", -1.0); + _spec.blue = props->getFloatValue("specular-blue", -1.0); + _spec.factor = props->getFloatValue("specular-factor", 1.0); + _spec.offset = props->getFloatValue("specular-offset", 0.0); + if (_spec.dirty()) + _update |= SPECULAR; + + _emis.red = props->getFloatValue("emission-red", -1.0); + _emis.green = props->getFloatValue("emission-green", -1.0); + _emis.blue = props->getFloatValue("emission-blue", -1.0); + _emis.factor = props->getFloatValue("emission-factor", 1.0); + _emis.offset = props->getFloatValue("emission-offset", 0.0); + if (_emis.dirty()) + _update |= EMISSION; + + _shi = props->getFloatValue("shininess", -1.0); + if (_shi >= 0.0) + _update |= SHININESS; + + _trans = props->getFloatValue("transparency", -1.0); + if (_trans >= 0.0) + _update |= TRANSPARENCY; + + _thresh = props->getFloatValue("threshold", -1.0); + if (_thresh >= 0.0) + _update |= THRESHOLD; + + string _texture_str = props->getStringValue("texture", ""); + if (!_texture_str.empty()) { + _texture = _base_dir; + _texture.append(_texture_str); + _update |= TEXTURE; + } -void SGEmissionAnimation::init() -{ - // clone material state(s) for this branch - cloneMaterials(_branch); + SGPropertyNode_ptr node = props->getChild("condition"); + _condition = node ? sgReadCondition(prop_root, node) : 0; + + node = props->getChild("diffuse-red-prop"); + _diff.red_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("diffuse-green-prop"); + _diff.green_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("diffuse-blue-prop"); + _diff.blue_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("diffuse-factor-prop"); + _diff.factor_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("diffuse-offset-prop"); + _diff.offset_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + if (_diff.live()) + _read |= DIFFUSE; + + node = props->getChild("ambient-red-prop"); + _amb.red_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("ambient-green-prop"); + _amb.green_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("ambient-blue-prop"); + _amb.blue_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("ambient-factor-prop"); + _amb.factor_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("ambient-offset-prop"); + _amb.offset_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + if (_amb.live()) + _read |= AMBIENT; + + node = props->getChild("specular-red-prop"); + _spec.red_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("specular-green-prop"); + _spec.green_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("specular-blue-prop"); + _spec.blue_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("specular-factor-prop"); + _spec.factor_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("specular-offset-prop"); + _spec.offset_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + if (_spec.live()) + _read |= SPECULAR; + + node = props->getChild("emission-red-prop"); + _emis.red_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("emission-green-prop"); + _emis.green_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("emission-blue-prop"); + _emis.blue_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("emission-factor-prop"); + _emis.factor_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("emission-offset-prop"); + _emis.offset_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + if (_emis.live()) + _read |= EMISSION; + + node = props->getChild("shininess-prop"); + _shi_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("transparency-prop"); + _trans_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("threshold-prop"); + _thresh_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; + node = props->getChild("texture-prop"); + _tex_prop = node ? prop_root->getNode(node->getStringValue(), true) : 0; +} + +void SGMaterialAnimation::init() +{ + if (!_global) + cloneMaterials(_branch); +} + +int SGMaterialAnimation::update() +{ + if (_condition && !_condition->test()) + return 2; + + if (_read & DIFFUSE) { + ColorSpec tmp = _diff; + if (_diff.red_prop) + _diff.red = _diff.red_prop->getFloatValue(); + if (_diff.green_prop) + _diff.green = _diff.green_prop->getFloatValue(); + if (_diff.blue_prop) + _diff.blue = _diff.blue_prop->getFloatValue(); + if (_diff.factor_prop) + _diff.factor = _diff.factor_prop->getFloatValue(); + if (_diff.offset_prop) + _diff.offset = _diff.offset_prop->getFloatValue(); + if (_diff != tmp) + _update |= DIFFUSE; + } + if (_read & AMBIENT) { + ColorSpec tmp = _amb; + if (_amb.red_prop) + _amb.red = _amb.red_prop->getFloatValue(); + if (_amb.green_prop) + _amb.green = _amb.green_prop->getFloatValue(); + if (_amb.blue_prop) + _amb.blue = _amb.blue_prop->getFloatValue(); + if (_amb.factor_prop) + _amb.factor = _amb.factor_prop->getFloatValue(); + if (_amb.offset_prop) + _amb.offset = _amb.offset_prop->getFloatValue(); + if (_amb != tmp) + _update |= AMBIENT; + } + if (_read & SPECULAR) { + ColorSpec tmp = _spec; + if (_spec.red_prop) + _spec.red = _spec.red_prop->getFloatValue(); + if (_spec.green_prop) + _spec.green = _spec.green_prop->getFloatValue(); + if (_spec.blue_prop) + _spec.blue = _spec.blue_prop->getFloatValue(); + if (_spec.factor_prop) + _spec.factor = _spec.factor_prop->getFloatValue(); + if (_spec.offset_prop) + _spec.offset = _spec.offset_prop->getFloatValue(); + if (_spec != tmp) + _update |= SPECULAR; + } + if (_read & EMISSION) { + ColorSpec tmp = _emis; + if (_emis.red_prop) + _emis.red = _emis.red_prop->getFloatValue(); + if (_emis.green_prop) + _emis.green = _emis.green_prop->getFloatValue(); + if (_emis.blue_prop) + _emis.blue = _emis.blue_prop->getFloatValue(); + if (_emis.factor_prop) + _emis.factor = _emis.factor_prop->getFloatValue(); + if (_emis.offset_prop) + _emis.offset = _emis.offset_prop->getFloatValue(); + if (_emis != tmp) + _update |= EMISSION; + } + float f; + if (_shi_prop) { + f = _shi; + _shi = _shi_prop->getFloatValue(); + if (_shi != f) + _update |= SHININESS; + } + if (_trans_prop) { + f = _trans; + _trans = _trans_prop->getFloatValue(); + if (_trans != f) + _update |= TRANSPARENCY; + } + if (_thresh_prop) { + f = _thresh; + _thresh = _thresh_prop->getFloatValue(); + if (_thresh != f) + _update |= THRESHOLD; + } + if (_tex_prop) { + string t = _tex_prop->getStringValue(); + if (!t.empty() && t != _texture_str) { + _texture_str = t; + _texture = _base_dir; + _texture.append(t); + _update |= TEXTURE; + } + } + if (_update) { + setMaterialBranch(_branch); + _update = 0; + } + return 2; } -void SGEmissionAnimation::cloneMaterials(ssgBranch *b) +void SGMaterialAnimation::cloneMaterials(ssgBranch *b) { - // clone material state(s) for this branch - int nb = b->getNumKids(); + for (int i = 0; i < b->getNumKids(); i++) + cloneMaterials((ssgBranch *)b->getKid(i)); - // Traverse the branch(es) and make clones of material settings for the leaves on - // this branch (ssgSimpleState objects). - // Try to be efficient (only make a new clone if the original is different - // than the previous). + if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState()) + return; - for (int i = 0; igetKid(i); - if (e->isAKindOf(ssgTypeLeaf())) { - ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState(); - // if this is a new material state, then make a copy of it... - if (!_cached_material || _cached_material != s) { - _cached_material = s; - _cloned_material = (ssgSimpleState*)s->clone(SSG_CLONE_STATE); - } - // set the material to the clone... - ((ssgLeaf*)e)->setState( _cloned_material ); - } else if (e->isAKindOf(ssgTypeBranch())) { - cloneMaterials( (ssgBranch*)e ); - } + ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState(); + if (!_cached_material || _cached_material != s) { + _cached_material = s; + _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE); } - + ((ssgLeaf *)b)->setState(_cloned_material); } -int SGEmissionAnimation::update() +void SGMaterialAnimation::setMaterialBranch(ssgBranch *b) { - float brightness = _prop->getFloatValue(); - - // clamp brightness 0 ~ 1 - if (brightness < 0.00) brightness = 0.00; - if (brightness > 1.00) brightness = 1.00; + for (int i = 0; i < b->getNumKids(); i++) + setMaterialBranch((ssgBranch *)b->getKid(i)); - // no need to update states unless something changes... - if (brightness != _old_brightness) { - _old_brightness = brightness; // save it - float rd,gr,bl; - rd = _color0 * brightness; - gr = _color1 * brightness; - bl = _color2 * brightness; - setEmissionBranch(_branch, rd, gr, bl); - } - return 1; -} + if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState()) + return; -void SGEmissionAnimation::setEmissionBranch(ssgBranch *b, float color0, float color1, float color2) -{ - int nb = b->getNumKids(); + ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState(); + s->disable(GL_COLOR_MATERIAL); + s->setColourMaterial(GL_AMBIENT_AND_DIFFUSE); - for (int i = 0; igetKid(i); - if (e->isAKindOf(ssgTypeLeaf())) { - ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState(); - s->setMaterial( GL_EMISSION, color0, color1, color2, 0.0 ); - } else if (e->isAKindOf(ssgTypeBranch())) { - setEmissionBranch((ssgBranch*)e, color0, color1, color2); + if (_update & DIFFUSE) { + float *v = _diff.rgba(); + SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3]; + s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha); } - } + if (_update & AMBIENT) + s->setMaterial(GL_AMBIENT, _amb.rgba()); + if (_update & SPECULAR) + s->setMaterial(GL_SPECULAR, _spec.rgba()); + if (_update & EMISSION) + s->setMaterial(GL_EMISSION, _emis.rgba()); + if (_update & SHININESS) + s->setShininess(clamp(_shi, 0.0, 128.0)); + if (_update & TRANSPARENCY) { + SGfloat *v = s->getMaterial(GL_DIFFUSE); + s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], 1.0 - clamp(_trans)); + } + if (_update & THRESHOLD) + s->setAlphaClamp(clamp(_thresh)); + if (_update & TEXTURE) + s->setTexture(_texture.c_str()); + if (_update & (TEXTURE|TRANSPARENCY)) { + SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3]; + ssgTexture *tex = s->getTexture(); + if ((tex && tex->hasAlpha()) || alpha < 0.999) { + s->enable(GL_BLEND); + s->enable(GL_ALPHA_TEST); + s->setTranslucent(); + } else { + s->disable(GL_BLEND); + s->disable(GL_ALPHA_TEST); + s->setOpaque(); + } + } + s->force(); } - + + //////////////////////////////////////////////////////////////////////// // Implementation of SGFlashAnimation //////////////////////////////////////////////////////////////////////// diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index abcae2e1..5c1b82dc 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -22,6 +22,7 @@ SG_USING_STD(map); #include #include +#include // Don't pull in the headers, since we don't need them here. @@ -434,25 +435,86 @@ private: /** - * An "animation" to modify emissive values on leaf nodes + * An "animation" to modify material properties */ -class SGEmissionAnimation : public SGAnimation +class SGMaterialAnimation : public SGAnimation { public: - SGEmissionAnimation(SGPropertyNode *prop_root, SGPropertyNode_ptr props); - virtual ~SGEmissionAnimation (); - virtual void init(); - virtual int update(); + SGMaterialAnimation(SGPropertyNode *prop_root, SGPropertyNode_ptr props, + const SGPath &texpath); + virtual ~SGMaterialAnimation() {} + virtual void init(); + virtual int update(); private: - SGPropertyNode_ptr _prop; - ssgSimpleState* _cached_material; - ssgSimpleState* _cloned_material; - void cloneMaterials(ssgBranch *b); - void setEmissionBranch(ssgBranch *b, float color0, float color1, float color2); - float _color0; - float _color1; - float _color2; - float _old_brightness; + enum { + DIFFUSE = 1, + AMBIENT = 2, + SPECULAR = 4, + EMISSION = 8, + SHININESS = 16, + TRANSPARENCY = 32, + THRESHOLD = 64, + TEXTURE = 128, + }; + struct ColorSpec { + float red, green, blue; + float factor; + float offset; + SGPropertyNode_ptr red_prop; + SGPropertyNode_ptr green_prop; + SGPropertyNode_ptr blue_prop; + SGPropertyNode_ptr factor_prop; + SGPropertyNode_ptr offset_prop; + sgVec4 v; + bool dirty() { + return red >= 0.0 || green >= 0.0 || blue >= 0.0; + } + bool live() { + return red_prop || green_prop || blue_prop + || factor_prop || offset_prop; + } + bool operator!=(ColorSpec& a) { + return red != a.red || green != a.green || blue != a.blue + || factor != a.factor || offset != a.offset; + } + sgVec4 &rgba() { + v[0] = clamp(red * factor + offset); + v[1] = clamp(green * factor + offset); + v[2] = clamp(blue * factor + offset); + v[3] = 1.0; + return v; + } + float clamp(float val) { + return val < 0.0 ? 0.0 : val > 1.0 ? 1.0 : val; + } + }; + SGCondition *_condition; + SGPath _base_dir; + SGPath _texture; + string _texture_str; + ssgSimpleState* _cached_material; + ssgSimpleState* _cloned_material; + unsigned _read; + unsigned _update; + bool _global; + ColorSpec _diff; + ColorSpec _amb; + ColorSpec _emis; + ColorSpec _spec; + float _shi; + float _trans; + float _thresh; // alpha_clamp (see man glAlphaFunc) + string _tex; + SGPropertyNode_ptr _shi_prop; + SGPropertyNode_ptr _trans_prop; + SGPropertyNode_ptr _thresh_prop; + SGPropertyNode_ptr _tex_prop; + + void cloneMaterials(ssgBranch *b); + void setMaterialBranch(ssgBranch *b); + float clamp(float val, float min = 0.0, float max = 1.0) { + return val < min ? min : val > max ? max : val; + } }; diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 3bbe52f8..676f834c 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -125,6 +124,7 @@ sgMakeAnimation( ssgBranch * model, SGPropertyNode *prop_root, SGPropertyNode_ptr node, double sim_time_sec, + SGPath &texture_path, set &ignore_branches ) { bool ignore = false; @@ -159,8 +159,8 @@ sgMakeAnimation( ssgBranch * model, ignore = true; } else if (!strcmp("alpha-test", type)) { animation = new SGAlphaTestAnimation(node); - } else if (!strcmp("material-emission", type)) { - animation = new SGEmissionAnimation(prop_root, node); + } else if (!strcmp("material", type)) { + animation = new SGMaterialAnimation(prop_root, node, texture_path); } else if (!strcmp("flash", type)) { animation = new SGFlashAnimation(node); } else if (!strcmp("dist-scale", type)) { @@ -327,7 +327,7 @@ sgLoad3DModel( const string &fg_root, const string &path, vector name_nodes = animation_nodes[i]->getChildren("object-name"); sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i], - sim_time_sec, ignore_branches); + sim_time_sec, texturepath, ignore_branches); } #if PLIB_VERSION > 183 diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index a4220cdb..b1165045 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -19,6 +19,7 @@ SG_USING_STD(set); #include #include +#include #include @@ -66,6 +67,7 @@ sgMakeAnimation( ssgBranch * model, SGPropertyNode *prop_root, SGPropertyNode_ptr node, double sim_time_sec, + SGPath &texture_path, set &ignore_branches ); /** -- 2.39.5