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-03 20:10:00 +02:00
parent 302deeb122
commit e202d4e4a5
3 changed files with 93 additions and 97 deletions
+3 -3
View File
@@ -31,9 +31,9 @@
#include "SGRotateTransform.hxx" #include "SGRotateTransform.hxx"
static void void SGRotateTransform::set_rotation (osg::Matrix &matrix, double position_rad,
set_rotation (osg::Matrix &matrix, double position_rad, const SGVec3d &center,
const SGVec3d &center, const SGVec3d &axis) const SGVec3d &axis)
{ {
double temp_angle = -position_rad; double temp_angle = -position_rad;
@@ -64,6 +64,9 @@ public:
virtual osg::BoundingSphere computeBound() const; 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: private:
SGVec3d _center; SGVec3d _center;
SGVec3d _axis; SGVec3d _axis;
+87 -94
View File
@@ -71,51 +71,6 @@ using namespace simgear;
// Static utility functions. // 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. * Set up the transform matrix for a translation.
*/ */
@@ -726,51 +681,81 @@ SGTranslateAnimation::createAnimationGroup(osg::Group& parent)
// Implementation of rotate/spin animation // Implementation of rotate/spin animation
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
//Cull callback class SGRotAnimTransform : public SGRotateTransform
class RotAnimCallback : public osg::NodeCallback
{ {
public: public:
RotAnimCallback(SGCondition const* condition, SGRotAnimTransform();
SGExpressiond const* animationValue, SGRotAnimTransform(const SGRotAnimTransform&,
double initialValue = 0.0) : const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
_condition(condition), META_Node(simgear, SGRotAnimTransform);
_animationValue(animationValue), virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
_initialValue(initialValue), osg::NodeVisitor* nv) const;
_lastValue(0.0) virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
{ } osg::NodeVisitor* nv) const;
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
public:
SGSharedPtr<SGCondition const> _condition; SGSharedPtr<SGCondition const> _condition;
SGSharedPtr<SGExpressiond const> _animationValue; SGSharedPtr<SGExpressiond const> _animationValue;
double _initialValue; // used when condition is false
double _lastValue; 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) SGRotAnimTransform::SGRotAnimTransform(const SGRotAnimTransform& rhs,
return; 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; double angle = 0.0;
if (!_condition || _condition->test()) { if (!_condition || _condition->test()) {
angle = _animationValue->getValue() - _initialValue; angle = _animationValue->getValue();
_lastValue = angle; _lastAngle = angle;
} else { } else {
angle = _lastValue; angle = _lastAngle;
} }
const SGVec3d& sgcenter = transform->getCenter(); double angleRad = SGMiscd::deg2rad(angle);
const SGVec3d& sgaxis = transform->getAxis(); if (_referenceFrame == RELATIVE_RF) {
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2]) // FIXME optimize
* Matrixd::rotate(SGMiscd::deg2rad(angle), sgaxis[0], sgaxis[1], sgaxis[2]) osg::Matrix tmp;
* Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2]) set_rotation(tmp, angleRad, getCenter(), getAxis());
* *cv->getModelViewMatrix(); matrix.preMult(tmp);
ref_ptr<RefMatrix> refmat = new RefMatrix(mat); } else {
cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame()); osg::Matrix tmp;
traverse(transform, nv); SGRotateTransform::set_rotation(tmp, angleRad, getCenter(), getAxis());
cv->popModelViewMatrix(); 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 // Cull callback
@@ -892,21 +877,28 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
osg::Group* osg::Group*
SGRotateAnimation::createAnimationGroup(osg::Group& parent) SGRotateAnimation::createAnimationGroup(osg::Group& parent)
{ {
SGRotateTransform* transform = new SGRotateTransform; if (_isSpin) {
transform->setName("rotate animation"); SGRotateTransform* transform = new SGRotateTransform;
if (_isSpin) { transform->setName("spin rotate animation");
SpinAnimCallback* cc; SpinAnimCallback* cc;
cc = new SpinAnimCallback(_condition, _animationValue, _initialValue); cc = new SpinAnimCallback(_condition, _animationValue, _initialValue);
transform->setCullCallback(cc); transform->setCullCallback(cc);
} else if (_animationValue || !_animationValue->isConst()) { transform->setCenter(_center);
RotAnimCallback* cc = new RotAnimCallback(_condition, _animationValue, _initialValue); transform->setAxis(_axis);
transform->setCullCallback(cc); transform->setAngleDeg(_initialValue);
} parent.addChild(transform);
transform->setCenter(_center); return transform;
transform->setAxis(_axis); } else {
transform->setAngleDeg(_initialValue); SGRotAnimTransform* transform = new SGRotAnimTransform;
parent.addChild(transform); transform->setName("rotate animation");
return transform; 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) virtual void transform(osg::Matrix& matrix)
{ {
osg::Matrix tmp; osg::Matrix tmp;
set_rotation(tmp, _value, _center, _axis); SGRotateTransform::set_rotation(tmp, SGMiscd::deg2rad(_value), _center,
_axis);
matrix.preMult(tmp); matrix.preMult(tmp);
} }
private: private: