Modified Files:

simgear/scene/model/Makefile.am
	simgear/scene/model/animation.cxx
	simgear/scene/model/animation.hxx
	simgear/scene/model/model.cxx
	simgear/scene/model/persparam.cxx
	simgear/scene/model/persparam.hxx
	simgear/scene/model/shadanim.cxx
Added Files:
	simgear/scene/model/SGMaterialAnimation.cxx
	simgear/scene/model/SGMaterialAnimation.hxx
	Big animation overhaul. Improoves animation correctness.
This commit is contained in:
frohlich 2006-12-03 16:57:20 +00:00
parent 8b3b0def03
commit bdd5ca140d
9 changed files with 2828 additions and 2149 deletions

View File

@ -11,7 +11,8 @@ include_HEADERS = \
modellib.hxx \
persparam.hxx \
placement.hxx \
placementtrans.hxx
placementtrans.hxx \
SGMaterialAnimation.hxx
libsgmodel_a_SOURCES = \
animation.cxx \
@ -21,6 +22,7 @@ libsgmodel_a_SOURCES = \
persparam.cxx \
placement.cxx \
placementtrans.cxx \
shadanim.cxx
shadanim.cxx \
SGMaterialAnimation.cxx
INCLUDES = -I$(top_srcdir)

View File

@ -0,0 +1,492 @@
// animation.cxx - classes to manage model animation.
// Written by David Megginson, started 2002.
//
// This file is in the Public Domain, and comes with no warranty.
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include "SGMaterialAnimation.hxx"
#include <osg/AlphaFunc>
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/StateSet>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/model/model.hxx>
struct SGMaterialAnimation::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;
SGVec4f v;
ColorSpec(const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
{
red = -1.0;
green = -1.0;
blue = -1.0;
if (!configNode)
return;
red = configNode->getFloatValue("red", -1.0);
green = configNode->getFloatValue("green", -1.0);
blue = configNode->getFloatValue("blue", -1.0);
factor = configNode->getFloatValue("factor", 1.0);
offset = configNode->getFloatValue("offset", 0.0);
if (!modelRoot)
return;
const SGPropertyNode *node;
node = configNode->getChild("red-prop");
if (node)
red_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("green-prop");
if (node)
green_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("blue-prop");
if (node)
blue_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("factor-prop");
if (node)
factor_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("offset-prop");
if (node)
offset_prop = modelRoot->getNode(node->getStringValue(), true);
}
bool dirty() {
return red >= 0 || green >= 0 || blue >= 0;
}
bool live() {
return red_prop || green_prop || blue_prop
|| factor_prop || offset_prop;
}
SGVec4f &rgba() {
if (red_prop)
red = red_prop->getFloatValue();
if (green_prop)
green = green_prop->getFloatValue();
if (blue_prop)
blue = blue_prop->getFloatValue();
if (factor_prop)
factor = factor_prop->getFloatValue();
if (offset_prop)
offset = offset_prop->getFloatValue();
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
v[3] = 1;
return v;
}
SGVec4f &initialRgba() {
v[0] = SGMiscf::clip(red*factor + offset, 0, 1);
v[1] = SGMiscf::clip(green*factor + offset, 0, 1);
v[2] = SGMiscf::clip(blue*factor + offset, 0, 1);
v[3] = 1;
return v;
}
};
struct SGMaterialAnimation::PropSpec {
float value;
float factor;
float offset;
float min;
float max;
SGPropertyNode_ptr value_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
PropSpec(const char* valueName, const char* valuePropName,
const SGPropertyNode* configNode, SGPropertyNode* modelRoot)
{
value = -1;
if (!configNode)
return;
value = configNode->getFloatValue(valueName, -1);
factor = configNode->getFloatValue("factor", 1);
offset = configNode->getFloatValue("offset", 0);
min = configNode->getFloatValue("min", 0);
max = configNode->getFloatValue("max", 1);
if (!modelRoot)
return;
const SGPropertyNode *node;
node = configNode->getChild(valuePropName);
if (node)
value_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("factor-prop");
if (node)
factor_prop = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("offset-prop");
if (node)
offset_prop = modelRoot->getNode(node->getStringValue(), true);
}
bool dirty() { return value >= 0.0; }
bool live() { return value_prop || factor_prop || offset_prop; }
float getValue()
{
if (value_prop)
value = value_prop->getFloatValue();
if (offset_prop)
offset = offset_prop->getFloatValue();
if (factor_prop)
factor = factor_prop->getFloatValue();
return SGMiscf::clip(value*factor + offset, min, max);
}
float getInitialValue()
{
return SGMiscf::clip(value*factor + offset, min, max);
}
};
class SGMaterialAnimation::MaterialVisitor : public osg::NodeVisitor {
public:
enum {
DIFFUSE = 1,
AMBIENT = 2,
SPECULAR = 4,
EMISSION = 8,
SHININESS = 16,
TRANSPARENCY = 32
};
MaterialVisitor() :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_updateMask(0),
_ambient(-1, -1, -1, -1),
_diffuse(-1, -1, -1, -1),
_specular(-1, -1, -1, -1),
_emission(-1, -1, -1, -1),
_shininess(-1),
_alpha(-1)
{
setVisitorType(osg::NodeVisitor::NODE_VISITOR);
}
void setDiffuse(const SGVec4f& diffuse)
{
if (diffuse != _diffuse)
_diffuse = diffuse;
_updateMask |= DIFFUSE;
}
void setAmbient(const SGVec4f& ambient)
{
if (ambient != _ambient)
_ambient = ambient;
_updateMask |= AMBIENT;
}
void setSpecular(const SGVec4f& specular)
{
if (specular != _specular)
_specular = specular;
_updateMask |= SPECULAR;
}
void setEmission(const SGVec4f& emission)
{
if (emission != _emission)
_emission = emission;
_updateMask |= EMISSION;
}
void setShininess(float shininess)
{
if (shininess != _shininess)
_shininess = shininess;
_updateMask |= SHININESS;
}
void setAlpha(float alpha)
{
if (alpha != _alpha)
_alpha = alpha;
_updateMask |= TRANSPARENCY;
}
virtual void reset()
{
_updateMask = 0;
}
virtual void apply(osg::Node& node)
{
updateStateSet(node.getStateSet());
traverse(node);
}
virtual void apply(osg::Geode& node)
{
apply((osg::Node&)node);
unsigned nDrawables = node.getNumDrawables();
for (unsigned i = 0; i < nDrawables; ++i) {
osg::Drawable* drawable = node.getDrawable(i);
updateStateSet(drawable->getStateSet());
if (_updateMask&TRANSPARENCY) {
osg::Geometry* geometry = drawable->asGeometry();
if (!geometry)
continue;
osg::Array* array = geometry->getColorArray();
if (!array)
continue;
osg::Vec4Array* vec4Array = dynamic_cast<osg::Vec4Array*>(array);
if (!vec4Array)
continue;
// FIXME, according to the colormode in the material
// we might incorporate the apropriate color value
geometry->dirtyDisplayList();
vec4Array->dirty();
for (unsigned k = 0; k < vec4Array->size(); ++k) {
(*vec4Array)[k][3] = _alpha;
}
}
}
}
void updateStateSet(osg::StateSet* stateSet)
{
if (!stateSet)
return;
osg::StateAttribute* stateAttribute;
stateAttribute = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
if (!stateAttribute)
return;
osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
if (!material)
return;
if (_updateMask&AMBIENT)
material->setAmbient(osg::Material::FRONT_AND_BACK, _ambient.osg());
if (_updateMask&DIFFUSE)
material->setDiffuse(osg::Material::FRONT_AND_BACK, _diffuse.osg());
if (_updateMask&SPECULAR)
material->setSpecular(osg::Material::FRONT_AND_BACK, _specular.osg());
if (_updateMask&EMISSION)
material->setEmission(osg::Material::FRONT_AND_BACK, _emission.osg());
if (_updateMask&SHININESS)
material->setShininess(osg::Material::FRONT_AND_BACK, _shininess);
if (_updateMask&TRANSPARENCY) {
material->setAlpha(osg::Material::FRONT_AND_BACK, _alpha);
if (_alpha < 1) {
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
} else {
stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN);
}
}
}
private:
unsigned _updateMask;
SGVec4f _ambient;
SGVec4f _diffuse;
SGVec4f _specular;
SGVec4f _emission;
float _shininess;
float _alpha;
};
class SGMaterialAnimation::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),
_texturePathList(texturePathList)
{
const SGPropertyNode* node;
node = configNode->getChild("threshold-prop");
if (node)
_thresholdProp = modelRoot->getNode(node->getStringValue(), true);
node = configNode->getChild("texture-prop");
if (node)
_textureProp = modelRoot->getNode(node->getStringValue(), true);
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (!_condition || _condition->test()) {
if (_textureProp) {
std::string textureName = _textureProp->getStringValue();
if (_textureName != textureName) {
osg::StateSet* stateSet = node->getOrCreateStateSet();
while (stateSet->getTextureAttribute(0, osg::StateAttribute::TEXTURE)) {
stateSet->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
}
std::string textureFile;
textureFile = osgDB::findFileInPath(textureName, _texturePathList);
if (!textureFile.empty()) {
osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
if (texture2D) {
stateSet->setTextureAttribute(0, texture2D);
stateSet->setTextureMode(0, GL_TEXTURE_2D,
osg::StateAttribute::ON);
_textureName = textureName;
}
}
}
}
if (_thresholdProp) {
osg::StateSet* stateSet = node->getOrCreateStateSet();
osg::StateAttribute* stateAttribute;
stateAttribute = stateSet->getAttribute(osg::StateAttribute::ALPHAFUNC);
assert(dynamic_cast<osg::AlphaFunc*>(stateAttribute));
osg::AlphaFunc* alphaFunc = static_cast<osg::AlphaFunc*>(stateAttribute);
alphaFunc->setReferenceValue(_thresholdProp->getFloatValue());
}
_visitor.reset();
if (_ambient.live())
_visitor.setAmbient(_ambient.rgba());
if (_diffuse.live())
_visitor.setDiffuse(_diffuse.rgba());
if (_specular.live())
_visitor.setSpecular(_specular.rgba());
if (_emission.live())
_visitor.setEmission(_emission.rgba());
if (_shininess.live())
_visitor.setShininess(_shininess.getValue());
if (_transparency.live())
_visitor.setAlpha(_transparency.getValue());
node->accept(_visitor);
}
traverse(node, nv);
}
private:
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGPropertyNode> _textureProp;
SGSharedPtr<const SGPropertyNode> _thresholdProp;
MaterialVisitor _visitor;
std::string _textureName;
ColorSpec _ambient;
ColorSpec _diffuse;
ColorSpec _specular;
ColorSpec _emission;
PropSpec _shininess;
PropSpec _transparency;
osgDB::FilePathList _texturePathList;
};
SGMaterialAnimation::SGMaterialAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot)
{
if (configNode->hasChild("global"))
SG_LOG(SG_IO, SG_ALERT, "Using global material animation that can "
"no longer work");
}
osg::Group*
SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
{
osg::Group* group = new osg::Group;
group->setName("material animation group");
SGPropertyNode* inputRoot = getModelRoot();
const SGPropertyNode* node = getConfig()->getChild("property-base");
if (node)
inputRoot = getModelRoot()->getRootNode()->getNode(node->getStringValue(),
true);
osgDB::FilePathList texturePathList = osgDB::getDataFilePathList();
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);
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
if (texture2D->getImage()->isImageTranslucent()) {
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
}
}
}
}
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);
alphaFunc->setReferenceValue(threshold);
stateSet->setAttributeAndModes(alphaFunc);
}
UpdateCallback* updateCallback;
updateCallback = new UpdateCallback(texturePathList, getCondition(),
getConfig(), inputRoot);
group->setUpdateCallback(updateCallback);
parent.addChild(group);
return group;
}
void
SGMaterialAnimation::install(osg::Node& node)
{
SGAnimation::install(node);
// make sure everything (except the texture attributes)
// below is private to our model
cloneDrawables(node);
// Remove all textures if required, they get replaced later on
if (getConfig()->hasChild("texture") ||
getConfig()->hasChild("texture-prop")) {
removeTextureAttribute(node, 0, osg::StateAttribute::TEXTURE);
removeTextureMode(node, 0, GL_TEXTURE_2D);
}
// Remove all nested alphaFuncs
if (getConfig()->hasChild("threshold") ||
getConfig()->hasChild("threshold-prop"))
removeAttribute(node, osg::StateAttribute::ALPHAFUNC);
ColorSpec ambient(getConfig()->getChild("ambient"), getModelRoot());
ColorSpec diffuse(getConfig()->getChild("diffuse"), getModelRoot());
ColorSpec specular(getConfig()->getChild("specular"), getModelRoot());
ColorSpec emission(getConfig()->getChild("emission"), getModelRoot());
PropSpec shininess("shininess", "shininess-prop",
getConfig()->getChild("shininess"), getModelRoot());
PropSpec transparency("alpha", "alpha-prop",
getConfig()->getChild("transparency"), getModelRoot());
MaterialVisitor visitor;
if (ambient.dirty())
visitor.setAmbient(ambient.initialRgba());
if (diffuse.dirty())
visitor.setDiffuse(diffuse.initialRgba());
if (specular.dirty())
visitor.setSpecular(specular.initialRgba());
if (emission.dirty())
visitor.setEmission(emission.initialRgba());
if (shininess.dirty())
visitor.setShininess(shininess.getInitialValue());
if (transparency.dirty())
visitor.setAlpha(transparency.getInitialValue());
node.accept(visitor);
}

