#include <algorithm>
#include <functional>
+#include <OpenThreads/Atomic>
#include <OpenThreads/Mutex>
#include <OpenThreads/ReentrantMutex>
#include <OpenThreads/ScopedLock>
#include <osg/Geometry>
#include <osg/LOD>
#include <osg/Math>
-#include <osg/PolygonMode>
-#include <osg/PolygonOffset>
+#include <osg/Object>
#include <osg/StateSet>
#include <osg/Switch>
#include <osg/TexMat>
#include <osg/Texture2D>
#include <osg/Transform>
+#include <osg/Uniform>
#include <osgDB/ReadFile>
+#include <osgDB/Registry>
+#include <osgDB/Input>
+#include <osgDB/ParameterOutput>
+
#include <simgear/math/interpolater.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
-#include <simgear/structure/SGBinding.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/util/DeletionManager.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/SGSceneUserData.hxx>
#include <simgear/scene/util/SGStateAttributeVisitor.hxx>
+#include <simgear/scene/util/StateAttributeFactory.hxx>
#include "animation.hxx"
#include "model.hxx"
#include "SGRotateTransform.hxx"
#include "SGScaleTransform.hxx"
#include "SGInteractionAnimation.hxx"
+#include "SGPickAnimation.hxx"
+#include "SGTrackToAnimation.hxx"
+
+#include "ConditionNode.hxx"
using OpenThreads::Mutex;
using OpenThreads::ReentrantMutex;
using OpenThreads::ScopedLock;
-\f
+using namespace simgear;
////////////////////////////////////////////////////////////////////////
// Static utility functions.
////////////////////////////////////////////////////////////////////////
-/**
- * Set up the transform matrix for a spin or rotation.
- */
-static void
-set_rotation (osg::Matrix &matrix, double position_deg,
- const SGVec3d ¢er, const SGVec3d &axis)
-{
- double temp_angle = -SGMiscd::deg2rad(position_deg);
-
- double s = sin(temp_angle);
- double c = cos(temp_angle);
- double t = 1 - c;
-
- // axis was normalized at load time
- // hint to the compiler to put these into FP registers
- double x = axis[0];
- double y = axis[1];
- double z = axis[2];
-
- matrix(0, 0) = t * x * x + c ;
- matrix(0, 1) = t * y * x - s * z ;
- matrix(0, 2) = t * z * x + s * y ;
- matrix(0, 3) = 0;
-
- matrix(1, 0) = t * x * y + s * z ;
- matrix(1, 1) = t * y * y + c ;
- matrix(1, 2) = t * z * y - s * x ;
- matrix(1, 3) = 0;
-
- matrix(2, 0) = t * x * z - s * y ;
- matrix(2, 1) = t * y * z + s * x ;
- matrix(2, 2) = t * z * z + c ;
- matrix(2, 3) = 0;
-
- // hint to the compiler to put these into FP registers
- x = center[0];
- y = center[1];
- z = center[2];
-
- matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
- matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
- matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
- matrix(3, 3) = 1;
-}
-
/**
* Set up the transform matrix for a translation.
*/
read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
const char* unit, double defMin, double defMax)
{
+ const SGPropertyNode * expression = configNode->getNode( "expression" );
+ if( expression != NULL )
+ return SGReadDoubleExpression( modelRoot, expression->getChild(0) );
+
SGExpression<double>* value = 0;
std::string inputPropertyName = configNode->getStringValue("property", "");
return 0;
}
-\f
////////////////////////////////////////////////////////////////////////
// Animation installer
////////////////////////////////////////////////////////////////////////
using namespace osg;
using namespace std;
- for (int i = 0; i < geode.getNumDrawables(); ++i)
+ for (int i = 0; i < (int)geode.getNumDrawables(); ++i)
geode.getDrawable(i)->setUseDisplayList(false);
}
};
{
_name = configNode->getStringValue("name", "");
_enableHOT = configNode->getBoolValue("enable-hot", true);
- _disableShadow = configNode->getBoolValue("disable-shadow", false);
std::vector<SGPropertyNode_ptr> objectNames =
configNode->getChildren("object-name");
for (unsigned i = 0; i < objectNames.size(); ++i)
SGAnimation::~SGAnimation()
{
- if (_found)
- return;
-
- SG_LOG(SG_IO, SG_ALERT, "Could not find at least one of the following"
- " objects for animation:\n");
- std::list<std::string>::const_iterator i;
- for (i = _objectNames.begin(); i != _objectNames.end(); ++i)
- SG_LOG(SG_IO, SG_ALERT, *i << "\n");
+ if (!_found)
+ {
+ std::list<std::string>::const_iterator i;
+ std::string info;
+ for (i = _objectNames.begin(); i != _objectNames.end(); ++i)
+ {
+ if (!info.empty())
+ info.append(", ");
+ info.append("'");
+ info.append(*i);
+ info.append("'");
+ }
+ if (!info.empty())
+ {
+ SG_LOG(SG_IO, SG_ALERT, "Could not find at least one of the following"
+ " objects for animation: " << info);
+ }
+ }
}
bool
SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
SGPropertyNode* modelRoot,
- const osgDB::ReaderWriter::Options* options)
+ const osgDB::Options* options,
+ const std::string &path, int i)
{
std::string type = configNode->getStringValue("type", "none");
if (type == "alpha-test") {
SGInteractionAnimation animInst(configNode, modelRoot);
animInst.apply(node);
} else if (type == "material") {
- SGMaterialAnimation animInst(configNode, modelRoot, options);
+ SGMaterialAnimation animInst(configNode, modelRoot, options, path);
animInst.apply(node);
} else if (type == "noshadow") {
SGShadowAnimation animInst(configNode, modelRoot);
} else if (type == "pick") {
SGPickAnimation animInst(configNode, modelRoot);
animInst.apply(node);
+ } else if (type == "knob") {
+ SGKnobAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "slider") {
+ SGSliderAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
} else if (type == "range") {
SGRangeAnimation animInst(configNode, modelRoot);
animInst.apply(node);
} else if (type == "timed") {
SGTimedAnimation animInst(configNode, modelRoot);
animInst.apply(node);
+ } else if (type == "locked-track") {
+ SGTrackToAnimation animInst(node, configNode, modelRoot);
+ animInst.apply(node);
} else if (type == "translate") {
SGTranslateAnimation animInst(configNode, modelRoot);
animInst.apply(node);
+ } else if (type == "light") {
+ SGLightAnimation animInst(configNode, modelRoot, options, path, i);
+ animInst.apply(node);
} else if (type == "null" || type == "none" || type.empty()) {
SGGroupAnimation animInst(configNode, modelRoot);
animInst.apply(node);
node.setNodeMask( SG_NODEMASK_TERRAIN_BIT | node.getNodeMask());
else
node.setNodeMask(~SG_NODEMASK_TERRAIN_BIT & node.getNodeMask());
- if (!_disableShadow)
- node.setNodeMask( SG_NODEMASK_CASTSHADOW_BIT | node.getNodeMask());
- else
- node.setNodeMask(~SG_NODEMASK_CASTSHADOW_BIT & node.getNodeMask());
}
osg::Group*
}
}
+//------------------------------------------------------------------------------
+SGVec3d SGAnimation::readVec3( const std::string& name,
+ const std::string& suffix,
+ const SGVec3d& def ) const
+{
+ SGVec3d vec;
+ vec[0] = _configNode->getDoubleValue(name + "/x" + suffix, def.x());
+ vec[1] = _configNode->getDoubleValue(name + "/y" + suffix, def.y());
+ vec[2] = _configNode->getDoubleValue(name + "/z" + suffix, def.z());
+ return vec;
+}
+
+//------------------------------------------------------------------------------
+// factored out to share with SGKnobAnimation
+void SGAnimation::readRotationCenterAndAxis( SGVec3d& center,
+ SGVec3d& axis ) const
+{
+ center = SGVec3d::zeros();
+ if( _configNode->hasValue("axis/x1-m") )
+ {
+ SGVec3d v1 = readVec3("axis", "1-m"), // axis/[xyz]1-m
+ v2 = readVec3("axis", "2-m"); // axis/[xyz]2-m
+ center = 0.5*(v1+v2);
+ axis = v2 - v1;
+ }
+ else
+ {
+ axis = readVec3("axis");
+ }
+ if( 8 * SGLimitsd::min() < norm(axis) )
+ axis = normalize(axis);
+
+ center = readVec3("center", "-m", center);
+}
+
+//------------------------------------------------------------------------------
+SGExpressiond* SGAnimation::readOffsetValue(const char* tag_name) const
+{
+ const SGPropertyNode* node = _configNode->getChild(tag_name);
+ if( !node )
+ return 0;
+
+ SGExpressiond_ref expression;
+ if( !node->nChildren() )
+ expression = new SGConstExpression<double>(node->getDoubleValue());
+ else
+ expression = SGReadDoubleExpression(_modelRoot, node->getChild(0));
+
+ if( !expression )
+ return 0;
+
+ expression = expression->simplify();
+
+ if( expression->isConst() && expression->getValue() == 0 )
+ return 0;
+
+ return expression.release();
+}
+
void
SGAnimation::removeMode(osg::Node& node, osg::StateAttribute::GLMode mode)
{
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of null animation
////////////////////////////////////////////////////////////////////////
return group;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of translate animation
////////////////////////////////////////////////////////////////////////
SGExpressiond const* animationValue) :
_condition(condition),
_animationValue(animationValue)
- { }
+ {
+ setName("SGTranslateAnimation::UpdateCallback");
+ }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (!_condition || _condition->test()) {
else
_initialValue = 0;
- if (configNode->hasValue("axis/x1-m")) {
- SGVec3d v1, v2;
- v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
- v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
- v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
- v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
- v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
- v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
- _axis = v2 - v1;
- } else {
- _axis[0] = configNode->getDoubleValue("axis/x", 0);
- _axis[1] = configNode->getDoubleValue("axis/y", 0);
- _axis[2] = configNode->getDoubleValue("axis/z", 0);
- }
- if (8*SGLimitsd::min() < norm(_axis))
- _axis = normalize(_axis);
+ _axis = readTranslateAxis(configNode);
}
osg::Group*
return transform;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of rotate/spin animation
////////////////////////////////////////////////////////////////////////
-class SGRotateAnimation::UpdateCallback : public osg::NodeCallback {
+class SGRotAnimTransform : public SGRotateTransform
+{
public:
- UpdateCallback(SGCondition const* condition,
- SGExpressiond const* animationValue) :
- _condition(condition),
- _animationValue(animationValue)
- { }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
+ SGRotAnimTransform();
+ SGRotAnimTransform(const SGRotAnimTransform&,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ META_Node(simgear, SGRotAnimTransform);
+ virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const;
+ virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const;
+ SGSharedPtr<SGCondition const> _condition;
+ SGSharedPtr<SGExpressiond const> _animationValue;
+ // used when condition is false
+ mutable double _lastAngle;
+};
+
+SGRotAnimTransform::SGRotAnimTransform()
+ : _lastAngle(0.0)
+{
+}
+
+SGRotAnimTransform::SGRotAnimTransform(const SGRotAnimTransform& rhs,
+ const osg::CopyOp& copyop)
+ : SGRotateTransform(rhs, copyop), _condition(rhs._condition),
+ _animationValue(rhs._animationValue), _lastAngle(rhs._lastAngle)
+{
+}
+
+bool SGRotAnimTransform::computeLocalToWorldMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const
+{
+ double angle = 0.0;
+ if (!_condition || _condition->test()) {
+ angle = _animationValue->getValue();
+ _lastAngle = angle;
+ } else {
+ angle = _lastAngle;
+ }
+ double angleRad = SGMiscd::deg2rad(angle);
+ if (_referenceFrame == RELATIVE_RF) {
+ // FIXME optimize
+ osg::Matrix tmp;
+ set_rotation(tmp, angleRad, getCenter(), getAxis());
+ matrix.preMult(tmp);
+ } else {
+ osg::Matrix tmp;
+ SGRotateTransform::set_rotation(tmp, angleRad, getCenter(), getAxis());
+ matrix = tmp;
+ }
+ return true;
+}
+
+bool SGRotAnimTransform::computeWorldToLocalMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const
+{
+ double angle = 0.0;
if (!_condition || _condition->test()) {
- SGRotateTransform* transform;
- transform = static_cast<SGRotateTransform*>(node);
- transform->setAngleDeg(_animationValue->getValue());
+ angle = _animationValue->getValue();
+ _lastAngle = angle;
+ } else {
+ angle = _lastAngle;
}
- traverse(node, nv);
- }
-public:
- SGSharedPtr<SGCondition const> _condition;
- SGSharedPtr<SGExpressiond const> _animationValue;
-};
+ double angleRad = SGMiscd::deg2rad(angle);
+ if (_referenceFrame == RELATIVE_RF) {
+ // FIXME optimize
+ osg::Matrix tmp;
+ set_rotation(tmp, -angleRad, getCenter(), getAxis());
+ matrix.postMult(tmp);
+ } else {
+ osg::Matrix tmp;
+ set_rotation(tmp, -angleRad, getCenter(), getAxis());
+ matrix = tmp;
+ }
+ return true;
+}
-class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback {
+// Cull callback
+class SpinAnimCallback : public osg::NodeCallback {
public:
- SpinUpdateCallback(SGCondition const* condition,
- SGExpressiond const* animationValue) :
+ SpinAnimCallback(SGCondition const* condition,
+ SGExpressiond const* animationValue,
+ double initialValue = 0.0) :
_condition(condition),
_animationValue(animationValue),
- _lastTime(-1)
- { }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- if (!_condition || _condition->test()) {
- SGRotateTransform* transform;
- transform = static_cast<SGRotateTransform*>(node);
-
- double t = nv->getFrameStamp()->getReferenceTime();
- double dt = 0;
- if (0 <= _lastTime)
- dt = t - _lastTime;
- _lastTime = t;
- double velocity_rpms = _animationValue->getValue()/60;
- double angle = transform->getAngleDeg();
- angle += dt*velocity_rpms*360;
- angle -= 360*floor(angle/360);
- transform->setAngleDeg(angle);
- }
- traverse(node, nv);
- }
+ _initialValue(initialValue)
+ {}
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
public:
- SGSharedPtr<SGCondition const> _condition;
- SGSharedPtr<SGExpressiond const> _animationValue;
- double _lastTime;
+ SGSharedPtr<SGCondition const> _condition;
+ SGSharedPtr<SGExpressiond const> _animationValue;
+ double _initialValue;
+protected:
+ // This cull callback can run in different threads if there is
+ // more than one camera. It is probably safe to overwrite the
+ // reference values in multiple threads, but we'll provide a
+ // threadsafe way to manage those values just to be safe.
+ struct ReferenceValues : public osg::Referenced
+ {
+ ReferenceValues(double t, double rot, double vel)
+ : _time(t), _rotation(rot), _rotVelocity(vel)
+ {
+ }
+ double _time;
+ double _rotation;
+ double _rotVelocity;
+ };
+ OpenThreads::AtomicPtr _referenceValues;
};
+void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+ using namespace osg;
+ SGRotateTransform* transform = static_cast<SGRotateTransform*>(node);
+ EffectCullVisitor* cv = dynamic_cast<EffectCullVisitor*>(nv);
+ if (!cv)
+ return;
+ if (!_condition || _condition->test()) {
+ double t = nv->getFrameStamp()->getSimulationTime();
+ double rps = _animationValue->getValue() / 60.0;
+ ref_ptr<ReferenceValues>
+ refval(static_cast<ReferenceValues*>(_referenceValues.get()));
+ if (!refval || refval->_rotVelocity != rps) {
+ ref_ptr<ReferenceValues> newref;
+ if (!refval.valid()) {
+ // initialization
+ newref = new ReferenceValues(t, 0.0, rps);
+ } else {
+ double newRot = refval->_rotation + (t - refval->_time) * refval->_rotVelocity;
+ newref = new ReferenceValues(t, newRot, rps);
+ }
+ // increment reference pointer, because it will be stored
+ // naked in _referenceValues.
+ newref->ref();
+ if (_referenceValues.assign(newref, refval)) {
+ if (refval.valid()) {
+ DeletionManager::instance()->addStaleObject(refval.get());
+ refval->unref();
+ }
+ } else {
+ // Another thread installed new values before us
+ newref->unref();
+ }
+ // Whatever happened, we can use the reference values just
+ // calculated.
+ refval = newref;
+ }
+ double rotation = refval->_rotation + (t - refval->_time) * rps;
+ double intPart;
+ double rot = modf(rotation, &intPart);
+ double angle = rot * 2.0 * osg::PI;
+ const SGVec3d& sgcenter = transform->getCenter();
+ const SGVec3d& sgaxis = transform->getAxis();
+ Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
+ * Matrixd::rotate(angle, sgaxis[0], sgaxis[1], sgaxis[2])
+ * Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2])
+ * *cv->getModelViewMatrix();
+ ref_ptr<RefMatrix> refmat = new RefMatrix(mat);
+ cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame());
+ traverse(transform, nv);
+ cv->popModelViewMatrix();
+ } else {
+ traverse(transform, nv);
+ }
+}
+
+SGVec3d readTranslateAxis(const SGPropertyNode* configNode)
+{
+ SGVec3d axis;
+
+ if (configNode->hasValue("axis/x1-m")) {
+ SGVec3d v1, v2;
+ v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
+ v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
+ v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
+ v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
+ v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
+ v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
+ axis = v2 - v1;
+ } else {
+ axis[0] = configNode->getDoubleValue("axis/x", 0);
+ axis[1] = configNode->getDoubleValue("axis/y", 0);
+ axis[2] = configNode->getDoubleValue("axis/z", 0);
+ }
+ if (8*SGLimitsd::min() < norm(axis))
+ axis = normalize(axis);
+
+ return axis;
+}
+
SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot)
_initialValue = _animationValue->getValue();
else
_initialValue = 0;
-
- _center = SGVec3d::zeros();
- if (configNode->hasValue("axis/x1-m")) {
- SGVec3d v1, v2;
- v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
- v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
- v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
- v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
- v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
- v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
- _center = 0.5*(v1+v2);
- _axis = v2 - v1;
- } else {
- _axis[0] = configNode->getDoubleValue("axis/x", 0);
- _axis[1] = configNode->getDoubleValue("axis/y", 0);
- _axis[2] = configNode->getDoubleValue("axis/z", 0);
- }
- if (8*SGLimitsd::min() < norm(_axis))
- _axis = normalize(_axis);
-
- _center[0] = configNode->getDoubleValue("center/x-m", _center[0]);
- _center[1] = configNode->getDoubleValue("center/y-m", _center[1]);
- _center[2] = configNode->getDoubleValue("center/z-m", _center[2]);
+
+ readRotationCenterAndAxis(_center, _axis);
}
osg::Group*
SGRotateAnimation::createAnimationGroup(osg::Group& parent)
{
- SGRotateTransform* transform = new SGRotateTransform;
- transform->setName("rotate animation");
- if (_isSpin) {
- SpinUpdateCallback* uc;
- uc = new SpinUpdateCallback(_condition, _animationValue);
- transform->setUpdateCallback(uc);
- } else if (_animationValue || !_animationValue->isConst()) {
- UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
- transform->setUpdateCallback(uc);
- }
- transform->setCenter(_center);
- transform->setAxis(_axis);
- transform->setAngleDeg(_initialValue);
- parent.addChild(transform);
- return transform;
+ if (_isSpin) {
+ SGRotateTransform* transform = new SGRotateTransform;
+ transform->setName("spin rotate animation");
+ SpinAnimCallback* cc;
+ cc = new SpinAnimCallback(_condition, _animationValue, _initialValue);
+ transform->setCullCallback(cc);
+ transform->setCenter(_center);
+ transform->setAxis(_axis);
+ transform->setAngleDeg(_initialValue);
+ parent.addChild(transform);
+ return transform;
+ } else {
+ SGRotAnimTransform* transform = new SGRotAnimTransform;
+ transform->setName("rotate animation");
+ transform->_condition = _condition;
+ transform->_animationValue = _animationValue;
+ transform->_lastAngle = _initialValue;
+ transform->setCenter(_center);
+ transform->setAxis(_axis);
+ parent.addChild(transform);
+ return transform;
+ }
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of scale animation
////////////////////////////////////////////////////////////////////////
_animationValue[0] = animationValue[0];
_animationValue[1] = animationValue[1];
_animationValue[2] = animationValue[2];
+ setName("SGScaleAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
return transform;
}
-\f
+
// Don't create a new state state everytime we need GL_NORMALIZE!
namespace
class SGDistScaleAnimation::Transform : public osg::Transform {
public:
+ Transform() : _min_v(0.0), _max_v(0.0), _factor(0.0), _offset(0.0) {}
+ Transform(const Transform& rhs,
+ const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY)
+ : osg::Transform(rhs, copyOp), _table(rhs._table), _center(rhs._center),
+ _min_v(rhs._min_v), _max_v(rhs._max_v), _factor(rhs._factor),
+ _offset(rhs._offset)
+ {
+ }
+ META_Node(simgear, SGDistScaleAnimation::Transform);
Transform(const SGPropertyNode* configNode)
{
setName(configNode->getStringValue("name", "dist scale animation"));
return true;
}
+ static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw)
+ {
+ const Transform& trans = static_cast<const Transform&>(obj);
+ fw.indent() << "center " << trans._center << "\n";
+ fw.indent() << "min_v " << trans._min_v << "\n";
+ fw.indent() << "max_v " << trans._max_v << "\n";
+ fw.indent() << "factor " << trans._factor << "\n";
+ fw.indent() << "offset " << trans._offset << "\n";
+ return true;
+ }
private:
double computeScaleFactor(osg::NodeVisitor* nv) const
{
if (!nv)
return 1;
- double scale_factor = (_center.osg() - nv->getEyePoint()).length();
+ double scale_factor = (toOsg(_center) - nv->getEyePoint()).length();
if (_table == 0) {
scale_factor = _factor * scale_factor + _offset;
} else {
return transform;
}
-\f
+namespace
+{
+ osgDB::RegisterDotOsgWrapperProxy distScaleAnimationTransformProxy
+ (
+ new SGDistScaleAnimation::Transform,
+ "SGDistScaleAnimation::Transform",
+ "Object Node Transform SGDistScaleAnimation::Transform Group",
+ 0,
+ &SGDistScaleAnimation::Transform::writeLocalData
+ );
+}
+
////////////////////////////////////////////////////////////////////////
// Implementation of flash animation
////////////////////////////////////////////////////////////////////////
class SGFlashAnimation::Transform : public osg::Transform {
public:
+ Transform() : _power(0.0), _factor(0.0), _offset(0.0), _min_v(0.0),
+ _max_v(0.0), _two_sides(false)
+ {}
+
+ Transform(const Transform& rhs,
+ const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY)
+ : osg::Transform(rhs, copyOp), _center(rhs._center), _axis(rhs._axis),
+ _power(rhs._power), _factor(rhs._factor), _offset(rhs._offset),
+ _min_v(rhs._min_v), _max_v(rhs._max_v), _two_sides(rhs._two_sides)
+ {
+ }
+ META_Node(simgear, SGFlashAnimation::Transform);
+
Transform(const SGPropertyNode* configNode)
{
setReferenceFrame(RELATIVE_RF);
return true;
}
+ static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw)
+ {
+ const Transform& trans = static_cast<const Transform&>(obj);
+ fw.indent() << "center " << trans._center[0] << " "
+ << trans._center[1] << " " << trans._center[2] << " " << "\n";
+ fw.indent() << "axis " << trans._axis[0] << " "
+ << trans._axis[1] << " " << trans._axis[2] << " " << "\n";
+ fw.indent() << "power " << trans._power << " \n";
+ fw.indent() << "min_v " << trans._min_v << "\n";
+ fw.indent() << "max_v " << trans._max_v << "\n";
+ fw.indent() << "factor " << trans._factor << "\n";
+ fw.indent() << "offset " << trans._offset << "\n";
+ fw.indent() << "twosides " << (trans._two_sides ? "true" : "false") << "\n";
+ return true;
+ }
private:
double computeScaleFactor(osg::NodeVisitor* nv) const
{
return transform;
}
-\f
+namespace
+{
+ osgDB::RegisterDotOsgWrapperProxy flashAnimationTransformProxy
+ (
+ new SGFlashAnimation::Transform,
+ "SGFlashAnimation::Transform",
+ "Object Node Transform SGFlashAnimation::Transform Group",
+ 0,
+ &SGFlashAnimation::Transform::writeLocalData
+ );
+}
+
////////////////////////////////////////////////////////////////////////
-// Implementation of flash animation
+// Implementation of billboard animation
////////////////////////////////////////////////////////////////////////
class SGBillboardAnimation::Transform : public osg::Transform {
public:
+ Transform() : _spherical(true) {}
+ Transform(const Transform& rhs,
+ const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY)
+ : osg::Transform(rhs, copyOp), _spherical(rhs._spherical) {}
+ META_Node(simgear, SGBillboardAnimation::Transform);
Transform(const SGPropertyNode* configNode) :
_spherical(configNode->getBoolValue("spherical", true))
{
// Hmm, don't yet know how to get that back ...
return false;
}
+ static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw)
+ {
+ const Transform& trans = static_cast<const Transform&>(obj);
+ fw.indent() << (trans._spherical ? "true" : "false") << "\n";
+ return true;
+ }
private:
bool _spherical;
};
return transform;
}
-\f
+namespace
+{
+ osgDB::RegisterDotOsgWrapperProxy billboardAnimationTransformProxy
+ (
+ new SGBillboardAnimation::Transform,
+ "SGBillboardAnimation::Transform",
+ "Object Node Transform SGBillboardAnimation::Transform Group",
+ 0,
+ &SGBillboardAnimation::Transform::writeLocalData
+ );
+}
+
////////////////////////////////////////////////////////////////////////
// Implementation of a range animation
////////////////////////////////////////////////////////////////////////
_maxAnimationValue(maxAnimationValue),
_minStaticValue(minValue),
_maxStaticValue(maxValue)
- {}
+ {
+ setName("SGRangeAnimation::UpdateCallback");
+ }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osg::LOD* lod = static_cast<osg::LOD*>(node);
return group;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of a select animation
////////////////////////////////////////////////////////////////////////
-class SGSelectAnimation::UpdateCallback : public osg::NodeCallback {
-public:
- UpdateCallback(const SGCondition* condition) :
- _condition(condition)
- {}
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::Switch* sw = static_cast<osg::Switch*>(node);
- if (_condition->test())
- sw->setAllChildrenOn();
- else
- sw->setAllChildrenOff();
- traverse(node, nv);
- }
-
-private:
- SGSharedPtr<SGCondition const> _condition;
-};
-
SGSelectAnimation::SGSelectAnimation(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGAnimation(configNode, modelRoot)
// when the animation installer returns
if (!condition)
return new osg::Group;
-
- osg::Switch* sw = new osg::Switch;
- sw->setName("select animation node");
- sw->setUpdateCallback(new UpdateCallback(condition));
- parent.addChild(sw);
- return sw;
+ simgear::ConditionNode* cn = new simgear::ConditionNode;
+ cn->setName("select animation node");
+ cn->setCondition(condition.ptr());
+ osg::Group* grp = new osg::Group;
+ cn->addChild(grp);
+ parent.addChild(cn);
+ return grp;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of alpha test animation
////////////////////////////////////////////////////////////////////////
}
}
-\f
+
//////////////////////////////////////////////////////////////////////
// Blend animation installer
//////////////////////////////////////////////////////////////////////
UpdateCallback(const SGPropertyNode* configNode, const SGExpressiond* v) :
_prev_value(-1),
_animationValue(v)
- { }
+ {
+ setName("SGBlendAnimation::UpdateCallback");
+ }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
double blend = _animationValue->getValue();
node.accept(visitor);
}
-\f
+
//////////////////////////////////////////////////////////////////////
// Timed animation installer
//////////////////////////////////////////////////////////////////////
rNode->getDoubleValue( "max", 1));
}
}
+ setName("SGTimedAnimation::UpdateCallback");
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
_current_index = _current_index % nChildren;
// update the time and compute the current systems time value
- double t = nv->getFrameStamp()->getReferenceTime();
+ double t = nv->getFrameStamp()->getSimulationTime();
if (_last_time_sec == SGLimitsd::max()) {
_last_time_sec = t;
} else {
return sw;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// dynamically switch on/off shadows
////////////////////////////////////////////////////////////////////////
public:
UpdateCallback(const SGCondition* condition) :
_condition(condition)
- {}
+ {
+ setName("SGShadowAnimation::UpdateCallback");
+ }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (_condition->test())
SGShadowAnimation::createAnimationGroup(osg::Group& parent)
{
SGSharedPtr<SGCondition const> condition = getCondition();
- if (!condition)
- return 0;
osg::Group* group = new osg::Group;
group->setName("shadow animation");
- group->setUpdateCallback(new UpdateCallback(condition));
+ if (condition)
+ group->setUpdateCallback(new UpdateCallback(condition));
+ else
+ group->setNodeMask(~SG_NODEMASK_CASTSHADOW_BIT & group->getNodeMask());
parent.addChild(group);
return group;
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Implementation of SGTexTransformAnimation
////////////////////////////////////////////////////////////////////////
virtual void transform(osg::Matrix& matrix)
{
osg::Matrix tmp;
- set_rotation(tmp, _value, _center, _axis);
+ SGRotateTransform::set_rotation(tmp, SGMiscd::deg2rad(_value), _center,
+ _axis);
matrix.preMult(tmp);
}
private:
public:
UpdateCallback(const SGCondition* condition) :
_condition(condition)
- { }
+ {
+ setName("SGTexTransformAnimation::UpdateCallback");
+ }
virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*)
{
if (!_condition || _condition->test()) {
updateCallback->appendTransform(rotation, value);
}
-
-////////////////////////////////////////////////////////////////////////
-// Implementation of SGPickAnimation
-////////////////////////////////////////////////////////////////////////
-
-class SGPickAnimation::PickCallback : public SGPickCallback {
-public:
- PickCallback(const SGPropertyNode* configNode,
- SGPropertyNode* modelRoot) :
- _button(configNode->getIntValue("button", -1)),
- _repeatable(configNode->getBoolValue("repeatable", false)),
- _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
- {
- SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
- std::vector<SGPropertyNode_ptr> bindings;
- bindings = configNode->getChildren("binding");
- for (unsigned int i = 0; i < bindings.size(); ++i) {
- _bindingsDown.push_back(new SGBinding(bindings[i], modelRoot));
- }
-
- const SGPropertyNode* upNode = configNode->getChild("mod-up");
- if (!upNode)
- return;
- bindings = upNode->getChildren("binding");
- for (unsigned int i = 0; i < bindings.size(); ++i) {
- _bindingsUp.push_back(new SGBinding(bindings[i], modelRoot));
- }
- }
- virtual bool buttonPressed(int button, const Info&)
- {
- if (0 <= _button && button != _button)
- return false;
- SGBindingList::const_iterator i;
- for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
- (*i)->fire();
- _repeatTime = 0;
- return true;
- }
- virtual void buttonReleased(void)
- {
- SGBindingList::const_iterator i;
- for (i = _bindingsUp.begin(); i != _bindingsUp.end(); ++i)
- (*i)->fire();
- }
- virtual void update(double dt)
- {
- if (!_repeatable)
- return;
-
- _repeatTime += dt;
- while (_repeatInterval < _repeatTime) {
- _repeatTime -= _repeatInterval;
- SGBindingList::const_iterator i;
- for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
- (*i)->fire();
- }
- }
-private:
- SGBindingList _bindingsDown;
- SGBindingList _bindingsUp;
- int _button;
- bool _repeatable;
- double _repeatInterval;
- double _repeatTime;
-};
-
-SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode,
- SGPropertyNode* modelRoot) :
- SGAnimation(configNode, modelRoot)
-{
-}
-
-osg::Group*
-SGPickAnimation::createAnimationGroup(osg::Group& parent)
-{
- osg::Group* commonGroup = new osg::Group;
-
- // Contains the normal geometry that is interactive
- osg::ref_ptr<osg::Group> normalGroup = new osg::Group;
- normalGroup->setName("pick normal group");
- normalGroup->addChild(commonGroup);
-
- // Used to render the geometry with just yellow edges
- osg::Group* highlightGroup = new osg::Group;
- highlightGroup->setName("pick highlight group");
- highlightGroup->setNodeMask(SG_NODEMASK_PICK_BIT);
- highlightGroup->addChild(commonGroup);
- SGSceneUserData* ud;
- ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup);
- std::vector<SGPropertyNode_ptr> actions;
- actions = getConfig()->getChildren("action");
- for (unsigned int i = 0; i < actions.size(); ++i)
- ud->addPickCallback(new PickCallback(actions[i], getModelRoot()));
-
- // prepare a state set that paints the edges of this object yellow
- osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet();
- stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
-
- osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
- polygonOffset->setFactor(-1);
- polygonOffset->setUnits(-1);
- stateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE);
- stateSet->setMode(GL_POLYGON_OFFSET_LINE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
-
- osg::PolygonMode* polygonMode = new osg::PolygonMode;
- polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
- osg::PolygonMode::LINE);
- stateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE);
-
- osg::Material* material = new osg::Material;
- material->setColorMode(osg::Material::OFF);
- material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
- material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
- material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
- material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
- stateSet->setAttribute(material, osg::StateAttribute::OVERRIDE);
-
- // Only add normal geometry if configured
- if (getConfig()->getBoolValue("visible", true))
- parent.addChild(normalGroup.get());
- parent.addChild(highlightGroup);
-
- return commonGroup;
-}