]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/animation.cxx
9e41c6cd1b2f638f6236fae45c3fcafbfdaf13e8
[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 {
364     SGPropertyNode_ptr node = props->getChild("condition");
365     if (node != 0)
366         _condition = sgReadCondition(prop_root, node);
367
368     _center[0] = 0;
369     _center[1] = 0;
370     _center[2] = 0;
371     if (props->hasValue("axis/x1-m")) {
372         double x1,y1,z1,x2,y2,z2;
373         x1 = props->getFloatValue("axis/x1-m");
374         y1 = props->getFloatValue("axis/y1-m");
375         z1 = props->getFloatValue("axis/z1-m");
376         x2 = props->getFloatValue("axis/x2-m");
377         y2 = props->getFloatValue("axis/y2-m");
378         z2 = props->getFloatValue("axis/z2-m");
379         _center[0] = (x1+x2)/2;
380         _center[1]= (y1+y2)/2;
381         _center[2] = (z1+z2)/2;
382         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
383         _axis[0] = (x2-x1)/vector_length;
384         _axis[1] = (y2-y1)/vector_length;
385         _axis[2] = (z2-z1)/vector_length;
386     } else {
387        _axis[0] = props->getFloatValue("axis/x", 0);
388        _axis[1] = props->getFloatValue("axis/y", 0);
389        _axis[2] = props->getFloatValue("axis/z", 0);
390     }
391     if (props->hasValue("center/x-m")) {
392        _center[0] = props->getFloatValue("center/x-m", 0);
393        _center[1] = props->getFloatValue("center/y-m", 0);
394        _center[2] = props->getFloatValue("center/z-m", 0);
395     }
396     sgNormalizeVec3(_axis);
397
398     //_factor(props->getDoubleValue("factor", 1.0)),
399     _factor = 1.0;
400     _factor_min = 1.0;
401     _factor_max = 1.0;
402     SGPropertyNode_ptr factor_n = props->getNode( "factor" );
403     if ( factor_n != 0 ) {
404        SGPropertyNode_ptr rand_n = factor_n->getNode( "random" );
405        if ( rand_n != 0 ) {
406           _factor_min = rand_n->getDoubleValue( "min", 0.0 );
407           _factor_max = rand_n->getDoubleValue( "max", 1.0 );
408           _factor = _factor_min + sg_random() * ( _factor_max - _factor_min );
409        } else {
410           _factor = _factor_min = _factor_max = props->getDoubleValue("factor", 1.0);
411        }
412     }
413     //_position_deg(props->getDoubleValue("starting-position-deg", 0)),
414     _position_deg = 0.0;
415     _position_deg_min = 0.0;
416     _position_deg_max = 0.0;
417     SGPropertyNode_ptr position_deg_n = props->getNode( "starting-position-deg" );
418     if ( position_deg_n != 0 ) {
419        SGPropertyNode_ptr rand_n = position_deg_n->getNode( "random" );
420        if ( rand_n != 0 ) {
421           _position_deg_min = rand_n->getDoubleValue( "min", 0.0 );
422           _position_deg_max = rand_n->getDoubleValue( "max", 1.0 );
423           _position_deg = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
424        } else {
425           _position_deg = _position_deg_min = _position_deg_max = 
426                   props->getDoubleValue("starting-position-deg", 1.0);
427        }
428     }
429 }
430
431 SGSpinAnimation::~SGSpinAnimation ()
432 {
433 }
434
435 int
436 SGSpinAnimation::update()
437 {
438   if ( _condition == 0 || _condition->test() ) {
439     double dt;
440     float velocity_rpms;
441     if ( _use_personality ) {
442       SGPersonalityBranch *key = current_object;
443       if ( !key->getIntValue( this, INIT_SPIN ) ) {
444         double v = _factor_min + sg_random() * ( _factor_max - _factor_min );
445         key->setDoubleValue( v, this, FACTOR_SPIN );
446
447         key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
448         key->setIntValue( 1, this, INIT_SPIN );
449
450         v = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
451         key->setDoubleValue( v, this, POSITION_DEG_SPIN );
452       }
453
454       _factor = key->getDoubleValue( this, FACTOR_SPIN );
455       _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
456       _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
457       dt = sim_time_sec - _last_time_sec;
458       _last_time_sec = sim_time_sec;
459       key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
460
461       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
462       _position_deg += (dt * velocity_rpms * 360);
463       while (_position_deg < 0)
464          _position_deg += 360.0;
465       while (_position_deg >= 360.0)
466          _position_deg -= 360.0;
467       key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
468     } else {
469       dt = sim_time_sec - _last_time_sec;
470       _last_time_sec = sim_time_sec;
471
472       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
473       _position_deg += (dt * velocity_rpms * 360);
474       while (_position_deg < 0)
475          _position_deg += 360.0;
476       while (_position_deg >= 360.0)
477          _position_deg -= 360.0;
478     }
479
480     set_rotation(_matrix, _position_deg, _center, _axis);
481     ((ssgTransform *)_branch)->setTransform(_matrix);
482   }
483   return 1;
484 }
485
486
487 \f
488 ////////////////////////////////////////////////////////////////////////
489 // Implementation of SGTimedAnimation
490 ////////////////////////////////////////////////////////////////////////
491
492 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
493   : SGAnimation(props, new ssgSelector),
494     _use_personality( props->getBoolValue("use-personality",false) ),
495     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
496     _last_time_sec( sim_time_sec ),
497     _total_duration_sec( 0 ),
498     _step( 0 )
499     
500 {
501     vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
502     size_t nb = nodes.size();
503     for ( size_t i = 0; i < nb; i++ ) {
504         size_t ind = nodes[ i ]->getIndex();
505         while ( ind >= _branch_duration_specs.size() ) {
506             _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
507         }
508         SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
509         if ( rNode == 0 ) {
510             _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
511         } else {
512             _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
513                                                           rNode->getDoubleValue( "max", 1.0 ) );
514         }
515     }
516 }
517
518 SGTimedAnimation::~SGTimedAnimation ()
519 {
520 }
521
522 void
523 SGTimedAnimation::init()
524 {
525     if ( !_use_personality ) {
526         for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
527             double v;
528             if ( i < (int)_branch_duration_specs.size() ) {
529                 DurationSpec &sp = _branch_duration_specs[ i ];
530                 v = sp._min + sg_random() * ( sp._max - sp._min );
531             } else {
532                 v = _duration_sec;
533             }
534             _branch_duration_sec.push_back( v );
535             _total_duration_sec += v;
536         }
537         // Sanity check : total duration shouldn't equal zero
538         if ( _total_duration_sec < 0.01 ) {
539             _total_duration_sec = 0.01;
540         }
541     }
542     ((ssgSelector *)getBranch())->selectStep(_step);
543 }
544
545 int
546 SGTimedAnimation::update()
547 {
548     if ( _use_personality ) {
549         SGPersonalityBranch *key = current_object;
550         if ( !key->getIntValue( this, INIT_TIMED ) ) {
551             double total = 0;
552             double offset = 1.0;
553             for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
554                 DurationSpec &sp = _branch_duration_specs[ i ];
555                 double v = sp._min + sg_random() * ( sp._max - sp._min );
556                 key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
557                 if ( i == 0 )
558                     offset = v;
559                 total += v;
560             }
561             // Sanity check : total duration shouldn't equal zero
562             if ( total < 0.01 ) {
563                 total = 0.01;
564             }
565             offset *= sg_random();
566             key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
567             key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
568             key->setIntValue( 0, this, STEP_TIMED );
569             key->setIntValue( 1, this, INIT_TIMED );
570         }
571
572         _step = key->getIntValue( this, STEP_TIMED );
573         _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
574         _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
575         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
576             _last_time_sec += _total_duration_sec;
577         }
578         double duration = _duration_sec;
579         if ( _step < (int)_branch_duration_specs.size() ) {
580             duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
581         }
582         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
583             _last_time_sec += duration;
584             _step += 1;
585             if ( _step >= getBranch()->getNumKids() )
586                 _step = 0;
587         }
588         ((ssgSelector *)getBranch())->selectStep( _step );
589         key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
590         key->setIntValue( _step, this, STEP_TIMED );
591     } else {
592         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
593             _last_time_sec += _total_duration_sec;
594         }
595         double duration = _duration_sec;
596         if ( _step < (int)_branch_duration_sec.size() ) {
597             duration = _branch_duration_sec[ _step ];
598         }
599         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
600             _last_time_sec += duration;
601             _step += 1;
602             if ( _step >= getBranch()->getNumKids() )
603                 _step = 0;
604             ((ssgSelector *)getBranch())->selectStep( _step );
605         }
606     }
607     return 1;
608 }
609
610
611 \f
612 ////////////////////////////////////////////////////////////////////////
613 // Implementation of SGRotateAnimation
614 ////////////////////////////////////////////////////////////////////////
615
616 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
617                                   SGPropertyNode_ptr props )
618     : SGAnimation(props, new ssgTransform),
619       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
620       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
621       _factor(props->getDoubleValue("factor", 1.0)),
622       _table(read_interpolation_table(props)),
623       _has_min(props->hasValue("min-deg")),
624       _min_deg(props->getDoubleValue("min-deg")),
625       _has_max(props->hasValue("max-deg")),
626       _max_deg(props->getDoubleValue("max-deg")),
627       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
628       _condition(0)
629 {
630     SGPropertyNode_ptr node = props->getChild("condition");
631     if (node != 0)
632       _condition = sgReadCondition(prop_root, node);
633
634     _center[0] = 0;
635     _center[1] = 0;
636     _center[2] = 0;
637     if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
638        _axis[0] = props->getFloatValue("axis/x", 0);
639        _axis[1] = props->getFloatValue("axis/y", 0);
640        _axis[2] = props->getFloatValue("axis/z", 0);
641     } else {
642         double x1,y1,z1,x2,y2,z2;
643         x1 = props->getFloatValue("axis/x1-m", 0);
644         y1 = props->getFloatValue("axis/y1-m", 0);
645         z1 = props->getFloatValue("axis/z1-m", 0);
646         x2 = props->getFloatValue("axis/x2-m", 0);
647         y2 = props->getFloatValue("axis/y2-m", 0);
648         z2 = props->getFloatValue("axis/z2-m", 0);
649         _center[0] = (x1+x2)/2;
650         _center[1]= (y1+y2)/2;
651         _center[2] = (z1+z2)/2;
652         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
653         _axis[0] = (x2-x1)/vector_length;
654         _axis[1] = (y2-y1)/vector_length;
655         _axis[2] = (z2-z1)/vector_length;
656     }
657     if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
658             || props->hasValue("center/z-m")) {
659         _center[0] = props->getFloatValue("center/x-m", 0);
660         _center[1] = props->getFloatValue("center/y-m", 0);
661         _center[2] = props->getFloatValue("center/z-m", 0);
662     }
663     sgNormalizeVec3(_axis);
664 }
665
666 SGRotateAnimation::~SGRotateAnimation ()
667 {
668   delete _table;
669 }
670
671 int
672 SGRotateAnimation::update()
673 {
674   if (_condition == 0 || _condition->test()) {
675     if (_table == 0) {
676       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
677       if (_has_min && _position_deg < _min_deg)
678         _position_deg = _min_deg;
679       if (_has_max && _position_deg > _max_deg)
680         _position_deg = _max_deg;
681     } else {
682       _position_deg = _table->interpolate(_prop->getDoubleValue());
683     }
684     set_rotation(_matrix, _position_deg, _center, _axis);
685     ((ssgTransform *)_branch)->setTransform(_matrix);
686   }
687   return 2;
688 }
689
690 \f
691 ////////////////////////////////////////////////////////////////////////
692 // Implementation of SGBlendAnimation
693 ////////////////////////////////////////////////////////////////////////
694
695 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
696                                         SGPropertyNode_ptr props )
697   : SGAnimation(props, new ssgTransform),
698     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
699     _table(read_interpolation_table(props)),
700     _prev_value(1.0),
701     _offset(props->getDoubleValue("offset", 0.0)),
702     _factor(props->getDoubleValue("factor", 1.0)),
703     _has_min(props->hasValue("min")),
704     _min(props->getDoubleValue("min", 0.0)),
705     _has_max(props->hasValue("max")),
706     _max(props->getDoubleValue("max", 1.0))
707 {
708 }
709
710 SGBlendAnimation::~SGBlendAnimation ()
711 {
712     delete _table;
713 }
714
715 int
716 SGBlendAnimation::update()
717 {
718   double _blend;
719
720   if (_table == 0) {
721     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
722
723     if (_has_min && (_blend < _min))
724       _blend = _min;
725     if (_has_max && (_blend > _max))
726       _blend = _max;
727   } else {
728     _blend = _table->interpolate(_prop->getDoubleValue());
729   }
730
731   if (_blend != _prev_value) {
732     _prev_value = _blend;
733     change_alpha( _branch, _blend );
734   }
735   return 1;
736 }
737
738
739 \f
740 ////////////////////////////////////////////////////////////////////////
741 // Implementation of SGTranslateAnimation
742 ////////////////////////////////////////////////////////////////////////
743
744 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
745                                         SGPropertyNode_ptr props )
746   : SGAnimation(props, new ssgTransform),
747       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
748     _offset_m(props->getDoubleValue("offset-m", 0.0)),
749     _factor(props->getDoubleValue("factor", 1.0)),
750     _table(read_interpolation_table(props)),
751     _has_min(props->hasValue("min-m")),
752     _min_m(props->getDoubleValue("min-m")),
753     _has_max(props->hasValue("max-m")),
754     _max_m(props->getDoubleValue("max-m")),
755     _position_m(props->getDoubleValue("starting-position-m", 0)),
756     _condition(0)
757 {
758   SGPropertyNode_ptr node = props->getChild("condition");
759   if (node != 0)
760     _condition = sgReadCondition(prop_root, node);
761
762   _axis[0] = props->getFloatValue("axis/x", 0);
763   _axis[1] = props->getFloatValue("axis/y", 0);
764   _axis[2] = props->getFloatValue("axis/z", 0);
765   sgNormalizeVec3(_axis);
766 }
767
768 SGTranslateAnimation::~SGTranslateAnimation ()
769 {
770   delete _table;
771 }
772
773 int
774 SGTranslateAnimation::update()
775 {
776   if (_condition == 0 || _condition->test()) {
777     if (_table == 0) {
778       _position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
779       if (_has_min && _position_m < _min_m)
780         _position_m = _min_m;
781       if (_has_max && _position_m > _max_m)
782         _position_m = _max_m;
783     } else {
784       _position_m = _table->interpolate(_prop->getDoubleValue());
785     }
786     set_translation(_matrix, _position_m, _axis);
787     ((ssgTransform *)_branch)->setTransform(_matrix);
788   }
789   return 2;
790 }
791
792
793 \f
794 ////////////////////////////////////////////////////////////////////////
795 // Implementation of SGScaleAnimation
796 ////////////////////////////////////////////////////////////////////////
797
798 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
799                                         SGPropertyNode_ptr props )
800   : SGAnimation(props, new ssgTransform),
801       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
802     _x_factor(props->getDoubleValue("x-factor", 1.0)),
803     _y_factor(props->getDoubleValue("y-factor", 1.0)),
804     _z_factor(props->getDoubleValue("z-factor", 1.0)),
805     _x_offset(props->getDoubleValue("x-offset", 1.0)),
806     _y_offset(props->getDoubleValue("y-offset", 1.0)),
807     _z_offset(props->getDoubleValue("z-offset", 1.0)),
808     _table(read_interpolation_table(props)),
809     _has_min_x(props->hasValue("x-min")),
810     _has_min_y(props->hasValue("y-min")),
811     _has_min_z(props->hasValue("z-min")),
812     _min_x(props->getDoubleValue("x-min")),
813     _min_y(props->getDoubleValue("y-min")),
814     _min_z(props->getDoubleValue("z-min")),
815     _has_max_x(props->hasValue("x-max")),
816     _has_max_y(props->hasValue("y-max")),
817     _has_max_z(props->hasValue("z-max")),
818     _max_x(props->getDoubleValue("x-max")),
819     _max_y(props->getDoubleValue("y-max")),
820     _max_z(props->getDoubleValue("z-max"))
821 {
822 }
823
824 SGScaleAnimation::~SGScaleAnimation ()
825 {
826   delete _table;
827 }
828
829 int
830 SGScaleAnimation::update()
831 {
832   if (_table == 0) {
833       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
834     if (_has_min_x && _x_scale < _min_x)
835       _x_scale = _min_x;
836     if (_has_max_x && _x_scale > _max_x)
837       _x_scale = _max_x;
838   } else {
839     _x_scale = _table->interpolate(_prop->getDoubleValue());
840   }
841
842   if (_table == 0) {
843     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
844     if (_has_min_y && _y_scale < _min_y)
845       _y_scale = _min_y;
846     if (_has_max_y && _y_scale > _max_y)
847       _y_scale = _max_y;
848   } else {
849     _y_scale = _table->interpolate(_prop->getDoubleValue());
850   }
851
852   if (_table == 0) {
853     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
854     if (_has_min_z && _z_scale < _min_z)
855       _z_scale = _min_z;
856     if (_has_max_z && _z_scale > _max_z)
857       _z_scale = _max_z;
858   } else {
859     _z_scale = _table->interpolate(_prop->getDoubleValue());
860   }
861
862   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
863   ((ssgTransform *)_branch)->setTransform(_matrix);
864   return 2;
865 }
866
867
868 ////////////////////////////////////////////////////////////////////////
869 // Implementation of SGTexRotateAnimation
870 ////////////////////////////////////////////////////////////////////////
871
872 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
873                                   SGPropertyNode_ptr props )
874     : SGAnimation(props, new ssgTexTrans),
875       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
876       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
877       _factor(props->getDoubleValue("factor", 1.0)),
878       _table(read_interpolation_table(props)),
879       _has_min(props->hasValue("min-deg")),
880       _min_deg(props->getDoubleValue("min-deg")),
881       _has_max(props->hasValue("max-deg")),
882       _max_deg(props->getDoubleValue("max-deg")),
883       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
884       _condition(0)
885 {
886   SGPropertyNode *node = props->getChild("condition");
887   if (node != 0)
888     _condition = sgReadCondition(prop_root, node);
889
890   _center[0] = props->getFloatValue("center/x", 0);
891   _center[1] = props->getFloatValue("center/y", 0);
892   _center[2] = props->getFloatValue("center/z", 0);
893   _axis[0] = props->getFloatValue("axis/x", 0);
894   _axis[1] = props->getFloatValue("axis/y", 0);
895   _axis[2] = props->getFloatValue("axis/z", 0);
896   sgNormalizeVec3(_axis);
897 }
898
899 SGTexRotateAnimation::~SGTexRotateAnimation ()
900 {
901   delete _table;
902 }
903
904 int
905 SGTexRotateAnimation::update()
906 {
907   if (_condition && !_condition->test())
908     return 1;
909
910   if (_table == 0) {
911    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
912    if (_has_min && _position_deg < _min_deg)
913      _position_deg = _min_deg;
914    if (_has_max && _position_deg > _max_deg)
915      _position_deg = _max_deg;
916   } else {
917     _position_deg = _table->interpolate(_prop->getDoubleValue());
918   }
919   set_rotation(_matrix, _position_deg, _center, _axis);
920   ((ssgTexTrans *)_branch)->setTransform(_matrix);
921   return 2;
922 }
923
924
925 ////////////////////////////////////////////////////////////////////////
926 // Implementation of SGTexTranslateAnimation
927 ////////////////////////////////////////////////////////////////////////
928
929 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
930                                         SGPropertyNode_ptr props )
931   : SGAnimation(props, new ssgTexTrans),
932       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
933     _offset(props->getDoubleValue("offset", 0.0)),
934     _factor(props->getDoubleValue("factor", 1.0)),
935     _step(props->getDoubleValue("step",0.0)),
936     _scroll(props->getDoubleValue("scroll",0.0)),
937     _table(read_interpolation_table(props)),
938     _has_min(props->hasValue("min")),
939     _min(props->getDoubleValue("min")),
940     _has_max(props->hasValue("max")),
941     _max(props->getDoubleValue("max")),
942     _position(props->getDoubleValue("starting-position", 0)),
943     _condition(0)
944 {
945   SGPropertyNode *node = props->getChild("condition");
946   if (node != 0)
947     _condition = sgReadCondition(prop_root, node);
948
949   _axis[0] = props->getFloatValue("axis/x", 0);
950   _axis[1] = props->getFloatValue("axis/y", 0);
951   _axis[2] = props->getFloatValue("axis/z", 0);
952   sgNormalizeVec3(_axis);
953 }
954
955 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
956 {
957   delete _table;
958 }
959
960 int
961 SGTexTranslateAnimation::update()
962 {
963   if (_condition && !_condition->test())
964     return 1;
965
966   if (_table == 0) {
967     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
968     if (_has_min && _position < _min)
969       _position = _min;
970     if (_has_max && _position > _max)
971       _position = _max;
972   } else {
973     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
974   }
975   set_translation(_matrix, _position, _axis);
976   ((ssgTexTrans *)_branch)->setTransform(_matrix);
977   return 2;
978 }
979
980
981 ////////////////////////////////////////////////////////////////////////
982 // Implementation of SGTexMultipleAnimation
983 ////////////////////////////////////////////////////////////////////////
984
985 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
986                                         SGPropertyNode_ptr props )
987   : SGAnimation(props, new ssgTexTrans),
988       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
989 {
990   unsigned int i;
991   // Load animations
992   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
993   _transform = new TexTransform [transform_nodes.size()];
994   _num_transforms = 0;
995   for (i = 0; i < transform_nodes.size(); i++) {
996     SGPropertyNode_ptr transform_props = transform_nodes[i];
997
998     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
999
1000       // transform is a translation
1001       _transform[i].subtype = 0;
1002
1003       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1004
1005       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
1006       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1007       _transform[i].step = transform_props->getDoubleValue("step",0.0);
1008       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
1009       _transform[i].table = read_interpolation_table(transform_props);
1010       _transform[i].has_min = transform_props->hasValue("min");
1011       _transform[i].min = transform_props->getDoubleValue("min");
1012       _transform[i].has_max = transform_props->hasValue("max");
1013       _transform[i].max = transform_props->getDoubleValue("max");
1014       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
1015
1016       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1017       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1018       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1019       sgNormalizeVec3(_transform[i].axis);
1020       _num_transforms++;
1021     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
1022
1023       // transform is a rotation
1024       _transform[i].subtype = 1;
1025
1026       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
1027       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
1028       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
1029       _transform[i].table = read_interpolation_table(transform_props);
1030       _transform[i].has_min = transform_props->hasValue("min-deg");
1031       _transform[i].min = transform_props->getDoubleValue("min-deg");
1032       _transform[i].has_max = transform_props->hasValue("max-deg");
1033       _transform[i].max = transform_props->getDoubleValue("max-deg");
1034       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
1035
1036       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
1037       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
1038       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
1039       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
1040       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
1041       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
1042       sgNormalizeVec3(_transform[i].axis);
1043       _num_transforms++;
1044     }
1045   }
1046 }
1047
1048 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
1049 {
1050    delete [] _transform;
1051 }
1052
1053 int
1054 SGTexMultipleAnimation::update()
1055 {
1056   int i;
1057   sgMat4 tmatrix;
1058   sgMakeIdentMat4(tmatrix);
1059   for (i = 0; i < _num_transforms; i++) {
1060
1061     if(_transform[i].subtype == 0) {
1062
1063       // subtype 0 is translation
1064       if (_transform[i].table == 0) {
1065         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
1066         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1067           _transform[i].position = _transform[i].min;
1068         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1069           _transform[i].position = _transform[i].max;
1070       } else {
1071          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
1072       }
1073       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
1074       sgPreMultMat4(tmatrix, _transform[i].matrix);
1075
1076     } else if (_transform[i].subtype == 1) {
1077
1078       // subtype 1 is rotation
1079
1080       if (_transform[i].table == 0) {
1081         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
1082         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
1083          _transform[i].position = _transform[i].min;
1084        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
1085          _transform[i].position = _transform[i].max;
1086      } else {
1087         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
1088       }
1089       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
1090       sgPreMultMat4(tmatrix, _transform[i].matrix);
1091     }
1092   }
1093   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
1094   return 2;
1095 }
1096
1097
1098 \f
1099 ////////////////////////////////////////////////////////////////////////
1100 // Implementation of SGAlphaTestAnimation
1101 ////////////////////////////////////////////////////////////////////////
1102
1103 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
1104   : SGAnimation(props, new ssgBranch)
1105 {
1106   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
1107 }
1108
1109 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
1110 {
1111 }
1112
1113 void SGAlphaTestAnimation::init()
1114 {
1115   setAlphaClampToBranch(_branch,_alpha_clamp);
1116 }
1117
1118 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
1119 {
1120   int nb = b->getNumKids();
1121   for (int i = 0; i<nb; i++) {
1122     ssgEntity *e = b->getKid(i);
1123     if (e->isAKindOf(ssgTypeLeaf())) {
1124       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
1125       s->enable( GL_ALPHA_TEST );
1126       s->setAlphaClamp( clamp );
1127     } else if (e->isAKindOf(ssgTypeBranch())) {
1128       setAlphaClampToBranch( (ssgBranch*)e, clamp );
1129     }
1130   }
1131 }
1132
1133
1134 \f
1135 ////////////////////////////////////////////////////////////////////////
1136 // Implementation of SGMaterialAnimation
1137 ////////////////////////////////////////////////////////////////////////
1138
1139 SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
1140         SGPropertyNode_ptr props, const SGPath &texture_path)
1141     : SGAnimation(props, new ssgBranch),
1142     _last_condition(false),
1143     _prop_root(prop_root),
1144     _prop_base(""),
1145     _texture_base(texture_path),
1146     _cached_material(0),
1147     _cloned_material(0),
1148     _read(0),
1149     _update(0),
1150     _global(props->getBoolValue("global", false))
1151 {
1152     SGPropertyNode_ptr n;
1153     n = props->getChild("condition");
1154     _condition = n ? sgReadCondition(_prop_root, n) : 0;
1155     n = props->getChild("property-base");
1156     if (n) {
1157         _prop_base = n->getStringValue();
1158         if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
1159             _prop_base += '/';
1160     }
1161
1162     initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
1163     initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
1164     initColorGroup(props->getChild("emission"), &_emis, EMISSION);
1165     initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
1166
1167     _shi = props->getFloatValue("shininess", -1.0);
1168     if (_shi >= 0.0)
1169         _update |= SHININESS;
1170
1171     SGPropertyNode_ptr group = props->getChild("transparency");
1172     if (group) {
1173         _trans.value = group->getFloatValue("alpha", -1.0);
1174         _trans.factor = group->getFloatValue("factor", 1.0);
1175         _trans.offset = group->getFloatValue("offset", 0.0);
1176         _trans.min = group->getFloatValue("min", 0.0);
1177         if (_trans.min < 0.0)
1178             _trans.min = 0.0;
1179         _trans.max = group->getFloatValue("max", 1.0);
1180         if (_trans.max > 1.0)
1181             _trans.max = 1.0;
1182         if (_trans.dirty())
1183             _update |= TRANSPARENCY;
1184
1185         n = group->getChild("alpha-prop");
1186         _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1187         n = group->getChild("factor-prop");
1188         _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1189         n = group->getChild("offset-prop");
1190         _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1191         if (_trans.live())
1192             _read |= TRANSPARENCY;
1193     }
1194
1195     _thresh = props->getFloatValue("threshold", -1.0);
1196     if (_thresh >= 0.0)
1197         _update |= THRESHOLD;
1198
1199     string _texture_str = props->getStringValue("texture", "");
1200     if (!_texture_str.empty()) {
1201         _texture = _texture_base;
1202         _texture.append(_texture_str);
1203         _update |= TEXTURE;
1204     }
1205
1206     n = props->getChild("shininess-prop");
1207     _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1208     n = props->getChild("threshold-prop");
1209     _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1210     n = props->getChild("texture-prop");
1211     _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1212
1213     _static_update = _update;
1214 }
1215
1216 void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
1217 {
1218     if (!group)
1219         return;
1220
1221     col->red = group->getFloatValue("red", -1.0);
1222     col->green = group->getFloatValue("green", -1.0);
1223     col->blue = group->getFloatValue("blue", -1.0);
1224     col->factor = group->getFloatValue("factor", 1.0);
1225     col->offset = group->getFloatValue("offset", 0.0);
1226     if (col->dirty())
1227         _update |= flag;
1228
1229     SGPropertyNode *n;
1230     n = group->getChild("red-prop");
1231     col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1232     n = group->getChild("green-prop");
1233     col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1234     n = group->getChild("blue-prop");
1235     col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1236     n = group->getChild("factor-prop");
1237     col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1238     n = group->getChild("offset-prop");
1239     col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
1240     if (col->live())
1241         _read |= flag;
1242 }
1243
1244 void SGMaterialAnimation::init()
1245 {
1246     if (!_global)
1247         cloneMaterials(_branch);
1248 }
1249
1250 int SGMaterialAnimation::update()
1251 {
1252     if (_condition) {
1253         bool cond = _condition->test();
1254         if (cond && !_last_condition)
1255             _update |= _static_update;
1256
1257         _last_condition = cond;
1258         if (!cond)
1259             return 2;
1260     }
1261
1262     if (_read & DIFFUSE)
1263         updateColorGroup(&_diff, DIFFUSE);
1264     if (_read & AMBIENT)
1265         updateColorGroup(&_amb, AMBIENT);
1266     if (_read & EMISSION)
1267         updateColorGroup(&_emis, EMISSION);
1268     if (_read & SPECULAR)
1269         updateColorGroup(&_spec, SPECULAR);
1270
1271     float f;
1272     if (_shi_prop) {
1273         f = _shi;
1274         _shi = _shi_prop->getFloatValue();
1275         if (_shi != f)
1276             _update |= SHININESS;
1277     }
1278     if (_read & TRANSPARENCY) {
1279         PropSpec tmp = _trans;
1280         if (_trans.value_prop)
1281             _trans.value = _trans.value_prop->getFloatValue();
1282         if (_trans.factor_prop)
1283             _trans.factor = _trans.factor_prop->getFloatValue();
1284         if (_trans.offset_prop)
1285             _trans.offset = _trans.offset_prop->getFloatValue();
1286         if (_trans != tmp)
1287             _update |= TRANSPARENCY;
1288     }
1289     if (_thresh_prop) {
1290         f = _thresh;
1291         _thresh = _thresh_prop->getFloatValue();
1292         if (_thresh != f)
1293             _update |= THRESHOLD;
1294     }
1295     if (_tex_prop) {
1296         string t = _tex_prop->getStringValue();
1297         if (!t.empty() && t != _texture_str) {
1298             _texture_str = t;
1299             _texture = _texture_base;
1300             _texture.append(t);
1301             _update |= TEXTURE;
1302         }
1303     }
1304     if (_update) {
1305         setMaterialBranch(_branch);
1306         _update = 0;
1307     }
1308     return 2;
1309 }
1310
1311 void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
1312 {
1313     ColorSpec tmp = *col;
1314     if (col->red_prop)
1315         col->red = col->red_prop->getFloatValue();
1316     if (col->green_prop)
1317         col->green = col->green_prop->getFloatValue();
1318     if (col->blue_prop)
1319         col->blue = col->blue_prop->getFloatValue();
1320     if (col->factor_prop)
1321         col->factor = col->factor_prop->getFloatValue();
1322     if (col->offset_prop)
1323         col->offset = col->offset_prop->getFloatValue();
1324     if (*col != tmp)
1325         _update |= flag;
1326 }
1327
1328 void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
1329 {
1330     for (int i = 0; i < b->getNumKids(); i++)
1331         cloneMaterials((ssgBranch *)b->getKid(i));
1332
1333     if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1334         return;
1335
1336     ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1337     if (!_cached_material || _cached_material != s) {
1338         _cached_material = s;
1339         _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
1340     }
1341     ((ssgLeaf *)b)->setState(_cloned_material);
1342 }
1343
1344 void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
1345 {
1346     for (int i = 0; i < b->getNumKids(); i++)
1347         setMaterialBranch((ssgBranch *)b->getKid(i));
1348
1349     if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
1350         return;
1351
1352     ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
1353
1354     if (_update & DIFFUSE) {
1355         float *v = _diff.rgba();
1356         SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1357         s->setColourMaterial(GL_DIFFUSE);
1358         s->enable(GL_COLOR_MATERIAL);
1359         s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
1360         s->disable(GL_COLOR_MATERIAL);
1361     }
1362     if (_update & AMBIENT) {
1363         s->setColourMaterial(GL_AMBIENT);
1364         s->enable(GL_COLOR_MATERIAL);
1365         s->setMaterial(GL_AMBIENT, _amb.rgba());
1366         s->disable(GL_COLOR_MATERIAL);
1367     }
1368     if (_update & EMISSION)
1369         s->setMaterial(GL_EMISSION, _emis.rgba());
1370     if (_update & SPECULAR)
1371         s->setMaterial(GL_SPECULAR, _spec.rgba());
1372     if (_update & SHININESS)
1373         s->setShininess(clamp(_shi, 0.0, 128.0));
1374     if (_update & TRANSPARENCY) {
1375         SGfloat *v = s->getMaterial(GL_DIFFUSE);
1376         float trans = _trans.value * _trans.factor + _trans.offset;
1377         trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
1378         s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
1379     }
1380     if (_update & THRESHOLD)
1381         s->setAlphaClamp(clamp(_thresh));
1382     if (_update & TEXTURE)
1383         s->setTexture(_texture.c_str());
1384     if (_update & (TEXTURE|TRANSPARENCY)) {
1385         SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
1386         ssgTexture *tex = s->getTexture();
1387         if ((tex && tex->hasAlpha()) || alpha < 0.999) {
1388             s->setColourMaterial(GL_DIFFUSE);
1389             s->enable(GL_COLOR_MATERIAL);
1390             s->enable(GL_BLEND);
1391             s->enable(GL_ALPHA_TEST);
1392             s->setTranslucent();
1393             s->disable(GL_COLOR_MATERIAL);
1394         } else {
1395             s->disable(GL_BLEND);
1396             s->disable(GL_ALPHA_TEST);
1397             s->setOpaque();
1398         }
1399     }
1400     s->force();
1401 }
1402
1403
1404 \f
1405 ////////////////////////////////////////////////////////////////////////
1406 // Implementation of SGFlashAnimation
1407 ////////////////////////////////////////////////////////////////////////
1408 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
1409   : SGAnimation( props, new SGCustomTransform )
1410 {
1411   _axis[0] = props->getFloatValue("axis/x", 0);
1412   _axis[1] = props->getFloatValue("axis/y", 0);
1413   _axis[2] = props->getFloatValue("axis/z", 1);
1414
1415   _center[0] = props->getFloatValue("center/x-m", 0);
1416   _center[1] = props->getFloatValue("center/y-m", 0);
1417   _center[2] = props->getFloatValue("center/z-m", 0);
1418
1419   _offset = props->getFloatValue("offset", 0.0);
1420   _factor = props->getFloatValue("factor", 1.0);
1421   _power = props->getFloatValue("power", 1.0);
1422   _two_sides = props->getBoolValue("two-sides", false);
1423
1424   _min_v = props->getFloatValue("min", 0.0);
1425   _max_v = props->getFloatValue("max", 1.0);
1426
1427   ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
1428 }
1429
1430 SGFlashAnimation::~SGFlashAnimation()
1431 {
1432 }
1433
1434 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1435 {
1436   ((SGFlashAnimation *)d)->flashCallback( r, f, m );
1437 }
1438
1439 void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1440 {
1441   sgVec3 transformed_axis;
1442   sgXformVec3( transformed_axis, _axis, m );
1443   sgNormalizeVec3( transformed_axis );
1444
1445   sgVec3 view;
1446   sgFullXformPnt3( view, _center, m );
1447   sgNormalizeVec3( view );
1448
1449   float cos_angle = -sgScalarProductVec3( transformed_axis, view );
1450   float scale_factor = 0.f;
1451   if ( _two_sides && cos_angle < 0 )
1452     scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset;
1453   else if ( cos_angle > 0 )
1454     scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
1455
1456   if ( scale_factor < _min_v )
1457       scale_factor = _min_v;
1458   if ( scale_factor > _max_v )
1459       scale_factor = _max_v;
1460
1461   sgMat4 transform;
1462   sgMakeIdentMat4( transform );
1463   transform[0][0] = scale_factor;
1464   transform[1][1] = scale_factor;
1465   transform[2][2] = scale_factor;
1466   transform[3][0] = _center[0] * ( 1 - scale_factor );
1467   transform[3][1] = _center[1] * ( 1 - scale_factor );
1468   transform[3][2] = _center[2] * ( 1 - scale_factor );
1469
1470   sgCopyMat4( r, m );
1471   sgPreMultMat4( r, transform );
1472 }
1473
1474
1475 \f
1476 ////////////////////////////////////////////////////////////////////////
1477 // Implementation of SGDistScaleAnimation
1478 ////////////////////////////////////////////////////////////////////////
1479 SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
1480   : SGAnimation( props, new SGCustomTransform ),
1481     _factor(props->getFloatValue("factor", 1.0)),
1482     _offset(props->getFloatValue("offset", 0.0)),
1483     _min_v(props->getFloatValue("min", 0.0)),
1484     _max_v(props->getFloatValue("max", 1.0)),
1485     _has_min(props->hasValue("min")),
1486     _has_max(props->hasValue("max")),
1487     _table(read_interpolation_table(props))
1488 {
1489   _center[0] = props->getFloatValue("center/x-m", 0);
1490   _center[1] = props->getFloatValue("center/y-m", 0);
1491   _center[2] = props->getFloatValue("center/z-m", 0);
1492
1493   ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
1494 }
1495
1496 SGDistScaleAnimation::~SGDistScaleAnimation()
1497 {
1498 }
1499
1500 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
1501 {
1502   ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
1503 }
1504
1505 void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
1506 {
1507   sgVec3 view;
1508   sgFullXformPnt3( view, _center, m );
1509
1510   float scale_factor = sgLengthVec3( view );
1511   if (_table == 0) {
1512     scale_factor = _factor * scale_factor + _offset;
1513     if ( _has_min && scale_factor < _min_v )
1514       scale_factor = _min_v;
1515     if ( _has_max && scale_factor > _max_v )
1516       scale_factor = _max_v;
1517   } else {
1518     scale_factor = _table->interpolate( scale_factor );
1519   }
1520
1521   sgMat4 transform;
1522   sgMakeIdentMat4( transform );
1523   transform[0][0] = scale_factor;
1524   transform[1][1] = scale_factor;
1525   transform[2][2] = scale_factor;
1526   transform[3][0] = _center[0] * ( 1 - scale_factor );
1527   transform[3][1] = _center[1] * ( 1 - scale_factor );
1528   transform[3][2] = _center[2] * ( 1 - scale_factor );
1529
1530   sgCopyMat4( r, m );
1531   sgPreMultMat4( r, transform );
1532 }
1533
1534 ////////////////////////////////////////////////////////////////////////
1535 // Implementation of SGShadowAnimation
1536 ////////////////////////////////////////////////////////////////////////
1537
1538 SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
1539                    SGPropertyNode_ptr props )
1540   : SGAnimation(props, new ssgBranch),
1541     _condition(0),
1542         _condition_value(true)
1543 {
1544         animation_type = 1;
1545         SGPropertyNode_ptr node = props->getChild("condition");
1546         if (node != 0) {
1547                 _condition = sgReadCondition(prop_root, node);
1548                 _condition_value = false;
1549         }
1550 }
1551
1552 SGShadowAnimation::~SGShadowAnimation ()
1553 {
1554         delete _condition;
1555 }
1556
1557 int
1558 SGShadowAnimation::update()
1559 {
1560         if (_condition)
1561                 _condition_value = _condition->test();
1562         return 2;
1563 }
1564
1565 bool SGShadowAnimation::get_condition_value(void) {
1566         return _condition_value;
1567 }
1568
1569 // end of animation.cxx