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