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