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