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