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