diff --git a/simgear/scene/material/matmodel.cxx b/simgear/scene/material/matmodel.cxx index db47a66b..abe20af4 100644 --- a/simgear/scene/material/matmodel.cxx +++ b/simgear/scene/material/matmodel.cxx @@ -126,6 +126,22 @@ SGMatModel::get_model_count( SGModelLib *modellib, return _models.size(); } +static void +setAlphaClampToBranch( ssgBranch *b, float clamp ) +{ + int nb = b->getNumKids(); + for (int i = 0; igetKid(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, @@ -147,6 +163,14 @@ SGMatModel::load_models ( SGModelLib *modellib, 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); diff --git a/simgear/scene/model/Makefile.am b/simgear/scene/model/Makefile.am index e9b91a7d..d376bdb2 100644 --- a/simgear/scene/model/Makefile.am +++ b/simgear/scene/model/Makefile.am @@ -6,7 +6,7 @@ noinst_HEADERS = include_HEADERS = \ animation.hxx \ - flash.hxx \ + custtrans.hxx \ location.hxx \ model.hxx \ modellib.hxx \ @@ -15,7 +15,7 @@ include_HEADERS = \ libsgmodel_a_SOURCES = \ animation.cxx \ - flash.cxx \ + custtrans.cxx \ location.cxx \ model.cxx \ modellib.cxx \ diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 298f0691..68cd908f 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -17,7 +17,7 @@ #include #include "animation.hxx" -#include "flash.hxx" +#include "custtrans.hxx" #include "personality.hxx" @@ -420,26 +420,12 @@ SGSpinAnimation::update() 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 nodes = props->getChildren( "branch-duration-sec" ); size_t nb = nodes.size(); for ( size_t i = 0; i < nb; i++ ) { @@ -477,13 +463,17 @@ SGTimedAnimation::update() 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 ); @@ -1040,33 +1030,129 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp) // 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 ); + _axis[0] = props->getFloatValue("axis/x", 0); + _axis[1] = props->getFloatValue("axis/y", 0); + _axis[2] = props->getFloatValue("axis/z", 1); - 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 ); + _center[0] = props->getFloatValue("center/x-m", 0); + _center[1] = props->getFloatValue("center/y-m", 0); + _center[2] = props->getFloatValue("center/z-m", 0); - 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 ); + _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); - float v_min = props->getFloatValue("min", 0.0); - float v_max = props->getFloatValue("max", 1.0); - ((SGFlash *)_branch)->setClampValues( v_min, v_max ); + _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 ); +} + + + +//////////////////////////////////////////////////////////////////////// +// 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 diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index 98193fce..95807afb 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -433,6 +433,35 @@ class SGFlashAnimation : public SGAnimation 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; }; diff --git a/simgear/scene/model/custtrans.cxx b/simgear/scene/model/custtrans.cxx new file mode 100755 index 00000000..bde8be13 --- /dev/null +++ b/simgear/scene/model/custtrans.cxx @@ -0,0 +1,61 @@ +/* + $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"; } diff --git a/simgear/scene/model/custtrans.hxx b/simgear/scene/model/custtrans.hxx new file mode 100755 index 00000000..2b0da4a5 --- /dev/null +++ b/simgear/scene/model/custtrans.hxx @@ -0,0 +1,32 @@ +/** + * $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 diff --git a/simgear/scene/model/flash.cxx b/simgear/scene/model/flash.cxx deleted file mode 100755 index 67a2ec52..00000000 --- a/simgear/scene/model/flash.cxx +++ /dev/null @@ -1,151 +0,0 @@ -/* - $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"; } diff --git a/simgear/scene/model/flash.hxx b/simgear/scene/model/flash.hxx deleted file mode 100755 index 47d4fe33..00000000 --- a/simgear/scene/model/flash.hxx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * $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 diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 3e6d508b..3d7cf5f3 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -156,6 +156,8 @@ sgMakeAnimation( ssgBranch * model, 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);