]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
928d90f112b1f14d90f01f0d724eb00e67319e21
[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   unsigned int i;
101
102   for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
103     change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
104
105   if ( strcmp("ssgLeaf", _branch->getTypeName()) &&
106        strcmp("ssgVtxTable", _branch->getTypeName()) &&
107        strcmp("ssgVTable", _branch->getTypeName()) )
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_ptr props)
218   : SGAnimation(props, new ssgRangeSelector)
219 {
220     float ranges[] = { props->getFloatValue("min-m", 0),
221                        props->getFloatValue("max-m", 5000) };
222     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
223                        
224 }
225
226 SGRangeAnimation::~SGRangeAnimation ()
227 {
228 }
229
230
231 \f
232 ////////////////////////////////////////////////////////////////////////
233 // Implementation of SGBillboardAnimation
234 ////////////////////////////////////////////////////////////////////////
235
236 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
237     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
238 {
239 }
240
241 SGBillboardAnimation::~SGBillboardAnimation ()
242 {
243 }
244
245
246 \f
247 ////////////////////////////////////////////////////////////////////////
248 // Implementation of SGSelectAnimation
249 ////////////////////////////////////////////////////////////////////////
250
251 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
252                                   SGPropertyNode_ptr props )
253   : SGAnimation(props, new ssgSelector),
254     _condition(0)
255 {
256   SGPropertyNode_ptr node = props->getChild("condition");
257   if (node != 0)
258     _condition = sgReadCondition(prop_root, node);
259 }
260
261 SGSelectAnimation::~SGSelectAnimation ()
262 {
263   delete _condition;
264 }
265
266 void
267 SGSelectAnimation::update()
268 {
269   if (_condition != 0 && _condition->test()) 
270       ((ssgSelector *)_branch)->select(0xffff);
271   else
272       ((ssgSelector *)_branch)->select(0x0000);
273 }
274
275
276 \f
277 ////////////////////////////////////////////////////////////////////////
278 // Implementation of SGSpinAnimation
279 ////////////////////////////////////////////////////////////////////////
280
281 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
282                               SGPropertyNode_ptr props,
283                               double sim_time_sec )
284   : SGAnimation(props, new ssgTransform),
285     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
286     _factor(props->getDoubleValue("factor", 1.0)),
287     _position_deg(props->getDoubleValue("starting-position-deg", 0)),
288     _last_time_sec( sim_time_sec )
289 {
290     _center[0] = 0;
291     _center[1] = 0;
292     _center[2] = 0;
293     if (props->hasValue("axis/x1-m")) {
294         double x1,y1,z1,x2,y2,z2;
295         x1 = props->getFloatValue("axis/x1-m");
296         y1 = props->getFloatValue("axis/y1-m");
297         z1 = props->getFloatValue("axis/z1-m");
298         x2 = props->getFloatValue("axis/x2-m");
299         y2 = props->getFloatValue("axis/y2-m");
300         z2 = props->getFloatValue("axis/z2-m");
301         _center[0] = (x1+x2)/2;
302         _center[1]= (y1+y2)/2;
303         _center[2] = (z1+z2)/2;
304         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
305         _axis[0] = (x2-x1)/vector_length;
306         _axis[1] = (y2-y1)/vector_length;
307         _axis[2] = (z2-z1)/vector_length;
308     } else {
309        _axis[0] = props->getFloatValue("axis/x", 0);
310        _axis[1] = props->getFloatValue("axis/y", 0);
311        _axis[2] = props->getFloatValue("axis/z", 0);
312     }
313     if (props->hasValue("center/x-m")) {
314        _center[0] = props->getFloatValue("center/x-m", 0);
315        _center[1] = props->getFloatValue("center/y-m", 0);
316        _center[2] = props->getFloatValue("center/z-m", 0);
317     }
318     sgNormalizeVec3(_axis);
319 }
320
321 SGSpinAnimation::~SGSpinAnimation ()
322 {
323 }
324
325 void
326 SGSpinAnimation::update()
327 {
328   double dt = sim_time_sec - _last_time_sec;
329   _last_time_sec = sim_time_sec;
330
331   float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
332   _position_deg += (dt * velocity_rpms * 360);
333   while (_position_deg < 0)
334     _position_deg += 360.0;
335   while (_position_deg >= 360.0)
336     _position_deg -= 360.0;
337   set_rotation(_matrix, _position_deg, _center, _axis);
338   ((ssgTransform *)_branch)->setTransform(_matrix);
339 }
340
341
342 \f
343 ////////////////////////////////////////////////////////////////////////
344 // Implementation of SGTimedAnimation
345 ////////////////////////////////////////////////////////////////////////
346
347 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
348   : SGAnimation(props, new ssgSelector),
349     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
350     _last_time_sec(0),
351     _step(-1)
352 {
353 }
354
355 SGTimedAnimation::~SGTimedAnimation ()
356 {
357 }
358
359 void
360 SGTimedAnimation::update()
361 {
362     if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
363         _last_time_sec = sim_time_sec;
364         _step++;
365         if (_step >= getBranch()->getNumKids())
366             _step = 0;
367         ((ssgSelector *)getBranch())->selectStep(_step);
368     }
369 }
370
371
372 \f
373 ////////////////////////////////////////////////////////////////////////
374 // Implementation of SGRotateAnimation
375 ////////////////////////////////////////////////////////////////////////
376
377 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
378                                   SGPropertyNode_ptr props )
379     : SGAnimation(props, new ssgTransform),
380       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
381       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
382       _factor(props->getDoubleValue("factor", 1.0)),
383       _table(read_interpolation_table(props)),
384       _has_min(props->hasValue("min-deg")),
385       _min_deg(props->getDoubleValue("min-deg")),
386       _has_max(props->hasValue("max-deg")),
387       _max_deg(props->getDoubleValue("max-deg")),
388       _position_deg(props->getDoubleValue("starting-position-deg", 0))
389 {
390     _center[0] = 0;
391     _center[1] = 0;
392     _center[2] = 0;
393     if (props->hasValue("axis/x1-m")) {
394         double x1,y1,z1,x2,y2,z2;
395         x1 = props->getFloatValue("axis/x1-m");
396         y1 = props->getFloatValue("axis/y1-m");
397         z1 = props->getFloatValue("axis/z1-m");
398         x2 = props->getFloatValue("axis/x2-m");
399         y2 = props->getFloatValue("axis/y2-m");
400         z2 = props->getFloatValue("axis/z2-m");
401         _center[0] = (x1+x2)/2;
402         _center[1]= (y1+y2)/2;
403         _center[2] = (z1+z2)/2;
404         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
405         _axis[0] = (x2-x1)/vector_length;
406         _axis[1] = (y2-y1)/vector_length;
407         _axis[2] = (z2-z1)/vector_length;
408     } else {
409        _axis[0] = props->getFloatValue("axis/x", 0);
410        _axis[1] = props->getFloatValue("axis/y", 0);
411        _axis[2] = props->getFloatValue("axis/z", 0);
412     }
413     if (props->hasValue("center/x-m")) {
414        _center[0] = props->getFloatValue("center/x-m", 0);
415        _center[1] = props->getFloatValue("center/y-m", 0);
416        _center[2] = props->getFloatValue("center/z-m", 0);
417     }
418     sgNormalizeVec3(_axis);
419 }
420
421 SGRotateAnimation::~SGRotateAnimation ()
422 {
423   delete _table;
424 }
425
426 void
427 SGRotateAnimation::update()
428 {
429   if (_table == 0) {
430    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
431    if (_has_min && _position_deg < _min_deg)
432      _position_deg = _min_deg;
433    if (_has_max && _position_deg > _max_deg)
434      _position_deg = _max_deg;
435   } else {
436     _position_deg = _table->interpolate(_prop->getDoubleValue());
437   }
438   set_rotation(_matrix, _position_deg, _center, _axis);
439   ((ssgTransform *)_branch)->setTransform(_matrix);
440 }
441
442 \f
443 ////////////////////////////////////////////////////////////////////////
444 // Implementation of SGBlendAnimation
445 ////////////////////////////////////////////////////////////////////////
446
447 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
448                                         SGPropertyNode_ptr props )
449   : SGAnimation(props, new ssgTransform),
450     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
451     _offset(props->getDoubleValue("offset", 0.0)),
452     _factor(props->getDoubleValue("factor", 1.0)),
453     _table(read_interpolation_table(props)),
454     _has_min(props->hasValue("min")),
455     _min(props->getDoubleValue("min", 0.0)),
456     _has_max(props->hasValue("max")),
457     _max(props->getDoubleValue("max", 1.0)),
458     _prev_value(1.0)
459 {
460 }
461
462 SGBlendAnimation::~SGBlendAnimation ()
463 {
464     delete _table;
465 }
466
467 void
468 SGBlendAnimation::update()
469 {
470   double _blend;
471
472   if (_table == 0) {
473     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
474
475     if (_has_min && (_blend < _min))
476       _blend = _min;
477     if (_has_max && (_blend > _max))
478       _blend = _max;
479   } else {
480     _blend = _table->interpolate(_prop->getDoubleValue());
481   }
482
483   if (_blend != _prev_value) {
484     _prev_value = _blend;
485     change_alpha( _branch, _blend );
486   }
487 }
488
489
490 \f
491 ////////////////////////////////////////////////////////////////////////
492 // Implementation of SGTranslateAnimation
493 ////////////////////////////////////////////////////////////////////////
494
495 SGTranslateAnimation::SGTranslateAnimation( 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_m(props->getDoubleValue("offset-m", 0.0)),
500     _factor(props->getDoubleValue("factor", 1.0)),
501     _table(read_interpolation_table(props)),
502     _has_min(props->hasValue("min-m")),
503     _min_m(props->getDoubleValue("min-m")),
504     _has_max(props->hasValue("max-m")),
505     _max_m(props->getDoubleValue("max-m")),
506     _position_m(props->getDoubleValue("starting-position-m", 0))
507 {
508   _axis[0] = props->getFloatValue("axis/x", 0);
509   _axis[1] = props->getFloatValue("axis/y", 0);
510   _axis[2] = props->getFloatValue("axis/z", 0);
511   sgNormalizeVec3(_axis);
512 }
513
514 SGTranslateAnimation::~SGTranslateAnimation ()
515 {
516   delete _table;
517 }
518
519 void
520 SGTranslateAnimation::update()
521 {
522   if (_table == 0) {
523     _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
524     if (_has_min && _position_m < _min_m)
525       _position_m = _min_m;
526     if (_has_max && _position_m > _max_m)
527       _position_m = _max_m;
528   } else {
529     _position_m = _table->interpolate(_prop->getDoubleValue());
530   }
531   set_translation(_matrix, _position_m, _axis);
532   ((ssgTransform *)_branch)->setTransform(_matrix);
533 }
534
535
536 \f
537 ////////////////////////////////////////////////////////////////////////
538 // Implementation of SGScaleAnimation
539 ////////////////////////////////////////////////////////////////////////
540
541 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
542                                         SGPropertyNode_ptr props )
543   : SGAnimation(props, new ssgTransform),
544       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
545     _x_factor(props->getDoubleValue("x-factor", 1.0)),
546     _y_factor(props->getDoubleValue("y-factor", 1.0)),
547     _z_factor(props->getDoubleValue("z-factor", 1.0)),
548     _x_offset(props->getDoubleValue("x-offset", 1.0)),
549     _y_offset(props->getDoubleValue("y-offset", 1.0)),
550     _z_offset(props->getDoubleValue("z-offset", 1.0)),
551     _table(read_interpolation_table(props)),
552     _has_min_x(props->hasValue("x-min")),
553     _has_min_y(props->hasValue("y-min")),
554     _has_min_z(props->hasValue("z-min")),
555     _min_x(props->getDoubleValue("x-min")),
556     _min_y(props->getDoubleValue("y-min")),
557     _min_z(props->getDoubleValue("z-min")),
558     _has_max_x(props->hasValue("x-max")),
559     _has_max_y(props->hasValue("y-max")),
560     _has_max_z(props->hasValue("z-max")),
561     _max_x(props->getDoubleValue("x-max")),
562     _max_y(props->getDoubleValue("y-max")),
563     _max_z(props->getDoubleValue("z-max"))
564 {
565 }
566
567 SGScaleAnimation::~SGScaleAnimation ()
568 {
569   delete _table;
570 }
571
572 void
573 SGScaleAnimation::update()
574 {
575   if (_table == 0) {
576       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
577     if (_has_min_x && _x_scale < _min_x)
578       _x_scale = _min_x;
579     if (_has_max_x && _x_scale > _max_x)
580       _x_scale = _max_x;
581   } else {
582     _x_scale = _table->interpolate(_prop->getDoubleValue());
583   }
584
585   if (_table == 0) {
586     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
587     if (_has_min_y && _y_scale < _min_y)
588       _y_scale = _min_y;
589     if (_has_max_y && _y_scale > _max_y)
590       _y_scale = _max_y;
591   } else {
592     _y_scale = _table->interpolate(_prop->getDoubleValue());
593   }
594
595   if (_table == 0) {
596     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
597     if (_has_min_z && _z_scale < _min_z)
598       _z_scale = _min_z;
599     if (_has_max_z && _z_scale > _max_z)
600       _z_scale = _max_z;
601   } else {
602     _z_scale = _table->interpolate(_prop->getDoubleValue());
603   }
604
605   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
606   ((ssgTransform *)_branch)->setTransform(_matrix);
607 }
608
609
610 ////////////////////////////////////////////////////////////////////////
611 // Implementation of SGTexRotateAnimation
612 ////////////////////////////////////////////////////////////////////////
613
614 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
615                                   SGPropertyNode_ptr props )
616     : SGAnimation(props, new ssgTexTrans),
617       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
618       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
619       _factor(props->getDoubleValue("factor", 1.0)),
620       _table(read_interpolation_table(props)),
621       _has_min(props->hasValue("min-deg")),
622       _min_deg(props->getDoubleValue("min-deg")),
623       _has_max(props->hasValue("max-deg")),
624       _max_deg(props->getDoubleValue("max-deg")),
625       _position_deg(props->getDoubleValue("starting-position-deg", 0))
626 {
627   _center[0] = props->getFloatValue("center/x", 0);
628   _center[1] = props->getFloatValue("center/y", 0);
629   _center[2] = props->getFloatValue("center/z", 0);
630   _axis[0] = props->getFloatValue("axis/x", 0);
631   _axis[1] = props->getFloatValue("axis/y", 0);
632   _axis[2] = props->getFloatValue("axis/z", 0);
633   sgNormalizeVec3(_axis);
634 }
635
636 SGTexRotateAnimation::~SGTexRotateAnimation ()
637 {
638   delete _table;
639 }
640
641 void
642 SGTexRotateAnimation::update()
643 {
644   if (_table == 0) {
645    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
646    if (_has_min && _position_deg < _min_deg)
647      _position_deg = _min_deg;
648    if (_has_max && _position_deg > _max_deg)
649      _position_deg = _max_deg;
650   } else {
651     _position_deg = _table->interpolate(_prop->getDoubleValue());
652   }
653   set_rotation(_matrix, _position_deg, _center, _axis);
654   ((ssgTexTrans *)_branch)->setTransform(_matrix);
655 }
656
657
658 ////////////////////////////////////////////////////////////////////////
659 // Implementation of SGTexTranslateAnimation
660 ////////////////////////////////////////////////////////////////////////
661
662 SGTexTranslateAnimation::SGTexTranslateAnimation( 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(props->getDoubleValue("offset", 0.0)),
667     _factor(props->getDoubleValue("factor", 1.0)),
668     _step(props->getDoubleValue("step",0.0)),
669     _scroll(props->getDoubleValue("scroll",0.0)),
670     _table(read_interpolation_table(props)),
671     _has_min(props->hasValue("min")),
672     _min(props->getDoubleValue("min")),
673     _has_max(props->hasValue("max")),
674     _max(props->getDoubleValue("max")),
675     _position(props->getDoubleValue("starting-position", 0))
676 {
677   _axis[0] = props->getFloatValue("axis/x", 0);
678   _axis[1] = props->getFloatValue("axis/y", 0);
679   _axis[2] = props->getFloatValue("axis/z", 0);
680   sgNormalizeVec3(_axis);
681 }
682
683 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
684 {
685   delete _table;
686 }
687
688 void
689 SGTexTranslateAnimation::update()
690 {
691   if (_table == 0) {
692     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
693     if (_has_min && _position < _min)
694       _position = _min;
695     if (_has_max && _position > _max)
696       _position = _max;
697   } else {
698     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
699   }
700   set_translation(_matrix, _position, _axis);
701   ((ssgTexTrans *)_branch)->setTransform(_matrix);
702 }
703
704
705 ////////////////////////////////////////////////////////////////////////
706 // Implementation of SGTexMultipleAnimation
707 ////////////////////////////////////////////////////////////////////////
708
709 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
710                                         SGPropertyNode_ptr props )
711   : SGAnimation(props, new ssgTexTrans),
712       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
713 {
714   unsigned int i;
715   // Load animations
716   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
717   _transform = new TexTransform [transform_nodes.size()];
718   _num_transforms = 0;
719   for (i = 0; i < transform_nodes.size(); i++) {
720     SGPropertyNode_ptr transform_props = transform_nodes[i];
721
722     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
723
724       // transform is a translation
725       _transform[i].subtype = 0;
726
727       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
728
729       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
730       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
731       _transform[i].step = transform_props->getDoubleValue("step",0.0);
732       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
733       _transform[i].table = read_interpolation_table(transform_props);
734       _transform[i].has_min = transform_props->hasValue("min");
735       _transform[i].min = transform_props->getDoubleValue("min");
736       _transform[i].has_max = transform_props->hasValue("max");
737       _transform[i].max = transform_props->getDoubleValue("max");
738       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
739
740       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
741       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
742       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
743       sgNormalizeVec3(_transform[i].axis);
744       _num_transforms++;
745     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
746
747       // transform is a rotation
748       _transform[i].subtype = 1;
749
750       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
751       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
752       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
753       _transform[i].table = read_interpolation_table(transform_props);
754       _transform[i].has_min = transform_props->hasValue("min-deg");
755       _transform[i].min = transform_props->getDoubleValue("min-deg");
756       _transform[i].has_max = transform_props->hasValue("max-deg");
757       _transform[i].max = transform_props->getDoubleValue("max-deg");
758       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
759
760       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
761       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
762       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
763       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
764       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
765       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
766       sgNormalizeVec3(_transform[i].axis);
767       _num_transforms++;
768     }
769   }
770 }
771
772 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
773 {
774   // delete _table;
775   delete _transform;
776 }
777
778 void
779 SGTexMultipleAnimation::update()
780 {
781   int i;
782   sgMat4 tmatrix;
783   sgMakeIdentMat4(tmatrix);
784   for (i = 0; i < _num_transforms; i++) {
785
786     if(_transform[i].subtype == 0) {
787
788       // subtype 0 is translation
789       if (_transform[i].table == 0) {
790         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
791         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
792           _transform[i].position = _transform[i].min;
793         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
794           _transform[i].position = _transform[i].max;
795       } else {
796          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
797       }
798       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
799       sgPreMultMat4(tmatrix, _transform[i].matrix);
800
801     } else if (_transform[i].subtype == 1) {
802
803       // subtype 1 is rotation
804
805       if (_transform[i].table == 0) {
806         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
807         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
808          _transform[i].position = _transform[i].min;
809        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
810          _transform[i].position = _transform[i].max;
811      } else {
812         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
813       }
814       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
815       sgPreMultMat4(tmatrix, _transform[i].matrix);
816     }
817   }
818   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
819 }
820
821 // end of animation.cxx