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