]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
36ae1e507284ffd07abe759bdb8c31ac9b288e3e
[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 #ifdef HAVE_CONFIG_H
7 #  include <simgear_config.h>
8 #endif
9
10 #include <string.h>             // for strcmp()
11 #include <math.h>
12
13 #include <plib/sg.h>
14 #include <plib/ssg.h>
15 #include <plib/ul.h>
16
17 #include <simgear/math/interpolater.hxx>
18 #include <simgear/props/condition.hxx>
19 #include <simgear/props/props.hxx>
20 #include <simgear/math/sg_random.h>
21
22 #include "animation.hxx"
23 #include "custtrans.hxx"
24 #include "personality.hxx"
25
26 \f
27 ////////////////////////////////////////////////////////////////////////
28 // Static utility functions.
29 ////////////////////////////////////////////////////////////////////////
30
31 /**
32  * Set up the transform matrix for a spin or rotation.
33  */
34 static void
35 set_rotation (sgMat4 &matrix, double position_deg,
36               sgVec3 &center, sgVec3 &axis)
37 {
38  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
39  
40  float s = (float) sin ( temp_angle ) ;
41  float c = (float) cos ( temp_angle ) ;
42  float t = SG_ONE - c ;
43
44  // axis was normalized at load time 
45  // hint to the compiler to put these into FP registers
46  float x = axis[0];
47  float y = axis[1];
48  float z = axis[2];
49
50  matrix[0][0] = t * x * x + c ;
51  matrix[0][1] = t * y * x - s * z ;
52  matrix[0][2] = t * z * x + s * y ;
53  matrix[0][3] = SG_ZERO;
54  
55  matrix[1][0] = t * x * y + s * z ;
56  matrix[1][1] = t * y * y + c ;
57  matrix[1][2] = t * z * y - s * x ;
58  matrix[1][3] = SG_ZERO;
59  
60  matrix[2][0] = t * x * z - s * y ;
61  matrix[2][1] = t * y * z + s * x ;
62  matrix[2][2] = t * z * z + c ;
63  matrix[2][3] = SG_ZERO;
64
65   // hint to the compiler to put these into FP registers
66  x = center[0];
67  y = center[1];
68  z = center[2];
69  
70  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
71  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
72  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
73  matrix[3][3] = SG_ONE;
74 }
75
76 /**
77  * Set up the transform matrix for a translation.
78  */
79 static void
80 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
81 {
82   sgVec3 xyz;
83   sgScaleVec3(xyz, axis, position_m);
84   sgMakeTransMat4(matrix, xyz);
85 }
86
87 /**
88  * Set up the transform matrix for a scale operation.
89  */
90 static void
91 set_scale (sgMat4 &matrix, double x, double y, double z)
92 {
93   sgMakeIdentMat4( matrix );
94   matrix[0][0] = x;
95   matrix[1][1] = y;
96   matrix[2][2] = z;
97 }
98
99 /**
100  * Recursively process all kids to change the alpha values
101  */
102 static void
103 change_alpha( ssgBase *_branch, float _blend )
104 {
105   int i;
106
107   for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
108     change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
109
110   if ( !_branch->isAKindOf(ssgTypeLeaf())
111        && !_branch->isAKindOf(ssgTypeVtxTable())
112        && !_branch->isAKindOf(ssgTypeVTable()) )
113     return;
114
115   int num_colors = ((ssgLeaf *)_branch)->getNumColours();
116 // unsigned int select_ = (_blend == 1.0) ? false : true;
117
118   for (i = 0; i < num_colors; i++)
119   {
120 //    ((ssgSelector *)_branch)->select( select_ );
121     float *color =  ((ssgLeaf *)_branch)->getColour(i);
122     color[3] = _blend;
123   }
124 }
125
126 /**
127  * Modify property value by step and scroll settings in texture translations
128  */
129 static double
130 apply_mods(double property, double step, double scroll)
131 {
132
133   double modprop;
134   if(step > 0) {
135     double scrollval = 0.0;
136     if(scroll > 0) {
137       // calculate scroll amount (for odometer like movement)
138       double remainder  =  step - fmod(fabs(property), step);
139       if (remainder < scroll) {
140         scrollval = (scroll - remainder) / scroll * step;
141       }
142     }
143   // apply stepping of input value
144   if(property > 0) 
145      modprop = ((floor(property/step) * step) + scrollval);
146   else
147      modprop = ((ceil(property/step) * step) + scrollval);
148   } else {
149      modprop = property;
150   }
151   return modprop;
152
153 }
154
155 /**
156  * Read an interpolation table from properties.
157  */
158 static SGInterpTable *
159 read_interpolation_table (SGPropertyNode_ptr props)
160 {
161   SGPropertyNode_ptr table_node = props->getNode("interpolation");
162   if (table_node != 0) {
163     SGInterpTable * table = new SGInterpTable();
164     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
165     for (unsigned int i = 0; i < entries.size(); i++)
166       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
167                       entries[i]->getDoubleValue("dep", 0.0));
168     return table;
169   } else {
170     return 0;
171   }
172 }
173
174
175 \f
176 ////////////////////////////////////////////////////////////////////////
177 // Implementation of SGAnimation
178 ////////////////////////////////////////////////////////////////////////
179
180 // Initialize the static data member
181 double SGAnimation::sim_time_sec = 0.0;
182 SGPersonalityBranch *SGAnimation::current_object = 0;
183
184 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
185     : _branch(branch),
186     animation_type(0)
187 {
188     _branch->setName(props->getStringValue("name", 0));
189     if ( props->getBoolValue( "enable-hot", true ) ) {
190         _branch->setTraversalMaskBits( SSGTRAV_HOT );
191     } else {
192         _branch->clrTraversalMaskBits( SSGTRAV_HOT );
193     }
194 }
195
196 SGAnimation::~SGAnimation ()
197 {
198 }
199
200 void
201 SGAnimation::init ()
202 {
203 }
204
205 int
206 SGAnimation::update()
207 {
208     return 1;
209 }
210
211 void
212 SGAnimation::restore()
213 {
214 }
215
216
217 \f
218 ////////////////////////////////////////////////////////////////////////
219 // Implementation of SGNullAnimation
220 ////////////////////////////////////////////////////////////////////////
221
222 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
223   : SGAnimation(props, new ssgBranch)
224 {
225 }
226
227 SGNullAnimation::~SGNullAnimation ()
228 {
229 }
230
231
232 \f
233 ////////////////////////////////////////////////////////////////////////
234 // Implementation of SGRangeAnimation
235 ////////////////////////////////////////////////////////////////////////
236
237 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
238                                     SGPropertyNode_ptr props)
239   : SGAnimation(props, new ssgRangeSelector),
240     _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
241     _condition(0)
242 {
243     SGPropertyNode_ptr node = props->getChild("condition");
244     if (node != 0)
245        _condition = sgReadCondition(prop_root, node);
246
247     float ranges[2];
248
249     node = props->getChild( "min-factor" );
250     if (node != 0) {
251        _min_factor = props->getFloatValue("min-factor", 1.0);
252     }
253     node = props->getChild( "max-factor" );
254     if (node != 0) {
255        _max_factor = props->getFloatValue("max-factor", 1.0);
256     }
257     node = props->getChild( "min-property" );
258     if (node != 0) {
259        _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
260        ranges[0] = _min_prop->getFloatValue() * _min_factor;
261     } else {
262        _min = props->getFloatValue("min-m", 0);
263        ranges[0] = _min * _min_factor;
264     }
265     node = props->getChild( "max-property" );
266     if (node != 0) {
267        _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
268        ranges[1] = _max_prop->getFloatValue() * _max_factor;
269     } else {
270        _max = props->getFloatValue("max-m", 0);
271        ranges[1] = _max * _max_factor;
272     }
273     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
274 }
275
276 SGRangeAnimation::~SGRangeAnimation ()
277 {
278 }
279
280 int
281 SGRangeAnimation::update()
282 {
283   float ranges[2];
284   if ( _condition == 0 || _condition->test() ) {
285     if (_min_prop != 0) {
286       ranges[0] = _min_prop->getFloatValue() * _min_factor;
287     } else {
288       ranges[0] = _min * _min_factor;
289     }
290     if (_max_prop != 0) {
291       ranges[1] = _max_prop->getFloatValue() * _max_factor;
292     } else {
293       ranges[1] = _max * _max_factor;
294     }
295   } else {
296     ranges[0] = 0.f;
297     ranges[1] = 1000000000.f;
298   }
299   ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
300   return 2;
301 }
302
303
304 \f
305 ////////////////////////////////////////////////////////////////////////
306 // Implementation of SGBillboardAnimation
307 ////////////////////////////////////////////////////////////////////////
308
309 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
310     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
311 {
312 }
313
314 SGBillboardAnimation::~SGBillboardAnimation ()
315 {
316 }
317
318
319 \f
320 ////////////////////////////////////////////////////////////////////////
321 // Implementation of SGSelectAnimation
322 ////////////////////////////////////////////////////////////////////////
323
324 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
325                                   SGPropertyNode_ptr props )
326   : SGAnimation(props, new ssgSelector),
327     _condition(0)
328 {
329   SGPropertyNode_ptr node = props->getChild("condition");
330   if (node != 0)
331     _condition = sgReadCondition(prop_root, node);
332 }
333
334 SGSelectAnimation::~SGSelectAnimation ()
335 {
336   delete _condition;
337 }
338
339 int
340 SGSelectAnimation::update()
341 {
342   if (_condition != 0 && _condition->test()) 
343       ((ssgSelector *)_branch)->select(0xffff);
344   else
345       ((ssgSelector *)_branch)->select(0x0000);
346   return 2;
347 }
348
349
350 \f
351 ////////////////////////////////////////////////////////////////////////
352 // Implementation of SGSpinAnimation
353 ////////////////////////////////////////////////////////////////////////
354
355 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
356                               SGPropertyNode_ptr props,
357                               double sim_time_sec )
358   : SGAnimation(props, new ssgTransform),
359     _use_personality( props->getBoolValue("use-personality",false) ),
360     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
361     _last_time_sec( sim_time_sec ),
362     _condition(0),
363     _factor( props, "factor", 1.0 ),
364     _position_deg( props, "starting-position-deg", 0.0 )
365 {
366     SGPropertyNode_ptr node = props->getChild("condition");
367     if (node != 0)
368         _condition = sgReadCondition(prop_root, node);
369
370     _center[0] = 0;
371     _center[1] = 0;
372     _center[2] = 0;
373     if (props->hasValue("axis/x1-m")) {
374         double x1,y1,z1,x2,y2,z2;
375         x1 = props->getFloatValue("axis/x1-m");
376         y1 = props->getFloatValue("axis/y1-m");
377         z1 = props->getFloatValue("axis/z1-m");
378         x2 = props->getFloatValue("axis/x2-m");
379         y2 = props->getFloatValue("axis/y2-m");
380         z2 = props->getFloatValue("axis/z2-m");
381         _center[0] = (x1+x2)/2;
382         _center[1]= (y1+y2)/2;
383         _center[2] = (z1+z2)/2;
384         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
385         _axis[0] = (x2-x1)/vector_length;
386         _axis[1] = (y2-y1)/vector_length;
387         _axis[2] = (z2-z1)/vector_length;
388     } else {
389        _axis[0] = props->getFloatValue("axis/x", 0);
390        _axis[1] = props->getFloatValue("axis/y", 0);
391        _axis[2] = props->getFloatValue("axis/z", 0);
392     }
393     if (props->hasValue("center/x-m")) {
394        _center[0] = props->getFloatValue("center/x-m", 0);
395        _center[1] = props->getFloatValue("center/y-m", 0);
396        _center[2] = props->getFloatValue("center/z-m", 0);
397     }
398     sgNormalizeVec3(_axis);
399 }
400
401 SGSpinAnimation::~SGSpinAnimation ()
402 {
403 }
404
405 int
406 SGSpinAnimation::update()
407 {
408   if ( _condition == 0 || _condition->test() ) {
409     double dt;
410     float velocity_rpms;
411     if ( _use_personality && current_object ) {
412       SGPersonalityBranch *key = current_object;
413       if ( !key->getIntValue( this, INIT_SPIN ) ) {
414         key->setDoubleValue( _factor.shuffle(), this, FACTOR_SPIN );
415         key->setDoubleValue( _position_deg.shuffle(), this, POSITION_DEG_SPIN );
416
417         key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
418         key->setIntValue( 1, this, INIT_SPIN );
419       }
420
421       _factor = key->getDoubleValue( this, FACTOR_SPIN );
422       _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
423       _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
424       dt = sim_time_sec - _last_time_sec;
425       _last_time_sec = sim_time_sec;
426       key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
427
428       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
429       _position_deg += (dt * velocity_rpms * 360);
430       while (_position_deg < 0)
431          _position_deg += 360.0;
432       while (_position_deg >= 360.0)
433          _position_deg -= 360.0;
434       key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
435     } else {
436       dt = sim_time_sec - _last_time_sec;
437       _last_time_sec = sim_time_sec;
438
439       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
440       _position_deg += (dt * velocity_rpms * 360);
441       while (_position_deg < 0)
442          _position_deg += 360.0;
443       while (_position_deg >= 360.0)
444          _position_deg -= 360.0;
445     }
446
447     set_rotation(_matrix, _position_deg, _center, _axis);
448     ((ssgTransform *)_branch)->setTransform(_matrix);
449   }
450   return 1;
451 }
452
453
454 \f
455 ////////////////////////////////////////////////////////////////////////
456 // Implementation of SGTimedAnimation
457 ////////////////////////////////////////////////////////////////////////
458
459 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
460   : SGAnimation(props, new ssgSelector),
461     _use_personality( props->getBoolValue("use-personality",false) ),
462     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
463     _last_time_sec( sim_time_sec ),
464     _total_duration_sec( 0 ),
465     _step( 0 )
466     
467 {
468     vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
469     size_t nb = nodes.size();
470     for ( size_t i = 0; i < nb; i++ ) {
471         size_t ind = nodes[ i ]->getIndex();
472         while ( ind >= _branch_duration_specs.size() ) {
473             _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
474         }
475         SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
476         if ( rNode == 0 ) {
477             _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
478         } else {
479             _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
480                                                           rNode->getDoubleValue( "max", 1.0 ) );
481         }
482     }
483 }
484
485 SGTimedAnimation::~SGTimedAnimation ()
486 {
487 }
488
489 void
490 SGTimedAnimation::init()
491 {
492     if ( !_use_personality ) {
493         for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
494             double v;
495             if ( i < (int)_branch_duration_specs.size() ) {
496                 DurationSpec &sp = _branch_duration_specs[ i ];
497                 v = sp._min + sg_random() * ( sp._max - sp._min );
498             } else {
499                 v = _duration_sec;
500             }
501             _branch_duration_sec.push_back( v );
502             _total_duration_sec += v;
503         }
504         // Sanity check : total duration shouldn't equal zero
505         if ( _total_duration_sec < 0.01 ) {
506             _total_duration_sec = 0.01;
507         }
508     }
509     ((ssgSelector *)getBranch())->selectStep(_step);
510 }
511
512 int
513 SGTimedAnimation::update()
514 {
515     if ( _use_personality && current_object ) {
516         SGPersonalityBranch *key = current_object;
517         if ( !key->getIntValue( this, INIT_TIMED ) ) {
518             double total = 0;
519             double offset = 1.0;
520             for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
521                 DurationSpec &sp = _branch_duration_specs[ i ];
522                 double v = sp._min + sg_random() * ( sp._max - sp._min );
523                 key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
524                 if ( i == 0 )
525                     offset = v;
526                 total += v;
527             }
528             // Sanity check : total duration shouldn't equal zero
529             if ( total < 0.01 ) {
530                 total = 0.01;
531             }
532             offset *= sg_random();
533             key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
534             key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
535             key->setIntValue( 0, this, STEP_TIMED );
536             key->setIntValue( 1, this, INIT_TIMED );
537         }
538
539         _step = key->getIntValue( this, STEP_TIMED );
540         _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
541         _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
542         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
543             _last_time_sec += _total_duration_sec;
544         }
545         double duration = _duration_sec;
546         if ( _step < (int)_branch_duration_specs.size() ) {
547             duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
548         }
549         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
550             _last_time_sec += duration;
551             _step += 1;
552             if ( _step >= getBranch()->getNumKids() )
553                 _step = 0;
554         }
555         ((ssgSelector *)getBranch())->selectStep( _step );
556         key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
557         key->setIntValue( _step, this, STEP_TIMED );
558     } else {
559         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
560             _last_time_sec += _total_duration_sec;
561         }
562         double duration = _duration_sec;
563         if ( _step < (int)_branch_duration_sec.size() ) {
564             duration = _branch_duration_sec[ _step ];
565         }
566         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
567             _last_time_sec += duration;
568             _step += 1;
569             if ( _step >= getBranch()->getNumKids() )
570                 _step = 0;
571             ((ssgSelector *)getBranch())->selectStep( _step );
572         }
573     }
574     return 1;
575 }
576
577
578 \f
579 ////////////////////////////////////////////////////////////////////////
580 // Implementation of SGRotateAnimation
581 ////////////////////////////////////////////////////////////////////////
582
583 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
584                                   SGPropertyNode_ptr props )
585     : SGAnimation(props, new ssgTransform),
586       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
587       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
588       _factor(props->getDoubleValue("factor", 1.0)),
589       _table(read_interpolation_table(props)),
590       _has_min(props->hasValue("min-deg")),
591       _min_deg(props->getDoubleValue("min-deg")),
592       _has_max(props->hasValue("max-deg")),
593       _max_deg(props->getDoubleValue("max-deg")),
594       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
595       _condition(0)
596 {
597     SGPropertyNode_ptr node = props->getChild("condition");
598     if (node != 0)
599       _condition = sgReadCondition(prop_root, node);
600
601     _center[0] = 0;
602     _center[1] = 0;
603     _center[2] = 0;
604     if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
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     } else {
609         double x1,y1,z1,x2,y2,z2;
610         x1 = props->getFloatValue("axis/x1-m", 0);
611         y1 = props->getFloatValue("axis/y1-m", 0);
612         z1 = props->getFloatValue("axis/z1-m", 0);
613         x2 = props->getFloatValue("axis/x2-m", 0);
614         y2 = props->getFloatValue("axis/y2-m", 0);
615         z2 = props->getFloatValue("axis/z2-m", 0);
616         _center[0] = (x1+x2)/2;
617         _center[1]= (y1+y2)/2;
618         _center[2] = (z1+z2)/2;
619         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
620         _axis[0] = (x2-x1)/vector_length;
621         _axis[1] = (y2-y1)/vector_length;
622         _axis[2] = (z2-z1)/vector_length;
623     }
624     if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
625             || props->hasValue("center/z-m")) {
626         _center[0] = props->getFloatValue("center/x-m", 0);
627         _center[1] = props->getFloatValue("center/y-m", 0);
628         _center[2] = props->getFloatValue("center/z-m", 0);
629     }
630     sgNormalizeVec3(_axis);
631 }
632
633 SGRotateAnimation::~SGRotateAnimation ()
634 {
635   delete _table;
636 }
637
638 int
639 SGRotateAnimation::update()
640 {
641   if (_condition == 0 || _condition->test()) {
642     if (_table == 0) {
643       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
644       if (_has_min && _position_deg < _min_deg)
645         _position_deg = _min_deg;
646       if (_has_max && _position_deg > _max_deg)
647         _position_deg = _max_deg;
648     } else {
649       _position_deg = _table->interpolate(_prop->getDoubleValue());
650     }
651     set_rotation(_matrix, _position_deg, _center, _axis);
652     ((ssgTransform *)_branch)->setTransform(_matrix);
653   }
654   return 2;
655 }
656
657 \f
658 ////////////////////////////////////////////////////////////////////////
659 // Implementation of SGBlendAnimation
660 ////////////////////////////////////////////////////////////////////////
661
662 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
663                                         SGPropertyNode_ptr props )
664   : SGAnimation(props, new ssgTransform),
665     _use_personality( props->getBoolValue("use-personality",false) ),
666     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
667     _table(read_interpolation_table(props)),
668     _prev_value(1.0),
669     _offset(props,"offset",0.0),
670     _factor(props,"factor",1.0),
671     _has_min(props->hasValue("min")),
672     _min(props->getDoubleValue("min", 0.0)),
673     _has_max(props->hasValue("max")),
674     _max(props->getDoubleValue("max", 1.0))
675 {
676 }
677
678 SGBlendAnimation::~SGBlendAnimation ()
679 {
680     delete _table;
681 }
682
683 int
684 SGBlendAnimation::update()
685 {
686   double _blend;
687
688   if ( _use_personality && current_object ) {
689     SGPersonalityBranch *key = current_object;
690     if ( !key->getIntValue( this, INIT_BLEND ) ) {
691       key->setDoubleValue( _factor.shuffle(), this, FACTOR_BLEND );
692       key->setDoubleValue( _offset.shuffle(), this, OFFSET_BLEND );
693
694       key->setIntValue( 1, this, INIT_BLEND );
695     }
696
697     _factor = key->getDoubleValue( this, FACTOR_BLEND );
698     _offset = key->getDoubleValue( this, OFFSET_BLEND );
699   }
700
701   if (_table == 0) {
702     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
703
704     if (_has_min && (_blend < _min))
705       _blend = _min;
706     if (_has_max && (_blend > _max))
707       _blend = _max;
708   } else {
709     _blend = _table->interpolate(_prop->getDoubleValue());
710   }
711
712   if (_blend != _prev_value) {
713     _prev_value = _blend;
714     change_alpha( _branch, _blend );
715   }
716   return 1;
717 }
718
719
720 \f
721 ////////////////////////////////////////////////////////////////////////
722 // Implementation of SGTranslateAnimation
723 ////////////////////////////////////////////////////////////////////////
724
725 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
726                                         SGPropertyNode_ptr props )
727   : SGAnimation(props, new ssgTransform),
728     _use_personality( props->getBoolValue("use-personality",false) ),
729     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
730     _table(read_interpolation_table(props)),
731     _has_min(props->hasValue("min-m")),
732     _min_m(props->getDoubleValue("min-m")),
733     _has_max(props->hasValue("max-m")),
734     _max_m(props->getDoubleValue("max-m")),
735     _position_m(props->getDoubleValue("starting-position-m", 0)),
736     _condition(0),
737     _factor( props, "factor", 1.0 ),
738     _offset_m( props, "offset-m", 0.0 )
739 {
740   SGPropertyNode_ptr node = props->getChild("condition");
741   if (node != 0)
742     _condition = sgReadCondition(prop_root, node);
743
744   _axis[0] = props->getFloatValue("axis/x", 0);
745   _axis[1] = props->getFloatValue("axis/y", 0);
746   _axis[2] = props->getFloatValue("axis/z", 0);
747   sgNormalizeVec3(_axis);
748 }
749
750 SGTranslateAnimation::~SGTranslateAnimation ()
751 {
752   delete _table;
753 }
754
755 int
756 SGTranslateAnimation::update()
757 {
758   if (_condition == 0 || _condition->test()) {
759     if ( _use_personality && current_object ) {
760       SGPersonalityBranch *key = current_object;
761       if ( !key->getIntValue( this, INIT_TRANSLATE ) ) {
762         key->setDoubleValue( _factor.shuffle(), this, FACTOR_TRANSLATE );
763         key->setDoubleValue( _offset_m.shuffle(), this, OFFSET_TRANSLATE );
764       }
765
766       _factor = key->getDoubleValue( this, FACTOR_TRANSLATE );
767       _offset_m = key->getDoubleValue( this, OFFSET_TRANSLATE );
768
769       key->setIntValue( 1, this, INIT_TRANSLATE );
770     }
771
772     if (_table == 0) {
773       _position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
774       if (_has_min && _position_m < _min_m)
775         _position_m = _min_m;
776       if (_has_max && _position_m > _max_m)
777         _position_m = _max_m;
778     } else {
779       _position_m = _table->interpolate(_prop->getDoubleValue());
780     }
781
782     set_translation(_matrix, _position_m, _axis);
783     ((ssgTransform *)_branch)->setTransform(_matrix);
784   }
785   return 2;
786 }
787
788
789 \f
790 ////////////////////////////////////////////////////////////////////////
791 // Implementation of SGScaleAnimation
792 ////////////////////////////////////////////////////////////////////////
793
794 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
795                                         SGPropertyNode_ptr props )
796   : SGAnimation(props, new ssgTransform),
797     _use_personality( props->getBoolValue("use-personality",false) ),
798     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
799     _x_factor(props,"x-factor",1.0),
800     _y_factor(props,"y-factor",1.0),
801     _z_factor(props,"z-factor",1.0),
802     _x_offset(props,"x-offset",1.0),
803     _y_offset(props,"y-offset",1.0),
804     _z_offset(props,"z-offset",1.0),
805     _table(read_interpolation_table(props)),
806     _has_min_x(props->hasValue("x-min")),
807     _has_min_y(props->hasValue("y-min")),
808     _has_min_z(props->hasValue("z-min")),
809     _min_x(props->getDoubleValue("x-min")),
810     _min_y(props->getDoubleValue("y-min")),
811     _min_z(props->getDoubleValue("z-min")),
812     _has_max_x(props->hasValue("x-max")),
813     _has_max_y(props->hasValue("y-max")),
814     _has_max_z(props->hasValue("z-max")),
815     _max_x(props->getDoubleValue("x-max")),
816     _max_y(props->getDoubleValue("y-max")),
817     _max_z(props->getDoubleValue("z-max"))
818 {
819 }
820
821 SGScaleAnimation::~SGScaleAnimation ()
822 {
823   delete _table;
824 }
825
826 int
827 SGScaleAnimation::update()
828 {
829   if ( _use_personality && current_object ) {
830     SGPersonalityBranch *key = current_object;
831     if ( !key->getIntValue( this, INIT_SCALE ) ) {
832       key->setDoubleValue( _x_factor.shuffle(), this, X_FACTOR_SCALE );
833       key->setDoubleValue( _x_offset.shuffle(), this, X_OFFSET_SCALE );
834       key->setDoubleValue( _y_factor.shuffle(), this, Y_FACTOR_SCALE );
835       key->setDoubleValue( _y_offset.shuffle(), this, Y_OFFSET_SCALE );
836       key->setDoubleValue( _z_factor.shuffle(), this, Z_FACTOR_SCALE );
837       key->setDoubleValue( _z_offset.shuffle(), this, Z_OFFSET_SCALE );
838
839       key->setIntValue( 1, this, INIT_SCALE );
840     }
841
842     _x_factor = key->getDoubleValue( this, X_FACTOR_SCALE );
843     _x_offset = key->getDoubleValue( this, X_OFFSET_SCALE );
844     _y_factor = key->getDoubleValue( this, Y_FACTOR_SCALE );
845     _y_offset = key->getDoubleValue( this, Y_OFFSET_SCALE );
846     _z_factor = key->getDoubleValue( this, Z_FACTOR_SCALE );
847     _z_offset = key->getDoubleValue( this, Z_OFFSET_SCALE );
848   }
849
850   if (_table == 0) {
851       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
852     if (_has_min_x && _x_scale < _min_x)
853       _x_scale = _min_x;
854     if (_has_max_x && _x_scale > _max_x)
855       _x_scale = _max_x;
856   } else {
857     _x_scale = _table->interpolate(_prop->getDoubleValue());
858   }
859
860   if (_table == 0) {
861     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
862     if (_has_min_y && _y_scale < _min_y)
863       _y_scale = _min_y;
864     if (_has_max_y && _y_scale > _max_y)
865       _y_scale = _max_y;
866   } else {
867     _y_scale = _table->interpolate(_prop->getDoubleValue());
868   }
869
870   if (_table == 0) {
871     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
872     if (_has_min_z && _z_scale < _min_z)
873       _z_scale = _min_z;
874     if (_has_max_z && _z_scale > _max_z)
875       _z_scale = _max_z;
876   } else {
877     _z_scale = _table->interpolate(_prop->getDoubleValue());
878   }
879
880   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
881   ((ssgTransform *)_branch)->setTransform(_matrix);
882   return 2;
883 }
884
885
886 ////////////////////////////////////////////////////////////////////////
887 // Implementation of SGTexRotateAnimation
888 ////////////////////////////////////////////////////////////////////////
889
890 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
891                                   SGPropertyNode_ptr props )
892     : SGAnimation(props, new ssgTexTrans),
893       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
894       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
895       _factor(props->getDoubleValue("factor", 1.0)),
896       _table(read_interpolation_table(props)),
897       _has_min(props->hasValue("min-deg")),
898       _min_deg(props->getDoubleValue("min-deg")),
899       _has_max(props->hasValue("max-deg")),
900       _max_deg(props->getDoubleValue("max-deg")),
901       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
902       _condition(0)
903 {
904   SGPropertyNode *node = props->getChild("condition");
905   if (node != 0)
906     _condition = sgReadCondition(prop_root, node);
907
908   _center[0] = props->getFloatValue("center/x", 0);
909   _center[1] = props->getFloatValue("center/y", 0);
910   _center[2] = props->getFloatValue("center/z", 0);
911   _axis[0] = props->getFloatValue("axis/x", 0);
912   _axis[1] = props->getFloatValue("axis/y", 0);
913   _axis[2] = props->getFloatValue("axis/z", 0);
914   sgNormalizeVec3(_axis);
915 }
916
917 SGTexRotateAnimation::~SGTexRotateAnimation ()
918 {
919   delete _table;
920 }
921
922 int
923 SGTexRotateAnimation::update()
924 {
925   if (_condition && !_condition->test())
926     return 1;
927
928   if (_table == 0) {
929    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
930    if (_has_min && _position_deg < _min_deg)
931      _position_deg = _min_deg;
932    if (_has_max && _position_deg > _max_deg)
933      _position_deg = _max_deg;
934   } else {
935     _position_deg = _table->interpolate(_prop->getDoubleValue());
936   }
937   set_rotation(_matrix, _position_deg, _center, _axis);
938   ((ssgTexTrans *)_branch)->setTransform(_matrix);
939   return 2;
940 }
941
942
943 ////////////////////////////////////////////////////////////////////////
944 // Implementation of SGTexTranslateAnimation
945 ////////////////////////////////////////////////////////////////////////
946
947 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
948                                         SGPropertyNode_ptr props )
949   : SGAnimation(props, new ssgTexTrans),
950       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
951     _offset(props->getDoubleValue("offset", 0.0)),
952     _factor(props->getDoubleValue("factor", 1.0)),
953     _step(props->getDoubleValue("step",0.0)),
954     _scroll(props->getDoubleValue("scroll",0.0)),
955     _table(read_interpolation_table(props)),
956     _has_min(props->hasValue("min")),
957     _min(props->getDoubleValue("min")),
958     _has_max(props->hasValue("max")),
959     _max(props->getDoubleValue("max")),
960     _position(props->getDoubleValue("starting-position", 0)),
961     _condition(0)
962 {
963   SGPropertyNode *node = props->getChild("condition");
964   if (node != 0)
965     _condition = sgReadCondition(prop_root, node);
966
967   _axis[0] = props->getFloatValue("axis/x", 0);
968   _axis[1] = props->getFloatValue("axis/y", 0);
969   _axis[2] = props->getFloatValue("axis/z", 0);
970   sgNormalizeVec3(_axis);
971 }
972
973 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
974 {
975   delete _table;
976 }
977
978 int
979 SGTexTranslateAnimation::update()
980 {
981   if (_condition && !_condition->test())
982     return 1;
983
984   if (_table == 0) {
985     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
986     if (_has_min && _position < _min)
987       _position = _min;
988     if (_has_max && _position > _max)
989       _position = _max;
990   } else {
991     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
992   }
993   set_translation(_matrix, _position, _axis);
994   ((ssgTexTrans *)_branch)->setTransform(_matrix);
995   return 2;
996 }
997
998
999 ////////////////////////////////////////////////////////////////////////
1000 // Implementation of SGTexMultipleAnimation
1001 ////////////////////////////////////////////////////////////////////////
1002
1003 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
1004                                         SGPropertyNode_ptr props )
1005   : SGAnimation(props, new ssgTexTrans),
1006       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
1007 {
1008   unsigned int i;
1009   // Load animations
1010   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
1011   _transform = new TexTransform [transform_nodes.size()];
1012   _num_transforms = 0;
1013   for (i = 0; i < transform_nodes.size(); i++) {
1014     SGPropertyNode_ptr transform_props = transform_nodes[i];
1015
1016     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
1017
1018       // transform is a translation
1019       _transform[i].subtype = 0;
1020
1021       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1022
1023       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
1024       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1025       _transform[i].step = transform_props->getDoubleValue("step",0.0);
1026       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
1027       _transform[i].table = read_interpolation_table(transform_props);
1028       _transform[i].has_min = transform_props->hasValue("min");
1029       _transform[i].min = transform_props->getDoubleValue("min");
1030       _transform[i].has_max = transform_props->hasValue("max");
1031       _transform[i].max = transform_props->getDoubleValue("max");
1032       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
1033
1034       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1035       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1036       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1037       sgNormalizeVec3(_transform[i].axis);
1038       _num_transforms++;
1039     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
1040
1041       // transform is a rotation
1042       _transform[i].subtype = 1;
1043
1044       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1045       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
1046       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1047       _transform[i].table = read_interpolation_table(transform_props);
1048       _transform[i].has_min = transform_props->hasValue("min-deg");
1049       _transform[i].min = transform_props->getDoubleValue("min-deg");
1050       _transform[i].has_max = transform_props->hasValue("max-deg");
1051       _transform[i].max = transform_props->getDoubleValue("max-deg");
1052       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
1053
1054       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
1055       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
1056       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
1057       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1058       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1059       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1060       sgNormalizeVec3(_transform[i].axis);
1061       _num_transforms++;
1062     }
1063   }
1064 }
1065
1066 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
1067 {
1068    delete [] _transform;
1069 }
1070
1071 int
1072 SGTexMultipleAnimation::update()
1073 {
1074   int i;
1075   sgMat4 tmatrix;
1076   sgMakeIdentMat4(tmatrix);
1077   for (i = 0; i < _num_transforms; i++) {
1078
1079     if(_transform[i].subtype == 0) {
1080
1081       // subtype 0 is translation
1082       if (_transform[i].table == 0) {
1083         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
1084         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1085           _transform[i].position = _transform[i].min;
1086         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1087           _transform[i].position = _transform[i].max;
1088       } else {
1089          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
1090       }
1091       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
1092       sgPreMultMat4(tmatrix, _transform[i].matrix);
1093
1094     } else if (_transform[i].subtype == 1) {
1095
1096       // subtype 1 is rotation
1097
1098       if (_transform[i].table == 0) {
1099         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
1100         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1101          _transform[i].position = _transform[i].min;
1102        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1103          _transform[i].position = _transform[i].max;
1104      } else {
1105         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1106       }
1107       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1108       sgPreMultMat4(tmatrix, _transform[i].matrix);
1109     }
1110   }
1111   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
1112   return 2;
1113 }
1114
1115
1116 \f
1117 ////////////////////////////////////////////////////////////////////////
1118 // Implementation of SGAlphaTestAnimation
1119 ////////////////////////////////////////////////////////////////////////
1120
1121 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1122   : SGAnimation(props, new ssgBranch)
1123 {
1124   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1125 }
1126
1127 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1128 {
1129 }
1130
1131 void SGAlphaTestAnimation::init()
1132 {
1133   setAlphaClampToBranch(_branch,_alpha_clamp);
1134 }
1135
1136 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
1137 {
1138   int nb = b->getNumKids();
1139   for (int i = 0; i<nb; i++) {
1140     ssgEntity *e = b->getKid(i);
1141     if (e->isAKindOf(ssgTypeLeaf())) {
1142       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1143       s->enable( GL_ALPHA_TEST );
1144       s->setAlphaClamp( clamp );
1145     } else if (e->isAKindOf(ssgTypeBranch())) {
1146       setAlphaClampToBranch( (ssgBranch*)e, clamp );
1147     }
1148   }
1149 }
1150
1151
1152 \f
1153 ////////////////////////////////////////////////////////////////////////
1154 // Implementation of SGMaterialAnimation
1155 ////////////////////////////////////////////////////////////////////////
1156
1157 SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
1158         SGPropertyNode_ptr props, const SGPath &texture_path)
1159     : SGAnimation(props, new ssgBranch),
1160     _last_condition(false),
1161     _prop_root(prop_root),
1162     _prop_base(""),
1163     _texture_base(texture_path),
1164     _cached_material(0),
1165     _cloned_material(0),
1166     _read(0),
1167     _update(0),
1168     _global(props->getBoolValue("global", false))
1169 {
1170     SGPropertyNode_ptr n;
1171     n = props->getChild("condition");
1172     _condition = n ? sgReadCondition(_prop_root, n) : 0;
1173     n = props->getChild("property-base");
1174     if (n) {
1175         _prop_base = n->getStringValue();
1176         if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
1177             _prop_base += '/';
1178     }
1179
1180     initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
1181     initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
1182     initColorGroup(props->getChild("emission"), &_emis, EMISSION);
1183     initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
1184
1185     _shi = props->getFloatValue("shininess", -1.0);
1186     if (_shi >= 0.0)
1187         _update |= SHININESS;
1188
1189     SGPropertyNode_ptr group = props->getChild("transparency");
1190     if (group) {
1191         _trans.value = group->getFloatValue("alpha", -1.0);
1192         _trans.factor = group->getFloatValue("factor", 1.0);
1193         _trans.offset = group->getFloatValue("offset", 0.0);
1194         _trans.min = group->getFloatValue("min", 0.0);
1195         if (_trans.min < 0.0)
1196             _trans.min = 0.0;
1197         _trans.max = group->getFloatValue("max", 1.0);
1198         if (_trans.max > 1.0)
1199             _trans.max = 1.0;
1200         if (_trans.dirty())
1201             _update |= TRANSPARENCY;
1202
1203         n = group->getChild("alpha-prop");
1204         _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1205         n = group->getChild("factor-prop");
1206         _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1207         n = group->getChild("offset-prop");
1208         _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1209         if (_trans.live())
1210             _read |= TRANSPARENCY;
1211     }
1212
1213     _thresh = props->getFloatValue("threshold", -1.0);
1214     if (_thresh >= 0.0)
1215         _update |= THRESHOLD;
1216
1217     string _texture_str = props->getStringValue("texture", "");
1218     if (!_texture_str.empty()) {
1219         _texture = _texture_base;
1220         _texture.append(_texture_str);
1221         _update |= TEXTURE;
1222     }
1223
1224     n = props->getChild("shininess-prop");
1225     _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1226     n = props->getChild("threshold-prop");
1227     _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1228     n = props->getChild("texture-prop");
1229     _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1230
1231     _static_update = _update;
1232 }
1233
1234 void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
1235 {
1236     if (!group)
1237         return;
1238
1239     col->red = group->getFloatValue("red", -1.0);
1240     col->green = group->getFloatValue("green", -1.0);
1241     col->blue = group->getFloatValue("blue", -1.0);
1242     col->factor = group->getFloatValue("factor", 1.0);
1243     col->offset = group->getFloatValue("offset", 0.0);
1244     if (col->dirty())
1245         _update |= flag;
1246
1247     SGPropertyNode *n;
1248     n = group->getChild("red-prop");
1249     col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1250     n = group->getChild("green-prop");
1251     col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1252     n = group->getChild("blue-prop");
1253     col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1254     n = group->getChild("factor-prop");
1255     col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1256     n = group->getChild("offset-prop");
1257     col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1258     if (col->live())
1259         _read |= flag;
1260 }
1261
1262 void SGMaterialAnimation::init()
1263 {
1264     if (!_global)
1265         cloneMaterials(_branch);
1266 }
1267
1268 int SGMaterialAnimation::update()
1269 {
1270     if (_condition) {
1271         bool cond = _condition->test();
1272         if (cond && !_last_condition)
1273             _update |= _static_update;
1274
1275         _last_condition = cond;
1276         if (!cond)
1277             return 2;
1278     }
1279
1280     if (_read & DIFFUSE)
1281         updateColorGroup(&_diff, DIFFUSE);
1282     if (_read & AMBIENT)
1283         updateColorGroup(&_amb, AMBIENT);
1284     if (_read & EMISSION)
1285         updateColorGroup(&_emis, EMISSION);
1286     if (_read & SPECULAR)
1287         updateColorGroup(&_spec, SPECULAR);
1288
1289     float f;
1290     if (_shi_prop) {
1291         f = _shi;
1292         _shi = _shi_prop->getFloatValue();
1293         if (_shi != f)
1294             _update |= SHININESS;
1295     }
1296     if (_read & TRANSPARENCY) {
1297         PropSpec tmp = _trans;
1298         if (_trans.value_prop)
1299             _trans.value = _trans.value_prop->getFloatValue();
1300         if (_trans.factor_prop)
1301             _trans.factor = _trans.factor_prop->getFloatValue();
1302         if (_trans.offset_prop)
1303             _trans.offset = _trans.offset_prop->getFloatValue();
1304         if (_trans != tmp)
1305             _update |= TRANSPARENCY;
1306     }
1307     if (_thresh_prop) {
1308         f = _thresh;
1309         _thresh = _thresh_prop->getFloatValue();
1310         if (_thresh != f)
1311             _update |= THRESHOLD;
1312     }
1313     if (_tex_prop) {
1314         string t = _tex_prop->getStringValue();
1315         if (!t.empty() && t != _texture_str) {
1316             _texture_str = t;
1317             _texture = _texture_base;
1318             _texture.append(t);
1319             _update |= TEXTURE;
1320         }
1321     }
1322     if (_update) {
1323         setMaterialBranch(_branch);
1324         _update = 0;
1325     }
1326     return 2;
1327 }
1328
1329 void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
1330 {
1331     ColorSpec tmp = *col;
1332     if (col->red_prop)
1333         col->red = col->red_prop->getFloatValue();
1334     if (col->green_prop)
1335         col->green = col->green_prop->getFloatValue();
1336     if (col->blue_prop)
1337         col->blue = col->blue_prop->getFloatValue();
1338     if (col->factor_prop)
1339         col->factor = col->factor_prop->getFloatValue();
1340     if (col->offset_prop)
1341         col->offset = col->offset_prop->getFloatValue();
1342     if (*col != tmp)
1343         _update |= flag;
1344 }
1345
1346 void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
1347 {
1348     for (int i = 0; i < b->getNumKids(); i++)
1349         cloneMaterials((ssgBranch *)b->getKid(i));
1350
1351     if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1352         return;
1353
1354     ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1355     if (!_cached_material || _cached_material != s) {
1356         _cached_material = s;
1357         _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
1358     }
1359     ((ssgLeaf *)b)->setState(_cloned_material);
1360 }
1361
1362 void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
1363 {
1364     for (int i = 0; i < b->getNumKids(); i++)
1365         setMaterialBranch((ssgBranch *)b->getKid(i));
1366
1367     if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1368         return;
1369
1370     ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1371
1372     if (_update & DIFFUSE) {
1373         float *v = _diff.rgba();
1374         SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1375         s->setColourMaterial(GL_DIFFUSE);
1376         s->enable(GL_COLOR_MATERIAL);
1377         s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
1378         s->disable(GL_COLOR_MATERIAL);
1379     }
1380     if (_update & AMBIENT) {
1381         s->setColourMaterial(GL_AMBIENT);
1382         s->enable(GL_COLOR_MATERIAL);
1383         s->setMaterial(GL_AMBIENT, _amb.rgba());
1384         s->disable(GL_COLOR_MATERIAL);
1385     }
1386     if (_update & EMISSION)
1387         s->setMaterial(GL_EMISSION, _emis.rgba());
1388     if (_update & SPECULAR)
1389         s->setMaterial(GL_SPECULAR, _spec.rgba());
1390     if (_update & SHININESS)
1391         s->setShininess(clamp(_shi, 0.0, 128.0));
1392     if (_update & TRANSPARENCY) {
1393         SGfloat *v = s->getMaterial(GL_DIFFUSE);
1394         float trans = _trans.value * _trans.factor + _trans.offset;
1395         trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
1396         s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
1397     }
1398     if (_update & THRESHOLD)
1399         s->setAlphaClamp(clamp(_thresh));
1400     if (_update & TEXTURE)
1401         s->setTexture(_texture.c_str());
1402     if (_update & (TEXTURE|TRANSPARENCY)) {
1403         SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1404         ssgTexture *tex = s->getTexture();
1405         if ((tex && tex->hasAlpha()) || alpha < 0.999) {
1406             s->setColourMaterial(GL_DIFFUSE);
1407             s->enable(GL_COLOR_MATERIAL);
1408             s->enable(GL_BLEND);
1409             s->enable(GL_ALPHA_TEST);
1410             s->setTranslucent();
1411             s->disable(GL_COLOR_MATERIAL);
1412         } else {
1413             s->disable(GL_BLEND);
1414             s->disable(GL_ALPHA_TEST);
1415             s->setOpaque();
1416         }
1417     }
1418     s->force();
1419 }
1420
1421
1422 \f
1423 ////////////////////////////////////////////////////////////////////////
1424 // Implementation of SGFlashAnimation
1425 ////////////////////////////////////////////////////////////////////////
1426 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1427   : SGAnimation( props, new SGCustomTransform )
1428 {
1429   _axis[0] = props->getFloatValue("axis/x", 0);
1430   _axis[1] = props->getFloatValue("axis/y", 0);
1431   _axis[2] = props->getFloatValue("axis/z", 1);
1432
1433   _center[0] = props->getFloatValue("center/x-m", 0);
1434   _center[1] = props->getFloatValue("center/y-m", 0);
1435   _center[2] = props->getFloatValue("center/z-m", 0);
1436
1437   _offset = props->getFloatValue("offset", 0.0);
1438   _factor = props->getFloatValue("factor", 1.0);
1439   _power = props->getFloatValue("power", 1.0);
1440   _two_sides = props->getBoolValue("two-sides", false);
1441
1442   _min_v = props->getFloatValue("min", 0.0);
1443   _max_v = props->getFloatValue("max", 1.0);
1444
1445   ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
1446 }
1447
1448 SGFlashAnimation::~SGFlashAnimation()
1449 {
1450 }
1451
1452 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1453 {
1454   ((SGFlashAnimation *)d)->flashCallback( r, f, m );
1455 }
1456
1457 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1458 {
1459   sgVec3 transformed_axis;
1460   sgXformVec3( transformed_axis, _axis, m );
1461   sgNormalizeVec3( transformed_axis );
1462
1463   sgVec3 view;
1464   sgFullXformPnt3( view, _center, m );
1465   sgNormalizeVec3( view );
1466
1467   float cos_angle = -sgScalarProductVec3( transformed_axis, view );
1468   float scale_factor = 0.f;
1469   if ( _two_sides && cos_angle < 0 )
1470     scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
1471   else if ( cos_angle > 0 )
1472     scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
1473
1474   if ( scale_factor < _min_v )
1475       scale_factor = _min_v;
1476   if ( scale_factor > _max_v )
1477       scale_factor = _max_v;
1478
1479   sgMat4 transform;
1480   sgMakeIdentMat4( transform );
1481   transform[0][0] = scale_factor;
1482   transform[1][1] = scale_factor;
1483   transform[2][2] = scale_factor;
1484   transform[3][0] = _center[0] * ( 1 - scale_factor );
1485   transform[3][1] = _center[1] * ( 1 - scale_factor );
1486   transform[3][2] = _center[2] * ( 1 - scale_factor );
1487
1488   sgCopyMat4( r, m );
1489   sgPreMultMat4( r, transform );
1490 }
1491
1492
1493 \f
1494 ////////////////////////////////////////////////////////////////////////
1495 // Implementation of SGDistScaleAnimation
1496 ////////////////////////////////////////////////////////////////////////
1497 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1498   : SGAnimation( props, new SGCustomTransform ),
1499     _factor(props->getFloatValue("factor", 1.0)),
1500     _offset(props->getFloatValue("offset", 0.0)),
1501     _min_v(props->getFloatValue("min", 0.0)),
1502     _max_v(props->getFloatValue("max", 1.0)),
1503     _has_min(props->hasValue("min")),
1504     _has_max(props->hasValue("max")),
1505     _table(read_interpolation_table(props))
1506 {
1507   _center[0] = props->getFloatValue("center/x-m", 0);
1508   _center[1] = props->getFloatValue("center/y-m", 0);
1509   _center[2] = props->getFloatValue("center/z-m", 0);
1510
1511   ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
1512 }
1513
1514 SGDistScaleAnimation::~SGDistScaleAnimation()
1515 {
1516 }
1517
1518 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1519 {
1520   ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
1521 }
1522
1523 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1524 {
1525   sgVec3 view;
1526   sgFullXformPnt3( view, _center, m );
1527
1528   float scale_factor = sgLengthVec3( view );
1529   if (_table == 0) {
1530     scale_factor = _factor * scale_factor + _offset;
1531     if ( _has_min && scale_factor < _min_v )
1532       scale_factor = _min_v;
1533     if ( _has_max && scale_factor > _max_v )
1534       scale_factor = _max_v;
1535   } else {
1536     scale_factor = _table->interpolate( scale_factor );
1537   }
1538
1539   sgMat4 transform;
1540   sgMakeIdentMat4( transform );
1541   transform[0][0] = scale_factor;
1542   transform[1][1] = scale_factor;
1543   transform[2][2] = scale_factor;
1544   transform[3][0] = _center[0] * ( 1 - scale_factor );
1545   transform[3][1] = _center[1] * ( 1 - scale_factor );
1546   transform[3][2] = _center[2] * ( 1 - scale_factor );
1547
1548   sgCopyMat4( r, m );
1549   sgPreMultMat4( r, transform );
1550 }
1551
1552 ////////////////////////////////////////////////////////////////////////
1553 // Implementation of SGShadowAnimation
1554 ////////////////////////////////////////////////////////////////////////
1555
1556 SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
1557                    SGPropertyNode_ptr props )
1558   : SGAnimation(props, new ssgBranch),
1559     _condition(0),
1560         _condition_value(true)
1561 {
1562         animation_type = 1;
1563         SGPropertyNode_ptr node = props->getChild("condition");
1564         if (node != 0) {
1565                 _condition = sgReadCondition(prop_root, node);
1566                 _condition_value = false;
1567         }
1568 }
1569
1570 SGShadowAnimation::~SGShadowAnimation ()
1571 {
1572         delete _condition;
1573 }
1574
1575 int
1576 SGShadowAnimation::update()
1577 {
1578         if (_condition)
1579                 _condition_value = _condition->test();
1580         return 2;
1581 }
1582
1583 bool SGShadowAnimation::get_condition_value(void) {
1584         return _condition_value;
1585 }
1586
1587 // end of animation.cxx