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:
parent
8b3b0def03
commit
bdd5ca140d
@ -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)
|
||||
|
492
simgear/scene/model/SGMaterialAnimation.cxx
Normal file
492
simgear/scene/model/SGMaterialAnimation.cxx
Normal 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);
|
||||
}
|
||||
|
33
simgear/scene/model/SGMaterialAnimation.hxx
Normal file
33
simgear/scene/model/SGMaterialAnimation.hxx
Normal 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
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user