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