bug: 823 change rotation animation to use a subclass of SGRotateTransform

The animation is implemented in the computeWorldToLocalMatrix() and
computeLocalToWorldMatrix() virtual functions. Doing the animation in a cull
callback breaks picking.

Fix for http://code.google.com/p/flightgear-bugs/issues/detail?id=823
This commit is contained in:
Tim Moore
2012-08-02 17:26:31 +02:00
parent 302deeb122
commit e202d4e4a5
3 changed files with 93 additions and 97 deletions

View File

@@ -31,9 +31,9 @@
#include "SGRotateTransform.hxx"
static void
set_rotation (osg::Matrix &matrix, double position_rad,
const SGVec3d &center, const SGVec3d &axis)
void SGRotateTransform::set_rotation (osg::Matrix &matrix, double position_rad,
const SGVec3d &center,
const SGVec3d &axis)
{
double temp_angle = -position_rad;

View File

@@ -64,6 +64,9 @@ public:
virtual osg::BoundingSphere computeBound() const;
// Useful for other classes too.
static void set_rotation (osg::Matrix &matrix, double position_rad,
const SGVec3d &center, const SGVec3d &axis);
private:
SGVec3d _center;
SGVec3d _axis;

View File

@@ -71,51 +71,6 @@ 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 &center, 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.
*/
@@ -726,51 +681,81 @@ SGTranslateAnimation::createAnimationGroup(osg::Group& parent)
// Implementation of rotate/spin animation
////////////////////////////////////////////////////////////////////////
//Cull callback
class RotAnimCallback : public osg::NodeCallback
class SGRotAnimTransform : public SGRotateTransform
{
public:
RotAnimCallback(SGCondition const* condition,
SGExpressiond const* animationValue,
double initialValue = 0.0) :
_condition(condition),
_animationValue(animationValue),
_initialValue(initialValue),
_lastValue(0.0)
{ }
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
public:
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;
double _initialValue;
double _lastValue;
// used when condition is false
mutable double _lastAngle;
};
void RotAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
SGRotAnimTransform::SGRotAnimTransform()
: _lastAngle(0.0)
{
using namespace osg;
SGRotateTransform* transform = static_cast<SGRotateTransform*>(node);
EffectCullVisitor* cv = dynamic_cast<EffectCullVisitor*>(nv);
}
if (!cv)
return;
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() - _initialValue;
_lastValue = angle;
angle = _animationValue->getValue();
_lastAngle = angle;
} else {
angle = _lastValue;
angle = _lastAngle;
}
const SGVec3d& sgcenter = transform->getCenter();
const SGVec3d& sgaxis = transform->getAxis();
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
* Matrixd::rotate(SGMiscd::deg2rad(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();
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()) {
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.postMult(tmp);
} else {
osg::Matrix tmp;
set_rotation(tmp, -angleRad, getCenter(), getAxis());
matrix = tmp;
}
return true;
}
// Cull callback
@@ -892,21 +877,28 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
osg::Group*
SGRotateAnimation::createAnimationGroup(osg::Group& parent)
{
SGRotateTransform* transform = new SGRotateTransform;
transform->setName("rotate animation");
if (_isSpin) {
SpinAnimCallback* cc;
cc = new SpinAnimCallback(_condition, _animationValue, _initialValue);
transform->setCullCallback(cc);
} else if (_animationValue || !_animationValue->isConst()) {
RotAnimCallback* cc = new RotAnimCallback(_condition, _animationValue, _initialValue);
transform->setCullCallback(cc);
}
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;
}
}
@@ -1956,7 +1948,8 @@ public:
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: