this patch introduce a new kind of animation and ssg branch.
I called them flash animation, because they help me to
enhance the look of the rotating beacon and possible future
lighthouse. It computes the cosine of the angle between an
arbitrary axis, transformed by the current modelview matrix,
and the view direction. No trig involved, just a dot/scalar
product.
The computed value can be modified by three parameters,
power, factor and offset, according to the formulae :
value = factor * pow( cosine, power ) + offset.
It is clamped between a minimum and a maximum.
This value is then used as the scale factor of a matrix
transformation applied to the children of the SGFlash
branch.
The xml syntax, with default values, is :
<animation>
<type>flash</type>
<object-name>HaloObject</object-name>
<center>
<x-m>0</x-m>
<y-m>0</y-m>
<z-m>0</z-m>
</center>
<axis>
<x>0</x>
<y>0</y>
<z>1</z>
</axis>
<power>1</power>
<factor>1</factor>
<offset>0</offset>
<min>0</min>
<max>1</max>
<two-sides>false</two-sides>
</animation>
include_HEADERS = \
animation.hxx \
+ flash.hxx \
location.hxx \
model.hxx \
modellib.hxx \
libsgmodel_a_SOURCES = \
animation.cxx \
+ flash.cxx \
location.cxx \
model.cxx \
modellib.cxx \
#include <simgear/props/props.hxx>
#include "animation.hxx"
-
+#include "flash.hxx"
\f
////////////////////////////////////////////////////////////////////////
{
}
-void
+int
SGAnimation::update()
+{
+ return 1;
+}
+
+void
+SGAnimation::restore()
{
}
{
}
-void
+int
SGRangeAnimation::update()
{
float ranges[2];
if (upd) {
((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
}
+ return 1;
}
delete _condition;
}
-void
+int
SGSelectAnimation::update()
{
if (_condition != 0 && _condition->test())
((ssgSelector *)_branch)->select(0xffff);
else
((ssgSelector *)_branch)->select(0x0000);
+ return 1;
}
{
}
-void
+int
SGSpinAnimation::update()
{
double dt = sim_time_sec - _last_time_sec;
_position_deg -= 360.0;
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTransform *)_branch)->setTransform(_matrix);
+ return 1;
}
{
}
-void
+int
SGTimedAnimation::update()
{
if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
_step = 0;
((ssgSelector *)getBranch())->selectStep(_step);
}
+ return 1;
}
delete _table;
}
-void
+int
SGRotateAnimation::update()
{
if (_table == 0) {
}
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTransform *)_branch)->setTransform(_matrix);
+ return 1;
}
\f
delete _table;
}
-void
+int
SGBlendAnimation::update()
{
double _blend;
_prev_value = _blend;
change_alpha( _branch, _blend );
}
+ return 1;
}
delete _table;
}
-void
+int
SGTranslateAnimation::update()
{
if (_table == 0) {
}
set_translation(_matrix, _position_m, _axis);
((ssgTransform *)_branch)->setTransform(_matrix);
+ return 1;
}
delete _table;
}
-void
+int
SGScaleAnimation::update()
{
if (_table == 0) {
set_scale(_matrix, _x_scale, _y_scale, _z_scale );
((ssgTransform *)_branch)->setTransform(_matrix);
+ return 1;
}
delete _table;
}
-void
+int
SGTexRotateAnimation::update()
{
if (_table == 0) {
}
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
+ return 1;
}
delete _table;
}
-void
+int
SGTexTranslateAnimation::update()
{
if (_table == 0) {
}
set_translation(_matrix, _position, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
+ return 1;
}
delete _transform;
}
-void
+int
SGTexMultipleAnimation::update()
{
int i;
}
}
((ssgTexTrans *)_branch)->setTransform(tmatrix);
+ return 1;
}
}
}
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGFlashAnimation
+////////////////////////////////////////////////////////////////////////
+SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
+ : SGAnimation( props, new SGFlash )
+{
+ sgVec3 axis;
+ axis[0] = props->getFloatValue("axis/x", 0);
+ axis[1] = props->getFloatValue("axis/y", 0);
+ axis[2] = props->getFloatValue("axis/z", 1);
+ ((SGFlash *)_branch)->setAxis( axis );
+
+ sgVec3 center;
+ center[0] = props->getFloatValue("center/x-m", 0);
+ center[1] = props->getFloatValue("center/y-m", 0);
+ center[2] = props->getFloatValue("center/z-m", 0);
+ ((SGFlash *)_branch)->setCenter( center );
+
+ float offset = props->getFloatValue("offset", 0.0);
+ float factor = props->getFloatValue("factor", 1.0);
+ float power = props->getFloatValue("power", 1.0);
+ bool two_sides = props->getBoolValue("two-sides", false);
+ ((SGFlash *)_branch)->setParameters( power, factor, offset, two_sides );
+
+ float v_min = props->getFloatValue("min", 0.0);
+ float v_max = props->getFloatValue("max", 1.0);
+ ((SGFlash *)_branch)->setClampValues( v_min, v_max );
+}
+
+SGFlashAnimation::~SGFlashAnimation()
+{
+}
+
// end of animation.cxx
/**
* Update the animation.
*/
- virtual void update();
+ virtual int update();
+
+ /**
+ * Restore the state after the animation.
+ */
+ virtual void restore();
/**
* Set the value of sim_time_sec. This needs to be called every
SGRangeAnimation (SGPropertyNode *prop_root,
SGPropertyNode_ptr props);
virtual ~SGRangeAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _min_prop;
SGPropertyNode_ptr _max_prop;
SGSelectAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGSelectAnimation ();
- virtual void update();
+ virtual int update();
private:
SGCondition * _condition;
};
SGPropertyNode_ptr props,
double sim_time_sec );
virtual ~SGSpinAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _factor;
public:
SGTimedAnimation (SGPropertyNode_ptr props);
virtual ~SGTimedAnimation ();
- virtual void update();
+ virtual int update();
private:
double _duration_sec;
double _last_time_sec;
public:
SGRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
virtual ~SGRotateAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _offset_deg;
SGTranslateAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTranslateAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _offset_m;
SGBlendAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGBlendAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
SGInterpTable * _table;
SGScaleAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGScaleAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _x_factor;
public:
SGTexRotateAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props );
virtual ~SGTexRotateAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _offset_deg;
SGTexTranslateAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTexTranslateAnimation ();
- virtual void update();
+ virtual int update();
private:
SGPropertyNode_ptr _prop;
double _offset;
SGTexMultipleAnimation( SGPropertyNode *prop_root,
SGPropertyNode_ptr props );
virtual ~SGTexMultipleAnimation ();
- virtual void update();
+ virtual int update();
private:
class TexTransform
{
/**
- * An animation to enable the alpha test
+ * An "animation" to enable the alpha test
*/
class SGAlphaTestAnimation : public SGAnimation
{
};
+/**
+ * An "animation" that compute a scale according to
+ * the angle between an axis and the view direction
+ */
+class SGFlashAnimation : public SGAnimation
+{
+public:
+ SGFlashAnimation(SGPropertyNode_ptr props);
+ virtual ~SGFlashAnimation ();
+};
+
+
#endif // _SG_ANIMATION_HXX
--- /dev/null
+/*
+ $Id$
+*/
+
+#include "plib/ssg.h"
+#include "flash.hxx"
+void _ssgPushMatrix ( sgMat4 m );
+void _ssgPopMatrix ();
+void _ssgReadInt ( FILE *fd, int *var );
+void _ssgWriteInt ( FILE *fd, const int var );
+extern sgMat4 _ssgOpenGLAxisSwapMatrix;
+
+void SGFlash::copy_from( SGFlash *src, int clone_flags )
+{
+ ssgBranch::copy_from( src, clone_flags );
+ sgCopyVec3( _center, src->_center );
+ sgCopyVec3( _axis, src->_axis );
+ _power = src->_power;
+ _factor = src->_factor;
+ _offset = src->_offset;
+ _min_v = src->_min_v;
+ _max_v = src->_max_v;
+ _two_sides = src->_two_sides;
+}
+
+ssgBase *SGFlash::clone( int clone_flags )
+{
+ SGFlash *b = new SGFlash;
+ b -> copy_from( this, clone_flags );
+ return b;
+}
+
+
+SGFlash::SGFlash()
+{
+ type = ssgTypeBranch();
+}
+
+SGFlash::~SGFlash()
+{
+}
+
+void SGFlash::setAxis( sgVec3 axis )
+{
+ sgCopyVec3( _axis, axis );
+ sgNormalizeVec3( _axis );
+}
+
+void SGFlash::setCenter( sgVec3 center )
+{
+ sgCopyVec3( _center, center );
+}
+
+void SGFlash::setParameters( float power, float factor, float offset, bool two_sides )
+{
+ _power = power;
+ _factor = factor;
+ _offset = offset;
+ _two_sides = two_sides;
+}
+
+void SGFlash::setClampValues( float min_v, float max_v )
+{
+ _min_v = min_v;
+ _max_v = max_v;
+}
+
+void SGFlash::cull( sgFrustum *f, sgMat4 m, int test_needed )
+{
+ if ( ! preTravTests( &test_needed, SSGTRAV_CULL ) )
+ return;
+
+ sgVec3 transformed_axis;
+ sgXformVec3( transformed_axis, _axis, m );
+ sgNormalizeVec3( transformed_axis );
+
+ float cos_angle = transformed_axis[ 2 ]; // z component, through the screen
+ float scale_factor = 0.f;
+ if ( _two_sides && cos_angle < 0 )
+ scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
+ else if ( cos_angle > 0 )
+ scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
+
+ if ( scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( scale_factor > _max_v )
+ scale_factor = _max_v;
+
+ sgMat4 tmp, transform;
+ sgMakeIdentMat4( transform );
+ 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 );
+
+ sgCopyMat4( tmp, m );
+ sgPreMultMat4( tmp, transform );
+
+ _ssgPushMatrix( tmp );
+ glPushMatrix();
+ glLoadMatrixf( (float *) tmp );
+
+ for ( ssgEntity *e = getKid ( 0 ); e != NULL; e = getNextKid() )
+ e -> cull( f, tmp, test_needed );
+
+ glPopMatrix();
+ _ssgPopMatrix();
+
+ postTravTests( SSGTRAV_CULL );
+}
+
+
+void SGFlash::hot( sgVec3 s, sgMat4 m, int test_needed )
+{
+ ssgBranch::hot( s, m, test_needed );
+}
+
+void SGFlash::los( sgVec3 s, sgMat4 m, int test_needed )
+{
+ ssgBranch::los( s, m, test_needed );
+}
+
+
+void SGFlash::isect( sgSphere *s, sgMat4 m, int test_needed )
+{
+ ssgBranch::isect( s, m, test_needed );
+}
+
+
+
+int SGFlash::load( FILE *fd )
+{
+// _ssgReadInt( fd, & point_rotate );
+
+ return ssgBranch::load(fd);
+}
+
+int SGFlash::save( FILE *fd )
+{
+// _ssgWriteInt( fd, point_rotate );
+
+ return ssgBranch::save(fd);
+}
+
+const char *SGFlash::getTypeName (void) { return "SGFlash"; }
--- /dev/null
+
+class SGFlash : public ssgBranch
+{
+public:
+ virtual ssgBase *clone( int clone_flags = 0 );
+ SGFlash();
+ virtual ~SGFlash(void);
+
+ void setAxis( sgVec3 axis );
+ void setCenter( sgVec3 center );
+ void setParameters( float power, float factor, float offset, bool two_sides );
+ void setClampValues( float min_v, float max_v );
+
+ virtual const char *getTypeName(void);
+ virtual int load( FILE *fd );
+ virtual int save( FILE *fd );
+ virtual void cull( sgFrustum *f, sgMat4 m, int test_needed );
+ virtual void isect( sgSphere *s, sgMat4 m, int test_needed );
+ virtual void hot( sgVec3 s, sgMat4 m, int test_needed );
+ virtual void los( sgVec3 s, sgMat4 m, int test_needed );
+
+protected:
+ virtual void copy_from( SGFlash *src, int clone_flags );
+
+private:
+ sgVec3 _axis, _center;
+ float _power, _factor, _offset, _min_v, _max_v;
+ bool _two_sides;
+};
static int
animation_callback (ssgEntity * entity, int mask)
{
- ((SGAnimation *)entity->getUserData())->update();
- return true;
+ return ((SGAnimation *)entity->getUserData())->update();
+}
+
+/**
+ * Callback to restore the state after an animation.
+ */
+static int
+restore_callback (ssgEntity * entity, int mask)
+{
+ ((SGAnimation *)entity->getUserData())->restore();
+ return 1;
}
animation = new SGBlendAnimation(prop_root, node);
} else if (!strcmp("alpha-test", type)) {
animation = new SGAlphaTestAnimation(node);
+ } else if (!strcmp("flash", type)) {
+ animation = new SGFlashAnimation(node);
} else {
animation = new SGNullAnimation(node);
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);
animation->init();
branch->setUserData(animation);
branch->setTravCallback(SSG_CALLBACK_PRETRAV, animation_callback);
+ branch->setTravCallback(SSG_CALLBACK_POSTTRAV, restore_callback);
}