]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
Frederic Bouvier:
[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
7 #include <string.h>             // for strcmp()
8 #include <math.h>
9
10 #include <plib/sg.h>
11 #include <plib/ssg.h>
12 #include <plib/ul.h>
13
14 #include <simgear/math/interpolater.hxx>
15 #include <simgear/props/condition.hxx>
16 #include <simgear/props/props.hxx>
17 #include <simgear/math/sg_random.h>
18
19 #include "animation.hxx"
20 #include "custtrans.hxx"
21 #include "personality.hxx"
22
23 \f
24 ////////////////////////////////////////////////////////////////////////
25 // Static utility functions.
26 ////////////////////////////////////////////////////////////////////////
27
28 /**
29  * Set up the transform matrix for a spin or rotation.
30  */
31 static void
32 set_rotation (sgMat4 &matrix, double position_deg,
33               sgVec3 &center, sgVec3 &axis)
34 {
35  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
36  
37  float s = (float) sin ( temp_angle ) ;
38  float c = (float) cos ( temp_angle ) ;
39  float t = SG_ONE - c ;
40
41  // axis was normalized at load time 
42  // hint to the compiler to put these into FP registers
43  float x = axis[0];
44  float y = axis[1];
45  float z = axis[2];
46
47  matrix[0][0] = t * x * x + c ;
48  matrix[0][1] = t * y * x - s * z ;
49  matrix[0][2] = t * z * x + s * y ;
50  matrix[0][3] = SG_ZERO;
51  
52  matrix[1][0] = t * x * y + s * z ;
53  matrix[1][1] = t * y * y + c ;
54  matrix[1][2] = t * z * y - s * x ;
55  matrix[1][3] = SG_ZERO;
56  
57  matrix[2][0] = t * x * z - s * y ;
58  matrix[2][1] = t * y * z + s * x ;
59  matrix[2][2] = t * z * z + c ;
60  matrix[2][3] = SG_ZERO;
61
62   // hint to the compiler to put these into FP registers
63  x = center[0];
64  y = center[1];
65  z = center[2];
66  
67  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
68  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
69  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
70  matrix[3][3] = SG_ONE;
71 }
72
73 /**
74  * Set up the transform matrix for a translation.
75  */
76 static void
77 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
78 {
79   sgVec3 xyz;
80   sgScaleVec3(xyz, axis, position_m);
81   sgMakeTransMat4(matrix, xyz);
82 }
83
84 /**
85  * Set up the transform matrix for a scale operation.
86  */
87 static void
88 set_scale (sgMat4 &matrix, double x, double y, double z)
89 {
90   sgMakeIdentMat4( matrix );
91   matrix[0][0] = x;
92   matrix[1][1] = y;
93   matrix[2][2] = z;
94 }
95
96 /**
97  * Recursively process all kids to change the alpha values
98  */
99 static void
100 change_alpha( ssgBase *_branch, float _blend )
101 {
102   int i;
103
104   for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
105     change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
106
107   if ( !_branch->isAKindOf(ssgTypeLeaf())
108        && !_branch->isAKindOf(ssgTypeVtxTable())
109        && !_branch->isAKindOf(ssgTypeVTable()) )
110     return;
111
112   int num_colors = ((ssgLeaf *)_branch)->getNumColours();
113 // unsigned int select_ = (_blend == 1.0) ? false : true;
114
115   for (i = 0; i < num_colors; i++)
116   {
117 //    ((ssgSelector *)_branch)->select( select_ );
118     float *color =  ((ssgLeaf *)_branch)->getColour(i);
119     color[3] = _blend;
120   }
121 }
122
123 /**
124  * Modify property value by step and scroll settings in texture translations
125  */
126 static double
127 apply_mods(double property, double step, double scroll)
128 {
129
130   double modprop;
131   if(step > 0) {
132     double scrollval = 0.0;
133     if(scroll > 0) {
134       // calculate scroll amount (for odometer like movement)
135       double remainder  =  step - fmod(fabs(property), step);
136       if (remainder < scroll) {
137         scrollval = (scroll - remainder) / scroll * step;
138       }
139     }
140   // apply stepping of input value
141   if(property > 0) 
142      modprop = ((floor(property/step) * step) + scrollval);
143   else
144      modprop = ((ceil(property/step) * step) + scrollval);
145   } else {
146      modprop = property;
147   }
148   return modprop;
149
150 }
151
152 /**
153  * Read an interpolation table from properties.
154  */
155 static SGInterpTable *
156 read_interpolation_table (SGPropertyNode_ptr props)
157 {
158   SGPropertyNode_ptr table_node = props->getNode("interpolation");
159   if (table_node != 0) {
160     SGInterpTable * table = new SGInterpTable();
161     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
162     for (unsigned int i = 0; i < entries.size(); i++)
163       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
164                       entries[i]->getDoubleValue("dep", 0.0));
165     return table;
166   } else {
167     return 0;
168   }
169 }
170
171
172 \f
173 ////////////////////////////////////////////////////////////////////////
174 // Implementation of SGAnimation
175 ////////////////////////////////////////////////////////////////////////
176
177 // Initialize the static data member
178 double SGAnimation::sim_time_sec = 0.0;
179 SGPersonalityBranch *SGAnimation::current_object = 0;
180
181 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
182     : _branch(branch)
183 {
184     _branch->setName(props->getStringValue("name", 0));
185     if ( props->getBoolValue( "enable-hot", true ) ) {
186         _branch->setTraversalMaskBits( SSGTRAV_HOT );
187     } else {
188         _branch->clrTraversalMaskBits( SSGTRAV_HOT );
189     }
190 }
191
192 SGAnimation::~SGAnimation ()
193 {
194 }
195
196 void
197 SGAnimation::init ()
198 {
199 }
200
201 int
202 SGAnimation::update()
203 {
204     return 1;
205 }
206
207 void
208 SGAnimation::restore()
209 {
210 }
211
212
213 \f
214 ////////////////////////////////////////////////////////////////////////
215 // Implementation of SGNullAnimation
216 ////////////////////////////////////////////////////////////////////////
217
218 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
219   : SGAnimation(props, new ssgBranch)
220 {
221 }
222
223 SGNullAnimation::~SGNullAnimation ()
224 {
225 }
226
227
228 \f
229 ////////////////////////////////////////////////////////////////////////
230 // Implementation of SGRangeAnimation
231 ////////////////////////////////////////////////////////////////////////
232
233 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
234                                     SGPropertyNode_ptr props)
235   : SGAnimation(props, new ssgRangeSelector),
236     _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
237     _condition(0)
238 {
239     SGPropertyNode_ptr node = props->getChild("condition");
240     if (node != 0)
241        _condition = sgReadCondition(prop_root, node);
242
243     float ranges[2];
244
245     node = props->getChild( "min-factor" );
246     if (node != 0) {
247        _min_factor = props->getFloatValue("min-factor", 1.0);
248     }
249     node = props->getChild( "max-factor" );
250     if (node != 0) {
251        _max_factor = props->getFloatValue("max-factor", 1.0);
252     }
253     node = props->getChild( "min-property" );
254     if (node != 0) {
255        _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
256        ranges[0] = _min_prop->getFloatValue() * _min_factor;
257     } else {
258        _min = props->getFloatValue("min-m", 0);
259        ranges[0] = _min * _min_factor;
260     }
261     node = props->getChild( "max-property" );
262     if (node != 0) {
263        _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
264        ranges[1] = _max_prop->getFloatValue() * _max_factor;
265     } else {
266        _max = props->getFloatValue("max-m", 0);
267        ranges[1] = _max * _max_factor;
268     }
269     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
270 }
271
272 SGRangeAnimation::~SGRangeAnimation ()
273 {
274 }
275
276 int
277 SGRangeAnimation::update()
278 {
279   float ranges[2];
280   if ( _condition == 0 || _condition->test() ) {
281     if (_min_prop != 0) {
282       ranges[0] = _min_prop->getFloatValue() * _min_factor;
283     } else {
284       ranges[0] = _min * _min_factor;
285     }
286     if (_max_prop != 0) {
287       ranges[1] = _max_prop->getFloatValue() * _max_factor;
288     } else {
289       ranges[1] = _max * _max_factor;
290     }
291   } else {
292     ranges[0] = 0.f;
293     ranges[1] = 1000000000.f;
294   }
295   ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
296   return 1;
297 }
298
299
300 \f
301 ////////////////////////////////////////////////////////////////////////
302 // Implementation of SGBillboardAnimation
303 ////////////////////////////////////////////////////////////////////////
304
305 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
306     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
307 {
308 }
309
310 SGBillboardAnimation::~SGBillboardAnimation ()
311 {
312 }
313
314
315 \f
316 ////////////////////////////////////////////////////////////////////////
317 // Implementation of SGSelectAnimation
318 ////////////////////////////////////////////////////////////////////////
319
320 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
321                                   SGPropertyNode_ptr props )
322   : SGAnimation(props, new ssgSelector),
323     _condition(0)
324 {
325   SGPropertyNode_ptr node = props->getChild("condition");
326   if (node != 0)
327     _condition = sgReadCondition(prop_root, node);
328 }
329
330 SGSelectAnimation::~SGSelectAnimation ()
331 {
332   delete _condition;
333 }
334
335 int
336 SGSelectAnimation::update()
337 {
338   if (_condition != 0 && _condition->test()) 
339       ((ssgSelector *)_branch)->select(0xffff);
340   else
341       ((ssgSelector *)_branch)->select(0x0000);
342   return 1;
343 }
344
345
346 \f
347 ////////////////////////////////////////////////////////////////////////
348 // Implementation of SGSpinAnimation
349 ////////////////////////////////////////////////////////////////////////
350
351 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
352                               SGPropertyNode_ptr props,
353                               double sim_time_sec )
354   : SGAnimation(props, new ssgTransform),
355     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
356     _factor(props->getDoubleValue("factor", 1.0)),
357     _position_deg(props->getDoubleValue("starting-position-deg", 0)),
358     _last_time_sec( sim_time_sec ),
359     _condition(0)
360 {
361     SGPropertyNode_ptr node = props->getChild("condition");
362     if (node != 0)
363         _condition = sgReadCondition(prop_root, node);
364
365     _center[0] = 0;
366     _center[1] = 0;
367     _center[2] = 0;
368     if (props->hasValue("axis/x1-m")) {
369         double x1,y1,z1,x2,y2,z2;
370         x1 = props->getFloatValue("axis/x1-m");
371         y1 = props->getFloatValue("axis/y1-m");
372         z1 = props->getFloatValue("axis/z1-m");
373         x2 = props->getFloatValue("axis/x2-m");
374         y2 = props->getFloatValue("axis/y2-m");
375         z2 = props->getFloatValue("axis/z2-m");
376         _center[0] = (x1+x2)/2;
377         _center[1]= (y1+y2)/2;
378         _center[2] = (z1+z2)/2;
379         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
380         _axis[0] = (x2-x1)/vector_length;
381         _axis[1] = (y2-y1)/vector_length;
382         _axis[2] = (z2-z1)/vector_length;
383     } else {
384        _axis[0] = props->getFloatValue("axis/x", 0);
385        _axis[1] = props->getFloatValue("axis/y", 0);
386        _axis[2] = props->getFloatValue("axis/z", 0);
387     }
388     if (props->hasValue("center/x-m")) {
389        _center[0] = props->getFloatValue("center/x-m", 0);
390        _center[1] = props->getFloatValue("center/y-m", 0);
391        _center[2] = props->getFloatValue("center/z-m", 0);
392     }
393     sgNormalizeVec3(_axis);
394 }
395
396 SGSpinAnimation::~SGSpinAnimation ()
397 {
398 }
399
400 int
401 SGSpinAnimation::update()
402 {
403   if ( _condition == 0 || _condition->test() ) {
404     double dt = sim_time_sec - _last_time_sec;
405     _last_time_sec = sim_time_sec;
406
407     float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
408     _position_deg += (dt * velocity_rpms * 360);
409     while (_position_deg < 0)
410         _position_deg += 360.0;
411     while (_position_deg >= 360.0)
412         _position_deg -= 360.0;
413     set_rotation(_matrix, _position_deg, _center, _axis);
414     ((ssgTransform *)_branch)->setTransform(_matrix);
415   }
416   return 1;
417 }
418
419
420 \f
421 ////////////////////////////////////////////////////////////////////////
422 // Implementation of SGTimedAnimation
423 ////////////////////////////////////////////////////////////////////////
424
425 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
426   : SGAnimation(props, new ssgSelector),
427     _use_personality( props->getBoolValue("use-personality",false) ),
428     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
429     _last_time_sec( sim_time_sec ),
430     _total_duration_sec( 0 ),
431     _step( 0 )
432     
433 {
434     vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
435     size_t nb = nodes.size();
436     for ( size_t i = 0; i < nb; i++ ) {
437         size_t ind = nodes[ i ]->getIndex();
438         while ( ind >= _branch_duration_specs.size() ) {
439             _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
440         }
441         SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
442         if ( rNode == 0 ) {
443             _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
444         } else {
445             _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
446                                                           rNode->getDoubleValue( "max", 1.0 ) );
447         }
448     }
449 }
450
451 SGTimedAnimation::~SGTimedAnimation ()
452 {
453 }
454
455 void
456 SGTimedAnimation::init()
457 {
458     if ( !_use_personality ) {
459         for ( size_t i = 0; i < getBranch()->getNumKids(); i++ ) {
460             double v;
461             if ( i < _branch_duration_specs.size() ) {
462                 DurationSpec &sp = _branch_duration_specs[ i ];
463                 v = sp._min + sg_random() * ( sp._max - sp._min );
464             } else {
465                 v = _duration_sec;
466             }
467             _branch_duration_sec.push_back( v );
468             _total_duration_sec += v;
469         }
470         // Sanity check : total duration shouldn't equal zero
471         if ( _total_duration_sec < 0.01 ) {
472             _total_duration_sec = 0.01;
473         }
474     }
475     ((ssgSelector *)getBranch())->selectStep(_step);
476 }
477
478 int
479 SGTimedAnimation::update()
480 {
481     if ( _use_personality ) {
482         SGPersonalityBranch *key = current_object;
483         if ( !key->getIntValue( this, INIT ) ) {
484             double total = 0;
485             double offset = 1.0;
486             for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
487                 DurationSpec &sp = _branch_duration_specs[ i ];
488                 double v = sp._min + sg_random() * ( sp._max - sp._min );
489                 key->setDoubleValue( v, this, BRANCH_DURATION_SEC, i );
490                 if ( i == 0 )
491                     offset = v;
492                 total += v;
493             }
494             // Sanity check : total duration shouldn't equal zero
495             if ( total < 0.01 ) {
496                 total = 0.01;
497             }
498             offset *= sg_random();
499             key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC );
500             key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
501             key->setIntValue( 0, this, STEP );
502             key->setIntValue( 1, this, INIT );
503         }
504
505         _step = key->getIntValue( this, STEP );
506         _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
507         _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
508         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
509             _last_time_sec += _total_duration_sec;
510         }
511         double duration = _duration_sec;
512         if ( _step < (int)_branch_duration_specs.size() ) {
513             duration = key->getDoubleValue( this, BRANCH_DURATION_SEC, _step );
514         }
515         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
516             _last_time_sec += duration;
517             _step += 1;
518             if ( _step >= getBranch()->getNumKids() )
519                 _step = 0;
520         }
521         ((ssgSelector *)getBranch())->selectStep( _step );
522         key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC );
523         key->setIntValue( _step, this, STEP );
524     } else {
525         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
526             _last_time_sec += _total_duration_sec;
527         }
528         double duration = _duration_sec;
529         if ( _step < (int)_branch_duration_sec.size() ) {
530             duration = _branch_duration_sec[ _step ];
531         }
532         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
533             _last_time_sec += duration;
534             _step += 1;
535             if ( _step >= getBranch()->getNumKids() )
536                 _step = 0;
537             ((ssgSelector *)getBranch())->selectStep( _step );
538         }
539     }
540     return 1;
541 }
542
543
544 \f
545 ////////////////////////////////////////////////////////////////////////
546 // Implementation of SGRotateAnimation
547 ////////////////////////////////////////////////////////////////////////
548
549 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
550                                   SGPropertyNode_ptr props )
551     : SGAnimation(props, new ssgTransform),
552       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
553       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
554       _factor(props->getDoubleValue("factor", 1.0)),
555       _table(read_interpolation_table(props)),
556       _has_min(props->hasValue("min-deg")),
557       _min_deg(props->getDoubleValue("min-deg")),
558       _has_max(props->hasValue("max-deg")),
559       _max_deg(props->getDoubleValue("max-deg")),
560       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
561       _condition(0)
562 {
563     SGPropertyNode_ptr node = props->getChild("condition");
564     if (node != 0)
565       _condition = sgReadCondition(prop_root, node);
566
567     _center[0] = 0;
568     _center[1] = 0;
569     _center[2] = 0;
570     if (props->hasValue("axis/x1-m")) {
571         double x1,y1,z1,x2,y2,z2;
572         x1 = props->getFloatValue("axis/x1-m");
573         y1 = props->getFloatValue("axis/y1-m");
574         z1 = props->getFloatValue("axis/z1-m");
575         x2 = props->getFloatValue("axis/x2-m");
576         y2 = props->getFloatValue("axis/y2-m");
577         z2 = props->getFloatValue("axis/z2-m");
578         _center[0] = (x1+x2)/2;
579         _center[1]= (y1+y2)/2;
580         _center[2] = (z1+z2)/2;
581         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
582         _axis[0] = (x2-x1)/vector_length;
583         _axis[1] = (y2-y1)/vector_length;
584         _axis[2] = (z2-z1)/vector_length;
585     } else {
586        _axis[0] = props->getFloatValue("axis/x", 0);
587        _axis[1] = props->getFloatValue("axis/y", 0);
588        _axis[2] = props->getFloatValue("axis/z", 0);
589     }
590     if (props->hasValue("center/x-m")) {
591        _center[0] = props->getFloatValue("center/x-m", 0);
592        _center[1] = props->getFloatValue("center/y-m", 0);
593        _center[2] = props->getFloatValue("center/z-m", 0);
594     }
595     sgNormalizeVec3(_axis);
596 }
597
598 SGRotateAnimation::~SGRotateAnimation ()
599 {
600   delete _table;
601 }
602
603 int
604 SGRotateAnimation::update()
605 {
606   if (_condition == 0 || _condition->test()) {
607     if (_table == 0) {
608       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
609       if (_has_min && _position_deg < _min_deg)
610         _position_deg = _min_deg;
611       if (_has_max && _position_deg > _max_deg)
612         _position_deg = _max_deg;
613     } else {
614       _position_deg = _table->interpolate(_prop->getDoubleValue());
615     }
616     set_rotation(_matrix, _position_deg, _center, _axis);
617     ((ssgTransform *)_branch)->setTransform(_matrix);
618   }
619   return 1;
620 }
621
622 \f
623 ////////////////////////////////////////////////////////////////////////
624 // Implementation of SGBlendAnimation
625 ////////////////////////////////////////////////////////////////////////
626
627 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
628                                         SGPropertyNode_ptr props )
629   : SGAnimation(props, new ssgTransform),
630     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
631     _table(read_interpolation_table(props)),
632     _prev_value(1.0),
633     _offset(props->getDoubleValue("offset", 0.0)),
634     _factor(props->getDoubleValue("factor", 1.0)),
635     _has_min(props->hasValue("min")),
636     _min(props->getDoubleValue("min", 0.0)),
637     _has_max(props->hasValue("max")),
638     _max(props->getDoubleValue("max", 1.0))
639 {
640 }
641
642 SGBlendAnimation::~SGBlendAnimation ()
643 {
644     delete _table;
645 }
646
647 int
648 SGBlendAnimation::update()
649 {
650   double _blend;
651
652   if (_table == 0) {
653     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
654
655     if (_has_min && (_blend < _min))
656       _blend = _min;
657     if (_has_max && (_blend > _max))
658       _blend = _max;
659   } else {
660     _blend = _table->interpolate(_prop->getDoubleValue());
661   }
662
663   if (_blend != _prev_value) {
664     _prev_value = _blend;
665     change_alpha( _branch, _blend );
666   }
667   return 1;
668 }
669
670
671 \f
672 ////////////////////////////////////////////////////////////////////////
673 // Implementation of SGTranslateAnimation
674 ////////////////////////////////////////////////////////////////////////
675
676 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
677                                         SGPropertyNode_ptr props )
678   : SGAnimation(props, new ssgTransform),
679       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
680     _offset_m(props->getDoubleValue("offset-m", 0.0)),
681     _factor(props->getDoubleValue("factor", 1.0)),
682     _table(read_interpolation_table(props)),
683     _has_min(props->hasValue("min-m")),
684     _min_m(props->getDoubleValue("min-m")),
685     _has_max(props->hasValue("max-m")),
686     _max_m(props->getDoubleValue("max-m")),
687     _position_m(props->getDoubleValue("starting-position-m", 0)),
688     _condition(0)
689 {
690   SGPropertyNode_ptr node = props->getChild("condition");
691   if (node != 0)
692     _condition = sgReadCondition(prop_root, node);
693
694   _axis[0] = props->getFloatValue("axis/x", 0);
695   _axis[1] = props->getFloatValue("axis/y", 0);
696   _axis[2] = props->getFloatValue("axis/z", 0);
697   sgNormalizeVec3(_axis);
698 }
699
700 SGTranslateAnimation::~SGTranslateAnimation ()
701 {
702   delete _table;
703 }
704
705 int
706 SGTranslateAnimation::update()
707 {
708   if (_condition == 0 || _condition->test()) {
709     if (_table == 0) {
710       _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
711       if (_has_min && _position_m < _min_m)
712         _position_m = _min_m;
713       if (_has_max && _position_m > _max_m)
714         _position_m = _max_m;
715     } else {
716       _position_m = _table->interpolate(_prop->getDoubleValue());
717     }
718     set_translation(_matrix, _position_m, _axis);
719     ((ssgTransform *)_branch)->setTransform(_matrix);
720   }
721   return 1;
722 }
723
724
725 \f
726 ////////////////////////////////////////////////////////////////////////
727 // Implementation of SGScaleAnimation
728 ////////////////////////////////////////////////////////////////////////
729
730 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
731                                         SGPropertyNode_ptr props )
732   : SGAnimation(props, new ssgTransform),
733       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
734     _x_factor(props->getDoubleValue("x-factor", 1.0)),
735     _y_factor(props->getDoubleValue("y-factor", 1.0)),
736     _z_factor(props->getDoubleValue("z-factor", 1.0)),
737     _x_offset(props->getDoubleValue("x-offset", 1.0)),
738     _y_offset(props->getDoubleValue("y-offset", 1.0)),
739     _z_offset(props->getDoubleValue("z-offset", 1.0)),
740     _table(read_interpolation_table(props)),
741     _has_min_x(props->hasValue("x-min")),
742     _has_min_y(props->hasValue("y-min")),
743     _has_min_z(props->hasValue("z-min")),
744     _min_x(props->getDoubleValue("x-min")),
745     _min_y(props->getDoubleValue("y-min")),
746     _min_z(props->getDoubleValue("z-min")),
747     _has_max_x(props->hasValue("x-max")),
748     _has_max_y(props->hasValue("y-max")),
749     _has_max_z(props->hasValue("z-max")),
750     _max_x(props->getDoubleValue("x-max")),
751     _max_y(props->getDoubleValue("y-max")),
752     _max_z(props->getDoubleValue("z-max"))
753 {
754 }
755
756 SGScaleAnimation::~SGScaleAnimation ()
757 {
758   delete _table;
759 }
760
761 int
762 SGScaleAnimation::update()
763 {
764   if (_table == 0) {
765       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
766     if (_has_min_x && _x_scale < _min_x)
767       _x_scale = _min_x;
768     if (_has_max_x && _x_scale > _max_x)
769       _x_scale = _max_x;
770   } else {
771     _x_scale = _table->interpolate(_prop->getDoubleValue());
772   }
773
774   if (_table == 0) {
775     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
776     if (_has_min_y && _y_scale < _min_y)
777       _y_scale = _min_y;
778     if (_has_max_y && _y_scale > _max_y)
779       _y_scale = _max_y;
780   } else {
781     _y_scale = _table->interpolate(_prop->getDoubleValue());
782   }
783
784   if (_table == 0) {
785     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
786     if (_has_min_z && _z_scale < _min_z)
787       _z_scale = _min_z;
788     if (_has_max_z && _z_scale > _max_z)
789       _z_scale = _max_z;
790   } else {
791     _z_scale = _table->interpolate(_prop->getDoubleValue());
792   }
793
794   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
795   ((ssgTransform *)_branch)->setTransform(_matrix);
796   return 1;
797 }
798
799
800 ////////////////////////////////////////////////////////////////////////
801 // Implementation of SGTexRotateAnimation
802 ////////////////////////////////////////////////////////////////////////
803
804 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
805                                   SGPropertyNode_ptr props )
806     : SGAnimation(props, new ssgTexTrans),
807       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
808       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
809       _factor(props->getDoubleValue("factor", 1.0)),
810       _table(read_interpolation_table(props)),
811       _has_min(props->hasValue("min-deg")),
812       _min_deg(props->getDoubleValue("min-deg")),
813       _has_max(props->hasValue("max-deg")),
814       _max_deg(props->getDoubleValue("max-deg")),
815       _position_deg(props->getDoubleValue("starting-position-deg", 0))
816 {
817   _center[0] = props->getFloatValue("center/x", 0);
818   _center[1] = props->getFloatValue("center/y", 0);
819   _center[2] = props->getFloatValue("center/z", 0);
820   _axis[0] = props->getFloatValue("axis/x", 0);
821   _axis[1] = props->getFloatValue("axis/y", 0);
822   _axis[2] = props->getFloatValue("axis/z", 0);
823   sgNormalizeVec3(_axis);
824 }
825
826 SGTexRotateAnimation::~SGTexRotateAnimation ()
827 {
828   delete _table;
829 }
830
831 int
832 SGTexRotateAnimation::update()
833 {
834   if (_table == 0) {
835    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
836    if (_has_min && _position_deg < _min_deg)
837      _position_deg = _min_deg;
838    if (_has_max && _position_deg > _max_deg)
839      _position_deg = _max_deg;
840   } else {
841     _position_deg = _table->interpolate(_prop->getDoubleValue());
842   }
843   set_rotation(_matrix, _position_deg, _center, _axis);
844   ((ssgTexTrans *)_branch)->setTransform(_matrix);
845   return 1;
846 }
847
848
849 ////////////////////////////////////////////////////////////////////////
850 // Implementation of SGTexTranslateAnimation
851 ////////////////////////////////////////////////////////////////////////
852
853 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
854                                         SGPropertyNode_ptr props )
855   : SGAnimation(props, new ssgTexTrans),
856       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
857     _offset(props->getDoubleValue("offset", 0.0)),
858     _factor(props->getDoubleValue("factor", 1.0)),
859     _step(props->getDoubleValue("step",0.0)),
860     _scroll(props->getDoubleValue("scroll",0.0)),
861     _table(read_interpolation_table(props)),
862     _has_min(props->hasValue("min")),
863     _min(props->getDoubleValue("min")),
864     _has_max(props->hasValue("max")),
865     _max(props->getDoubleValue("max")),
866     _position(props->getDoubleValue("starting-position", 0))
867 {
868   _axis[0] = props->getFloatValue("axis/x", 0);
869   _axis[1] = props->getFloatValue("axis/y", 0);
870   _axis[2] = props->getFloatValue("axis/z", 0);
871   sgNormalizeVec3(_axis);
872 }
873
874 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
875 {
876   delete _table;
877 }
878
879 int
880 SGTexTranslateAnimation::update()
881 {
882   if (_table == 0) {
883     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
884     if (_has_min && _position < _min)
885       _position = _min;
886     if (_has_max && _position > _max)
887       _position = _max;
888   } else {
889     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
890   }
891   set_translation(_matrix, _position, _axis);
892   ((ssgTexTrans *)_branch)->setTransform(_matrix);
893   return 1;
894 }
895
896
897 ////////////////////////////////////////////////////////////////////////
898 // Implementation of SGTexMultipleAnimation
899 ////////////////////////////////////////////////////////////////////////
900
901 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
902                                         SGPropertyNode_ptr props )
903   : SGAnimation(props, new ssgTexTrans),
904       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
905 {
906   unsigned int i;
907   // Load animations
908   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
909   _transform = new TexTransform [transform_nodes.size()];
910   _num_transforms = 0;
911   for (i = 0; i < transform_nodes.size(); i++) {
912     SGPropertyNode_ptr transform_props = transform_nodes[i];
913
914     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
915
916       // transform is a translation
917       _transform[i].subtype = 0;
918
919       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
920
921       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
922       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
923       _transform[i].step = transform_props->getDoubleValue("step",0.0);
924       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
925       _transform[i].table = read_interpolation_table(transform_props);
926       _transform[i].has_min = transform_props->hasValue("min");
927       _transform[i].min = transform_props->getDoubleValue("min");
928       _transform[i].has_max = transform_props->hasValue("max");
929       _transform[i].max = transform_props->getDoubleValue("max");
930       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
931
932       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
933       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
934       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
935       sgNormalizeVec3(_transform[i].axis);
936       _num_transforms++;
937     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
938
939       // transform is a rotation
940       _transform[i].subtype = 1;
941
942       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
943       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
944       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
945       _transform[i].table = read_interpolation_table(transform_props);
946       _transform[i].has_min = transform_props->hasValue("min-deg");
947       _transform[i].min = transform_props->getDoubleValue("min-deg");
948       _transform[i].has_max = transform_props->hasValue("max-deg");
949       _transform[i].max = transform_props->getDoubleValue("max-deg");
950       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
951
952       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
953       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
954       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
955       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
956       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
957       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
958       sgNormalizeVec3(_transform[i].axis);
959       _num_transforms++;
960     }
961   }
962 }
963
964 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
965 {
966   // delete _table;
967   delete _transform;
968 }
969
970 int
971 SGTexMultipleAnimation::update()
972 {
973   int i;
974   sgMat4 tmatrix;
975   sgMakeIdentMat4(tmatrix);
976   for (i = 0; i < _num_transforms; i++) {
977
978     if(_transform[i].subtype == 0) {
979
980       // subtype 0 is translation
981       if (_transform[i].table == 0) {
982         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
983         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
984           _transform[i].position = _transform[i].min;
985         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
986           _transform[i].position = _transform[i].max;
987       } else {
988          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
989       }
990       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
991       sgPreMultMat4(tmatrix, _transform[i].matrix);
992
993     } else if (_transform[i].subtype == 1) {
994
995       // subtype 1 is rotation
996
997       if (_transform[i].table == 0) {
998         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
999         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1000          _transform[i].position = _transform[i].min;
1001        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1002          _transform[i].position = _transform[i].max;
1003      } else {
1004         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1005       }
1006       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1007       sgPreMultMat4(tmatrix, _transform[i].matrix);
1008     }
1009   }
1010   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
1011   return 1;
1012 }
1013
1014
1015 \f
1016 ////////////////////////////////////////////////////////////////////////
1017 // Implementation of SGAlphaTestAnimation
1018 ////////////////////////////////////////////////////////////////////////
1019
1020 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1021   : SGAnimation(props, new ssgBranch)
1022 {
1023   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1024 }
1025
1026 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1027 {
1028 }
1029
1030 void SGAlphaTestAnimation::init()
1031 {
1032   setAlphaClampToBranch(_branch,_alpha_clamp);
1033 }
1034
1035 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
1036 {
1037   int nb = b->getNumKids();
1038   for (int i = 0; i<nb; i++) {
1039     ssgEntity *e = b->getKid(i);
1040     if (e->isAKindOf(ssgTypeLeaf())) {
1041       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1042       s->enable( GL_ALPHA_TEST );
1043       s->setAlphaClamp( clamp );
1044     } else if (e->isAKindOf(ssgTypeBranch())) {
1045       setAlphaClampToBranch( (ssgBranch*)e, clamp );
1046     }
1047   }
1048 }
1049
1050
1051 \f
1052 ////////////////////////////////////////////////////////////////////////
1053 // Implementation of SGFlashAnimation
1054 ////////////////////////////////////////////////////////////////////////
1055 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1056   : SGAnimation( props, new SGCustomTransform )
1057 {
1058   _axis[0] = props->getFloatValue("axis/x", 0);
1059   _axis[1] = props->getFloatValue("axis/y", 0);
1060   _axis[2] = props->getFloatValue("axis/z", 1);
1061
1062   _center[0] = props->getFloatValue("center/x-m", 0);
1063   _center[1] = props->getFloatValue("center/y-m", 0);
1064   _center[2] = props->getFloatValue("center/z-m", 0);
1065
1066   _offset = props->getFloatValue("offset", 0.0);
1067   _factor = props->getFloatValue("factor", 1.0);
1068   _power = props->getFloatValue("power", 1.0);
1069   _two_sides = props->getBoolValue("two-sides", false);
1070
1071   _min_v = props->getFloatValue("min", 0.0);
1072   _max_v = props->getFloatValue("max", 1.0);
1073
1074   ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
1075 }
1076
1077 SGFlashAnimation::~SGFlashAnimation()
1078 {
1079 }
1080
1081 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1082 {
1083   ((SGFlashAnimation *)d)->flashCallback( r, f, m );
1084 }
1085
1086 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1087 {
1088   sgVec3 transformed_axis;
1089   sgXformVec3( transformed_axis, _axis, m );
1090   sgNormalizeVec3( transformed_axis );
1091
1092   sgVec3 view;
1093   sgFullXformPnt3( view, _center, m );
1094   sgNormalizeVec3( view );
1095
1096   float cos_angle = -sgScalarProductVec3( transformed_axis, view );
1097   float scale_factor = 0.f;
1098   if ( _two_sides && cos_angle < 0 )
1099     scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
1100   else if ( cos_angle > 0 )
1101     scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
1102
1103   if ( scale_factor < _min_v )
1104       scale_factor = _min_v;
1105   if ( scale_factor > _max_v )
1106       scale_factor = _max_v;
1107
1108   sgMat4 transform;
1109   sgMakeIdentMat4( transform );
1110   transform[0][0] = scale_factor;
1111   transform[1][1] = scale_factor;
1112   transform[2][2] = scale_factor;
1113   transform[3][0] = _center[0] * ( 1 - scale_factor );
1114   transform[3][1] = _center[1] * ( 1 - scale_factor );
1115   transform[3][2] = _center[2] * ( 1 - scale_factor );
1116
1117   sgCopyMat4( r, m );
1118   sgPreMultMat4( r, transform );
1119 }
1120
1121
1122 \f
1123 ////////////////////////////////////////////////////////////////////////
1124 // Implementation of SGDistScaleAnimation
1125 ////////////////////////////////////////////////////////////////////////
1126 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1127   : SGAnimation( props, new SGCustomTransform ),
1128     _factor(props->getFloatValue("factor", 1.0)),
1129     _offset(props->getFloatValue("offset", 0.0)),
1130     _min_v(props->getFloatValue("min", 0.0)),
1131     _max_v(props->getFloatValue("max", 1.0)),
1132     _has_min(props->hasValue("min")),
1133     _has_max(props->hasValue("max")),
1134     _table(read_interpolation_table(props))
1135 {
1136   _center[0] = props->getFloatValue("center/x-m", 0);
1137   _center[1] = props->getFloatValue("center/y-m", 0);
1138   _center[2] = props->getFloatValue("center/z-m", 0);
1139
1140   ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
1141 }
1142
1143 SGDistScaleAnimation::~SGDistScaleAnimation()
1144 {
1145 }
1146
1147 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1148 {
1149   ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
1150 }
1151
1152 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1153 {
1154   sgVec3 view;
1155   sgFullXformPnt3( view, _center, m );
1156
1157   float scale_factor = sgLengthVec3( view );
1158   if (_table == 0) {
1159     scale_factor = _factor * scale_factor + _offset;
1160     if ( _has_min && scale_factor < _min_v )
1161       scale_factor = _min_v;
1162     if ( _has_max && scale_factor > _max_v )
1163       scale_factor = _max_v;
1164   } else {
1165     scale_factor = _table->interpolate( scale_factor );
1166   }
1167
1168   sgMat4 transform;
1169   sgMakeIdentMat4( transform );
1170   transform[0][0] = scale_factor;
1171   transform[1][1] = scale_factor;
1172   transform[2][2] = scale_factor;
1173   transform[3][0] = _center[0] * ( 1 - scale_factor );
1174   transform[3][1] = _center[1] * ( 1 - scale_factor );
1175   transform[3][2] = _center[2] * ( 1 - scale_factor );
1176
1177   sgCopyMat4( r, m );
1178   sgPreMultMat4( r, transform );
1179 }
1180
1181 // end of animation.cxx