return _models.size();
}
+static void
+setAlphaClampToBranch( ssgBranch *b, float clamp )
+{
+ int nb = b->getNumKids();
+ for (int i = 0; i<nb; i++) {
+ ssgEntity *e = b->getKid(i);
+ if (e->isAKindOf(ssgTypeLeaf())) {
+ ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
+ s->enable( GL_ALPHA_TEST );
+ s->setAlphaClamp( clamp );
+ } else if (e->isAKindOf(ssgTypeBranch())) {
+ setAlphaClampToBranch( (ssgBranch*)e, clamp );
+ }
+ }
+}
+
inline void
SGMatModel::load_models ( SGModelLib *modellib,
const string &fg_root,
lod->ref();
lod->setRanges(ranges, 2);
if (_heading_type == HEADING_BILLBOARD) {
+ // if the model is a billboard, it is likely :
+ // 1. a branch with only leaves,
+ // 2. a tree or a non rectangular shape faked by transparency
+ // We add alpha clamp then
+ if ( entity->isAKindOf(ssgTypeBranch()) ) {
+ ssgBranch *b = (ssgBranch *)entity;
+ setAlphaClampToBranch( b, 0.01f );
+ }
ssgCutout * cutout = new ssgCutout(false);
cutout->addKid(entity);
lod->addKid(cutout);
include_HEADERS = \
animation.hxx \
- flash.hxx \
+ custtrans.hxx \
location.hxx \
model.hxx \
modellib.hxx \
libsgmodel_a_SOURCES = \
animation.cxx \
- flash.cxx \
+ custtrans.cxx \
location.cxx \
model.cxx \
modellib.cxx \
#include <simgear/math/sg_random.h>
#include "animation.hxx"
-#include "flash.hxx"
+#include "custtrans.hxx"
#include "personality.hxx"
\f
SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
: SGAnimation(props, new ssgSelector),
_use_personality( props->getBoolValue("use-personality",false) ),
+ _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
+ _last_time_sec( sim_time_sec ),
_total_duration_sec( 0 ),
_step( 0 )
{
- SGPropertyNode_ptr dNode = props->getChild( "duration-sec" );
- if ( dNode == 0 ) {
- _duration_sec = 1.0;
- } else {
- SGPropertyNode_ptr rNode = dNode->getChild("random");
- if ( rNode == 0 ) {
- _duration_sec = dNode->getDoubleValue();
- } else {
- double dmin = rNode->getDoubleValue( "min", 0.0 ),
- dmax = rNode->getDoubleValue( "max", 1.0 );
- _duration_sec = dmin + sg_random() * ( dmax - dmin );
- }
- }
-
- _last_time_sec = sim_time_sec - _duration_sec;
-
vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
size_t nb = nodes.size();
for ( size_t i = 0; i < nb; i++ ) {
SGPersonalityBranch *key = current_object;
if ( !key->getIntValue( this, INIT ) ) {
double total = 0;
+ double offset = 1.0;
for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
DurationSpec &sp = _branch_duration_specs[ i ];
double v = sp._min + sg_random() * ( sp._max - sp._min );
key->setDoubleValue( v, this, BRANCH_DURATION_SEC, i );
+ if ( i == 0 )
+ offset = v;
total += v;
}
- key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC );
+ offset *= sg_random();
+ key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC );
key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
key->setIntValue( 0, this, STEP );
key->setIntValue( 1, this, INIT );
// Implementation of SGFlashAnimation
////////////////////////////////////////////////////////////////////////
SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
- : SGAnimation( props, new SGFlash )
+ : SGAnimation( props, new SGCustomTransform )
{
- 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 );
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 1);
+
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ _offset = props->getFloatValue("offset", 0.0);
+ _factor = props->getFloatValue("factor", 1.0);
+ _power = props->getFloatValue("power", 1.0);
+ _two_sides = props->getBoolValue("two-sides", false);
+
+ _min_v = props->getFloatValue("min", 0.0);
+ _max_v = props->getFloatValue("max", 1.0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
}
SGFlashAnimation::~SGFlashAnimation()
{
}
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGFlashAnimation *)d)->flashCallback( r, f, m );
+}
+
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 transformed_axis;
+ sgXformVec3( transformed_axis, _axis, m );
+ sgNormalizeVec3( transformed_axis );
+
+ sgVec3 view;
+ sgFullXformPnt3( view, _center, m );
+ sgNormalizeVec3( view );
+
+ float cos_angle = -sgScalarProductVec3( transformed_axis, view );
+ 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 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( r, m );
+ sgPreMultMat4( r, transform );
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGDistScaleAnimation
+////////////////////////////////////////////////////////////////////////
+SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
+ : SGAnimation( props, new SGCustomTransform ),
+ _factor(props->getFloatValue("factor", 1.0)),
+ _offset(props->getFloatValue("offset", 0.0)),
+ _min_v(props->getFloatValue("min", 0.0)),
+ _max_v(props->getFloatValue("max", 1.0)),
+ _has_min(props->hasValue("min")),
+ _has_max(props->hasValue("max")),
+ _table(read_interpolation_table(props))
+{
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
+}
+
+SGDistScaleAnimation::~SGDistScaleAnimation()
+{
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 view;
+ sgFullXformPnt3( view, _center, m );
+
+ float scale_factor = sgLengthVec3( view );
+ if (_table == 0) {
+ scale_factor = _factor * scale_factor + _offset;
+ if ( _has_min && scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( _has_max && scale_factor > _max_v )
+ scale_factor = _max_v;
+ } else {
+ scale_factor = _table->interpolate( scale_factor );
+ }
+
+ sgMat4 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( r, m );
+ sgPreMultMat4( r, transform );
+}
+
// end of animation.cxx
public:
SGFlashAnimation(SGPropertyNode_ptr props);
virtual ~SGFlashAnimation ();
+
+ static void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
+ void flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
+
+private:
+ sgVec3 _axis, _center;
+ float _power, _factor, _offset, _min_v, _max_v;
+ bool _two_sides;
+};
+
+
+/**
+ * An animation that compute a scale according to
+ * the distance from a point and the viewer
+ */
+class SGDistScaleAnimation : public SGAnimation
+{
+public:
+ SGDistScaleAnimation(SGPropertyNode_ptr props);
+ virtual ~SGDistScaleAnimation ();
+
+ static void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
+ void distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m );
+
+private:
+ sgVec3 _center;
+ float _factor, _offset, _min_v, _max_v;
+ bool _has_min, _has_max;
+ SGInterpTable * _table;
};
--- /dev/null
+/*
+ $Id$
+*/
+
+#include "plib/ssg.h"
+#include "custtrans.hxx"
+void _ssgPushMatrix ( sgMat4 m );
+void _ssgPopMatrix ();
+void _ssgReadInt ( FILE *fd, int *var );
+void _ssgWriteInt ( FILE *fd, const int var );
+extern sgMat4 _ssgOpenGLAxisSwapMatrix;
+
+void SGCustomTransform::copy_from( SGCustomTransform *src, int clone_flags )
+{
+ ssgBranch::copy_from( src, clone_flags );
+ _callback = src->_callback;
+ _data = (void *)src->_callback;
+}
+
+ssgBase *SGCustomTransform::clone( int clone_flags )
+{
+ SGCustomTransform *b = new SGCustomTransform;
+ b -> copy_from( this, clone_flags );
+ return b;
+}
+
+
+SGCustomTransform::SGCustomTransform()
+ : _callback(0),_data(0)
+{
+ type = ssgTypeBranch();
+}
+
+SGCustomTransform::~SGCustomTransform()
+{
+}
+
+void SGCustomTransform::cull( sgFrustum *f, sgMat4 m, int test_needed )
+{
+ if ( ! preTravTests( &test_needed, SSGTRAV_CULL ) )
+ return;
+
+ if ( _callback ) {
+ sgMat4 tmp;
+ _callback( tmp, f, m, _data );
+
+ _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 );
+}
+
+
+const char *SGCustomTransform::getTypeName (void) { return "SGCustomTransform"; }
--- /dev/null
+/**
+ * $Id$
+ */
+
+#ifndef _SG_CUSTOM_TRANSFORM_HXX
+#define _SG_CUSTOM_TRANSFORM_HXX 1
+
+class SGCustomTransform : public ssgBranch
+{
+public:
+ typedef void (*TransCallback)( sgMat4 r, sgFrustum *f, sgMat4 m, void *d );
+ virtual ssgBase *clone( int clone_flags = 0 );
+ SGCustomTransform();
+ virtual ~SGCustomTransform(void);
+
+ void setTransCallback( TransCallback c, void *d ) {
+ _callback = c;
+ _data = d;
+ }
+
+ virtual const char *getTypeName(void);
+ virtual void cull( sgFrustum *f, sgMat4 m, int test_needed );
+
+protected:
+ virtual void copy_from( SGCustomTransform *src, int clone_flags );
+
+private:
+ TransCallback _callback;
+ void *_data;
+};
+
+#endif // _SG_CUSTOM_TRANSFORM_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 );
-
- sgVec3 view;
- sgFullXformPnt3( view, _center, m );
- sgNormalizeVec3( view );
-
- float cos_angle = -sgScalarProductVec3( transformed_axis, view );
- 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
-/**
- * $Id$
- */
-
-#ifndef _SG_FLASH_HXX
-#define _SG_FLASH_HXX 1
-
-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;
-};
-
-#endif // _SG_FLASH_HXX
animation = new SGAlphaTestAnimation(node);
} else if (!strcmp("flash", type)) {
animation = new SGFlashAnimation(node);
+ } else if (!strcmp("dist-scale", type)) {
+ animation = new SGDistScaleAnimation(node);
} else {
animation = new SGNullAnimation(node);
SG_LOG(SG_INPUT, SG_WARN, "Unknown animation type " << type);