]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
Jim Wilson:
[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
9 #include <plib/sg.h>
10 #include <plib/ssg.h>
11 #include <plib/ul.h>
12
13 #include <simgear/math/interpolater.hxx>
14 #include <simgear/props/condition.hxx>
15 #include <simgear/props/props.hxx>
16
17 #include "animation.hxx"
18
19
20 \f
21 ////////////////////////////////////////////////////////////////////////
22 // Static utility functions.
23 ////////////////////////////////////////////////////////////////////////
24
25 /**
26  * Set up the transform matrix for a spin or rotation.
27  */
28 static void
29 set_rotation (sgMat4 &matrix, double position_deg,
30               sgVec3 &center, sgVec3 &axis)
31 {
32  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
33  
34  float s = (float) sin ( temp_angle ) ;
35  float c = (float) cos ( temp_angle ) ;
36  float t = SG_ONE - c ;
37
38  // axis was normalized at load time 
39  // hint to the compiler to put these into FP registers
40  float x = axis[0];
41  float y = axis[1];
42  float z = axis[2];
43
44  matrix[0][0] = t * x * x + c ;
45  matrix[0][1] = t * y * x - s * z ;
46  matrix[0][2] = t * z * x + s * y ;
47  matrix[0][3] = SG_ZERO;
48  
49  matrix[1][0] = t * x * y + s * z ;
50  matrix[1][1] = t * y * y + c ;
51  matrix[1][2] = t * z * y - s * x ;
52  matrix[1][3] = SG_ZERO;
53  
54  matrix[2][0] = t * x * z - s * y ;
55  matrix[2][1] = t * y * z + s * x ;
56  matrix[2][2] = t * z * z + c ;
57  matrix[2][3] = SG_ZERO;
58
59   // hint to the compiler to put these into FP registers
60  x = center[0];
61  y = center[1];
62  z = center[2];
63  
64  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
65  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
66  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
67  matrix[3][3] = SG_ONE;
68 }
69
70 /**
71  * Set up the transform matrix for a translation.
72  */
73 static void
74 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
75 {
76   sgVec3 xyz;
77   sgScaleVec3(xyz, axis, position_m);
78   sgMakeTransMat4(matrix, xyz);
79 }
80
81
82 /**
83  * Read an interpolation table from properties.
84  */
85 static SGInterpTable *
86 read_interpolation_table (SGPropertyNode_ptr props)
87 {
88   SGPropertyNode_ptr table_node = props->getNode("interpolation");
89   if (table_node != 0) {
90     SGInterpTable * table = new SGInterpTable();
91     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
92     for (unsigned int i = 0; i < entries.size(); i++)
93       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
94                       entries[i]->getDoubleValue("dep", 0.0));
95     return table;
96   } else {
97     return 0;
98   }
99 }
100
101
102 \f
103 ////////////////////////////////////////////////////////////////////////
104 // Implementation of SGAnimation
105 ////////////////////////////////////////////////////////////////////////
106
107 // Initialize the static data member
108 double SGAnimation::sim_time_sec = 0.0;
109
110 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
111     : _branch(branch)
112 {
113     _branch->setName(props->getStringValue("name", 0));
114 }
115
116 SGAnimation::~SGAnimation ()
117 {
118 }
119
120 void
121 SGAnimation::init ()
122 {
123 }
124
125 void
126 SGAnimation::update()
127 {
128 }
129
130
131 \f
132 ////////////////////////////////////////////////////////////////////////
133 // Implementation of SGNullAnimation
134 ////////////////////////////////////////////////////////////////////////
135
136 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
137   : SGAnimation(props, new ssgBranch)
138 {
139 }
140
141 SGNullAnimation::~SGNullAnimation ()
142 {
143 }
144
145
146 \f
147 ////////////////////////////////////////////////////////////////////////
148 // Implementation of SGRangeAnimation
149 ////////////////////////////////////////////////////////////////////////
150
151 SGRangeAnimation::SGRangeAnimation (SGPropertyNode_ptr props)
152   : SGAnimation(props, new ssgRangeSelector)
153 {
154     float ranges[] = { props->getFloatValue("min-m", 0),
155                        props->getFloatValue("max-m", 5000) };
156     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
157                        
158 }
159
160 SGRangeAnimation::~SGRangeAnimation ()
161 {
162 }
163
164
165 \f
166 ////////////////////////////////////////////////////////////////////////
167 // Implementation of SGBillboardAnimation
168 ////////////////////////////////////////////////////////////////////////
169
170 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
171     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
172 {
173 }
174
175 SGBillboardAnimation::~SGBillboardAnimation ()
176 {
177 }
178
179
180 \f
181 ////////////////////////////////////////////////////////////////////////
182 // Implementation of SGSelectAnimation
183 ////////////////////////////////////////////////////////////////////////
184
185 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
186                                   SGPropertyNode_ptr props )
187   : SGAnimation(props, new ssgSelector),
188     _condition(0)
189 {
190   SGPropertyNode_ptr node = props->getChild("condition");
191   if (node != 0)
192     _condition = sgReadCondition(prop_root, node);
193 }
194
195 SGSelectAnimation::~SGSelectAnimation ()
196 {
197   delete _condition;
198 }
199
200 void
201 SGSelectAnimation::update()
202 {
203   if (_condition != 0 && _condition->test()) 
204       ((ssgSelector *)_branch)->select(0xffff);
205   else
206       ((ssgSelector *)_branch)->select(0x0000);
207 }
208
209
210 \f
211 ////////////////////////////////////////////////////////////////////////
212 // Implementation of SGSpinAnimation
213 ////////////////////////////////////////////////////////////////////////
214
215 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
216                               SGPropertyNode_ptr props,
217                               double sim_time_sec )
218   : SGAnimation(props, new ssgTransform),
219     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
220     _factor(props->getDoubleValue("factor", 1.0)),
221     _position_deg(props->getDoubleValue("starting-position-deg", 0)),
222     _last_time_sec( sim_time_sec )
223 {
224     _center[0] = 0;
225     _center[1] = 0;
226     _center[2] = 0;
227     if (props->hasValue("axis/x1-m")) {
228         double x1,y1,z1,x2,y2,z2;
229         x1 = props->getFloatValue("axis/x1-m");
230         y1 = props->getFloatValue("axis/y1-m");
231         z1 = props->getFloatValue("axis/z1-m");
232         x2 = props->getFloatValue("axis/x2-m");
233         y2 = props->getFloatValue("axis/y2-m");
234         z2 = props->getFloatValue("axis/z2-m");
235         _center[0] = (x1+x2)/2;
236         _center[1]= (y1+y2)/2;
237         _center[2] = (z1+z2)/2;
238         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
239         _axis[0] = (x2-x1)/vector_length;
240         _axis[1] = (y2-y1)/vector_length;
241         _axis[2] = (z2-z1)/vector_length;
242     } else {
243        _axis[0] = props->getFloatValue("axis/x", 0);
244        _axis[1] = props->getFloatValue("axis/y", 0);
245        _axis[2] = props->getFloatValue("axis/z", 0);
246     }
247     if (props->hasValue("center/x-m")) {
248        _center[0] = props->getFloatValue("center/x-m", 0);
249        _center[1] = props->getFloatValue("center/y-m", 0);
250        _center[2] = props->getFloatValue("center/z-m", 0);
251     }
252     sgNormalizeVec3(_axis);
253 }
254
255 SGSpinAnimation::~SGSpinAnimation ()
256 {
257 }
258
259 void
260 SGSpinAnimation::update()
261 {
262   double dt = sim_time_sec - _last_time_sec;
263   _last_time_sec = sim_time_sec;
264
265   float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
266   _position_deg += (dt * velocity_rpms * 360);
267   while (_position_deg < 0)
268     _position_deg += 360.0;
269   while (_position_deg >= 360.0)
270     _position_deg -= 360.0;
271   set_rotation(_matrix, _position_deg, _center, _axis);
272   ((ssgTransform *)_branch)->setTransform(_matrix);
273 }
274
275
276 \f
277 ////////////////////////////////////////////////////////////////////////
278 // Implementation of SGTimedAnimation
279 ////////////////////////////////////////////////////////////////////////
280
281 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
282   : SGAnimation(props, new ssgSelector),
283     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
284     _last_time_sec(0),
285     _step(-1)
286 {
287 }
288
289 SGTimedAnimation::~SGTimedAnimation ()
290 {
291 }
292
293 void
294 SGTimedAnimation::update()
295 {
296     if ((sim_time_sec - _last_time_sec) >= _duration_sec) {
297         _last_time_sec = sim_time_sec;
298         _step++;
299         if (_step >= getBranch()->getNumKids())
300             _step = 0;
301         ((ssgSelector *)getBranch())->selectStep(_step);
302     }
303 }
304
305
306 \f
307 ////////////////////////////////////////////////////////////////////////
308 // Implementation of SGRotateAnimation
309 ////////////////////////////////////////////////////////////////////////
310
311 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
312                                   SGPropertyNode_ptr props )
313     : SGAnimation(props, new ssgTransform),
314       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
315       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
316       _factor(props->getDoubleValue("factor", 1.0)),
317       _table(read_interpolation_table(props)),
318       _has_min(props->hasValue("min-deg")),
319       _min_deg(props->getDoubleValue("min-deg")),
320       _has_max(props->hasValue("max-deg")),
321       _max_deg(props->getDoubleValue("max-deg")),
322       _position_deg(props->getDoubleValue("starting-position-deg", 0))
323 {
324     _center[0] = 0;
325     _center[1] = 0;
326     _center[2] = 0;
327     if (props->hasValue("axis/x1-m")) {
328         double x1,y1,z1,x2,y2,z2;
329         x1 = props->getFloatValue("axis/x1-m");
330         y1 = props->getFloatValue("axis/y1-m");
331         z1 = props->getFloatValue("axis/z1-m");
332         x2 = props->getFloatValue("axis/x2-m");
333         y2 = props->getFloatValue("axis/y2-m");
334         z2 = props->getFloatValue("axis/z2-m");
335         _center[0] = (x1+x2)/2;
336         _center[1]= (y1+y2)/2;
337         _center[2] = (z1+z2)/2;
338         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
339         _axis[0] = (x2-x1)/vector_length;
340         _axis[1] = (y2-y1)/vector_length;
341         _axis[2] = (z2-z1)/vector_length;
342     } else {
343        _axis[0] = props->getFloatValue("axis/x", 0);
344        _axis[1] = props->getFloatValue("axis/y", 0);
345        _axis[2] = props->getFloatValue("axis/z", 0);
346     }
347     if (props->hasValue("center/x-m")) {
348        _center[0] = props->getFloatValue("center/x-m", 0);
349        _center[1] = props->getFloatValue("center/y-m", 0);
350        _center[2] = props->getFloatValue("center/z-m", 0);
351     }
352     sgNormalizeVec3(_axis);
353 }
354
355 SGRotateAnimation::~SGRotateAnimation ()
356 {
357   delete _table;
358 }
359
360 void
361 SGRotateAnimation::update()
362 {
363   if (_table == 0) {
364    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
365    if (_has_min && _position_deg < _min_deg)
366      _position_deg = _min_deg;
367    if (_has_max && _position_deg > _max_deg)
368      _position_deg = _max_deg;
369   } else {
370     _position_deg = _table->interpolate(_prop->getDoubleValue());
371   }
372   set_rotation(_matrix, _position_deg, _center, _axis);
373   ((ssgTransform *)_branch)->setTransform(_matrix);
374 }
375
376
377 \f
378 ////////////////////////////////////////////////////////////////////////
379 // Implementation of SGTranslateAnimation
380 ////////////////////////////////////////////////////////////////////////
381
382 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
383                                         SGPropertyNode_ptr props )
384   : SGAnimation(props, new ssgTransform),
385       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
386     _offset_m(props->getDoubleValue("offset-m", 0.0)),
387     _factor(props->getDoubleValue("factor", 1.0)),
388     _table(read_interpolation_table(props)),
389     _has_min(props->hasValue("min-m")),
390     _min_m(props->getDoubleValue("min-m")),
391     _has_max(props->hasValue("max-m")),
392     _max_m(props->getDoubleValue("max-m")),
393     _position_m(props->getDoubleValue("starting-position-m", 0))
394 {
395   _axis[0] = props->getFloatValue("axis/x", 0);
396   _axis[1] = props->getFloatValue("axis/y", 0);
397   _axis[2] = props->getFloatValue("axis/z", 0);
398   sgNormalizeVec3(_axis);
399 }
400
401 SGTranslateAnimation::~SGTranslateAnimation ()
402 {
403   delete _table;
404 }
405
406 void
407 SGTranslateAnimation::update()
408 {
409   if (_table == 0) {
410     _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
411     if (_has_min && _position_m < _min_m)
412       _position_m = _min_m;
413     if (_has_max && _position_m > _max_m)
414       _position_m = _max_m;
415   } else {
416     _position_m = _table->interpolate(_prop->getDoubleValue());
417   }
418   set_translation(_matrix, _position_m, _axis);
419   ((ssgTransform *)_branch)->setTransform(_matrix);
420 }
421
422
423 ////////////////////////////////////////////////////////////////////////
424 // Implementation of SGTexRotateAnimation
425 ////////////////////////////////////////////////////////////////////////
426
427 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
428                                   SGPropertyNode_ptr props )
429     : SGAnimation(props, new ssgTexTrans),
430       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
431       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
432       _factor(props->getDoubleValue("factor", 1.0)),
433       _table(read_interpolation_table(props)),
434       _has_min(props->hasValue("min-deg")),
435       _min_deg(props->getDoubleValue("min-deg")),
436       _has_max(props->hasValue("max-deg")),
437       _max_deg(props->getDoubleValue("max-deg")),
438       _position_deg(props->getDoubleValue("starting-position-deg", 0))
439 {
440   _center[0] = props->getFloatValue("center/x-m", 0);
441   _center[1] = props->getFloatValue("center/y-m", 0);
442   _center[2] = props->getFloatValue("center/z-m", 0);
443   _axis[0] = props->getFloatValue("axis/x", 0);
444   _axis[1] = props->getFloatValue("axis/y", 0);
445   _axis[2] = props->getFloatValue("axis/z", 0);
446   sgNormalizeVec3(_axis);
447 }
448
449 SGTexRotateAnimation::~SGTexRotateAnimation ()
450 {
451   delete _table;
452 }
453
454 void
455 SGTexRotateAnimation::update()
456 {
457   if (_table == 0) {
458    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
459    if (_has_min && _position_deg < _min_deg)
460      _position_deg = _min_deg;
461    if (_has_max && _position_deg > _max_deg)
462      _position_deg = _max_deg;
463   } else {
464     _position_deg = _table->interpolate(_prop->getDoubleValue());
465   }
466   set_rotation(_matrix, _position_deg, _center, _axis);
467   ((ssgTexTrans *)_branch)->setTransform(_matrix);
468 }
469
470
471 ////////////////////////////////////////////////////////////////////////
472 // Implementation of SGTexTranslateAnimation
473 ////////////////////////////////////////////////////////////////////////
474
475 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
476                                         SGPropertyNode_ptr props )
477   : SGAnimation(props, new ssgTexTrans),
478       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
479     _offset_m(props->getDoubleValue("offset-m", 0.0)),
480     _factor(props->getDoubleValue("factor", 1.0)),
481     _table(read_interpolation_table(props)),
482     _has_min(props->hasValue("min-m")),
483     _min_m(props->getDoubleValue("min-m")),
484     _has_max(props->hasValue("max-m")),
485     _max_m(props->getDoubleValue("max-m")),
486     _position_m(props->getDoubleValue("starting-position-m", 0))
487 {
488   _axis[0] = props->getFloatValue("axis/x", 0);
489   _axis[1] = props->getFloatValue("axis/y", 0);
490   _axis[2] = props->getFloatValue("axis/z", 0);
491   sgNormalizeVec3(_axis);
492 }
493
494 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
495 {
496   delete _table;
497 }
498
499 void
500 SGTexTranslateAnimation::update()
501 {
502   if (_table == 0) {
503     _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
504     if (_has_min && _position_m < _min_m)
505       _position_m = _min_m;
506     if (_has_max && _position_m > _max_m)
507       _position_m = _max_m;
508   } else {
509     _position_m = _table->interpolate(_prop->getDoubleValue());
510   }
511   set_translation(_matrix, _position_m, _axis);
512   ((ssgTexTrans *)_branch)->setTransform(_matrix);
513 }
514
515
516 // end of animation.cxx