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