+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);
+ setName(configNode->getStringValue("name", "flash animation"));
+ setStateSet(getNormalizeStateSet());
+
+ _axis[0] = configNode->getFloatValue("axis/x", 0);
+ _axis[1] = configNode->getFloatValue("axis/y", 0);
+ _axis[2] = configNode->getFloatValue("axis/z", 1);
+ _axis.normalize();
+
+ _center[0] = configNode->getFloatValue("center/x-m", 0);
+ _center[1] = configNode->getFloatValue("center/y-m", 0);
+ _center[2] = configNode->getFloatValue("center/z-m", 0);
+
+ _offset = configNode->getFloatValue("offset", 0);
+ _factor = configNode->getFloatValue("factor", 1);
+ _power = configNode->getFloatValue("power", 1);
+ _two_sides = configNode->getBoolValue("two-sides", false);
+
+ _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon());
+ _max_v = configNode->getFloatValue("max", 1);
+ }
+ virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const
+ {
+ osg::Matrix transform;
+ double scale_factor = computeScaleFactor(nv);
+ transform(0,0) = scale_factor;
+ transform(1,1) = scale_factor;
+ transform(2,2) = scale_factor;
+ transform(3,0) = _center[0]*(1 - scale_factor);
+ transform(3,1) = _center[1]*(1 - scale_factor);
+ transform(3,2) = _center[2]*(1 - scale_factor);
+ matrix.preMult(transform);
+ return true;
+ }
+
+ virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
+ osg::NodeVisitor* nv) const
+ {
+ double scale_factor = computeScaleFactor(nv);
+ if (fabs(scale_factor) <= SGLimits<double>::min())
+ return false;
+ osg::Matrix transform;
+ double rScaleFactor = 1/scale_factor;
+ transform(0,0) = rScaleFactor;
+ transform(1,1) = rScaleFactor;
+ transform(2,2) = rScaleFactor;
+ transform(3,0) = _center[0]*(1 - rScaleFactor);
+ transform(3,1) = _center[1]*(1 - rScaleFactor);
+ transform(3,2) = _center[2]*(1 - rScaleFactor);
+ matrix.postMult(transform);
+ 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
+ {
+ if (!nv)
+ return 1;
+
+ osg::Vec3 localEyeToCenter = nv->getEyePoint() - _center;
+ localEyeToCenter.normalize();
+
+ double cos_angle = localEyeToCenter*_axis;
+ double scale_factor = 0;
+ if ( _two_sides && cos_angle < 0 )
+ scale_factor = _factor * pow( -cos_angle, _power ) + _offset;
+ else if ( cos_angle > 0 )
+ scale_factor = _factor * pow( cos_angle, _power ) + _offset;
+
+ if ( scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( scale_factor > _max_v )
+ scale_factor = _max_v;
+
+ return scale_factor;
+ }
+
+ virtual osg::BoundingSphere computeBound() const
+ {
+ // avoid being culled away by small feature culling
+ osg::BoundingSphere bs = osg::Group::computeBound();
+ bs.radius() *= _max_v;
+ return bs;
+ }
+
+private:
+ osg::Vec3 _center;
+ osg::Vec3 _axis;
+ double _power, _factor, _offset, _min_v, _max_v;
+ bool _two_sides;
+};
+
+
+SGFlashAnimation::SGFlashAnimation(const SGPropertyNode* configNode,
+ SGPropertyNode* modelRoot) :
+ SGAnimation(configNode, modelRoot)