View File

@ -0,0 +1,33 @@
// animation.hxx - classes to manage model animation.
// Written by David Megginson, started 2002.
//
// This file is in the Public Domain, and comes with no warranty.
#ifndef _SG_MATERIALANIMATION_HXX
#define _SG_MATERIALANIMATION_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include "animation.hxx"
//////////////////////////////////////////////////////////////////////
// Material animation
//////////////////////////////////////////////////////////////////////
class SGMaterialAnimation : public SGAnimation {
public:
SGMaterialAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
virtual void install(osg::Node& node);
private:
struct ColorSpec;
struct PropSpec;
class MaterialVisitor;
class UpdateCallback;
};
#endif // _SG_MATERIALANIMATION_HXX

File diff suppressed because it is too large Load Diff

View File

@ -31,9 +31,11 @@
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/math/interpolater.hxx>
#include <simgear/scene/model/persparam.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
SG_USING_STD(vector);
SG_USING_STD(map);
@ -52,554 +54,310 @@ class SGCondition;
//////////////////////////////////////////////////////////////////////
// Animation classes
// Helper classes, FIXME: factor out
//////////////////////////////////////////////////////////////////////
/**
* Abstract base class for all animations.
*/
class SGAnimation : public osg::NodeCallback
{
class SGDoubleValue : public SGReferenced {
public:
SGAnimation (SGPropertyNode_ptr props, osg::Group * branch);
virtual ~SGDoubleValue() {}
virtual double getValue() const = 0;
};
virtual ~SGAnimation ();
//////////////////////////////////////////////////////////////////////
// Base class for animation installers
//////////////////////////////////////////////////////////////////////
/**
* Get the SSG branch holding the animation.
*/
virtual osg::Group * getBranch () { return _branch; }
class SGAnimation : protected osg::NodeVisitor {
public:
SGAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot);
virtual ~SGAnimation();
/**
* Initialize the animation, after children have been added.
*/
virtual void init ();
/**
* Update the animation.
*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
/**
* Restore the state after the animation.
*/
virtual void restore();
int get_animation_type(void) { return animation_type; }
static bool animate(osg::Node* node, const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
protected:
void apply(osg::Node* node);
osg::Group* _branch;
virtual void install(osg::Node& node);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
int animation_type;
};
virtual void apply(osg::Group& group);
void removeMode(osg::Node& node, osg::StateAttribute::GLMode mode);
void removeAttribute(osg::Node& node, osg::StateAttribute::Type type);
void removeTextureMode(osg::Node& node, unsigned unit,
osg::StateAttribute::GLMode mode);
void removeTextureAttribute(osg::Node& node, unsigned unit,
osg::StateAttribute::Type type);
void setRenderBinToInherit(osg::Node& node);
void cloneDrawables(osg::Node& node);
/**
* A no-op animation.
*/
class SGNullAnimation : public SGAnimation
{
public:
SGNullAnimation (SGPropertyNode_ptr props);
virtual ~SGNullAnimation ();
};
std::string getType() const
{ return std::string(_configNode->getStringValue("type", "")); }
const SGPropertyNode* getConfig() const
{ return _configNode; }
SGPropertyNode* getModelRoot() const
{ return _modelRoot; }
const SGCondition* getCondition() const;
/**
* A range, or level-of-detail (LOD) animation.
*/
class SGRangeAnimation : public SGAnimation
{
public:
SGRangeAnimation (SGPropertyNode *prop_root,
SGPropertyNode_ptr props);
virtual ~SGRangeAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
private:
SGPropertyNode_ptr _min_prop;
SGPropertyNode_ptr _max_prop;
float _min;
float _max;
float _min_factor;
float _max_factor;
SGSharedPtr<SGCondition> _condition;
void installInGroup(const std::string& name, osg::Group& group,
osg::ref_ptr<osg::Group>& animationGroup);
class RemoveModeVisitor;
class RemoveAttributeVisitor;
class RemoveTextureModeVisitor;
class RemoveTextureAttributeVisitor;
class BinToInheritVisitor;
class DrawableCloneVisitor;
bool _found;
std::string _name;
SGSharedPtr<SGPropertyNode const> _configNode;
SGPropertyNode* _modelRoot;
std::list<std::string> _objectNames;
bool _enableHOT;
bool _disableShadow;
};
//////////////////////////////////////////////////////////////////////
// Null animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to turn and face the screen.
*/
class SGBillboardAnimation : public SGAnimation
{
class SGGroupAnimation : public SGAnimation {
public:
SGBillboardAnimation (SGPropertyNode_ptr props);
virtual ~SGBillboardAnimation ();
SGGroupAnimation(const SGPropertyNode*, SGPropertyNode*);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
};
//////////////////////////////////////////////////////////////////////
// Translate animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to select alternative versions of the same object.
*/
class SGSelectAnimation : public SGAnimation
{
class SGTranslateAnimation : public SGAnimation {
public:
SGSelectAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGSelectAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGTranslateAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
SGSharedPtr<SGCondition> _condition;
class UpdateCallback;
class Transform;
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGDoubleValue> _animationValue;
SGVec3d _axis;
double _initialValue;
};
//////////////////////////////////////////////////////////////////////
// Rotate/Spin animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to spin an object around a center point.
*
* This animation rotates at a specific velocity.
*/
class SGSpinAnimation : public SGAnimation
{
class SGRotateAnimation : public SGAnimation {
public:
SGSpinAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props,
double sim_time_sec );
virtual ~SGSpinAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGRotateAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
bool _use_personality;
SGPropertyNode_ptr _prop;
SGPersonalityParameter<double> _factor;
SGPersonalityParameter<double> _position_deg;
double _last_time_sec;
osg::Vec3 _center;
osg::Vec3 _axis;
SGSharedPtr<SGCondition> _condition;
class UpdateCallback;
class SpinUpdateCallback;
class Transform;
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGDoubleValue> _animationValue;
SGVec3d _axis;
SGVec3d _center;
double _initialValue;
bool _isSpin;
};
//////////////////////////////////////////////////////////////////////
// Scale animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to draw objects for a specific amount of time each.
*/
class SGTimedAnimation : public SGAnimation
{
class SGScaleAnimation : public SGAnimation {
public:
SGTimedAnimation (SGPropertyNode_ptr props);
virtual ~SGTimedAnimation ();
virtual void init();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGScaleAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
bool _use_personality;
double _duration_sec;
double _last_time_sec;
double _total_duration_sec;
unsigned _step;
struct DurationSpec {
DurationSpec( double m = 0.0 ) : _min(m), _max(m) {}
DurationSpec( double m1, double m2 ) : _min(m1), _max(m2) {}
double _min, _max;
};
vector<DurationSpec> _branch_duration_specs;
vector<double> _branch_duration_sec;
class UpdateCallback;
class Transform;
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGDoubleValue> _animationValue[3];
SGVec3d _initialValue;
SGVec3d _center;
};
//////////////////////////////////////////////////////////////////////
// dist scale animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to rotate an object around a center point.
*
* This animation rotates to a specific position.
*/
class SGRotateAnimation : public SGAnimation
{
class SGDistScaleAnimation : public SGAnimation {
public:
SGRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
virtual ~SGRotateAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGDistScaleAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
SGPropertyNode_ptr _prop;
double _offset_deg;
double _factor;
SGSharedPtr<SGInterpTable> _table;
bool _has_min;
double _min_deg;
bool _has_max;
double _max_deg;
double _position_deg;
osg::Vec3 _center;
osg::Vec3 _axis;
SGSharedPtr<SGCondition> _condition;
class Transform;
};
//////////////////////////////////////////////////////////////////////
// dist scale animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to slide along an axis.
*/
class SGTranslateAnimation : public SGAnimation
{
class SGFlashAnimation : public SGAnimation {
public:
SGTranslateAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTranslateAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGFlashAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
bool _use_personality;
SGPropertyNode_ptr _prop;
SGPersonalityParameter<double> _offset_m;
SGPersonalityParameter<double> _factor;
SGSharedPtr<SGInterpTable> _table;
bool _has_min;
double _min_m;
bool _has_max;
double _max_m;
double _position_m;
osg::Vec3 _axis;
SGSharedPtr<SGCondition> _condition;
class Transform;
};
/**
* Animation to blend an object.
*/
class SGBlendAnimation : public SGAnimation
{
//////////////////////////////////////////////////////////////////////
// dist scale animation installer
//////////////////////////////////////////////////////////////////////
class SGBillboardAnimation : public SGAnimation {
public:
SGBlendAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGBlendAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGBillboardAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
bool _use_personality;
SGPropertyNode_ptr _prop;
SGSharedPtr<SGInterpTable> _table;
double _prev_value;
SGPersonalityParameter<double> _offset;
SGPersonalityParameter<double> _factor;
double _min;
double _max;
class Transform;
};
/**
* Animation to scale an object.
*/
class SGScaleAnimation : public SGAnimation
{
//////////////////////////////////////////////////////////////////////
// Range animation installer
//////////////////////////////////////////////////////////////////////
class SGRangeAnimation : public SGAnimation {
public:
SGScaleAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGScaleAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGRangeAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
bool _use_personality;
SGPropertyNode_ptr _prop;
SGPersonalityParameter<double> _x_factor;
SGPersonalityParameter<double> _y_factor;
SGPersonalityParameter<double> _z_factor;
SGPersonalityParameter<double> _x_offset;
SGPersonalityParameter<double> _y_offset;
SGPersonalityParameter<double> _z_offset;
SGSharedPtr<SGInterpTable> _table;
bool _has_min_x;
bool _has_min_y;
bool _has_min_z;
double _min_x;
double _min_y;
double _min_z;
bool _has_max_x;
bool _has_max_y;
bool _has_max_z;
double _max_x;
double _max_y;
double _max_z;
double _x_scale;
double _y_scale;
double _z_scale;
class UpdateCallback;
SGSharedPtr<const SGCondition> _condition;
SGSharedPtr<const SGDoubleValue> _minAnimationValue;
SGSharedPtr<const SGDoubleValue> _maxAnimationValue;
SGVec2d _initialValue;
};
/**
* Animation to rotate texture mappings around a center point.
*
* This animation rotates to a specific position.
*/
class SGTexRotateAnimation : public SGAnimation
{
//////////////////////////////////////////////////////////////////////
// Select animation installer
//////////////////////////////////////////////////////////////////////
class SGSelectAnimation : public SGAnimation {
public:
SGTexRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
virtual ~SGTexRotateAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGSelectAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
SGPropertyNode_ptr _prop;
double _offset_deg;
double _factor;
SGSharedPtr<SGInterpTable> _table;
bool _has_min;
double _min_deg;
bool _has_max;
double _max_deg;
double _position_deg;
osg::Vec3 _center;
osg::Vec3 _axis;
SGSharedPtr<SGCondition> _condition;
osg::ref_ptr<osg::TexMat> _texMat;
class UpdateCallback;
};
//////////////////////////////////////////////////////////////////////
// Alpha test animation installer
//////////////////////////////////////////////////////////////////////
/**
* Animation to slide texture mappings along an axis.
*/
class SGTexTranslateAnimation : public SGAnimation
{
class SGAlphaTestAnimation : public SGAnimation {
public:
SGTexTranslateAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTexTranslateAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGAlphaTestAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual void install(osg::Node& node);
};
//////////////////////////////////////////////////////////////////////
// Blend animation installer
//////////////////////////////////////////////////////////////////////
class SGBlendAnimation : public SGAnimation {
public:
SGBlendAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
virtual void install(osg::Node& node);
private:
SGPropertyNode_ptr _prop;
double _offset;
double _factor;
double _step;
double _scroll;
SGSharedPtr<SGInterpTable> _table;
bool _has_min;
double _min;
bool _has_max;
double _max;
double _position;
osg::Vec3 _axis;
SGSharedPtr<SGCondition> _condition;
osg::ref_ptr<osg::TexMat> _texMat;
class BlendVisitor;
class UpdateCallback;
SGSharedPtr<SGDoubleValue> _animationValue;
};
//////////////////////////////////////////////////////////////////////
// Timed animation installer
//////////////////////////////////////////////////////////////////////
/**
* Classes for handling multiple types of Texture translations on one object
*/
class SGTexMultipleAnimation : public SGAnimation
{
class SGTimedAnimation : public SGAnimation {
public:
SGTexMultipleAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTexMultipleAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGTimedAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
class TexTransform
{
public:
SGPropertyNode_ptr prop;
int subtype; // 0=translation, 1=rotation
double offset;
double factor;
double step;
double scroll;
SGSharedPtr<SGInterpTable> table;
bool has_min;
double min;
bool has_max;
double max;
double position;
osg::Vec3 center;
osg::Vec3 axis;
};
SGPropertyNode_ptr _prop;
TexTransform* _transform;
int _num_transforms;
osg::ref_ptr<osg::TexMat> _texMat;
class UpdateCallback;
};
//////////////////////////////////////////////////////////////////////
// Shadow animation installer
//////////////////////////////////////////////////////////////////////
/**
* An "animation" to enable the alpha test
*/
class SGAlphaTestAnimation : public SGAnimation
{
class SGShadowAnimation : public SGAnimation {
public:
SGAlphaTestAnimation(SGPropertyNode_ptr props);
virtual ~SGAlphaTestAnimation ();
virtual void init();
SGShadowAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
float _alpha_clamp;
class UpdateCallback;
};
//////////////////////////////////////////////////////////////////////
// TextureTransform animation
//////////////////////////////////////////////////////////////////////
/**
* An "animation" to modify material properties
*/
class SGMaterialAnimation : public SGAnimation
{
class SGTexTransformAnimation : public SGAnimation {
public:
SGMaterialAnimation(SGPropertyNode *prop_root, SGPropertyNode_ptr props,
const SGPath &texpath);
virtual ~SGMaterialAnimation();
virtual void init();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
SGTexTransformAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
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;
osg::Vec4 v;
inline bool dirty() {
return red >= 0.0 || green >= 0.0 || blue >= 0.0;
}
inline bool live() {
return red_prop || green_prop || blue_prop
|| factor_prop || offset_prop;
}
inline bool operator!=(ColorSpec& a) {
return red != a.red || green != a.green || blue != a.blue
|| factor != a.factor || offset != a.offset;
}
osg::Vec4 &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;
}
inline float clamp(float val) {
return val < 0.0 ? 0.0 : val > 1.0 ? 1.0 : val;
}
};
struct PropSpec {
float value;
float factor;
float offset;
float min;
float max;
SGPropertyNode_ptr value_prop;
SGPropertyNode_ptr factor_prop;
SGPropertyNode_ptr offset_prop;
inline bool dirty() { return value >= 0.0; }
inline bool live() { return value_prop || factor_prop || offset_prop; }
inline bool operator!=(PropSpec& a) {
return value != a.value || factor != a.factor || offset != a.offset;
}
};
SGSharedPtr<SGCondition> _condition;
bool _last_condition;
SGPropertyNode_ptr _prop_root;
string _prop_base;
SGPath _texture_base;
SGPath _texture;
string _texture_str;
unsigned _read;
unsigned _update;
unsigned _static_update;
bool _global;
ColorSpec _diff;
ColorSpec _amb;
ColorSpec _emis;
ColorSpec _spec;
float _shi;
PropSpec _trans;
float _thresh; // alpha_clamp (see man glAlphaFunc)
string _tex;
string _tmpstr;
SGPropertyNode_ptr _shi_prop;
SGPropertyNode_ptr _thresh_prop;
SGPropertyNode_ptr _tex_prop;
std::vector<osg::ref_ptr<osg::Material> > _materialList;
osg::ref_ptr<osg::AlphaFunc> _alphaFunc;
osg::ref_ptr<osg::Texture2D> _texture2D;
void cloneMaterials(osg::Group *b);
void setMaterialBranch(osg::Group *b);
void initColorGroup(SGPropertyNode_ptr, ColorSpec *, int flag);
void updateColorGroup(ColorSpec *, int flag);
inline float clamp(float val, float min = 0.0, float max = 1.0) {
return val < min ? min : val > max ? max : val;
}
const char *path(const char *rel) {
return (_tmpstr = _prop_base + rel).c_str();
}
class Transform;
class Translation;
class Rotation;
class UpdateCallback;
void appendTexTranslate(const SGPropertyNode* config,
UpdateCallback* updateCallback);
void appendTexRotate(const SGPropertyNode* config,
UpdateCallback* updateCallback);
};
//////////////////////////////////////////////////////////////////////
// Shader animation
//////////////////////////////////////////////////////////////////////
/**
* An "animation" that compute a scale according to
* the angle between an axis and the view direction
*/
class SGFlashAnimation : public SGAnimation
{
class SGShaderAnimation : public SGAnimation {
public:
SGFlashAnimation(SGPropertyNode_ptr props);
virtual ~SGFlashAnimation ();
};
/**
* An animation that compute a scale according to
* the distance from a point and the viewer
*/
class SGDistScaleAnimation : public SGAnimation
{
public:
SGDistScaleAnimation(SGPropertyNode_ptr props);
virtual ~SGDistScaleAnimation ();
};
/**
* An animation to tell wich objects don't cast shadows.
*/
class SGShadowAnimation : public SGAnimation
{
public:
SGShadowAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGShadowAnimation ();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
bool get_condition_value(void);
SGShaderAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot);
virtual osg::Group* createAnimationGroup(osg::Group& parent);
private:
SGSharedPtr<SGCondition> _condition;
bool _condition_value;
class UpdateCallback;
};
/**
+ * An "animation" that replace fixed opengl pipeline by shaders
+ */
class SGShaderAnimation : public SGAnimation
{
public:
SGShaderAnimation ( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGShaderAnimation ();
virtual void init();
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
bool get_condition_value(void);
private:
SGSharedPtr<SGCondition> _condition;
bool _condition_value;
int _shader_type;
float _param_1;
osg::Vec4 _param_color;
public:
bool _depth_test;
float _factor;
SGPropertyNode_ptr _factor_prop;
float _speed;
float totalTime;
SGPropertyNode_ptr _speed_prop;
osg::ref_ptr<osg::Texture2D> _effectTexture;
unsigned char *_textureData;
GLint _texWidth, _texHeight;
osg::Vec4 _envColor;
};
#endif // _SG_ANIMATION_HXX

View File

@ -19,6 +19,7 @@
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/Registry>
#include <osgDB/SharedStateManager>
#include <osgUtil/Optimizer>
@ -65,9 +66,11 @@ public:
SGTextureUpdateVisitor(const osgDB::FilePathList& pathList) :
mPathList(pathList)
{ }
osg::Texture2D* textureReplace(int unit, osg::StateSet::RefAttributePair& refAttr)
osg::Texture2D* textureReplace(int unit,
osg::StateSet::RefAttributePair& refAttr)
{
osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(refAttr.first.get());
osg::Texture2D* texture;
texture = dynamic_cast<osg::Texture2D*>(refAttr.first.get());
if (!texture)
return 0;
@ -113,7 +116,8 @@ public:
if (texture) {
stateSet->removeTextureAttribute(unit, i->second.first.get());
stateSet->setTextureAttribute(unit, texture, i->second.second);
stateSet->setTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::ON);
stateSet->setTextureMode(unit, GL_TEXTURE_2D,
osg::StateAttribute::ON);
}
++i;
}
@ -132,7 +136,8 @@ public:
virtual void apply(int, osg::StateSet::RefAttributePair& refAttr)
{
osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(refAttr.first.get());
osg::Texture2D* texture;
texture = dynamic_cast<osg::Texture2D*>(refAttr.first.get());
if (!texture)
return;
@ -157,7 +162,8 @@ class SGAcMaterialCrippleVisitor : public SGStateAttributeVisitor {
public:
virtual void apply(osg::StateSet::RefAttributePair& refAttr)
{
osg::Material* material = dynamic_cast<osg::Material*>(refAttr.first.get());
osg::Material* material;
material = dynamic_cast<osg::Material*>(refAttr.first.get());
if (!material)
return;
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
@ -168,7 +174,8 @@ class SGReadFileCallback :
public osgDB::Registry::ReadFileCallback {
public:
virtual osgDB::ReaderWriter::ReadResult
readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* opt)
readImage(const std::string& fileName,
const osgDB::ReaderWriter::Options* opt)
{
std::string absFileName = osgDB::findDataFile(fileName);
if (!osgDB::fileExists(absFileName)) {
@ -178,7 +185,8 @@ public:
}
osgDB::Registry* registry = osgDB::Registry::instance();
osgDB::ReaderWriter::ReadResult res = registry->readImageImplementation(absFileName, opt);
osgDB::ReaderWriter::ReadResult res;
res = registry->readImageImplementation(absFileName, opt);
if (res.loadedFromCache())
SG_LOG(SG_IO, SG_INFO, "Returning cached image \""
<< res.getImage()->getFileName() << "\"");
@ -190,7 +198,8 @@ public:
}
virtual osgDB::ReaderWriter::ReadResult
readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* opt)
readNode(const std::string& fileName,
const osgDB::ReaderWriter::Options* opt)
{
std::string absFileName = osgDB::findDataFile(fileName);
if (!osgDB::fileExists(absFileName)) {
@ -234,19 +243,23 @@ public:
osgUtil::Optimizer optimizer;
unsigned opts = osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
optimizer.optimize(root.get(), opts);
// strip away unneeded groups
if (root->getNumChildren() == 1 && root->getName().empty()) {
res = osgDB::ReaderWriter::ReadResult(root->getChild(0));
} else
res = osgDB::ReaderWriter::ReadResult(root.get());
// Ok, this step is questionable.
// It is there to have the same visual appearance of ac objects for the
// first cut. Osg's ac3d loader will correctly set materials from the
// ac file. But the old plib loader used GL_AMBIENT_AND_DIFFUSE for the
// materials that in effect igored the ambient part specified in the
// file. We emulate that for the first cut here by changing all ac models
// here. But in the long term we should use the unchanged model and fix
// the input files instead ...
// file. We emulate that for the first cut here by changing all
// ac models here. But in the long term we should use the
// unchanged model and fix the input files instead ...
SGAcMaterialCrippleVisitor matCriple;
root->accept(matCriple);
res = osgDB::ReaderWriter::ReadResult(root.get());
res.getNode()->accept(matCriple);
}
osgUtil::Optimizer optimizer;
@ -261,6 +274,7 @@ public:
// opts |= osgUtil::Optimizer::CHECK_GEOMETRY;
// opts |= osgUtil::Optimizer::SPATIALIZE_GROUPS;
// opts |= osgUtil::Optimizer::COPY_SHARED_NODES;
opts |= osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS;
if (needTristrip)
opts |= osgUtil::Optimizer::TRISTRIP_GEOMETRY;
// opts |= osgUtil::Optimizer::TESSELATE_GEOMETRY;
@ -271,7 +285,8 @@ public:
registry->getSharedStateManager()->share(res.getNode());
// OSGFIXME: guard that with a flag
// OSGFIXME: in the long term it is unclear if we have an OpenGL context here...
// OSGFIXME: in the long term it is unclear if we have an OpenGL
// context here...
osg::Texture::Extensions* e = osg::Texture::getExtensions(0, true);
if (e->isTextureCompressionARBSupported()) {
SGTexCompressionVisitor texComp(osg::Texture::USE_ARB_COMPRESSION);
@ -284,10 +299,11 @@ public:
// Add an extra reference to the model stored in the database.
// That it to avoid expiring the object from the cache even if it is still
// in use. Note that the object cache will think that a model is unused if the
// reference count is 1. If we clone all structural nodes here we need that extra
// reference to the original object
SGDatabaseReference* databaseReference = new SGDatabaseReference(res.getNode());
// in use. Note that the object cache will think that a model is unused
// if the reference count is 1. If we clone all structural nodes here
// we need that extra reference to the original object
SGDatabaseReference* databaseReference;
databaseReference = new SGDatabaseReference(res.getNode());
osg::CopyOp::CopyFlags flags = osg::CopyOp::DEEP_COPY_ALL;
flags &= ~osg::CopyOp::DEEP_COPY_TEXTURES;
flags &= ~osg::CopyOp::DEEP_COPY_IMAGES;
@ -383,157 +399,9 @@ public:
}
private:
SGCondition* mCondition;
SGSharedPtr<SGCondition> mCondition;
};
/**
* Locate a named node in a branch.
*/
class NodeFinder : public osg::NodeVisitor {
public:
NodeFinder(const std::string& nameToFind) :
osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR,
osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
mName(nameToFind),
mNode(0)
{ }
virtual void apply(osg::Node& node)
{
if (mNode)
return;
if (mName == node.getName()) {
mNode = &node;
return;
}
traverse(node);
}
osg::Node* getNode() const
{ return mNode; }
private:
std::string mName;
osg::Node* mNode;
};
/**
* Splice a branch in between all child nodes and their parents.
*/
static void
splice_branch(osg::Group* group, osg::Node* child)
{
osg::Node::ParentList parents = child->getParents();
group->addChild(child);
osg::Node::ParentList::iterator i;
for (i = parents.begin(); i != parents.end(); ++i)
(*i)->replaceChild(child, group);
}
void
sgMakeAnimation( osg::Node * model,
const char * name,
vector<SGPropertyNode_ptr> &name_nodes,
SGPropertyNode *prop_root,
SGPropertyNode_ptr node,
double sim_time_sec,
SGPath &texture_path,
set<osg::Node*> &ignore_branches )
{
bool ignore = false;
SGAnimation * animation = 0;
const char * type = node->getStringValue("type", "none");
if (!strcmp("none", type)) {
animation = new SGNullAnimation(node);
} else if (!strcmp("range", type)) {
animation = new SGRangeAnimation(prop_root, node);
} else if (!strcmp("billboard", type)) {
animation = new SGBillboardAnimation(node);
} else if (!strcmp("select", type)) {
animation = new SGSelectAnimation(prop_root, node);
} else if (!strcmp("spin", type)) {
animation = new SGSpinAnimation(prop_root, node, sim_time_sec );
} else if (!strcmp("timed", type)) {
animation = new SGTimedAnimation(node);
} else if (!strcmp("rotate", type)) {
animation = new SGRotateAnimation(prop_root, node);
} else if (!strcmp("translate", type)) {
animation = new SGTranslateAnimation(prop_root, node);
} else if (!strcmp("scale", type)) {
animation = new SGScaleAnimation(prop_root, node);
} else if (!strcmp("texrotate", type)) {
animation = new SGTexRotateAnimation(prop_root, node);
} else if (!strcmp("textranslate", type)) {
animation = new SGTexTranslateAnimation(prop_root, node);
} else if (!strcmp("texmultiple", type)) {
animation = new SGTexMultipleAnimation(prop_root, node);
} else if (!strcmp("blend", type)) {
animation = new SGBlendAnimation(prop_root, node);
ignore = true;
} else if (!strcmp("alpha-test", type)) {
animation = new SGAlphaTestAnimation(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)) {
animation = new SGDistScaleAnimation(node);
} else if (!strcmp("noshadow", type)) {
animation = new SGShadowAnimation(prop_root, node);
} else if (!strcmp("shader", type)) {
animation = new SGShaderAnimation(prop_root, node);
} else {
animation = new SGNullAnimation(node);
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
}
if (name != 0)
animation->setName(name);
osg::Node * object = 0;
if (!name_nodes.empty()) {
const char * name = name_nodes[0]->getStringValue();
NodeFinder nodeFinder(name);
model->accept(nodeFinder);
object = nodeFinder.getNode();
if (object == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "Object " << name << " not found");
delete animation;
animation = 0;
}
} else {
object = model;
}
if ( animation == 0 )
return;
osg::Group* branch = animation->getBranch();
splice_branch(branch, object);
for (unsigned int i = 1; i < name_nodes.size(); i++) {
const char * name = name_nodes[i]->getStringValue();
NodeFinder nodeFinder(name);
model->accept(nodeFinder);
object = nodeFinder.getNode();
if (object == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "Object " << name << " not found");
delete animation;
animation = 0;
} else {
osg::Group* oldParent = object->getParent(0);
branch->addChild(object);
oldParent->removeChild(object);
}
}
if ( animation != 0 ) {
animation->init();
branch->setUpdateCallback(animation);
if ( ignore ) {
ignore_branches.insert( branch );
}
}
}
////////////////////////////////////////////////////////////////////////
// Global functions.
@ -546,10 +414,10 @@ sgLoad3DModel( const string &fg_root, const string &path,
SGModelData *data,
const SGPath& externalTexturePath )
{
osg::Switch* model = 0;
osg::Node* model = 0;
SGPropertyNode props;
// Load the 3D aircraft object itself
// Load the 3D aircraft object itself
SGPath modelpath = path, texturepath = path;
if ( !ulIsAbsolutePathName( path.c_str() ) ) {
SGPath tmp = fg_root;
@ -557,7 +425,7 @@ sgLoad3DModel( const string &fg_root, const string &path,
modelpath = texturepath = tmp;
}
// Check for an XML wrapper
// Check for an XML wrapper
if (modelpath.str().substr(modelpath.str().size() - 4, 4) == ".xml") {
readProperties(modelpath.str(), &props);
if (props.hasValue("/path")) {
@ -576,25 +444,23 @@ sgLoad3DModel( const string &fg_root, const string &path,
osgDB::FilePathList pathList = osgDB::getDataFilePathList();
osgDB::Registry::instance()->initFilePathLists();
// Assume that textures are in
// the same location as the XML file.
// Assume that textures are in
// the same location as the XML file.
if (model == 0) {
if (texturepath.extension() != "")
texturepath = texturepath.dir();
osgDB::Registry::instance()->getDataFilePathList().push_front(texturepath.str());
osg::Node* node = osgDB::readNodeFile(modelpath.str());
if (node == 0)
model = osgDB::readNodeFile(modelpath.str());
if (model == 0)
throw sg_io_exception("Failed to load 3D model",
sg_location(modelpath.str()));
model = new osg::Switch;
model->addChild(node, true);
}
osgDB::Registry::instance()->getDataFilePathList().push_front(externalTexturePath.str());
// Set up the alignment node
// Set up the alignment node
osg::MatrixTransform* alignmainmodel = new osg::MatrixTransform;
alignmainmodel->addChild(model);
osg::Matrix res_matrix;
@ -612,30 +478,28 @@ sgLoad3DModel( const string &fg_root, const string &path,
props.getFloatValue("/offsets/z-m", 0.0));
alignmainmodel->setMatrix(res_matrix*tmat);
unsigned int i;
// Load sub-models
// Load sub-models
vector<SGPropertyNode_ptr> model_nodes = props.getChildren("model");
for (i = 0; i < model_nodes.size(); i++) {
for (unsigned i = 0; i < model_nodes.size(); i++) {
SGPropertyNode_ptr node = model_nodes[i];
osg::MatrixTransform* align = new osg::MatrixTransform;
res_matrix.makeIdentity();
res_matrix.makeRotate(
node->getFloatValue("offsets/heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
node->getDoubleValue("offsets/heading-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 0, 1),
node->getFloatValue("offsets/roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
node->getDoubleValue("offsets/roll-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(1, 0, 0),
node->getFloatValue("offsets/pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
node->getDoubleValue("offsets/pitch-deg", 0.0)*SG_DEGREES_TO_RADIANS,
osg::Vec3(0, 1, 0));
tmat.makeIdentity();
tmat.makeTranslate(node->getFloatValue("offsets/x-m", 0.0),
node->getFloatValue("offsets/y-m", 0.0),
node->getFloatValue("offsets/z-m", 0.0));
tmat.makeTranslate(node->getDoubleValue("offsets/x-m", 0),
node->getDoubleValue("offsets/y-m", 0),
node->getDoubleValue("offsets/z-m", 0));
align->setMatrix(res_matrix*tmat);
osg::Node* kid;
const char * submodel = node->getStringValue("path");
const char* submodel = node->getStringValue("path");
try {
kid = sgLoad3DModel( fg_root, submodel, prop_root, sim_time_sec, load_panel );
@ -646,22 +510,28 @@ sgLoad3DModel( const string &fg_root, const string &path,
align->addChild(kid);
align->setName(node->getStringValue("name", ""));
model->addChild(align);
SGPropertyNode *cond = node->getNode("condition", false);
if (cond)
model->setUpdateCallback(new SGSwitchUpdateCallback(sgReadCondition(prop_root, cond)));
if (cond) {
osg::Switch* sw = new osg::Switch;
sw->setUpdateCallback(new SGSwitchUpdateCallback(sgReadCondition(prop_root, cond)));
alignmainmodel->addChild(sw);
sw->addChild(align);
sw->setName("submodel condition switch");
} else {
alignmainmodel->addChild(align);
}
}
if ( load_panel ) {
// Load panels
// Load panels
vector<SGPropertyNode_ptr> panel_nodes = props.getChildren("panel");
for (i = 0; i < panel_nodes.size(); i++) {
for (unsigned i = 0; i < panel_nodes.size(); i++) {
SG_LOG(SG_INPUT, SG_DEBUG, "Loading a panel");
osg::Node * panel = load_panel(panel_nodes[i]);
if (panel_nodes[i]->hasValue("name"))
panel->setName((char *)panel_nodes[i]->getStringValue("name"));
model->addChild(panel);
alignmainmodel->addChild(panel);
}
}
@ -669,20 +539,22 @@ sgLoad3DModel( const string &fg_root, const string &path,
alignmainmodel->setUserData(data);
data->modelLoaded(path, &props, alignmainmodel);
}
// Load animations
set<osg::Node*> ignore_branches;
vector<SGPropertyNode_ptr> animation_nodes = props.getChildren("animation");
for (i = 0; i < animation_nodes.size(); i++) {
const char * name = animation_nodes[i]->getStringValue("name", 0);
vector<SGPropertyNode_ptr> name_nodes =
animation_nodes[i]->getChildren("object-name");
sgMakeAnimation( model, name, name_nodes, prop_root, animation_nodes[i],
sim_time_sec, texturepath, ignore_branches);
}
std::vector<SGPropertyNode_ptr> animation_nodes;
animation_nodes = props.getChildren("animation");
for (unsigned i = 0; i < animation_nodes.size(); ++i)
/// OSGFIXME: duh, why not only model?????
SGAnimation::animate(alignmainmodel, animation_nodes[i], prop_root);
// restore old path list
osgDB::setDataFilePathList(pathList);
if (props.hasChild("debug-outfile")) {
std::string outputfile = props.getStringValue("debug-outfile",
"debug-model.osg");
osgDB::writeNodeFile(*alignmainmodel, outputfile);
}
return alignmainmodel;
}

View File

@ -6,7 +6,7 @@
#include "persparam.hxx"
template <> double
SGPersonalityParameter<double>::getNodeValue( SGPropertyNode *props,
SGPersonalityParameter<double>::getNodeValue( const SGPropertyNode *props,
const char *name,
double defval ) const
{

View File

@ -11,11 +11,11 @@
template <class T>
class SGPersonalityParameter {
public:
SGPersonalityParameter( SGPropertyNode *props, const char *name, T defval )
SGPersonalityParameter(const SGPropertyNode *props, const char *name, T defval )
: _var( defval ), _min( defval ), _max( defval ) {
SGPropertyNode_ptr node = props->getNode( name );
const SGPropertyNode* node = props->getNode( name );
if ( node != 0 ) {
SGPropertyNode_ptr rand_n = node->getNode( "random" );
const SGPropertyNode* rand_n = node->getNode( "random" );
if ( rand_n != 0 ) {
_min = getNodeValue( rand_n, "min", (T)0 );
_max = getNodeValue( rand_n, "max", (T)1 );
@ -30,7 +30,7 @@ public:
SGPersonalityParameter<T> &operator-=( T v ) { _var -= v; return *this; }
T shuffle() { return ( _var = _min + sg_random() * ( _max - _min ) ); }
T value() const { return _var; }
T getNodeValue( SGPropertyNode *props, const char *name, T defval ) const;
T getNodeValue(const SGPropertyNode *props, const char *name, T defval ) const;
operator T() const { return _var; }
private:
@ -40,7 +40,7 @@ private:
};
template <> double
SGPersonalityParameter<double>::getNodeValue( SGPropertyNode *props,
SGPersonalityParameter<double>::getNodeValue( const SGPropertyNode *props,
const char *name,
double defval ) const;

View File

@ -24,11 +24,22 @@
# include <simgear_config.h>
#endif
#include <plib/ul.h>
#include <osg/Group>
#include <osg/Program>
#include <osg/Shader>
#include <osg/StateSet>
#include <osg/TextureCubeMap>
#include <osg/TexEnvCombine>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osgUtil/HighlightMapGenerator>
#include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/screen/extensions.hxx>
#include <simgear/debug/logstream.hxx>
@ -66,6 +77,130 @@
</animation>
*/
class SGMapGenCallback :
public osg::StateAttribute::Callback {
public:
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
{
SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
if (!updateVisitor)
return;
if (distSqr(_lastLightDirection, updateVisitor->getLightDirection()) < 1e-4
&& distSqr(_lastLightColor, updateVisitor->getAmbientLight()) < 1e-4)
return;
_lastLightDirection = updateVisitor->getLightDirection();
_lastLightColor = updateVisitor->getAmbientLight();
osg::TextureCubeMap *tcm = static_cast<osg::TextureCubeMap*>(sa);
// FIXME: need an update or callback ...
// generate the six highlight map images (light direction = [1, 1, -1])
osg::ref_ptr<osgUtil::HighlightMapGenerator> mapgen;
mapgen = new osgUtil::HighlightMapGenerator(_lastLightDirection.osg(),
_lastLightColor.osg(), 5);
mapgen->generateMap();
// assign the six images to the texture object
tcm->setImage(osg::TextureCubeMap::POSITIVE_X,
mapgen->getImage(osg::TextureCubeMap::POSITIVE_X));
tcm->setImage(osg::TextureCubeMap::NEGATIVE_X,
mapgen->getImage(osg::TextureCubeMap::NEGATIVE_X));
tcm->setImage(osg::TextureCubeMap::POSITIVE_Y,
mapgen->getImage(osg::TextureCubeMap::POSITIVE_Y));
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y,
mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Y));
tcm->setImage(osg::TextureCubeMap::POSITIVE_Z,
mapgen->getImage(osg::TextureCubeMap::POSITIVE_Z));
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z,
mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Z));
}
private:
SGVec3f _lastLightDirection;
SGVec4f _lastLightColor;
};
static osg::TextureCubeMap*
getOrCreateTextureCubeMap()
{
static osg::TextureCubeMap* textureCubeMap = 0;
if (textureCubeMap)
return textureCubeMap;
static SGMutex mutex;
SGGuard<SGMutex> locker(mutex);
if (textureCubeMap)
return textureCubeMap;
// create and setup the texture object
textureCubeMap = new osg::TextureCubeMap;
textureCubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
textureCubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
textureCubeMap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP);
textureCubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
textureCubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
textureCubeMap->setUpdateCallback(new SGMapGenCallback);
return textureCubeMap;
}
static void create_specular_highlights(osg::Node *node)
{
osg::StateSet *ss = node->getOrCreateStateSet();
// create and setup the texture object
osg::TextureCubeMap *tcm = getOrCreateTextureCubeMap();
// enable texturing, replacing any textures in the subgraphs
ss->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
// texture coordinate generation
osg::TexGen *tg = new osg::TexGen;
tg->setMode(osg::TexGen::REFLECTION_MAP);
ss->setTextureAttributeAndModes(0, tg, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
// use TexEnvCombine to add the highlights to the original lighting
osg::TexEnvCombine *te = new osg::TexEnvCombine;
te->setCombine_RGB(osg::TexEnvCombine::ADD);
te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
te->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
te->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
te->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
}
SGShaderAnimation::SGShaderAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot)
{
}
osg::Group*
SGShaderAnimation::createAnimationGroup(osg::Group& parent)
{
osg::Group* group = new osg::Group;
group->setName("shader animation");
parent.addChild(group);
std::string shader_name = getConfig()->getStringValue("shader", "");
// if( shader_name == "fresnel" || shader_name == "reflection" )
// _shader_type = 1;
// else if( shader_name == "heat-haze" )
// _shader_type = 2;
// else
if( shader_name == "chrome")
create_specular_highlights(group);
return group;
}
#if 0
// static Shader *shFresnel=NULL;
// static GLuint texFresnel = 0;
@ -621,3 +756,4 @@ SGShaderAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
// that the rest of cullbacks and the scene graph are traversed.
traverse(node, nv);
}
#endif