]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
30e5d16af523b33e0fd994af4c5afe06938150d9
[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
18 #include "animation.hxx"
19
20
21 \f
22 ////////////////////////////////////////////////////////////////////////
23 // Static utility functions.
24 ////////////////////////////////////////////////////////////////////////
25
26 /**
27  * Set up the transform matrix for a spin or rotation.
28  */
29 static void
30 set_rotation (sgMat4 &matrix, double position_deg,
31               sgVec3 &center, sgVec3 &axis)
32 {
33  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
34  
35  float s = (float) sin ( temp_angle ) ;
36  float c = (float) cos ( temp_angle ) ;
37  float t = SG_ONE - c ;
38
39  // axis was normalized at load time 
40  // hint to the compiler to put these into FP registers
41  float x = axis[0];
42  float y = axis[1];
43  float z = axis[2];
44
45  matrix[0][0] = t * x * x + c ;
46  matrix[0][1] = t * y * x - s * z ;
47  matrix[0][2] = t * z * x + s * y ;
48  matrix[0][3] = SG_ZERO;
49  
50  matrix[1][0] = t * x * y + s * z ;
51  matrix[1][1] = t * y * y + c ;
52  matrix[1][2] = t * z * y - s * x ;
53  matrix[1][3] = SG_ZERO;
54  
55  matrix[2][0] = t * x * z - s * y ;
56  matrix[2][1] = t * y * z + s * x ;
57  matrix[2][2] = t * z * z + c ;
58  matrix[2][3] = SG_ZERO;
59
60   // hint to the compiler to put these into FP registers
61  x = center[0];
62  y = center[1];
63  z = center[2];
64  
65  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
66  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
67  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
68  matrix[3][3] = SG_ONE;
69 }
70
71 /**
72  * Set up the transform matrix for a translation.
73  */
74 static void
75 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
76 {
77   sgVec3 xyz;
78   sgScaleVec3(xyz, axis, position_m);
79   sgMakeTransMat4(matrix, xyz);
80 }
81
82 /**
83  * Set up the transform matrix for a scale operation.
84  */
85 static void
86 set_scale (sgMat4 &matrix, double x, double y, double z)
87 {
88   sgMakeIdentMat4( matrix );
89   matrix[0][0] = x;
90   matrix[1][1] = y;
91   matrix[2][2] = z;
92 }
93
94 /**
95  * Recursively process all kids to change the alpha values
96  */
97 static void
98 change_alpha( ssgBase *_branch, float _blend )
99 {
100   int i;
101
102   for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
103     change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
104
105   if ( !_branch->isAKindOf(ssgTypeLeaf())
106        && !_branch->isAKindOf(ssgTypeVtxTable())
107        && !_branch->isAKindOf(ssgTypeVTable()) )
108     return;
109
110   int num_colors = ((ssgLeaf *)_branch)->getNumColours();
111
112   for (i = 0; i < num_colors; i++)
113   {
114     float *color =  ((ssgLeaf *)_branch)->getColour(i);
115     color[3] = _blend;
116   }
117 }
118
119 /**
120  * Modify property value by step and scroll settings in texture translations
121  */
122 static double
123 apply_mods(double property, double step, double scroll)
124 {
125
126   double modprop;
127   if(step > 0) {
128     double scrollval = 0.0;
129     if(scroll > 0) {
130       // calculate scroll amount (for odometer like movement)
131       double remainder  =  step - fmod(fabs(property), step);
132       if (remainder < scroll) {
133         scrollval = (scroll - remainder) / scroll * step;
134       }
135     }
136   // apply stepping of input value
137   if(property > 0) 
138      modprop = ((floor(property/step) * step) + scrollval);
139   else
140      modprop = ((ceil(property/step) * step) + scrollval);
141   } else {
142      modprop = property;
143   }
144   return modprop;
145
146 }
147
148 /**
149  * Read an interpolation table from properties.
150  */
151 static SGInterpTable *
152 read_interpolation_table (SGPropertyNode_ptr props)
153 {
154   SGPropertyNode_ptr table_node = props->getNode("interpolation");
155   if (table_node != 0) {
156     SGInterpTable * table = new SGInterpTable();
157     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
158     for (unsigned int i = 0; i < entries.size(); i++)
159       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
160                       entries[i]->getDoubleValue("dep", 0.0));
161     return table;
162   } else {
163     return 0;
164   }
165 }
166
167
168 \f
169 ////////////////////////////////////////////////////////////////////////
170 // Implementation of SGAnimation
171 ////////////////////////////////////////////////////////////////////////
172
173 // Initialize the static data member
174 double SGAnimation::sim_time_sec = 0.0;
175
176 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
177     : _branch(branch)
178 {
179     _branch->setName(props->getStringValue("name", 0));
180 }
181
182 SGAnimation::~SGAnimation ()
183 {
184 }
185
186 void
187 SGAnimation::init ()
188 {
189 }
190
191 void
192 SGAnimation::update()
193 {
194 }
195
196
197 \f
198 ////////////////////////////////////////////////////////////////////////
199 // Implementation of SGNullAnimation
200 ////////////////////////////////////////////////////////////////////////
201
202 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
203   : SGAnimation(props, new ssgBranch)
204 {
205 }
206
207 SGNullAnimation::~SGNullAnimation ()
208 {
209 }
210
211
212 \f
213 ////////////////////////////////////////////////////////////////////////
214 // Implementation of SGRangeAnimation
215 ////////////////////////////////////////////////////////////////////////
216
217 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
218                                     SGPropertyNode_ptr props)
219   : SGAnimation(props, new ssgRangeSelector),
220     _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0)
221
222 {
223     float ranges[2];
224
225     SGPropertyNode_ptr node = props->getChild( "min-factor" );
226     if (node != 0) {
227        _min_factor = props->getFloatValue("min-factor", 1.0);
228     }
229     node = props->getChild( "max-factor" );
230     if (node != 0) {
231        _max_factor = props->getFloatValue("max-factor", 1.0);
232     }
233     node = props->getChild( "min-property" );
234     if (node != 0) {
235        _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
236        ranges[0] = _min_prop->getFloatValue() * _min_factor;
237     } else {
238        _min = props->getFloatValue("min-m", 0);
239        ranges[0] = _min * _min_factor;
240     }
241     node = props->getChild( "max-property" );
242     if (node != 0) {
243        _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
244        ranges[1] = _max_prop->getFloatValue() * _max_factor;
245     } else {
246        _max = props->getFloatValue("max-m", 0);
247        ranges[1] = _max * _max_factor;
248     }
249     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
250 }
251
252 SGRangeAnimation::~SGRangeAnimation ()
253 {
254 }
255
256 void
257 SGRangeAnimation::update()
258 {
259     float ranges[2];
260     bool upd = false;
261     if (_min_prop != 0) {
262        ranges[0] = _min_prop->getFloatValue() * _min_factor;
263        upd = true;
264     } else {
265        ranges[0] = _min * _min_factor;
266     }
267     if (_max_prop != 0) {
268        ranges[1] = _max_prop->getFloatValue() * _max_factor;
269        upd = true;
270     } else {
271        ranges[1] = _max * _max_factor;
272     }
273     if (upd) {
274        ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
275     }
276 }
277
278
279 \f
280 ////////////////////////////////////////////////////////////////////////
281 // Implementation of SGBillboardAnimation
282 ////////////////////////////////////////////////////////////////////////
283
284 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
285     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
286 {
287 }
288
289 SGBillboardAnimation::~SGBillboardAnimation ()
290 {
291 }
292
293
294 \f
295 ////////////////////////////////////////////////////////////////////////
296 // Implementation of SGSelectAnimation
297 ////////////////////////////////////////////////////////////////////////
298
299 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
300                                   SGPropertyNode_ptr props )
301   : SGAnimation(props, new ssgSelector),
302     _condition(0)
303 {
304   SGPropertyNode_ptr node = props->getChild("condition");
305   if (node != 0)
306     _condition = sgReadCondition(prop_root, node);
307 }
308
309 SGSelectAnimation::~SGSelectAnimation ()
310 {
311   delete _condition;
312 }
313
314 void
315 SGSelectAnimation::update()
316 {
317   if (_condition != 0 && _condition->test()) 
318       ((ssgSelector *)_branch)->select(0xffff);
319   else
320       ((ssgSelector *)_branch)->select(0x0000);
321 }
322
323
324 \f
325 ////////////////////////////////////////////////////////////////////////
326 // Implementation of SGSpinAnimation
327 ////////////////////////////////////////////////////////////////////////
328
329 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
330                               SGPropertyNode_ptr props,
331                               double sim_time_sec )
332   : SGAnimation(props, new ssgTransform),
333     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
334     _factor(props->getDoubleValue("factor", 1.0)),
335     _position_deg(props->getDoubleValue("starting-position-deg", 0)),
336     _last_time_sec( sim_time_sec )
337 {
338     _center[0] = 0;
339     _center[1] = 0;
340     _center[2] = 0;
341     if (props->hasValue("axis/x1-m")) {
342         double x1,y1,z1,x2,y2,z2;
343         x1 = props->getFloatValue("axis/x1-m");
344         y1 = props->getFloatValue("axis/y1-m");
345         z1 = props->getFloatValue("axis/z1-m");
346         x2 = props->getFloatValue("axis/x2-m");
347         y2 = props->getFloatValue("axis/y2-m");
348         z2 = props->getFloatValue("axis/z2-m");
349         _center[0] = (x1+x2)/2;
350         _center[1]= (y1+y2)/2;
351         _center[2] = (z1+z2)/2;
352         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
353         _axis[0] = (x2-x1)/vector_length;
354         _axis[1] = (y2-y1)/vector_length;
355         _axis[2] = (z2-z1)/vector_length;
356     } else {
357        _axis[0] = props->getFloatValue("axis/x", 0);
358        _axis[1] = props->getFloatValue("axis/y", 0);
359        _axis[2] = props->getFloatValue("axis/z", 0);
360     }
361     if (props->hasValue("center/x-m")) {
362        _center[0] = props->getFloatValue("center/x-m", 0);
363        _center[1] = props->getFloatValue("center/y-m", 0);
364        _center[2] = props->getFloatValue("center/z-m", 0);
365     }
366     sgNormalizeVec3(_axis);
367 }
368
369 SGSpinAnimation::~SGSpinAnimation ()
370 {
371 }
372
373 void
374 SGSpinAnimation::update()
375 {
376   double dt = sim_time_sec - _last_time_sec;
377   _last_time_sec = sim_time_sec;
378
379   float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
380   _position_deg += (dt * velocity_rpms * 360);
381   while (_position_deg < 0)
382     _position_deg += 360.0;
383   while (_position_deg >= 360.0)
384     _position_deg -= 360.0;
385   set_rotation(_matrix, _position_deg, _center, _axis);
386   ((ssgTransform *)_branch)->setTransform(_matrix);
387 }
388
389
390 \f
391 ////////////////////////////////////////////////////////////////////////
392 // Implementation of SGTimedAnimation
393 ////////////////////////////////////////////////////////////////////////
394
395 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
396   : SGAnimation(props, new ssgSelector),
397     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
398     _last_time_sec(0),
399     _step(-1)
400 {
401 }
402
403 SGTimedAnimation::~SGTimedAnimation ()
404 {
405 }
406
407 void
408 SGTimedAnimation::update()
409 {
410     if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
411         _last_time_sec = sim_time_sec;
412         _step++;
413         if (_step >= getBranch()->getNumKids())
414             _step = 0;
415         ((ssgSelector *)getBranch())->selectStep(_step);
416     }
417 }
418
419
420 \f
421 ////////////////////////////////////////////////////////////////////////
422 // Implementation of SGRotateAnimation
423 ////////////////////////////////////////////////////////////////////////
424
425 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
426                                   SGPropertyNode_ptr props )
427     : SGAnimation(props, new ssgTransform),
428       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
429       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
430       _factor(props->getDoubleValue("factor", 1.0)),
431       _table(read_interpolation_table(props)),
432       _has_min(props->hasValue("min-deg")),
433       _min_deg(props->getDoubleValue("min-deg")),
434       _has_max(props->hasValue("max-deg")),
435       _max_deg(props->getDoubleValue("max-deg")),
436       _position_deg(props->getDoubleValue("starting-position-deg", 0))
437 {
438     _center[0] = 0;
439     _center[1] = 0;
440     _center[2] = 0;
441     if (props->hasValue("axis/x1-m")) {
442         double x1,y1,z1,x2,y2,z2;
443         x1 = props->getFloatValue("axis/x1-m");
444         y1 = props->getFloatValue("axis/y1-m");
445         z1 = props->getFloatValue("axis/z1-m");
446         x2 = props->getFloatValue("axis/x2-m");
447         y2 = props->getFloatValue("axis/y2-m");
448         z2 = props->getFloatValue("axis/z2-m");
449         _center[0] = (x1+x2)/2;
450         _center[1]= (y1+y2)/2;
451         _center[2] = (z1+z2)/2;
452         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
453         _axis[0] = (x2-x1)/vector_length;
454         _axis[1] = (y2-y1)/vector_length;
455         _axis[2] = (z2-z1)/vector_length;
456     } else {
457        _axis[0] = props->getFloatValue("axis/x", 0);
458        _axis[1] = props->getFloatValue("axis/y", 0);
459        _axis[2] = props->getFloatValue("axis/z", 0);
460     }
461     if (props->hasValue("center/x-m")) {
462        _center[0] = props->getFloatValue("center/x-m", 0);
463        _center[1] = props->getFloatValue("center/y-m", 0);
464        _center[2] = props->getFloatValue("center/z-m", 0);
465     }
466     sgNormalizeVec3(_axis);
467 }
468
469 SGRotateAnimation::~SGRotateAnimation ()
470 {
471   delete _table;
472 }
473
474 void
475 SGRotateAnimation::update()
476 {
477   if (_table == 0) {
478    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
479    if (_has_min && _position_deg < _min_deg)
480      _position_deg = _min_deg;
481    if (_has_max && _position_deg > _max_deg)
482      _position_deg = _max_deg;
483   } else {
484     _position_deg = _table->interpolate(_prop->getDoubleValue());
485   }
486   set_rotation(_matrix, _position_deg, _center, _axis);
487   ((ssgTransform *)_branch)->setTransform(_matrix);
488 }
489
490 \f
491 ////////////////////////////////////////////////////////////////////////
492 // Implementation of SGBlendAnimation
493 ////////////////////////////////////////////////////////////////////////
494
495 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
496                                         SGPropertyNode_ptr props )
497   : SGAnimation(props, new ssgTransform),
498     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
499     _offset(props->getDoubleValue("offset", 0.0)),
500     _factor(props->getDoubleValue("factor", 1.0)),
501     _table(read_interpolation_table(props)),
502     _has_min(props->hasValue("min")),
503     _min(props->getDoubleValue("min", 0.0)),
504     _has_max(props->hasValue("max")),
505     _max(props->getDoubleValue("max", 1.0)),
506     _prev_value(1.0)
507 {
508 }
509
510 SGBlendAnimation::~SGBlendAnimation ()
511 {
512     delete _table;
513 }
514
515 void
516 SGBlendAnimation::update()
517 {
518   double _blend;
519
520   if (_table == 0) {
521     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
522
523     if (_has_min && (_blend < _min))
524       _blend = _min;
525     if (_has_max && (_blend > _max))
526       _blend = _max;
527   } else {
528     _blend = _table->interpolate(_prop->getDoubleValue());
529   }
530
531   if (_blend != _prev_value) {
532     _prev_value = _blend;
533     change_alpha( _branch, _blend );
534   }
535 }
536
537
538 \f
539 ////////////////////////////////////////////////////////////////////////
540 // Implementation of SGTranslateAnimation
541 ////////////////////////////////////////////////////////////////////////
542
543 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
544                                         SGPropertyNode_ptr props )
545   : SGAnimation(props, new ssgTransform),
546       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
547     _offset_m(props->getDoubleValue("offset-m", 0.0)),
548     _factor(props->getDoubleValue("factor", 1.0)),
549     _table(read_interpolation_table(props)),
550     _has_min(props->hasValue("min-m")),
551     _min_m(props->getDoubleValue("min-m")),
552     _has_max(props->hasValue("max-m")),
553     _max_m(props->getDoubleValue("max-m")),
554     _position_m(props->getDoubleValue("starting-position-m", 0))
555 {
556   _axis[0] = props->getFloatValue("axis/x", 0);
557   _axis[1] = props->getFloatValue("axis/y", 0);
558   _axis[2] = props->getFloatValue("axis/z", 0);
559   sgNormalizeVec3(_axis);
560 }
561
562 SGTranslateAnimation::~SGTranslateAnimation ()
563 {
564   delete _table;
565 }
566
567 void
568 SGTranslateAnimation::update()
569 {
570   if (_table == 0) {
571     _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
572     if (_has_min && _position_m < _min_m)
573       _position_m = _min_m;
574     if (_has_max && _position_m > _max_m)
575       _position_m = _max_m;
576   } else {
577     _position_m = _table->interpolate(_prop->getDoubleValue());
578   }
579   set_translation(_matrix, _position_m, _axis);
580   ((ssgTransform *)_branch)->setTransform(_matrix);
581 }
582
583
584 \f
585 ////////////////////////////////////////////////////////////////////////
586 // Implementation of SGScaleAnimation
587 ////////////////////////////////////////////////////////////////////////
588
589 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
590                                         SGPropertyNode_ptr props )
591   : SGAnimation(props, new ssgTransform),
592       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
593     _x_factor(props->getDoubleValue("x-factor", 1.0)),
594     _y_factor(props->getDoubleValue("y-factor", 1.0)),
595     _z_factor(props->getDoubleValue("z-factor", 1.0)),
596     _x_offset(props->getDoubleValue("x-offset", 1.0)),
597     _y_offset(props->getDoubleValue("y-offset", 1.0)),
598     _z_offset(props->getDoubleValue("z-offset", 1.0)),
599     _table(read_interpolation_table(props)),
600     _has_min_x(props->hasValue("x-min")),
601     _has_min_y(props->hasValue("y-min")),
602     _has_min_z(props->hasValue("z-min")),
603     _min_x(props->getDoubleValue("x-min")),
604     _min_y(props->getDoubleValue("y-min")),
605     _min_z(props->getDoubleValue("z-min")),
606     _has_max_x(props->hasValue("x-max")),
607     _has_max_y(props->hasValue("y-max")),
608     _has_max_z(props->hasValue("z-max")),
609     _max_x(props->getDoubleValue("x-max")),
610     _max_y(props->getDoubleValue("y-max")),
611     _max_z(props->getDoubleValue("z-max"))
612 {
613 }
614
615 SGScaleAnimation::~SGScaleAnimation ()
616 {
617   delete _table;
618 }
619
620 void
621 SGScaleAnimation::update()
622 {
623   if (_table == 0) {
624       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
625     if (_has_min_x && _x_scale < _min_x)
626       _x_scale = _min_x;
627     if (_has_max_x && _x_scale > _max_x)
628       _x_scale = _max_x;
629   } else {
630     _x_scale = _table->interpolate(_prop->getDoubleValue());
631   }
632
633   if (_table == 0) {
634     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
635     if (_has_min_y && _y_scale < _min_y)
636       _y_scale = _min_y;
637     if (_has_max_y && _y_scale > _max_y)
638       _y_scale = _max_y;
639   } else {
640     _y_scale = _table->interpolate(_prop->getDoubleValue());
641   }
642
643   if (_table == 0) {
644     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
645     if (_has_min_z && _z_scale < _min_z)
646       _z_scale = _min_z;
647     if (_has_max_z && _z_scale > _max_z)
648       _z_scale = _max_z;
649   } else {
650     _z_scale = _table->interpolate(_prop->getDoubleValue());
651   }
652
653   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
654   ((ssgTransform *)_branch)->setTransform(_matrix);
655 }
656
657
658 ////////////////////////////////////////////////////////////////////////
659 // Implementation of SGTexRotateAnimation
660 ////////////////////////////////////////////////////////////////////////
661
662 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
663                                   SGPropertyNode_ptr props )
664     : SGAnimation(props, new ssgTexTrans),
665       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
666       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
667       _factor(props->getDoubleValue("factor", 1.0)),
668       _table(read_interpolation_table(props)),
669       _has_min(props->hasValue("min-deg")),
670       _min_deg(props->getDoubleValue("min-deg")),
671       _has_max(props->hasValue("max-deg")),
672       _max_deg(props->getDoubleValue("max-deg")),
673       _position_deg(props->getDoubleValue("starting-position-deg", 0))
674 {
675   _center[0] = props->getFloatValue("center/x", 0);
676   _center[1] = props->getFloatValue("center/y", 0);
677   _center[2] = props->getFloatValue("center/z", 0);
678   _axis[0] = props->getFloatValue("axis/x", 0);
679   _axis[1] = props->getFloatValue("axis/y", 0);
680   _axis[2] = props->getFloatValue("axis/z", 0);
681   sgNormalizeVec3(_axis);
682 }
683
684 SGTexRotateAnimation::~SGTexRotateAnimation ()
685 {
686   delete _table;
687 }
688
689 void
690 SGTexRotateAnimation::update()
691 {
692   if (_table == 0) {
693    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
694    if (_has_min && _position_deg < _min_deg)
695      _position_deg = _min_deg;
696    if (_has_max && _position_deg > _max_deg)
697      _position_deg = _max_deg;
698   } else {
699     _position_deg = _table->interpolate(_prop->getDoubleValue());
700   }
701   set_rotation(_matrix, _position_deg, _center, _axis);
702   ((ssgTexTrans *)_branch)->setTransform(_matrix);
703 }
704
705
706 ////////////////////////////////////////////////////////////////////////
707 // Implementation of SGTexTranslateAnimation
708 ////////////////////////////////////////////////////////////////////////
709
710 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
711                                         SGPropertyNode_ptr props )
712   : SGAnimation(props, new ssgTexTrans),
713       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
714     _offset(props->getDoubleValue("offset", 0.0)),
715     _factor(props->getDoubleValue("factor", 1.0)),
716     _step(props->getDoubleValue("step",0.0)),
717     _scroll(props->getDoubleValue("scroll",0.0)),
718     _table(read_interpolation_table(props)),
719     _has_min(props->hasValue("min")),
720     _min(props->getDoubleValue("min")),
721     _has_max(props->hasValue("max")),
722     _max(props->getDoubleValue("max")),
723     _position(props->getDoubleValue("starting-position", 0))
724 {
725   _axis[0] = props->getFloatValue("axis/x", 0);
726   _axis[1] = props->getFloatValue("axis/y", 0);
727   _axis[2] = props->getFloatValue("axis/z", 0);
728   sgNormalizeVec3(_axis);
729 }
730
731 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
732 {
733   delete _table;
734 }
735
736 void
737 SGTexTranslateAnimation::update()
738 {
739   if (_table == 0) {
740     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
741     if (_has_min && _position < _min)
742       _position = _min;
743     if (_has_max && _position > _max)
744       _position = _max;
745   } else {
746     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
747   }
748   set_translation(_matrix, _position, _axis);
749   ((ssgTexTrans *)_branch)->setTransform(_matrix);
750 }
751
752
753 ////////////////////////////////////////////////////////////////////////
754 // Implementation of SGTexMultipleAnimation
755 ////////////////////////////////////////////////////////////////////////
756
757 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
758                                         SGPropertyNode_ptr props )
759   : SGAnimation(props, new ssgTexTrans),
760       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
761 {
762   unsigned int i;
763   // Load animations
764   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
765   _transform = new TexTransform [transform_nodes.size()];
766   _num_transforms = 0;
767   for (i = 0; i < transform_nodes.size(); i++) {
768     SGPropertyNode_ptr transform_props = transform_nodes[i];
769
770     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
771
772       // transform is a translation
773       _transform[i].subtype = 0;
774
775       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
776
777       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
778       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
779       _transform[i].step = transform_props->getDoubleValue("step",0.0);
780       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
781       _transform[i].table = read_interpolation_table(transform_props);
782       _transform[i].has_min = transform_props->hasValue("min");
783       _transform[i].min = transform_props->getDoubleValue("min");
784       _transform[i].has_max = transform_props->hasValue("max");
785       _transform[i].max = transform_props->getDoubleValue("max");
786       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
787
788       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
789       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
790       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
791       sgNormalizeVec3(_transform[i].axis);
792       _num_transforms++;
793     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
794
795       // transform is a rotation
796       _transform[i].subtype = 1;
797
798       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
799       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
800       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
801       _transform[i].table = read_interpolation_table(transform_props);
802       _transform[i].has_min = transform_props->hasValue("min-deg");
803       _transform[i].min = transform_props->getDoubleValue("min-deg");
804       _transform[i].has_max = transform_props->hasValue("max-deg");
805       _transform[i].max = transform_props->getDoubleValue("max-deg");
806       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
807
808       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
809       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
810       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
811       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
812       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
813       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
814       sgNormalizeVec3(_transform[i].axis);
815       _num_transforms++;
816     }
817   }
818 }
819
820 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
821 {
822   // delete _table;
823   delete _transform;
824 }
825
826 void
827 SGTexMultipleAnimation::update()
828 {
829   int i;
830   sgMat4 tmatrix;
831   sgMakeIdentMat4(tmatrix);
832   for (i = 0; i < _num_transforms; i++) {
833
834     if(_transform[i].subtype == 0) {
835
836       // subtype 0 is translation
837       if (_transform[i].table == 0) {
838         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
839         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
840           _transform[i].position = _transform[i].min;
841         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
842           _transform[i].position = _transform[i].max;
843       } else {
844          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
845       }
846       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
847       sgPreMultMat4(tmatrix, _transform[i].matrix);
848
849     } else if (_transform[i].subtype == 1) {
850
851       // subtype 1 is rotation
852
853       if (_transform[i].table == 0) {
854         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
855         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
856          _transform[i].position = _transform[i].min;
857        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
858          _transform[i].position = _transform[i].max;
859      } else {
860         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
861       }
862       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
863       sgPreMultMat4(tmatrix, _transform[i].matrix);
864     }
865   }
866   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
867 }
868
869
870 \f
871 ////////////////////////////////////////////////////////////////////////
872 // Implementation of SGAlphaTestAnimation
873 ////////////////////////////////////////////////////////////////////////
874
875 SGAlphaTestAnimation::SGAlphaTestAnimation (SGPropertyNode *prop_root,
876                                     SGPropertyNode_ptr props)
877   : SGAnimation(props, new ssgBranch),
878     _done(false)
879 {
880   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
881 }
882
883 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
884 {
885 }
886
887 void SGAlphaTestAnimation::update()
888 {
889   if (!_done) {
890     _done = true;
891     setAlphaClampToBranch(_branch,_alpha_clamp);
892   }
893 }
894
895 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
896 {
897   int nb = b->getNumKids();
898   for (int i = 0; i<nb; i++) {
899     ssgEntity *e = b->getKid(i);
900     if (e->isAKindOf(ssgTypeLeaf())) {
901       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
902       s->enable( GL_ALPHA_TEST );
903       s->setAlphaClamp( clamp );
904     } else if (e->isAKindOf(ssgTypeBranch())) {
905       setAlphaClampToBranch( (ssgBranch*)e, clamp );
906     }
907   }
908 }
909
910 // end of animation.cxx