]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
e11a580eb14c8bdb8364c07847c35afcbb997af3
[simgear.git] / simgear / scene / model / animation.cxx
1 // animation.cxx - classes to manage model animation.
2 // Written by David Megginson, started 2002.
3 //
4 // This file is in the Public Domain, and comes with no warranty.
5
6 #ifdef HAVE_CONFIG_H
7 #  include <simgear_config.h>
8 #endif
9
10 #include <string.h>             // for strcmp()
11 #include <math.h>
12
13 #include <osg/AlphaFunc>
14 #include <osg/AutoTransform>
15 #include <osg/Drawable>
16 #include <osg/Geode>
17 #include <osg/Geometry>
18 #include <osg/LOD>
19 #include <osg/MatrixTransform>
20 #include <osg/StateSet>
21 #include <osg/Switch>
22 #include <osg/TexMat>
23 #include <osg/Texture2D>
24 #include <osgDB/ReadFile>
25
26 #include <simgear/math/interpolater.hxx>
27 #include <simgear/props/condition.hxx>
28 #include <simgear/props/props.hxx>
29 #include <simgear/math/sg_random.h>
30 #include <simgear/scene/util/SGNodeMasks.hxx>
31
32 #include "animation.hxx"
33 #include "model.hxx"
34
35 \f
36 ////////////////////////////////////////////////////////////////////////
37 // Static utility functions.
38 ////////////////////////////////////////////////////////////////////////
39
40 /**
41  * Set up the transform matrix for a spin or rotation.
42  */
43 static void
44 set_rotation (osg::Matrix &matrix, double position_deg,
45               const osg::Vec3 &center, const osg::Vec3 &axis)
46 {
47  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
48  
49  float s = (float) sin ( temp_angle ) ;
50  float c = (float) cos ( temp_angle ) ;
51  float t = SG_ONE - c ;
52
53  // axis was normalized at load time 
54  // hint to the compiler to put these into FP registers
55  float x = axis[0];
56  float y = axis[1];
57  float z = axis[2];
58
59  matrix(0, 0) = t * x * x + c ;
60  matrix(0, 1) = t * y * x - s * z ;
61  matrix(0, 2) = t * z * x + s * y ;
62  matrix(0, 3) = SG_ZERO;
63  
64  matrix(1, 0) = t * x * y + s * z ;
65  matrix(1, 1) = t * y * y + c ;
66  matrix(1, 2) = t * z * y - s * x ;
67  matrix(1, 3) = SG_ZERO;
68  
69  matrix(2, 0) = t * x * z - s * y ;
70  matrix(2, 1) = t * y * z + s * x ;
71  matrix(2, 2) = t * z * z + c ;
72  matrix(2, 3) = SG_ZERO;
73
74   // hint to the compiler to put these into FP registers
75  x = center[0];
76  y = center[1];
77  z = center[2];
78  
79  matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
80  matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
81  matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
82  matrix(3, 3) = SG_ONE;
83 }
84
85 /**
86  * Set up the transform matrix for a translation.
87  */
88 static void
89 set_translation (osg::Matrix &matrix, double position_m, const osg::Vec3 &axis)
90 {
91   osg::Vec3 xyz = axis * position_m;
92   matrix.makeIdentity();
93   matrix(3, 0) = xyz[0];
94   matrix(3, 1) = xyz[1];
95   matrix(3, 2) = xyz[2];
96 }
97
98 /**
99  * Set up the transform matrix for a scale operation.
100  */
101 static void
102 set_scale (osg::Matrix &matrix, double x, double y, double z)
103 {
104   matrix.makeIdentity();
105   matrix(0, 0) = x;
106   matrix(1, 1) = y;
107   matrix(2, 2) = z;
108 }
109
110 /**
111  * Modify property value by step and scroll settings in texture translations
112  */
113 static double
114 apply_mods(double property, double step, double scroll)
115 {
116
117   double modprop;
118   if(step > 0) {
119     double scrollval = 0.0;
120     if(scroll > 0) {
121       // calculate scroll amount (for odometer like movement)
122       double remainder  =  step - fmod(fabs(property), step);
123       if (remainder < scroll) {
124         scrollval = (scroll - remainder) / scroll * step;
125       }
126     }
127   // apply stepping of input value
128   if(property > 0) 
129      modprop = ((floor(property/step) * step) + scrollval);
130   else
131      modprop = ((ceil(property/step) * step) + scrollval);
132   } else {
133      modprop = property;
134   }
135   return modprop;
136
137 }
138
139 /**
140  * Read an interpolation table from properties.
141  */
142 static SGInterpTable *
143 read_interpolation_table (SGPropertyNode_ptr props)
144 {
145   SGPropertyNode_ptr table_node = props->getNode("interpolation");
146   if (table_node != 0) {
147     SGInterpTable * table = new SGInterpTable();
148     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
149     for (unsigned int i = 0; i < entries.size(); i++)
150       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
151                       entries[i]->getDoubleValue("dep", 0.0));
152     return table;
153   } else {
154     return 0;
155   }
156 }
157
158
159 \f
160 ////////////////////////////////////////////////////////////////////////
161 // Implementation of SGAnimation
162 ////////////////////////////////////////////////////////////////////////
163
164 SGAnimation::SGAnimation (SGPropertyNode_ptr props, osg::Group * branch)
165     : _branch(branch),
166     animation_type(0)
167 {
168     _branch->setName(props->getStringValue("name", "Animation"));
169     if ( props->getBoolValue( "enable-hot", true ) ) {
170         _branch->setNodeMask(SG_NODEMASK_TERRAIN_BIT|_branch->getNodeMask());
171     } else {
172         _branch->setNodeMask(~SG_NODEMASK_TERRAIN_BIT&_branch->getNodeMask());
173     }
174 }
175
176 SGAnimation::~SGAnimation ()
177 {
178 }
179
180 void
181 SGAnimation::init ()
182 {
183 }
184
185 void
186 SGAnimation::restore()
187 {
188 }
189
190 void
191 SGAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
192 {
193     traverse(node, nv);
194 }
195
196 \f
197 ////////////////////////////////////////////////////////////////////////
198 // Implementation of SGNullAnimation
199 ////////////////////////////////////////////////////////////////////////
200
201 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
202   : SGAnimation(props, new osg::Group)
203 {
204 }
205
206 SGNullAnimation::~SGNullAnimation ()
207 {
208 }
209
210
211 \f
212 ////////////////////////////////////////////////////////////////////////
213 // Implementation of SGRangeAnimation
214 ////////////////////////////////////////////////////////////////////////
215
216 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
217                                     SGPropertyNode_ptr props)
218   : SGAnimation(props, new osg::LOD),
219     _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
220     _condition(0)
221 {
222     SGPropertyNode_ptr node = props->getChild("condition");
223     if (node != 0)
224        _condition = sgReadCondition(prop_root, node);
225
226     float ranges[2];
227
228     node = props->getChild( "min-factor" );
229     if (node != 0) {
230        _min_factor = props->getFloatValue("min-factor", 1.0);
231     }
232     node = props->getChild( "max-factor" );
233     if (node != 0) {
234        _max_factor = props->getFloatValue("max-factor", 1.0);
235     }
236     node = props->getChild( "min-property" );
237     if (node != 0) {
238        _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
239        ranges[0] = _min_prop->getFloatValue() * _min_factor;
240     } else {
241        _min = props->getFloatValue("min-m", 0);
242        ranges[0] = _min * _min_factor;
243     }
244     node = props->getChild( "max-property" );
245     if (node != 0) {
246        _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
247        ranges[1] = _max_prop->getFloatValue() * _max_factor;
248     } else {
249        _max = props->getFloatValue("max-m", 0);
250        ranges[1] = _max * _max_factor;
251     }
252     static_cast<osg::LOD*>(_branch)->setRange(0, ranges[0], ranges[1]);
253 }
254
255 SGRangeAnimation::~SGRangeAnimation ()
256 {
257 }
258
259 void
260 SGRangeAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
261 {
262   float ranges[2];
263   if ( _condition == 0 || _condition->test() ) {
264     if (_min_prop != 0) {
265       ranges[0] = _min_prop->getFloatValue() * _min_factor;
266     } else {
267       ranges[0] = _min * _min_factor;
268     }
269     if (_max_prop != 0) {
270       ranges[1] = _max_prop->getFloatValue() * _max_factor;
271     } else {
272       ranges[1] = _max * _max_factor;
273     }
274   } else {
275     ranges[0] = 0.f;
276     ranges[1] = 1000000000.f;
277   }
278   static_cast<osg::LOD*>(_branch)->setRange(0, ranges[0], ranges[1]);
279   traverse(node, nv);
280 }
281
282
283 \f
284 ////////////////////////////////////////////////////////////////////////
285 // Implementation of SGBillboardAnimation
286 ////////////////////////////////////////////////////////////////////////
287
288 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
289   : SGAnimation(props, new osg::AutoTransform)
290 {
291 //OSGFIXME: verify
292   bool spherical = props->getBoolValue("spherical", true);
293   osg::AutoTransform* autoTrans = static_cast<osg::AutoTransform*>(_branch);
294   if (spherical) {
295     autoTrans->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
296   } else {
297     autoTrans->setAutoRotateMode(osg::AutoTransform::NO_ROTATION);
298     autoTrans->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
299   }
300   autoTrans->setAutoScaleToScreen(false);
301 }
302
303 SGBillboardAnimation::~SGBillboardAnimation ()
304 {
305 }
306
307
308 \f
309 ////////////////////////////////////////////////////////////////////////
310 // Implementation of SGSelectAnimation
311 ////////////////////////////////////////////////////////////////////////
312
313 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
314                                   SGPropertyNode_ptr props )
315   : SGAnimation(props, new osg::Switch),
316     _condition(0)
317 {
318   SGPropertyNode_ptr node = props->getChild("condition");
319   if (node != 0)
320     _condition = sgReadCondition(prop_root, node);
321 }
322
323 SGSelectAnimation::~SGSelectAnimation ()
324 {
325 }
326
327 void
328 SGSelectAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
329
330   if (_condition != 0 && _condition->test())
331     static_cast<osg::Switch*>(_branch)->setAllChildrenOn();
332   else
333     static_cast<osg::Switch*>(_branch)->setAllChildrenOff();
334   traverse(node, nv);
335 }
336
337 \f
338 ////////////////////////////////////////////////////////////////////////
339 // Implementation of SGSpinAnimation
340 ////////////////////////////////////////////////////////////////////////
341
342 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
343                                   SGPropertyNode_ptr props,
344                                   double sim_time_sec )
345   : SGAnimation(props, new osg::MatrixTransform),
346     _use_personality( props->getBoolValue("use-personality",false) ),
347     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
348     _factor( props, "factor", 1.0 ),
349     _position_deg( props, "starting-position-deg", 0.0 ),
350     _last_time_sec( sim_time_sec ),
351     _condition(0)
352 {
353     SGPropertyNode_ptr node = props->getChild("condition");
354     if (node != 0)
355         _condition = sgReadCondition(prop_root, node);
356
357     _center[0] = 0;
358     _center[1] = 0;
359     _center[2] = 0;
360     if (props->hasValue("axis/x1-m")) {
361         double x1,y1,z1,x2,y2,z2;
362         x1 = props->getFloatValue("axis/x1-m");
363         y1 = props->getFloatValue("axis/y1-m");
364         z1 = props->getFloatValue("axis/z1-m");
365         x2 = props->getFloatValue("axis/x2-m");
366         y2 = props->getFloatValue("axis/y2-m");
367         z2 = props->getFloatValue("axis/z2-m");
368         _center[0] = (x1+x2)/2;
369         _center[1]= (y1+y2)/2;
370         _center[2] = (z1+z2)/2;
371         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
372         _axis[0] = (x2-x1)/vector_length;
373         _axis[1] = (y2-y1)/vector_length;
374         _axis[2] = (z2-z1)/vector_length;
375     } else {
376        _axis[0] = props->getFloatValue("axis/x", 0);
377        _axis[1] = props->getFloatValue("axis/y", 0);
378        _axis[2] = props->getFloatValue("axis/z", 0);
379     }
380     if (props->hasValue("center/x-m")) {
381        _center[0] = props->getFloatValue("center/x-m", 0);
382        _center[1] = props->getFloatValue("center/y-m", 0);
383        _center[2] = props->getFloatValue("center/z-m", 0);
384     }
385     
386     _axis.normalize();
387
388     if ( _use_personality ) {
389       _factor.shuffle();
390       _position_deg.shuffle();
391     }
392 }
393
394 SGSpinAnimation::~SGSpinAnimation ()
395 {
396 }
397
398 void
399 SGSpinAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
400 {
401   double sim_time_sec = nv->getFrameStamp()->getReferenceTime();
402   if ( _condition == 0 || _condition->test() ) {
403     double dt;
404     float velocity_rpms;
405     dt = sim_time_sec - _last_time_sec;
406     _last_time_sec = sim_time_sec;
407     
408     velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
409     _position_deg += (dt * velocity_rpms * 360);
410     _position_deg -= 360*floor(_position_deg/360);
411
412     osg::Matrix _matrix;
413     set_rotation(_matrix, _position_deg, _center, _axis);
414     static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
415   }
416   traverse(node, nv);
417 }
418
419
420 \f
421 ////////////////////////////////////////////////////////////////////////
422 // Implementation of SGTimedAnimation
423 ////////////////////////////////////////////////////////////////////////
424
425 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
426   : SGAnimation(props, new osg::Switch),
427     _use_personality( props->getBoolValue("use-personality",false) ),
428     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
429     _last_time_sec( 0 ),
430     _total_duration_sec( 0 ),
431     _step( 0 )
432     
433 {
434     vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
435     size_t nb = nodes.size();
436     for ( size_t i = 0; i < nb; i++ ) {
437         size_t ind = nodes[ i ]->getIndex();
438         while ( ind >= _branch_duration_specs.size() ) {
439             _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
440         }
441         SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
442         if ( rNode == 0 ) {
443             _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
444         } else {
445             _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
446                                                           rNode->getDoubleValue( "max", 1.0 ) );
447         }
448     }
449 }
450
451 SGTimedAnimation::~SGTimedAnimation ()
452 {
453 }
454
455 void
456 SGTimedAnimation::init()
457 {
458     if ( !_use_personality ) {
459         for ( unsigned i = 0; i < getBranch()->getNumChildren(); i++ ) {
460             double v;
461             if ( i < _branch_duration_specs.size() ) {
462                 DurationSpec &sp = _branch_duration_specs[ i ];
463                 v = sp._min + sg_random() * ( sp._max - sp._min );
464             } else {
465                 v = _duration_sec;
466             }
467             _branch_duration_sec.push_back( v );
468             _total_duration_sec += v;
469         }
470     }
471     // Sanity check : total duration shouldn't equal zero
472     if (_duration_sec < 0.01)
473         _duration_sec = 0.01;
474     if ( _total_duration_sec < 0.01 )
475         _total_duration_sec = 0.01;
476
477     static_cast<osg::Switch*>(getBranch())->setSingleChildOn(_step);
478 }
479
480 void
481 SGTimedAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
482 {
483     double sim_time_sec = nv->getFrameStamp()->getReferenceTime();
484     _last_time_sec -= _total_duration_sec*floor((sim_time_sec - _last_time_sec)/_total_duration_sec);
485     double duration = _duration_sec;
486     if ( _step < _branch_duration_sec.size() ) {
487       duration = _branch_duration_sec[ _step ];
488     }
489     if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
490       _last_time_sec += duration;
491       _step += 1;
492       if ( _step >= getBranch()->getNumChildren() )
493         _step = 0;
494       static_cast<osg::Switch*>(getBranch())->setSingleChildOn(_step);
495     }
496     traverse(node, nv);
497 }
498
499
500 \f
501 ////////////////////////////////////////////////////////////////////////
502 // Implementation of SGRotateAnimation
503 ////////////////////////////////////////////////////////////////////////
504
505 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
506                                   SGPropertyNode_ptr props )
507   : SGAnimation(props, new osg::MatrixTransform),
508       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
509       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
510       _factor(props->getDoubleValue("factor", 1.0)),
511       _table(read_interpolation_table(props)),
512       _has_min(props->hasValue("min-deg")),
513       _min_deg(props->getDoubleValue("min-deg")),
514       _has_max(props->hasValue("max-deg")),
515       _max_deg(props->getDoubleValue("max-deg")),
516       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
517       _condition(0)
518 {
519     SGPropertyNode_ptr node = props->getChild("condition");
520     if (node != 0)
521       _condition = sgReadCondition(prop_root, node);
522
523     _center[0] = 0;
524     _center[1] = 0;
525     _center[2] = 0;
526     if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
527        _axis[0] = props->getFloatValue("axis/x", 0);
528        _axis[1] = props->getFloatValue("axis/y", 0);
529        _axis[2] = props->getFloatValue("axis/z", 0);
530     } else {
531         double x1,y1,z1,x2,y2,z2;
532         x1 = props->getFloatValue("axis/x1-m", 0);
533         y1 = props->getFloatValue("axis/y1-m", 0);
534         z1 = props->getFloatValue("axis/z1-m", 0);
535         x2 = props->getFloatValue("axis/x2-m", 0);
536         y2 = props->getFloatValue("axis/y2-m", 0);
537         z2 = props->getFloatValue("axis/z2-m", 0);
538         _center[0] = (x1+x2)/2;
539         _center[1]= (y1+y2)/2;
540         _center[2] = (z1+z2)/2;
541         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
542         _axis[0] = (x2-x1)/vector_length;
543         _axis[1] = (y2-y1)/vector_length;
544         _axis[2] = (z2-z1)/vector_length;
545     }
546     if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
547             || props->hasValue("center/z-m")) {
548         _center[0] = props->getFloatValue("center/x-m", 0);
549         _center[1] = props->getFloatValue("center/y-m", 0);
550         _center[2] = props->getFloatValue("center/z-m", 0);
551     }
552     _axis.normalize();
553 }
554
555 SGRotateAnimation::~SGRotateAnimation ()
556 {
557 }
558
559 void
560 SGRotateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
561 {
562   if (_condition == 0 || _condition->test()) {
563     if (_table == 0) {
564       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
565       if (_has_min && _position_deg < _min_deg)
566         _position_deg = _min_deg;
567       if (_has_max && _position_deg > _max_deg)
568         _position_deg = _max_deg;
569     } else {
570       _position_deg = _table->interpolate(_prop->getDoubleValue());
571     }
572     osg::Matrix _matrix;
573     set_rotation(_matrix, _position_deg, _center, _axis);
574     static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
575   }
576   traverse(node, nv);
577 }
578
579 \f
580 ////////////////////////////////////////////////////////////////////////
581 // Implementation of SGBlendAnimation
582 ////////////////////////////////////////////////////////////////////////
583
584 class SGBlendAnimationVisitor : public osg::NodeVisitor {
585 public:
586   SGBlendAnimationVisitor(float blend) :
587     osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
588     _blend(blend)
589   {
590     setVisitorType(osg::NodeVisitor::NODE_VISITOR);
591   }
592   virtual void apply(osg::Node& node)
593   {
594     updateStateSet(node.getStateSet());
595     traverse(node);
596   }
597   virtual void apply(osg::Geode& node)
598   {
599     apply((osg::Node&)node);
600     unsigned nDrawables = node.getNumDrawables();
601     for (unsigned i = 0; i < nDrawables; ++i) {
602       osg::Drawable* drawable = node.getDrawable(i);
603       updateStateSet(drawable->getStateSet());
604       osg::Geometry* geometry = drawable->asGeometry();
605       if (!geometry)
606         continue;
607       osg::Array* array = geometry->getColorArray();
608       if (!array)
609         continue;
610       osg::Vec4Array* vec4Array = dynamic_cast<osg::Vec4Array*>(array);
611       if (!vec4Array)
612         continue;
613       geometry->dirtyDisplayList();
614       vec4Array->dirty();
615       for (unsigned k = 0; k < vec4Array->size(); ++k) {
616         (*vec4Array)[k][3] = _blend;
617       }
618     }
619   }
620   void updateStateSet(osg::StateSet* stateSet)
621   {
622     if (!stateSet)
623       return;
624     osg::StateAttribute* stateAttribute = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
625     if (!stateAttribute)
626       return;
627     osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
628     if (!material)
629       return;
630     material->setAlpha(osg::Material::FRONT_AND_BACK, _blend);
631   }
632 private:
633   float _blend;
634 };
635
636
637 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
638                                         SGPropertyNode_ptr props )
639   : SGAnimation(props, new osg::Group),
640     _use_personality( props->getBoolValue("use-personality",false) ),
641     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
642     _table(read_interpolation_table(props)),
643     _prev_value(1.0),
644     _offset(props,"offset",0.0),
645     _factor(props,"factor",1.0),
646     _min(props->getDoubleValue("min", 0.0)),
647     _max(props->getDoubleValue("max", 1.0))
648 {
649   if ( _use_personality ) {
650     _factor.shuffle();
651     _offset.shuffle();
652   }
653 }
654
655 SGBlendAnimation::~SGBlendAnimation ()
656 {
657 }
658
659 void
660 SGBlendAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
661 {
662   double _blend;
663
664   if (_table == 0) {
665     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
666   } else {
667     _blend = _table->interpolate(_prop->getDoubleValue());
668   }
669   if (_blend < _min)
670     _blend = _min;
671   if (_blend > _max)
672     _blend = _max;
673
674   if (_blend != _prev_value) {
675     _prev_value = _blend;
676     SGBlendAnimationVisitor visitor(1-_blend);
677     _branch->accept(visitor);
678   }
679   traverse(node, nv);
680 }
681
682
683 \f
684 ////////////////////////////////////////////////////////////////////////
685 // Implementation of SGTranslateAnimation
686 ////////////////////////////////////////////////////////////////////////
687
688 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
689                                         SGPropertyNode_ptr props )
690   : SGAnimation(props, new osg::MatrixTransform),
691     _use_personality( props->getBoolValue("use-personality",false) ),
692     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
693     _offset_m( props, "offset-m", 0.0 ),
694     _factor( props, "factor", 1.0 ),
695     _table(read_interpolation_table(props)),
696     _has_min(props->hasValue("min-m")),
697     _min_m(props->getDoubleValue("min-m")),
698     _has_max(props->hasValue("max-m")),
699     _max_m(props->getDoubleValue("max-m")),
700     _position_m(props->getDoubleValue("starting-position-m", 0)),
701     _condition(0)
702 {
703   SGPropertyNode_ptr node = props->getChild("condition");
704   if (node != 0)
705     _condition = sgReadCondition(prop_root, node);
706
707   _axis[0] = props->getFloatValue("axis/x", 0);
708   _axis[1] = props->getFloatValue("axis/y", 0);
709   _axis[2] = props->getFloatValue("axis/z", 0);
710   _axis.normalize();
711
712   if ( _use_personality ) {
713     _factor.shuffle();
714     _offset_m.shuffle();
715   }
716 }
717
718 SGTranslateAnimation::~SGTranslateAnimation ()
719 {
720 }
721
722 void
723 SGTranslateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
724 {
725   if (_condition == 0 || _condition->test()) {
726
727     if (_table == 0) {
728       _position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
729       if (_has_min && _position_m < _min_m)
730         _position_m = _min_m;
731       if (_has_max && _position_m > _max_m)
732         _position_m = _max_m;
733     } else {
734       _position_m = _table->interpolate(_prop->getDoubleValue());
735     }
736
737     osg::Matrix _matrix;
738     set_translation(_matrix, _position_m, _axis);
739     static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
740   }
741   traverse(node, nv);
742 }
743
744
745 \f
746 ////////////////////////////////////////////////////////////////////////
747 // Implementation of SGScaleAnimation
748 ////////////////////////////////////////////////////////////////////////
749
750 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
751                                         SGPropertyNode_ptr props )
752   : SGAnimation(props, new osg::MatrixTransform),
753     _use_personality( props->getBoolValue("use-personality",false) ),
754     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
755     _x_factor(props,"x-factor",1.0),
756     _y_factor(props,"y-factor",1.0),
757     _z_factor(props,"z-factor",1.0),
758     _x_offset(props,"x-offset",1.0),
759     _y_offset(props,"y-offset",1.0),
760     _z_offset(props,"z-offset",1.0),
761     _table(read_interpolation_table(props)),
762     _has_min_x(props->hasValue("x-min")),
763     _has_min_y(props->hasValue("y-min")),
764     _has_min_z(props->hasValue("z-min")),
765     _min_x(props->getDoubleValue("x-min")),
766     _min_y(props->getDoubleValue("y-min")),
767     _min_z(props->getDoubleValue("z-min")),
768     _has_max_x(props->hasValue("x-max")),
769     _has_max_y(props->hasValue("y-max")),
770     _has_max_z(props->hasValue("z-max")),
771     _max_x(props->getDoubleValue("x-max")),
772     _max_y(props->getDoubleValue("y-max")),
773     _max_z(props->getDoubleValue("z-max"))
774 {
775   if ( _use_personality ) {
776     _x_factor.shuffle();
777     _x_offset.shuffle();
778     _y_factor.shuffle();
779     _y_offset.shuffle();
780     _z_factor.shuffle();
781     _z_offset.shuffle();
782   }
783 }
784
785 SGScaleAnimation::~SGScaleAnimation ()
786 {
787 }
788
789 void
790 SGScaleAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
791 {
792   if (_table == 0) {
793       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
794     if (_has_min_x && _x_scale < _min_x)
795       _x_scale = _min_x;
796     if (_has_max_x && _x_scale > _max_x)
797       _x_scale = _max_x;
798   } else {
799     _x_scale = _table->interpolate(_prop->getDoubleValue());
800   }
801
802   if (_table == 0) {
803     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
804     if (_has_min_y && _y_scale < _min_y)
805       _y_scale = _min_y;
806     if (_has_max_y && _y_scale > _max_y)
807       _y_scale = _max_y;
808   } else {
809     _y_scale = _table->interpolate(_prop->getDoubleValue());
810   }
811
812   if (_table == 0) {
813     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
814     if (_has_min_z && _z_scale < _min_z)
815       _z_scale = _min_z;
816     if (_has_max_z && _z_scale > _max_z)
817       _z_scale = _max_z;
818   } else {
819     _z_scale = _table->interpolate(_prop->getDoubleValue());
820   }
821
822   osg::Matrix _matrix;
823   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
824   static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
825   traverse(node, nv);
826 }
827
828
829 ////////////////////////////////////////////////////////////////////////
830 // Implementation of SGTexRotateAnimation
831 ////////////////////////////////////////////////////////////////////////
832
833 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
834                                   SGPropertyNode_ptr props )
835     : SGAnimation(props, new osg::Group),
836       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
837       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
838       _factor(props->getDoubleValue("factor", 1.0)),
839       _table(read_interpolation_table(props)),
840       _has_min(props->hasValue("min-deg")),
841       _min_deg(props->getDoubleValue("min-deg")),
842       _has_max(props->hasValue("max-deg")),
843       _max_deg(props->getDoubleValue("max-deg")),
844       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
845       _condition(0)
846 {
847   SGPropertyNode *node = props->getChild("condition");
848   if (node != 0)
849     _condition = sgReadCondition(prop_root, node);
850
851   _center[0] = props->getFloatValue("center/x", 0);
852   _center[1] = props->getFloatValue("center/y", 0);
853   _center[2] = props->getFloatValue("center/z", 0);
854   _axis[0] = props->getFloatValue("axis/x", 0);
855   _axis[1] = props->getFloatValue("axis/y", 0);
856   _axis[2] = props->getFloatValue("axis/z", 0);
857   _axis.normalize();
858
859   osg::StateSet* stateSet = _branch->getOrCreateStateSet();
860   _texMat = new osg::TexMat;
861   stateSet->setTextureAttribute(0, _texMat.get());
862 }
863
864 SGTexRotateAnimation::~SGTexRotateAnimation ()
865 {
866 }
867
868 void
869 SGTexRotateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
870 {
871   if (!_condition || _condition->test()) {
872     if (_table == 0) {
873       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
874       if (_has_min && _position_deg < _min_deg)
875         _position_deg = _min_deg;
876       if (_has_max && _position_deg > _max_deg)
877         _position_deg = _max_deg;
878     } else {
879       _position_deg = _table->interpolate(_prop->getDoubleValue());
880     }
881     osg::Matrix _matrix;
882     set_rotation(_matrix, _position_deg, _center, _axis);
883     _texMat->setMatrix(_matrix);
884   }
885   traverse(node, nv);
886 }
887
888
889 ////////////////////////////////////////////////////////////////////////
890 // Implementation of SGTexTranslateAnimation
891 ////////////////////////////////////////////////////////////////////////
892
893 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
894                                         SGPropertyNode_ptr props )
895   : SGAnimation(props, new osg::Group),
896       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
897     _offset(props->getDoubleValue("offset", 0.0)),
898     _factor(props->getDoubleValue("factor", 1.0)),
899     _step(props->getDoubleValue("step",0.0)),
900     _scroll(props->getDoubleValue("scroll",0.0)),
901     _table(read_interpolation_table(props)),
902     _has_min(props->hasValue("min")),
903     _min(props->getDoubleValue("min")),
904     _has_max(props->hasValue("max")),
905     _max(props->getDoubleValue("max")),
906     _position(props->getDoubleValue("starting-position", 0)),
907     _condition(0)
908 {
909   SGPropertyNode *node = props->getChild("condition");
910   if (node != 0)
911     _condition = sgReadCondition(prop_root, node);
912
913   _axis[0] = props->getFloatValue("axis/x", 0);
914   _axis[1] = props->getFloatValue("axis/y", 0);
915   _axis[2] = props->getFloatValue("axis/z", 0);
916   _axis.normalize();
917
918   osg::StateSet* stateSet = _branch->getOrCreateStateSet();
919   _texMat = new osg::TexMat;
920   stateSet->setTextureAttribute(0, _texMat.get());
921 }
922
923 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
924 {
925 }
926
927 void
928 SGTexTranslateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
929 {
930   if (!_condition || _condition->test()) {
931     if (_table == 0) {
932       _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
933       if (_has_min && _position < _min)
934         _position = _min;
935       if (_has_max && _position > _max)
936         _position = _max;
937     } else {
938       _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
939     }
940     osg::Matrix _matrix;
941     set_translation(_matrix, _position, _axis);
942     _texMat->setMatrix(_matrix);
943   }
944   traverse(node, nv);
945 }
946
947
948 ////////////////////////////////////////////////////////////////////////
949 // Implementation of SGTexMultipleAnimation
950 ////////////////////////////////////////////////////////////////////////
951
952 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
953                                         SGPropertyNode_ptr props )
954   : SGAnimation(props, new osg::Group),
955       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
956 {
957   unsigned int i;
958   // Load animations
959   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
960   _transform = new TexTransform [transform_nodes.size()];
961   _num_transforms = 0;
962   for (i = 0; i < transform_nodes.size(); i++) {
963     SGPropertyNode_ptr transform_props = transform_nodes[i];
964
965     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
966
967       // transform is a translation
968       _transform[i].subtype = 0;
969
970       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
971
972       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
973       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
974       _transform[i].step = transform_props->getDoubleValue("step",0.0);
975       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
976       _transform[i].table = read_interpolation_table(transform_props);
977       _transform[i].has_min = transform_props->hasValue("min");
978       _transform[i].min = transform_props->getDoubleValue("min");
979       _transform[i].has_max = transform_props->hasValue("max");
980       _transform[i].max = transform_props->getDoubleValue("max");
981       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
982
983       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
984       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
985       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
986       _transform[i].axis.normalize();
987       _num_transforms++;
988     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
989
990       // transform is a rotation
991       _transform[i].subtype = 1;
992
993       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
994       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
995       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
996       _transform[i].table = read_interpolation_table(transform_props);
997       _transform[i].has_min = transform_props->hasValue("min-deg");
998       _transform[i].min = transform_props->getDoubleValue("min-deg");
999       _transform[i].has_max = transform_props->hasValue("max-deg");
1000       _transform[i].max = transform_props->getDoubleValue("max-deg");
1001       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
1002
1003       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
1004       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
1005       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
1006       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1007       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1008       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1009       _transform[i].axis.normalize();
1010       _num_transforms++;
1011     }
1012   }
1013   osg::StateSet* stateSet = _branch->getOrCreateStateSet();
1014   _texMat = new osg::TexMat;
1015   stateSet->setTextureAttribute(0, _texMat.get());
1016 }
1017
1018 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
1019 {
1020    delete [] _transform;
1021 }
1022
1023 void
1024 SGTexMultipleAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
1025 {
1026   int i;
1027   osg::Matrix tmatrix;
1028   tmatrix.makeIdentity();
1029   for (i = 0; i < _num_transforms; i++) {
1030
1031     if(_transform[i].subtype == 0) {
1032
1033       // subtype 0 is translation
1034       if (_transform[i].table == 0) {
1035         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
1036         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1037           _transform[i].position = _transform[i].min;
1038         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1039           _transform[i].position = _transform[i].max;
1040       } else {
1041          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
1042       }
1043       osg::Matrix matrix;
1044       set_translation(matrix, _transform[i].position, _transform[i].axis);
1045       tmatrix = matrix*tmatrix;
1046
1047     } else if (_transform[i].subtype == 1) {
1048
1049       // subtype 1 is rotation
1050
1051       if (_transform[i].table == 0) {
1052         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
1053         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1054          _transform[i].position = _transform[i].min;
1055        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1056          _transform[i].position = _transform[i].max;
1057      } else {
1058         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1059       }
1060
1061       osg::Matrix matrix;
1062       set_rotation(matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1063       tmatrix = matrix*tmatrix;
1064     }
1065   }
1066   _texMat->setMatrix(tmatrix);
1067   traverse(node, nv);
1068 }
1069
1070
1071 \f
1072 ////////////////////////////////////////////////////////////////////////
1073 // Implementation of SGAlphaTestAnimation
1074 ////////////////////////////////////////////////////////////////////////
1075
1076 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1077   : SGAnimation(props, new osg::Group)
1078 {
1079   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1080 }
1081
1082 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1083 {
1084 }
1085
1086 void SGAlphaTestAnimation::init()
1087 {
1088   osg::StateSet* stateSet = _branch->getOrCreateStateSet();
1089   osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
1090   alphaFunc->setFunction(osg::AlphaFunc::GREATER);
1091   alphaFunc->setReferenceValue(_alpha_clamp);
1092   stateSet->setAttribute(alphaFunc);
1093   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
1094   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1095   stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1096 }
1097
1098
1099 \f
1100 ////////////////////////////////////////////////////////////////////////
1101 // Implementation of SGMaterialAnimation
1102 ////////////////////////////////////////////////////////////////////////
1103
1104 SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
1105         SGPropertyNode_ptr props, const SGPath &texture_path)
1106     : SGAnimation(props, new osg::Group),
1107     _last_condition(false),
1108     _prop_root(prop_root),
1109     _prop_base(""),
1110     _texture_base(texture_path),
1111     _read(0),
1112     _update(0),
1113     _global(props->getBoolValue("global", false))
1114 {
1115     SGPropertyNode_ptr n;
1116     n = props->getChild("condition");
1117     _condition = n ? sgReadCondition(_prop_root, n) : 0;
1118     n = props->getChild("property-base");
1119     if (n) {
1120         _prop_base = n->getStringValue();
1121         if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
1122             _prop_base += '/';
1123     }
1124
1125     initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
1126     initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
1127     initColorGroup(props->getChild("emission"), &_emis, EMISSION);
1128     initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
1129
1130     _shi = props->getFloatValue("shininess", -1.0);
1131     if (_shi >= 0.0)
1132         _update |= SHININESS;
1133
1134     SGPropertyNode_ptr group = props->getChild("transparency");
1135     if (group) {
1136         _trans.value = group->getFloatValue("alpha", -1.0);
1137         _trans.factor = group->getFloatValue("factor", 1.0);
1138         _trans.offset = group->getFloatValue("offset", 0.0);
1139         _trans.min = group->getFloatValue("min", 0.0);
1140         if (_trans.min < 0.0)
1141             _trans.min = 0.0;
1142         _trans.max = group->getFloatValue("max", 1.0);
1143         if (_trans.max > 1.0)
1144             _trans.max = 1.0;
1145         if (_trans.dirty())
1146             _update |= TRANSPARENCY;
1147
1148         n = group->getChild("alpha-prop");
1149         _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1150         n = group->getChild("factor-prop");
1151         _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1152         n = group->getChild("offset-prop");
1153         _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1154         if (_trans.live())
1155             _read |= TRANSPARENCY;
1156     }
1157
1158     _thresh = props->getFloatValue("threshold", -1.0);
1159     if (_thresh >= 0.0)
1160         _update |= THRESHOLD;
1161
1162     string _texture_str = props->getStringValue("texture", "");
1163     if (!_texture_str.empty()) {
1164         _texture = _texture_base;
1165         _texture.append(_texture_str);
1166         _texture2D = SGLoadTexture2D(_texture);
1167         _update |= TEXTURE;
1168     }
1169
1170     n = props->getChild("shininess-prop");
1171     _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1172     n = props->getChild("threshold-prop");
1173     _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1174     n = props->getChild("texture-prop");
1175     _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1176
1177     _static_update = _update;
1178
1179     _alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0);
1180 }
1181
1182 SGMaterialAnimation::~SGMaterialAnimation()
1183 {
1184 }
1185
1186 void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
1187 {
1188     if (!group)
1189         return;
1190
1191     col->red = group->getFloatValue("red", -1.0);
1192     col->green = group->getFloatValue("green", -1.0);
1193     col->blue = group->getFloatValue("blue", -1.0);
1194     col->factor = group->getFloatValue("factor", 1.0);
1195     col->offset = group->getFloatValue("offset", 0.0);
1196     if (col->dirty())
1197         _update |= flag;
1198
1199     SGPropertyNode *n;
1200     n = group->getChild("red-prop");
1201     col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1202     n = group->getChild("green-prop");
1203     col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1204     n = group->getChild("blue-prop");
1205     col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1206     n = group->getChild("factor-prop");
1207     col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1208     n = group->getChild("offset-prop");
1209     col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1210     if (col->live())
1211         _read |= flag;
1212 }
1213
1214 void SGMaterialAnimation::init()
1215 {
1216     if (!_global)
1217         cloneMaterials(_branch);
1218
1219     // OSGFIXME
1220     osg::StateSet* stateSet = _branch->getOrCreateStateSet();
1221     if (_update & THRESHOLD) {
1222       stateSet->setAttribute(_alphaFunc.get(), osg::StateAttribute::OVERRIDE);
1223       stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
1224     }
1225     if ((_update & TEXTURE) && _texture2D.valid()) {
1226       stateSet->setTextureAttribute(0, _texture2D.get(), osg::StateAttribute::OVERRIDE);
1227       stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
1228     }
1229 }
1230
1231 void
1232 SGMaterialAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
1233 {
1234     if (_condition) {
1235         bool cond = _condition->test();
1236         if (cond && !_last_condition)
1237             _update |= _static_update;
1238
1239         _last_condition = cond;
1240         if (!cond) {
1241             traverse(node, nv);
1242             return;
1243         }
1244     }
1245
1246     if (_read & DIFFUSE)
1247         updateColorGroup(&_diff, DIFFUSE);
1248     if (_read & AMBIENT)
1249         updateColorGroup(&_amb, AMBIENT);
1250     if (_read & EMISSION)
1251         updateColorGroup(&_emis, EMISSION);
1252     if (_read & SPECULAR)
1253         updateColorGroup(&_spec, SPECULAR);
1254
1255     float f;
1256     if (_shi_prop) {
1257         f = _shi;
1258         _shi = _shi_prop->getFloatValue();
1259         if (_shi != f)
1260             _update |= SHININESS;
1261     }
1262     if (_read & TRANSPARENCY) {
1263         PropSpec tmp = _trans;
1264         if (_trans.value_prop)
1265             _trans.value = _trans.value_prop->getFloatValue();
1266         if (_trans.factor_prop)
1267             _trans.factor = _trans.factor_prop->getFloatValue();
1268         if (_trans.offset_prop)
1269             _trans.offset = _trans.offset_prop->getFloatValue();
1270         if (_trans != tmp)
1271             _update |= TRANSPARENCY;
1272     }
1273     if (_thresh_prop) {
1274         f = _thresh;
1275         _thresh = _thresh_prop->getFloatValue();
1276         if (_thresh != f)
1277             _update |= THRESHOLD;
1278     }
1279     if (_tex_prop) {
1280         string t = _tex_prop->getStringValue();
1281         if (!t.empty() && t != _texture_str) {
1282             _texture_str = t;
1283             _texture = _texture_base;
1284             _texture.append(t);
1285             _update |= TEXTURE;
1286         }
1287     }
1288     if (_update) {
1289         setMaterialBranch(_branch);
1290         _update = 0;
1291     }
1292     traverse(node, nv);
1293 }
1294
1295 void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
1296 {
1297     ColorSpec tmp = *col;
1298     if (col->red_prop)
1299         col->red = col->red_prop->getFloatValue();
1300     if (col->green_prop)
1301         col->green = col->green_prop->getFloatValue();
1302     if (col->blue_prop)
1303         col->blue = col->blue_prop->getFloatValue();
1304     if (col->factor_prop)
1305         col->factor = col->factor_prop->getFloatValue();
1306     if (col->offset_prop)
1307         col->offset = col->offset_prop->getFloatValue();
1308     if (*col != tmp)
1309         _update |= flag;
1310 }
1311
1312 class SGMaterialAnimationCloneVisitor : public osg::NodeVisitor {
1313 public:
1314   SGMaterialAnimationCloneVisitor() :
1315     osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
1316   {
1317     setVisitorType(osg::NodeVisitor::NODE_VISITOR);
1318   }
1319   virtual void apply(osg::Node& node)
1320   {
1321     traverse(node);
1322     osg::StateSet* stateSet = node.getStateSet();
1323     if (!stateSet)
1324       return;
1325     if (1 < stateSet->referenceCount()) {
1326       osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATESETS);
1327       osg::Object* object = stateSet->clone(copyOp);
1328       stateSet = static_cast<osg::StateSet*>(object);
1329       node.setStateSet(stateSet);
1330     }
1331     cloneMaterial(stateSet);
1332   }
1333   virtual void apply(osg::Geode& node)
1334   {
1335     apply((osg::Node&)node);
1336     traverse(node);
1337     unsigned nDrawables = node.getNumDrawables();
1338     for (unsigned i = 0; i < nDrawables; ++i) {
1339       osg::Drawable* drawable = node.getDrawable(i);
1340       osg::StateSet* stateSet = drawable->getStateSet();
1341       if (!stateSet)
1342         continue;
1343       if (1 < stateSet->referenceCount()) {
1344         osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATESETS);
1345         osg::Object* object = stateSet->clone(copyOp);
1346         stateSet = static_cast<osg::StateSet*>(object);
1347         drawable->setStateSet(stateSet);
1348       }
1349       cloneMaterial(stateSet);
1350     }
1351   }
1352   void cloneMaterial(osg::StateSet* stateSet)
1353   {
1354     osg::StateAttribute* stateAttr;
1355     stateAttr = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
1356     if (!stateAttr)
1357       return;
1358     osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATEATTRIBUTES);
1359     osg::Object* object = stateAttr->clone(copyOp);
1360     osg::Material* material = static_cast<osg::Material*>(object);
1361     materialList.push_back(material);
1362     while (stateSet->getAttribute(osg::StateAttribute::MATERIAL)) {
1363       stateSet->removeAttribute(osg::StateAttribute::MATERIAL);
1364     }
1365     stateSet->setAttribute(material);
1366   }
1367   std::vector<osg::ref_ptr<osg::Material> > materialList;
1368 };
1369
1370 void SGMaterialAnimation::cloneMaterials(osg::Group *b)
1371 {
1372   SGMaterialAnimationCloneVisitor cloneVisitor;
1373   b->accept(cloneVisitor);
1374   _materialList.swap(cloneVisitor.materialList);
1375 }
1376
1377 void SGMaterialAnimation::setMaterialBranch(osg::Group *b)
1378 {
1379   std::vector<osg::ref_ptr<osg::Material> >::iterator i;
1380   for (i = _materialList.begin(); i != _materialList.end(); ++i) {
1381     osg::Material* material = i->get();
1382     if (_update & DIFFUSE) {
1383       osg::Vec4 v = _diff.rgba();
1384       float alpha = material->getDiffuse(osg::Material::FRONT_AND_BACK)[3];
1385       material->setColorMode(osg::Material::DIFFUSE);
1386       material->setDiffuse(osg::Material::FRONT_AND_BACK,
1387                            osg::Vec4(v[0], v[1], v[2], alpha));
1388     }
1389     if (_update & AMBIENT) {
1390       material->setColorMode(osg::Material::AMBIENT);
1391       material->setDiffuse(osg::Material::FRONT_AND_BACK, _amb.rgba());
1392     }
1393     if (_update & EMISSION)
1394       material->setEmission(osg::Material::FRONT_AND_BACK, _emis.rgba());
1395     if (_update & SPECULAR)
1396       material->setSpecular(osg::Material::FRONT_AND_BACK, _spec.rgba());
1397     if (_update & SHININESS)
1398       material->setShininess(osg::Material::FRONT_AND_BACK,
1399                              clamp(_shi, 0.0, 128.0));
1400     if (_update & THRESHOLD)
1401         _alphaFunc->setReferenceValue(clamp(_thresh));
1402   }
1403
1404   if (_update & TRANSPARENCY) {
1405     float trans = _trans.value * _trans.factor + _trans.offset;
1406     trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
1407     SGBlendAnimationVisitor visitor(trans);
1408     _branch->accept(visitor);
1409   }
1410   if (_update & TEXTURE) {
1411     if (!_texture2D) {
1412       _texture2D = new osg::Texture2D;
1413       osg::StateSet* stateSet = _branch->getOrCreateStateSet();
1414       stateSet->setTextureAttribute(0, _texture2D.get(), osg::StateAttribute::OVERRIDE);
1415       stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
1416     }
1417     osg::Image* image = osgDB::readImageFile(_texture.str());
1418     if (image) {
1419       _texture2D->setImage(image);
1420       if (image->isImageTranslucent()) {
1421         osg::StateSet* stateSet = _branch->getOrCreateStateSet();
1422         stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1423         stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
1424         stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1425       }
1426     }
1427   }
1428 }
1429
1430
1431 \f
1432 ////////////////////////////////////////////////////////////////////////
1433 // Implementation of SGFlashAnimation
1434 ////////////////////////////////////////////////////////////////////////
1435 class SGFlashAnimationTransform : public osg::Transform {
1436 public:
1437   SGFlashAnimationTransform(SGPropertyNode* props)
1438   {
1439     getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1440
1441     _axis[0] = props->getFloatValue("axis/x", 0);
1442     _axis[1] = props->getFloatValue("axis/y", 0);
1443     _axis[2] = props->getFloatValue("axis/z", 1);
1444     _axis.normalize();
1445     
1446     _center[0] = props->getFloatValue("center/x-m", 0);
1447     _center[1] = props->getFloatValue("center/y-m", 0);
1448     _center[2] = props->getFloatValue("center/z-m", 0);
1449     
1450     _offset = props->getFloatValue("offset", 0.0);
1451     _factor = props->getFloatValue("factor", 1.0);
1452     _power = props->getFloatValue("power", 1.0);
1453     _two_sides = props->getBoolValue("two-sides", false);
1454     
1455     _min_v = props->getFloatValue("min", 0.0);
1456     _max_v = props->getFloatValue("max", 1.0);
1457   }
1458
1459   virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1460                                          osg::NodeVisitor* nv) const 
1461   {
1462     double scale_factor = computeScaleFactor(nv);
1463     osg::Matrix transform;
1464     transform(0,0) = scale_factor;
1465     transform(1,1) = scale_factor;
1466     transform(2,2) = scale_factor;
1467     transform(3,0) = _center[0] * ( 1 - scale_factor );
1468     transform(3,1) = _center[1] * ( 1 - scale_factor );
1469     transform(3,2) = _center[2] * ( 1 - scale_factor );
1470     if (_referenceFrame == RELATIVE_RF)
1471       matrix.preMult(transform);
1472     else
1473       matrix = transform;
1474
1475     return true;
1476   }
1477   
1478   virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1479                                          osg::NodeVisitor* nv) const
1480   {
1481     double scale_factor = computeScaleFactor(nv);
1482     if (fabs(scale_factor) <= std::numeric_limits<double>::min())
1483       return false;
1484     osg::Matrix transform;
1485     double rScaleFactor = 1/scale_factor;
1486     transform(0,0) = rScaleFactor;
1487     transform(1,1) = rScaleFactor;
1488     transform(2,2) = rScaleFactor;
1489     transform(3,0) = rScaleFactor*_center[0] * ( scale_factor - 1 );
1490     transform(3,1) = rScaleFactor*_center[1] * ( scale_factor - 1 );
1491     transform(3,2) = rScaleFactor*_center[2] * ( scale_factor - 1 );
1492     if (_referenceFrame == RELATIVE_RF)
1493       matrix.postMult(transform);
1494     else
1495       matrix = transform;
1496     return true;
1497   }
1498
1499   double computeScaleFactor(osg::NodeVisitor* nv) const
1500   {
1501     if (!nv)
1502       return 1;
1503
1504     osg::Vec3 localEyeToCenter = nv->getEyePoint() - _center;
1505     localEyeToCenter.normalize();
1506
1507     double cos_angle = localEyeToCenter*_axis;
1508     double scale_factor = 0;
1509     if ( _two_sides && cos_angle < 0 )
1510       scale_factor = _factor * pow( -cos_angle, _power ) + _offset;
1511     else if ( cos_angle > 0 )
1512       scale_factor = _factor * pow( cos_angle, _power ) + _offset;
1513     
1514     if ( scale_factor < _min_v )
1515       scale_factor = _min_v;
1516     if ( scale_factor > _max_v )
1517       scale_factor = _max_v;
1518
1519     return scale_factor;
1520   }
1521
1522 private:
1523   osg::Vec3 _axis, _center;
1524   double _power, _factor, _offset, _min_v, _max_v;
1525   bool _two_sides;
1526 };
1527
1528 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1529   : SGAnimation( props, new SGFlashAnimationTransform(props) )
1530 {
1531 }
1532
1533 SGFlashAnimation::~SGFlashAnimation()
1534 {
1535 }
1536
1537
1538 \f
1539 ////////////////////////////////////////////////////////////////////////
1540 // Implementation of SGDistScaleAnimation
1541 ////////////////////////////////////////////////////////////////////////
1542 class SGDistScaleTransform : public osg::Transform {
1543 public:
1544   SGDistScaleTransform(SGPropertyNode* props)
1545   {
1546     getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1547
1548     _factor = props->getFloatValue("factor", 1.0);
1549     _offset = props->getFloatValue("offset", 0.0);
1550     _min_v = props->getFloatValue("min", 0.0);
1551     _max_v = props->getFloatValue("max", 1.0);
1552     _has_min = props->hasValue("min");
1553     _has_max = props->hasValue("max");
1554     _table = read_interpolation_table(props);
1555     _center[0] = props->getFloatValue("center/x-m", 0);
1556     _center[1] = props->getFloatValue("center/y-m", 0);
1557     _center[2] = props->getFloatValue("center/z-m", 0);
1558   }
1559   ~SGDistScaleTransform()
1560   {
1561   }
1562
1563   virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1564                                          osg::NodeVisitor* nv) const 
1565   {
1566     osg::Matrix transform;
1567     double scale_factor = computeScaleFactor(nv);
1568     transform(0,0) = scale_factor;
1569     transform(1,1) = scale_factor;
1570     transform(2,2) = scale_factor;
1571     transform(3,0) = _center[0] * ( 1 - scale_factor );
1572     transform(3,1) = _center[1] * ( 1 - scale_factor );
1573     transform(3,2) = _center[2] * ( 1 - scale_factor );
1574     if (_referenceFrame == RELATIVE_RF)
1575       matrix.preMult(transform);
1576     else
1577       matrix = transform;
1578     return true;
1579   }
1580   
1581   virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1582                                          osg::NodeVisitor* nv) const
1583   {
1584     double scale_factor = computeScaleFactor(nv);
1585     if (fabs(scale_factor) <= std::numeric_limits<double>::min())
1586       return false;
1587     osg::Matrix transform;
1588     double rScaleFactor = 1/scale_factor;
1589     transform(0,0) = rScaleFactor;
1590     transform(1,1) = rScaleFactor;
1591     transform(2,2) = rScaleFactor;
1592     transform(3,0) = rScaleFactor*_center[0] * ( scale_factor - 1 );
1593     transform(3,1) = rScaleFactor*_center[1] * ( scale_factor - 1 );
1594     transform(3,2) = rScaleFactor*_center[2] * ( scale_factor - 1 );
1595     if (_referenceFrame == RELATIVE_RF)
1596       matrix.postMult(transform);
1597     else
1598       matrix = transform;
1599     return true;
1600   }
1601
1602   double computeScaleFactor(osg::NodeVisitor* nv) const
1603   {
1604     if (!nv)
1605       return 1;
1606
1607     osg::Vec3 localEyeToCenter = _center - nv->getEyePoint();
1608     double scale_factor = localEyeToCenter.length();
1609     if (_table == 0) {
1610       scale_factor = _factor * scale_factor + _offset;
1611       if ( _has_min && scale_factor < _min_v )
1612         scale_factor = _min_v;
1613       if ( _has_max && scale_factor > _max_v )
1614         scale_factor = _max_v;
1615     } else {
1616       scale_factor = _table->interpolate( scale_factor );
1617     }
1618
1619     return scale_factor;
1620   }
1621
1622
1623 private:
1624   osg::Vec3 _center;
1625   float _factor, _offset, _min_v, _max_v;
1626   bool _has_min, _has_max;
1627   SGSharedPtr<SGInterpTable> _table;
1628 };
1629
1630 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1631   : SGAnimation( props, new SGDistScaleTransform(props) )
1632 {
1633 }
1634
1635 SGDistScaleAnimation::~SGDistScaleAnimation()
1636 {
1637 }
1638
1639 ////////////////////////////////////////////////////////////////////////
1640 // Implementation of SGShadowAnimation
1641 ////////////////////////////////////////////////////////////////////////
1642
1643 SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
1644                                        SGPropertyNode_ptr props )
1645   : SGAnimation(props, new osg::Group),
1646     _condition(0),
1647     _condition_value(true)
1648 {
1649     animation_type = 1;
1650     SGPropertyNode_ptr node = props->getChild("condition");
1651     if (node != 0) {
1652         _condition = sgReadCondition(prop_root, node);
1653         _condition_value = false;
1654     }
1655 }
1656
1657 SGShadowAnimation::~SGShadowAnimation ()
1658 {
1659 }
1660
1661 void
1662 SGShadowAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
1663 {
1664     if (_condition)
1665         _condition_value = _condition->test();
1666
1667     if ( _condition_value ) {
1668         _branch->setNodeMask(SG_NODEMASK_SHADOW_BIT|_branch->getNodeMask());
1669     } else {
1670         _branch->setNodeMask(~SG_NODEMASK_SHADOW_BIT&_branch->getNodeMask());
1671     }
1672     traverse(node, nv);
1673 }
1674
1675 bool SGShadowAnimation::get_condition_value(void) {
1676     return _condition_value;
1677 }
1678
1679 // end of animation.cxx