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