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