added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / libs / lib3ds / tracks.c
1 /*
2  * The 3D Studio File Format Library
3  * Copyright (C) 1996-2001 by J.E. Hoffmann <je-h@gmx.net>
4  * All rights reserved.
5  *
6  * This program is  free  software;  you can redistribute it and/or modify it
7  * under the terms of the  GNU Lesser General Public License  as published by 
8  * the  Free Software Foundation;  either version 2.1 of the License,  or (at 
9  * your option) any later version.
10  *
11  * This  program  is  distributed in  the  hope that it will  be useful,  but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or  FITNESS FOR A  PARTICULAR PURPOSE.  See the  GNU Lesser General Public  
14  * License for more details.
15  *
16  * You should  have received  a copy of the GNU Lesser General Public License
17  * along with  this program;  if not, write to the  Free Software Foundation,
18  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * $Id: tracks.c,v 1.14 2004/11/20 09:00:38 efalk Exp $
21  */
22 #define LIB3DS_EXPORT
23 #include <lib3ds/tracks.h>
24 #include <lib3ds/io.h>
25 #include <lib3ds/chunk.h>
26 #include <lib3ds/float.h>
27 #include <lib3ds/vector.h>
28 #include <lib3ds/quat.h>
29 #include <lib3ds/node.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #ifdef WITH_DMALLOC
34 #include <dmalloc.h>
35 #endif
36
37
38 /*!
39  * \defgroup tracks Keyframing Tracks
40  *
41  * \author J.E. Hoffmann <je-h@gmx.net>
42  */
43
44
45 /*!
46  * \ingroup tracks 
47  */
48 Lib3dsBoolKey*
49 lib3ds_bool_key_new()
50 {
51   Lib3dsBoolKey* k;
52   k=(Lib3dsBoolKey*)calloc(sizeof(Lib3dsBoolKey), 1);
53   return(k);
54 }
55
56
57 /*!
58  * \ingroup tracks 
59  */
60 void
61 lib3ds_bool_key_free(Lib3dsBoolKey *key)
62 {
63   ASSERT(key);
64   free(key);
65 }
66
67
68 /*!
69  * \ingroup tracks 
70  */
71 void
72 lib3ds_bool_track_free_keys(Lib3dsBoolTrack *track)
73 {
74   Lib3dsBoolKey *p,*q;
75
76   ASSERT(track);
77   for (p=track->keyL; p; p=q) {
78     q=p->next;
79     lib3ds_bool_key_free(p);
80   }
81 }
82
83
84 /*!
85  * \ingroup tracks 
86  */
87 void
88 lib3ds_bool_track_insert(Lib3dsBoolTrack *track, Lib3dsBoolKey *key)
89 {
90   ASSERT(track);
91   ASSERT(key);
92   ASSERT(!key->next);
93
94   if (!track->keyL) {
95     track->keyL=key;
96     key->next=0;
97   }
98   else {
99     Lib3dsBoolKey *k,*p;
100
101     for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
102       if (k->tcb.frame>key->tcb.frame) {
103         break;
104       }
105     }
106     if (!p) {
107       key->next=track->keyL;
108       track->keyL=key;
109     }
110     else {
111       key->next=k;
112       p->next=key;
113     }
114  
115     if (k && (key->tcb.frame==k->tcb.frame)) {
116       key->next=k->next;
117       lib3ds_bool_key_free(k);
118     }
119   }
120 }
121
122
123 /*!
124  * \ingroup tracks 
125  */
126 void
127 lib3ds_bool_track_remove(Lib3dsBoolTrack *track, Lib3dsIntd frame)
128 {
129   Lib3dsBoolKey *k,*p;
130   
131   ASSERT(track);
132   if (!track->keyL) {
133     return;
134   }
135   for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
136     if (k->tcb.frame==frame) {
137       if (!p) {
138         track->keyL=track->keyL->next;
139       }
140       else {
141         p->next=k->next;
142       }
143       lib3ds_bool_key_free(k);
144       break;
145     }
146   }
147 }
148
149
150 /*!
151  * \ingroup tracks 
152  */
153 void
154 lib3ds_bool_track_eval(Lib3dsBoolTrack *track, Lib3dsBool *p, Lib3dsFloat t)
155 {
156   Lib3dsBoolKey *k;
157   Lib3dsBool result;
158
159   ASSERT(p);
160   if (!track->keyL) {
161     *p=LIB3DS_FALSE;
162     return;
163   }
164   if (!track->keyL->next) {
165     *p = LIB3DS_TRUE;
166     return;
167   }
168
169   result=LIB3DS_FALSE;
170   k=track->keyL;
171   while ((t<(Lib3dsFloat)k->tcb.frame) && (t>=(Lib3dsFloat)k->next->tcb.frame)) {
172     if (result) {
173       result=LIB3DS_FALSE;
174     }
175     else {
176       result=LIB3DS_TRUE;
177     }
178     if (!k->next) {
179       if (track->flags&LIB3DS_REPEAT) {
180         t-=(Lib3dsFloat)k->tcb.frame;
181         k=track->keyL;
182       }
183       else {
184         break;
185       }
186     }
187     else {
188       k=k->next;
189     }
190   }
191   *p=result;
192 }
193
194
195 /*!
196  * \ingroup tracks 
197  */
198 Lib3dsBool
199 lib3ds_bool_track_read(Lib3dsBoolTrack *track, Lib3dsIo *io)
200 {
201   int keys;
202   int i;
203   Lib3dsBoolKey *k;
204
205   track->flags=lib3ds_io_read_word(io);
206   lib3ds_io_read_dword(io);
207   lib3ds_io_read_dword(io);
208   keys=lib3ds_io_read_intd(io);
209
210   for (i=0; i<keys; ++i) {
211     k=lib3ds_bool_key_new();
212     if (!lib3ds_tcb_read(&k->tcb, io)) {
213       return(LIB3DS_FALSE);
214     }
215     lib3ds_bool_track_insert(track, k);
216   }
217   
218   return(LIB3DS_TRUE);
219 }
220
221
222 /*!
223  * \ingroup tracks 
224  */
225 Lib3dsBool
226 lib3ds_bool_track_write(Lib3dsBoolTrack *track, Lib3dsIo *io)
227 {
228   Lib3dsBoolKey *k;
229   Lib3dsDword num=0;
230   for (k=track->keyL; k; k=k->next) {
231     ++num;
232   }
233   lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
234   lib3ds_io_write_dword(io, 0);
235   lib3ds_io_write_dword(io, 0);
236   lib3ds_io_write_dword(io, num);
237
238   for (k=track->keyL; k; k=k->next) {
239     if (!lib3ds_tcb_write(&k->tcb,io)) {
240       return(LIB3DS_FALSE);
241     }
242   }
243   return(LIB3DS_TRUE);
244 }
245
246
247 /*!
248  * \ingroup tracks 
249  */
250 Lib3dsLin1Key*
251 lib3ds_lin1_key_new()
252 {
253   Lib3dsLin1Key* k;
254   k=(Lib3dsLin1Key*)calloc(sizeof(Lib3dsLin1Key), 1);
255   return(k);
256 }
257
258
259 /*!
260  * \ingroup tracks 
261  */
262 void
263 lib3ds_lin1_key_free(Lib3dsLin1Key *key)
264 {
265   ASSERT(key);
266   free(key);
267 }
268
269
270 /*!
271  * \ingroup tracks 
272  */
273 void
274 lib3ds_lin1_track_free_keys(Lib3dsLin1Track *track)
275 {
276   Lib3dsLin1Key *p,*q;
277
278   ASSERT(track);
279   for (p=track->keyL; p; p=q) {
280     q=p->next;
281     lib3ds_lin1_key_free(p);
282   }
283 }
284
285
286 /*!
287  * \ingroup tracks 
288  */
289 void
290 lib3ds_lin1_key_setup(Lib3dsLin1Key *p, Lib3dsLin1Key *cp, Lib3dsLin1Key *c,
291   Lib3dsLin1Key *cn, Lib3dsLin1Key *n)
292 {
293   Lib3dsFloat np,nn;
294   Lib3dsFloat ksm,ksp,kdm,kdp;
295   
296   ASSERT(c);
297   if (!cp) {
298     cp=c;
299   }
300   if (!cn) {
301     cn=c;
302   }
303   if (!p && !n) {
304     c->ds=0;
305     c->dd=0;
306     return;
307   }
308
309   if (n && p) {
310     lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
311     np = c->value - p->value; 
312     nn = n->value - c->value; 
313
314     c->ds=ksm*np + ksp*nn;
315     c->dd=kdm*np + kdp*nn;
316   }
317   else {
318     if (p) {
319       np = c->value - p->value;
320       c->ds = np;
321       c->dd = np;
322     }
323     if (n) {
324       nn = n->value - c->value; 
325       c->ds = nn;
326       c->dd = nn;
327     }
328   }
329 }
330
331
332 /*!
333  * \ingroup tracks 
334  */
335 void
336 lib3ds_lin1_track_setup(Lib3dsLin1Track *track)
337 {
338   Lib3dsLin1Key *pp,*pc,*pn,*pl;
339
340   ASSERT(track);
341   pc=track->keyL;
342   if (!pc) {
343     return;
344   }
345   if (!pc->next) {
346     pc->ds=0;
347     pc->dd=0;
348     return;
349   }
350
351   if (track->flags&LIB3DS_SMOOTH) {
352     for (pl=track->keyL; pl->next->next; pl=pl->next);
353     lib3ds_lin1_key_setup(pl, pl->next, pc, 0, pc->next);
354  }
355  else {
356    lib3ds_lin1_key_setup(0, 0, pc, 0, pc->next);
357  }
358   for (;;) {
359     pp=pc;
360     pc=pc->next;
361     pn=pc->next;
362     if (!pn) {
363       break;
364     }
365     lib3ds_lin1_key_setup(pp, 0, pc, 0, pn);
366   }
367
368   if (track->flags&LIB3DS_SMOOTH) {
369     lib3ds_lin1_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
370   }
371   else {
372     lib3ds_lin1_key_setup(pp, 0, pc, 0, 0);
373   }
374 }
375
376
377 /*!
378  * \ingroup tracks 
379  */
380 void
381 lib3ds_lin1_track_insert(Lib3dsLin1Track *track, Lib3dsLin1Key *key)
382 {
383   ASSERT(track);
384   ASSERT(key);
385   ASSERT(!key->next);
386
387   if (!track->keyL) {
388     track->keyL=key;
389     key->next=0;
390   }
391   else {
392     Lib3dsLin1Key *k,*p;
393
394     for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
395       if (k->tcb.frame>key->tcb.frame) {
396         break;
397       }
398     }
399     if (!p) {
400       key->next=track->keyL;
401       track->keyL=key;
402     }
403     else {
404       key->next=k;
405       p->next=key;
406     }
407  
408     if (k && (key->tcb.frame==k->tcb.frame)) {
409       key->next=k->next;
410       lib3ds_lin1_key_free(k);
411     }
412   }
413 }
414
415
416 /*!
417  * \ingroup tracks 
418  */
419 void
420 lib3ds_lin1_track_remove(Lib3dsLin1Track *track, Lib3dsIntd frame)
421 {
422   Lib3dsLin1Key *k,*p;
423   
424   ASSERT(track);
425   if (!track->keyL) {
426     return;
427   }
428   for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
429     if (k->tcb.frame==frame) {
430       if (!p) {
431         track->keyL=track->keyL->next;
432       }
433       else {
434         p->next=k->next;
435       }
436       lib3ds_lin1_key_free(k);
437       break;
438     }
439   }
440 }
441
442
443 /*!
444  * \ingroup tracks 
445  */
446 void
447 lib3ds_lin1_track_eval(Lib3dsLin1Track *track, Lib3dsFloat *p, Lib3dsFloat t)
448 {
449   Lib3dsLin1Key *k;
450   Lib3dsFloat nt;
451   Lib3dsFloat u;
452
453   ASSERT(p);
454   if (!track->keyL) {
455     *p=0;
456     return;
457   }
458   if (!track->keyL->next) {
459     *p = track->keyL->value;
460     return;
461   }
462
463   for (k=track->keyL; k->next!=0; k=k->next) {
464     if ((t>=(Lib3dsFloat)k->tcb.frame) && (t<(Lib3dsFloat)k->next->tcb.frame)) {
465       break;
466     }
467   }
468   if (!k->next) {
469     if (track->flags&LIB3DS_REPEAT) {
470       nt=(Lib3dsFloat)fmod(t, k->tcb.frame);
471       for (k=track->keyL; k->next!=0; k=k->next) {
472         if ((nt>=(Lib3dsFloat)k->tcb.frame) && (nt<(Lib3dsFloat)k->next->tcb.frame)) {
473           break;
474         }
475       }
476       ASSERT(k->next);
477     }
478     else {
479       *p = k->value;
480       return;
481     }
482   }
483   else {
484     nt=t;
485   }
486   u=nt - (Lib3dsFloat)k->tcb.frame;
487   u/=(Lib3dsFloat)(k->next->tcb.frame - k->tcb.frame);
488
489   *p = lib3ds_float_cubic(
490     k->value,
491     k->dd,
492     k->next->ds,
493     k->next->value,
494     u
495   );
496 }
497
498
499 /*!
500  * \ingroup tracks 
501  */
502 Lib3dsBool
503 lib3ds_lin1_track_read(Lib3dsLin1Track *track, Lib3dsIo *io)
504 {
505   int keys;
506   int i;
507   Lib3dsLin1Key *k;
508
509   track->flags=lib3ds_io_read_word(io);
510   lib3ds_io_read_dword(io);
511   lib3ds_io_read_dword(io);
512   keys=lib3ds_io_read_intd(io);
513
514   for (i=0; i<keys; ++i) {
515     k=lib3ds_lin1_key_new();
516     if (!lib3ds_tcb_read(&k->tcb, io)) {
517       return(LIB3DS_FALSE);
518     }
519     k->value=lib3ds_io_read_float(io);
520     lib3ds_lin1_track_insert(track, k);
521   }
522   lib3ds_lin1_track_setup(track);
523   return(LIB3DS_TRUE);
524 }
525
526
527 /*!
528  * \ingroup tracks 
529  */
530 Lib3dsBool
531 lib3ds_lin1_track_write(Lib3dsLin1Track *track, Lib3dsIo *io)
532 {
533   Lib3dsLin1Key *k;
534   Lib3dsDword num=0;
535   for (k=track->keyL; k; k=k->next) {
536     ++num;
537   }
538   lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
539   lib3ds_io_write_dword(io, 0);
540   lib3ds_io_write_dword(io, 0);
541   lib3ds_io_write_dword(io, num);
542
543   for (k=track->keyL; k; k=k->next) {
544     if (!lib3ds_tcb_write(&k->tcb,io)) {
545       return(LIB3DS_FALSE);
546     }
547     lib3ds_io_write_float(io, k->value);
548   }
549   return(LIB3DS_TRUE);
550 }
551
552
553 /*!
554  * Create and return one keyframe in a Lin3 track.  All values are
555  * initialized to zero.
556  *
557  * \ingroup tracks 
558  */
559 Lib3dsLin3Key*
560 lib3ds_lin3_key_new()
561 {
562   Lib3dsLin3Key* k;
563   k=(Lib3dsLin3Key*)calloc(sizeof(Lib3dsLin3Key), 1);
564   return(k);
565 }
566
567
568 /*!
569  * Free a Lin3 keyframe.
570  *
571  * \ingroup tracks 
572  */
573 void
574 lib3ds_lin3_key_free(Lib3dsLin3Key *key)
575 {
576   ASSERT(key);
577   free(key);
578 }
579
580
581 /*!
582  * Free all keyframes in a Lin3 track.
583  *
584  * \ingroup tracks 
585  */
586 void
587 lib3ds_lin3_track_free_keys(Lib3dsLin3Track *track)
588 {
589   Lib3dsLin3Key *p,*q;
590
591   ASSERT(track);
592   for (p=track->keyL; p; p=q) {
593     q=p->next;
594     lib3ds_lin3_key_free(p);
595   }
596 }
597
598
599 /*!
600  * \ingroup tracks 
601  */
602 void
603 lib3ds_lin3_key_setup(Lib3dsLin3Key *p, Lib3dsLin3Key *cp, Lib3dsLin3Key *c,
604   Lib3dsLin3Key *cn, Lib3dsLin3Key *n)
605 {
606   Lib3dsVector np,nn;
607   Lib3dsFloat ksm,ksp,kdm,kdp;
608   int i;
609   
610   ASSERT(c);
611   if (!cp) {
612     cp=c;
613   }
614   if (!cn) {
615     cn=c;
616   }
617   if (!p && !n) {
618     lib3ds_vector_zero(c->ds);
619     lib3ds_vector_zero(c->dd);
620     return;
621   }
622
623   if (n && p) {
624     lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
625     lib3ds_vector_sub(np, c->value, p->value); 
626     lib3ds_vector_sub(nn, n->value, c->value); 
627
628     for(i=0; i<3; ++i) {
629       c->ds[i]=ksm*np[i] + ksp*nn[i];
630       c->dd[i]=kdm*np[i] + kdp*nn[i];
631     }
632   }
633   else {
634     if (p) {
635       lib3ds_vector_sub(np, c->value, p->value);
636       lib3ds_vector_copy(c->ds, np);
637       lib3ds_vector_copy(c->dd, np);
638     }
639     if (n) {
640       lib3ds_vector_sub(nn, n->value, c->value); 
641       lib3ds_vector_copy(c->ds, nn);
642       lib3ds_vector_copy(c->dd, nn);
643     }
644   }
645 }
646
647
648 /*!
649  * \ingroup tracks 
650  */
651 void
652 lib3ds_lin3_track_setup(Lib3dsLin3Track *track)
653 {
654   Lib3dsLin3Key *pp,*pc,*pn,*pl;
655
656   ASSERT(track);
657   pc=track->keyL;
658   if (!pc) {
659     return;
660   }
661   if (!pc->next) {
662     lib3ds_vector_zero(pc->ds);
663     lib3ds_vector_zero(pc->dd);
664     return;
665   }
666
667   if (track->flags&LIB3DS_SMOOTH) {
668     for (pl=track->keyL; pl->next->next; pl=pl->next);
669     lib3ds_lin3_key_setup(pl, pl->next, pc, 0, pc->next);
670  }
671  else {
672    lib3ds_lin3_key_setup(0, 0, pc, 0, pc->next);
673  }
674   for (;;) {
675     pp=pc;
676     pc=pc->next;
677     pn=pc->next;
678     if (!pn) {
679       break;
680     }
681     lib3ds_lin3_key_setup(pp, 0, pc, 0, pn);
682   }
683
684   if (track->flags&LIB3DS_SMOOTH) {
685     lib3ds_lin3_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
686   }
687   else {
688     lib3ds_lin3_key_setup(pp, 0, pc, 0, 0);
689   }
690 }
691
692
693 /*!
694  * \ingroup tracks 
695  */
696 void
697 lib3ds_lin3_track_insert(Lib3dsLin3Track *track, Lib3dsLin3Key *key)
698 {
699   ASSERT(track);
700   ASSERT(key);
701   ASSERT(!key->next);
702
703   if (!track->keyL) {
704     track->keyL=key;
705     key->next=0;
706   }
707   else {
708     Lib3dsLin3Key *k,*p;
709
710     for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
711       if (k->tcb.frame>key->tcb.frame) {
712         break;
713       }
714     }
715     if (!p) {
716       key->next=track->keyL;
717       track->keyL=key;
718     }
719     else {
720       key->next=k;
721       p->next=key;
722     }
723  
724     if (k && (key->tcb.frame==k->tcb.frame)) {
725       key->next=k->next;
726       lib3ds_lin3_key_free(k);
727     }
728   }
729 }
730
731
732 /*!
733  * \ingroup tracks 
734  */
735 void
736 lib3ds_lin3_track_remove(Lib3dsLin3Track *track, Lib3dsIntd frame)
737 {
738   Lib3dsLin3Key *k,*p;
739   
740   ASSERT(track);
741   if (!track->keyL) {
742     return;
743   }
744   for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
745     if (k->tcb.frame==frame) {
746       if (!p) {
747         track->keyL=track->keyL->next;
748       }
749       else {
750         p->next=k->next;
751       }
752       lib3ds_lin3_key_free(k);
753       break;
754     }
755   }
756 }
757
758
759 /*!
760  * \ingroup tracks 
761  */
762 void
763 lib3ds_lin3_track_eval(Lib3dsLin3Track *track, Lib3dsVector p, Lib3dsFloat t)
764 {
765   Lib3dsLin3Key *k;
766   Lib3dsFloat nt;
767   Lib3dsFloat u;
768
769   if (!track->keyL) {
770     lib3ds_vector_zero(p);
771     return;
772   }
773   if (!track->keyL->next) {
774       lib3ds_vector_copy(p, track->keyL->value);
775     return;
776   }
777
778   for (k=track->keyL; k->next!=0; k=k->next) {
779     if ((t>=(Lib3dsFloat)k->tcb.frame) && (t<(Lib3dsFloat)k->next->tcb.frame)) {
780       break;
781     }
782   }
783   if (!k->next) {
784     if (track->flags&LIB3DS_REPEAT) {
785       nt=(Lib3dsFloat)fmod(t, k->tcb.frame);
786       for (k=track->keyL; k->next!=0; k=k->next) {
787         if ((nt>=(Lib3dsFloat)k->tcb.frame) && (nt<(Lib3dsFloat)k->next->tcb.frame)) {
788           break;
789         }
790       }
791       ASSERT(k->next);
792     }
793     else {
794       lib3ds_vector_copy(p, k->value);
795       return;
796     }
797   }
798   else {
799     nt=t;
800   }
801   u=nt - (Lib3dsFloat)k->tcb.frame;
802   u/=(Lib3dsFloat)(k->next->tcb.frame - k->tcb.frame);
803   
804   lib3ds_vector_cubic(
805     p,
806     k->value,
807     k->dd,
808     k->next->ds,
809     k->next->value,
810     u
811   );
812 }
813
814
815 /*!
816  * \ingroup tracks 
817  */
818 Lib3dsBool
819 lib3ds_lin3_track_read(Lib3dsLin3Track *track, Lib3dsIo *io)
820 {
821   int keys;
822   int i,j;
823   Lib3dsLin3Key *k;
824
825   track->flags=lib3ds_io_read_word(io);
826   lib3ds_io_read_dword(io);
827   lib3ds_io_read_dword(io);
828   keys=lib3ds_io_read_intd(io);
829
830   for (i=0; i<keys; ++i) {
831     k=lib3ds_lin3_key_new();
832     if (!lib3ds_tcb_read(&k->tcb, io)) {
833       return(LIB3DS_FALSE);
834     }
835     for (j=0; j<3; ++j) {
836       k->value[j]=lib3ds_io_read_float(io);
837     }
838     lib3ds_lin3_track_insert(track, k);
839   }
840   lib3ds_lin3_track_setup(track);
841   return(LIB3DS_TRUE);
842 }
843
844
845 /*!
846  * \ingroup tracks 
847  */
848 Lib3dsBool
849 lib3ds_lin3_track_write(Lib3dsLin3Track *track, Lib3dsIo *io)
850 {
851   Lib3dsLin3Key *k;
852   Lib3dsDword num=0;
853   for (k=track->keyL; k; k=k->next) {
854     ++num;
855   }
856   lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
857   lib3ds_io_write_dword(io, 0);
858   lib3ds_io_write_dword(io, 0);
859   lib3ds_io_write_dword(io, num);
860
861   for (k=track->keyL; k; k=k->next) {
862     if (!lib3ds_tcb_write(&k->tcb,io)) {
863       return(LIB3DS_FALSE);
864     }
865     lib3ds_io_write_vector(io, k->value);
866   }
867   return(LIB3DS_TRUE);
868 }
869
870
871 /*!
872  * \ingroup tracks 
873  */
874 Lib3dsQuatKey*
875 lib3ds_quat_key_new()
876 {
877   Lib3dsQuatKey* k;
878   k=(Lib3dsQuatKey*)calloc(sizeof(Lib3dsQuatKey), 1);
879   return(k);
880 }
881
882
883 /*!
884  * \ingroup tracks 
885  */
886 void
887 lib3ds_quat_key_free(Lib3dsQuatKey *key)
888 {
889   ASSERT(key);
890   free(key);
891 }
892
893
894 /*!
895  * \ingroup tracks 
896  */
897 void
898 lib3ds_quat_track_free_keys(Lib3dsQuatTrack *track)
899 {
900   Lib3dsQuatKey *p,*q;
901
902   ASSERT(track);
903   for (p=track->keyL; p; p=q) {
904     q=p->next;
905     lib3ds_quat_key_free(p);
906   }
907 }
908
909
910 /*!
911  * \ingroup tracks 
912  */
913 void
914 lib3ds_quat_key_setup(Lib3dsQuatKey *p, Lib3dsQuatKey *cp, Lib3dsQuatKey *c,
915   Lib3dsQuatKey *cn, Lib3dsQuatKey *n)
916 {
917   Lib3dsFloat ksm,ksp,kdm,kdp;
918   Lib3dsQuat q,qp,qn,qa,qb;
919   int i;
920   
921   ASSERT(c);
922   if (!cp) {
923     cp=c;
924   }
925   if (!cn) {
926     cn=c;
927   }
928   if (!p || !n) {
929     lib3ds_quat_copy(c->ds, c->q);
930     lib3ds_quat_copy(c->dd, c->q);
931     return;
932   }
933
934   if (p) {
935     if (p->angle>LIB3DS_TWOPI-LIB3DS_EPSILON) {
936       lib3ds_quat_axis_angle(qp, p->axis, 0.0f);
937       lib3ds_quat_ln(qp);
938     }
939     else {
940       lib3ds_quat_copy(q, p->q);
941       if (lib3ds_quat_dot(q,c->q)<0) lib3ds_quat_neg(q);
942       lib3ds_quat_ln_dif(qp, c->q, q);
943     }
944   }
945   if (n) {
946     if (n->angle>LIB3DS_TWOPI-LIB3DS_EPSILON) {
947       lib3ds_quat_axis_angle(qn, n->axis, 0.0f);
948       lib3ds_quat_ln(qn);
949     }
950     else {
951       lib3ds_quat_copy(q, n->q);
952       if (lib3ds_quat_dot(q,c->q)<0) lib3ds_quat_neg(q);
953       lib3ds_quat_ln_dif(qn, c->q, q);
954     }
955   }
956
957   if (n && p) {
958     lib3ds_tcb(&p->tcb, &cp->tcb, &c->tcb, &cn->tcb, &n->tcb, &ksm, &ksp, &kdm, &kdp);
959     for(i=0; i<4; i++) {
960       qa[i]=-0.5f*(kdm*qn[i]+kdp*qp[i]);
961       qb[i]=-0.5f*(ksm*qn[i]+ksp*qp[i]);
962     }
963     lib3ds_quat_exp(qa);
964     lib3ds_quat_exp(qb);
965     
966     lib3ds_quat_mul(c->ds, c->q, qa);
967     lib3ds_quat_mul(c->dd, c->q, qb);
968   }
969   else {
970     if (p) {
971       lib3ds_quat_exp(qp);
972       lib3ds_quat_mul(c->ds, c->q, qp);
973       lib3ds_quat_mul(c->dd, c->q, qp);
974     }
975     if (n) {
976       lib3ds_quat_exp(qn);
977       lib3ds_quat_mul(c->ds, c->q, qn);
978       lib3ds_quat_mul(c->dd, c->q, qn);
979     }
980   }
981 }
982
983
984 /*!
985  * \ingroup tracks 
986  */
987 void
988 lib3ds_quat_track_setup(Lib3dsQuatTrack *track)
989 {
990   Lib3dsQuatKey *pp,*pc,*pn,*pl;
991   Lib3dsQuat q;
992
993   ASSERT(track);
994   for (pp=0,pc=track->keyL; pc; pp=pc,pc=pc->next) {
995     lib3ds_quat_axis_angle(q, pc->axis, pc->angle);
996     if (pp) {
997       lib3ds_quat_mul(pc->q, q, pp->q);
998     }
999     else {
1000       lib3ds_quat_copy(pc->q, q);
1001     }
1002   }
1003
1004   pc=track->keyL;
1005   if (!pc) {
1006     return;
1007   }
1008   if (!pc->next) {
1009     lib3ds_quat_copy(pc->ds, pc->q);
1010     lib3ds_quat_copy(pc->dd, pc->q);
1011     return;
1012   }
1013
1014   if (track->flags&LIB3DS_SMOOTH) {
1015     for (pl=track->keyL; pl->next->next; pl=pl->next);
1016     lib3ds_quat_key_setup(pl, pl->next, pc, 0, pc->next);
1017  }
1018   else {
1019     lib3ds_quat_key_setup(0, 0, pc, 0, pc->next);
1020   }
1021   for (;;) {
1022     pp=pc;
1023     pc=pc->next;
1024     pn=pc->next;
1025     if (!pn) {
1026       break;
1027     }
1028     lib3ds_quat_key_setup(pp, 0, pc, 0, pn);
1029   }
1030
1031   if (track->flags&LIB3DS_SMOOTH) {
1032     lib3ds_quat_key_setup(pp, 0, pc, track->keyL, track->keyL->next);
1033   }
1034   else {
1035     lib3ds_quat_key_setup(pp, 0, pc, 0, 0);
1036   }
1037 }
1038
1039
1040 /*!
1041  * \ingroup tracks 
1042  */
1043 void
1044 lib3ds_quat_track_insert(Lib3dsQuatTrack *track, Lib3dsQuatKey *key)
1045 {
1046   ASSERT(track);
1047   ASSERT(key);
1048   ASSERT(!key->next);
1049
1050   if (!track->keyL) {
1051     track->keyL=key;
1052     key->next=0;
1053   }
1054   else {
1055     Lib3dsQuatKey *k,*p;
1056
1057     for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
1058       if (k->tcb.frame>key->tcb.frame) {
1059         break;
1060       }
1061     }
1062     if (!p) {
1063       key->next=track->keyL;
1064       track->keyL=key;
1065     }
1066     else {
1067       key->next=k;
1068       p->next=key;
1069     }
1070  
1071     if (k && (key->tcb.frame==k->tcb.frame)) {
1072       key->next=k->next;
1073       lib3ds_quat_key_free(k);
1074     }
1075   }
1076 }
1077
1078
1079 /*!
1080  * \ingroup tracks 
1081  */
1082 void
1083 lib3ds_quat_track_remove(Lib3dsQuatTrack *track, Lib3dsIntd frame)
1084 {
1085   Lib3dsQuatKey *k,*p;
1086   
1087   ASSERT(track);
1088   if (!track->keyL) {
1089     return;
1090   }
1091   for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
1092     if (k->tcb.frame==frame) {
1093       if (!p) {
1094         track->keyL=track->keyL->next;
1095       }
1096       else {
1097         p->next=k->next;
1098       }
1099       lib3ds_quat_key_free(k);
1100       break;
1101     }
1102   }
1103 }
1104
1105
1106 /*!
1107  * \ingroup tracks 
1108  */
1109 void
1110 lib3ds_quat_track_eval(Lib3dsQuatTrack *track, Lib3dsQuat q, Lib3dsFloat t)
1111 {
1112   Lib3dsQuatKey *k;
1113   Lib3dsFloat nt;
1114   Lib3dsFloat u;
1115
1116   if (!track->keyL) {
1117     lib3ds_quat_identity(q);
1118     return;
1119   }
1120   if (!track->keyL->next) {
1121     lib3ds_quat_copy(q, track->keyL->q);
1122     return;
1123   }
1124
1125   for (k=track->keyL; k->next!=0; k=k->next) {
1126     if ((t>=k->tcb.frame) && (t<k->next->tcb.frame)) {
1127       break;
1128     }
1129   }
1130   if (!k->next) {
1131     if (track->flags&LIB3DS_REPEAT) {
1132       nt=(Lib3dsFloat)fmod(t, k->tcb.frame);
1133       for (k=track->keyL; k->next!=0; k=k->next) {
1134         if ((nt>=k->tcb.frame) && (nt<k->next->tcb.frame)) {
1135           break;
1136         }
1137       }
1138       ASSERT(k->next);
1139     }
1140     else {
1141       lib3ds_quat_copy(q, k->q);
1142       return;
1143     }
1144   }
1145   else {
1146     nt=t;
1147   }
1148   u=nt - k->tcb.frame;
1149   u/=(k->next->tcb.frame - k->tcb.frame);
1150
1151   lib3ds_quat_squad(
1152     q,
1153     k->q,
1154     k->dd,
1155     k->next->ds,
1156     k->next->q,
1157     u
1158   );
1159 }
1160
1161
1162 /*!
1163  * \ingroup tracks 
1164  */
1165 Lib3dsBool
1166 lib3ds_quat_track_read(Lib3dsQuatTrack *track, Lib3dsIo *io)
1167 {
1168   int keys;
1169   int i,j;
1170   Lib3dsQuatKey *p,*k;
1171
1172   track->flags=lib3ds_io_read_word(io);
1173   lib3ds_io_read_dword(io);
1174   lib3ds_io_read_dword(io);
1175   keys=lib3ds_io_read_intd(io);
1176
1177   for (p=0,i=0; i<keys; p=k,++i) {
1178     k=lib3ds_quat_key_new();
1179     if (!lib3ds_tcb_read(&k->tcb, io)) {
1180       return(LIB3DS_FALSE);
1181     }
1182     k->angle=lib3ds_io_read_float(io);
1183     for (j=0; j<3; ++j) {
1184       k->axis[j]=lib3ds_io_read_float(io);
1185     }
1186     lib3ds_quat_track_insert(track, k);
1187   }
1188   lib3ds_quat_track_setup(track);
1189   return(LIB3DS_TRUE);
1190 }
1191
1192
1193 /*!
1194  * \ingroup tracks 
1195  */
1196 Lib3dsBool
1197 lib3ds_quat_track_write(Lib3dsQuatTrack *track, Lib3dsIo *io)
1198 {
1199   Lib3dsQuatKey *k;
1200   Lib3dsDword num=0;
1201   for (k=track->keyL; k; k=k->next) {
1202     ++num;
1203   }
1204   lib3ds_io_write_word(io, (Lib3dsWord)track->flags);
1205   lib3ds_io_write_dword(io, 0);
1206   lib3ds_io_write_dword(io, 0);
1207   lib3ds_io_write_dword(io, num);
1208
1209   for (k=track->keyL; k; k=k->next) {
1210     if (!lib3ds_tcb_write(&k->tcb,io)) {
1211       return(LIB3DS_FALSE);
1212     }
1213     lib3ds_io_write_float(io, k->angle);
1214     lib3ds_io_write_vector(io, k->axis);
1215   }
1216   return(LIB3DS_TRUE);
1217 }
1218
1219
1220 /*!
1221  * \ingroup tracks 
1222  */
1223 Lib3dsMorphKey*
1224 lib3ds_morph_key_new()
1225 {
1226   Lib3dsMorphKey* k;
1227   k=(Lib3dsMorphKey*)calloc(sizeof(Lib3dsMorphKey), 1);
1228   return(k);
1229 }
1230
1231
1232 /*!
1233  * \ingroup tracks 
1234  */
1235 void
1236 lib3ds_morph_key_free(Lib3dsMorphKey *key)
1237 {
1238   ASSERT(key);
1239   free(key);
1240 }
1241
1242
1243 /*!
1244  * \ingroup tracks 
1245  */
1246 void
1247 lib3ds_morph_track_free_keys(Lib3dsMorphTrack *track)
1248 {
1249   Lib3dsMorphKey *p,*q;
1250
1251   ASSERT(track);
1252   for (p=track->keyL; p; p=q) {
1253     q=p->next;
1254     lib3ds_morph_key_free(p);
1255   }
1256 }
1257
1258
1259 /*!
1260  * \ingroup tracks 
1261  */
1262 void
1263 lib3ds_morph_track_insert(Lib3dsMorphTrack *track, Lib3dsMorphKey *key)
1264 {
1265   ASSERT(track);
1266   ASSERT(key);
1267   ASSERT(!key->next);
1268
1269   if (!track->keyL) {
1270     track->keyL=key;
1271     key->next=0;
1272   }
1273   else {
1274     Lib3dsMorphKey *k,*p;
1275
1276     for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
1277       if (k->tcb.frame>key->tcb.frame) {
1278         break;
1279       }
1280     }
1281     if (!p) {
1282       key->next=track->keyL;
1283       track->keyL=key;
1284     }
1285     else {
1286       key->next=k;
1287       p->next=key;
1288     }
1289  
1290     if (k && (key->tcb.frame==k->tcb.frame)) {
1291       key->next=k->next;
1292       lib3ds_morph_key_free(k);
1293     }
1294   }
1295 }
1296
1297
1298 /*!
1299  * \ingroup tracks 
1300  */
1301 void
1302 lib3ds_morph_track_remove(Lib3dsMorphTrack *track, Lib3dsIntd frame)
1303 {
1304   Lib3dsMorphKey *k,*p;
1305   
1306   ASSERT(track);
1307   if (!track->keyL) {
1308     return;
1309   }
1310   for (p=0,k=track->keyL; k!=0; p=k, k=k->next) {
1311     if (k->tcb.frame==frame) {
1312       if (!p) {
1313         track->keyL=track->keyL->next;
1314       }
1315       else {
1316         p->next=k->next;
1317       }
1318       lib3ds_morph_key_free(k);
1319       break;
1320     }
1321   }
1322 }
1323
1324
1325 /*!
1326  * \ingroup tracks 
1327  */
1328 void
1329 lib3ds_morph_track_eval(Lib3dsMorphTrack *track, char *p, Lib3dsFloat t)
1330 {
1331   Lib3dsMorphKey *k;
1332   char* result;
1333
1334   ASSERT(p);
1335   if (!track->keyL) {
1336     strcpy(p,"");
1337     return;
1338   }
1339   if (!track->keyL->next) {
1340     strcpy(p,track->keyL->name);
1341     return;
1342   }
1343
1344
1345   /* TODO: this function finds the mesh frame that corresponds to this
1346    * timeframe.  It would be better to actually interpolate the mesh.
1347    */
1348
1349   result=0;
1350
1351   for(k = track->keyL;
1352       k->next != NULL && t >= k->next->tcb.frame;
1353       k = k->next);
1354
1355   result=k->name;
1356
1357   if (result) {
1358     strcpy(p,result);
1359   }
1360   else {
1361     strcpy(p,"");
1362   }
1363 }
1364
1365
1366 /*!
1367  * \ingroup tracks
1368  */
1369 Lib3dsBool
1370 lib3ds_morph_track_read(Lib3dsMorphTrack *track, Lib3dsIo *io)
1371 {
1372   /* This function was written by Stephane Denis on 5-18-04 */
1373     int i;
1374     Lib3dsMorphKey *k, *pk = 0;
1375     int keys;
1376     track->flags=lib3ds_io_read_word(io);
1377     lib3ds_io_read_dword(io);
1378     lib3ds_io_read_dword(io);
1379     keys=lib3ds_io_read_intd(io);
1380
1381     for (i=0; i<keys; ++i) {
1382         k=lib3ds_morph_key_new();
1383         if (!lib3ds_tcb_read(&k->tcb, io)) {
1384             return(LIB3DS_FALSE);
1385         }
1386         if (!lib3ds_io_read_string(io, k->name, 11)) {
1387             return(LIB3DS_FALSE);
1388         }
1389         if (!track->keyL)
1390             track->keyL = k;
1391         else
1392             pk->next = k;
1393         pk = k;
1394     }
1395   return(LIB3DS_TRUE);
1396 }
1397
1398
1399 /*!
1400  * \ingroup tracks 
1401  */
1402 Lib3dsBool
1403 lib3ds_morph_track_write(Lib3dsMorphTrack *track, Lib3dsIo *io)
1404 {
1405   /* FIXME: */
1406   ASSERT(0);
1407   return(LIB3DS_FALSE);
1408 }
1409
1410
1411
1412 void
1413 tcb_dump(Lib3dsTcb *tcb)
1414 {
1415   printf("  tcb: frame=%d, flags=%04x, tens=%g, cont=%g, ",
1416     (int)tcb->frame, tcb->flags, tcb->tens, tcb->cont);
1417   printf("bias=%g, ease_to=%g, ease_from=%g\n",
1418     tcb->bias, tcb->ease_to, tcb->ease_from);
1419 }
1420
1421
1422 void
1423 lib3ds_boolTrack_dump(Lib3dsBoolTrack *track)
1424 {
1425   Lib3dsBoolKey *key;
1426   printf("flags: %08x, keys:\n", (unsigned int)track->flags);
1427   for( key = track->keyL; key != NULL; key = key->next)
1428   {
1429     tcb_dump(&key->tcb);
1430   }
1431 }
1432
1433
1434 void
1435 lib3ds_lin1Track_dump(Lib3dsLin1Track *track)
1436 {
1437   Lib3dsLin1Key *key;
1438   printf("flags: %08x, keys:\n", (unsigned int)track->flags);
1439   for( key = track->keyL; key != NULL; key = key->next)
1440   {
1441     tcb_dump(&key->tcb);
1442     printf("    value = %g, dd=%g, ds=%g\n",
1443       key->value, key->dd, key->ds);
1444   }
1445 }
1446
1447
1448 void
1449 lib3ds_lin3Track_dump(Lib3dsLin3Track *track)
1450 {
1451   Lib3dsLin3Key *key;
1452   printf("flags: %08x, keys:\n", (unsigned int)track->flags);
1453   for( key = track->keyL; key != NULL; key = key->next)
1454   {
1455     tcb_dump(&key->tcb);
1456     printf("    value = %g,%g,%g, dd=%g,%g,%g, ds=%g,%g,%g\n",
1457       key->value[0], key->value[1], key->value[2],
1458       key->dd[0], key->dd[1], key->dd[2],
1459       key->ds[0], key->ds[1], key->ds[2]);
1460   }
1461 }
1462
1463
1464 void
1465 lib3ds_quatTrack_dump(Lib3dsQuatTrack *track)
1466 {
1467   Lib3dsQuatKey *key;
1468   printf("flags: %08x, keys:\n", (unsigned int)track->flags);
1469   for( key = track->keyL; key != NULL; key = key->next)
1470   {
1471     tcb_dump(&key->tcb);
1472     printf("    axis = %g,%g,%g, angle=%g, q=%g,%g,%g,%g\n",
1473       key->axis[0], key->axis[1], key->axis[2], key->angle,
1474       key->q[0], key->q[1], key->q[2], key->q[3]);
1475     printf("    dd = %g,%g,%g,%g, ds=%g,%g,%g,%g\n",
1476       key->dd[0], key->dd[1], key->dd[2], key->dd[3],
1477       key->ds[0], key->ds[1], key->ds[2], key->ds[3]);
1478   }
1479 }
1480
1481
1482 void
1483 lib3ds_morphTrack_dump(Lib3dsMorphTrack *track)
1484 {
1485   Lib3dsMorphKey *key;
1486   printf("flags: %08x, keys:\n", (unsigned int)track->flags);
1487   for( key = track->keyL; key != NULL; key = key->next)
1488   {
1489     tcb_dump(&key->tcb);
1490     printf("    name = %s\n", key->name);
1491   }
1492 }
1493
1494
1495
1496 void
1497 lib3ds_dump_tracks(Lib3dsNode *node)
1498 {
1499   switch( node->type ) {
1500     case LIB3DS_AMBIENT_NODE:
1501       printf("ambient: ");
1502       lib3ds_lin3Track_dump(&node->data.ambient.col_track);
1503       break;
1504     case LIB3DS_OBJECT_NODE:
1505       printf("pos: ");
1506       lib3ds_lin3Track_dump(&node->data.object.pos_track);
1507       printf("rot: ");
1508       lib3ds_quatTrack_dump(&node->data.object.rot_track);
1509       printf("scl: ");
1510       lib3ds_lin3Track_dump(&node->data.object.scl_track);
1511       printf("morph: ");
1512       lib3ds_morphTrack_dump(&node->data.object.morph_track);
1513       printf("hide: ");
1514       lib3ds_boolTrack_dump(&node->data.object.hide_track);
1515       break;
1516     case LIB3DS_CAMERA_NODE:
1517       printf("pos: ");
1518       lib3ds_lin3Track_dump(&node->data.camera.pos_track);
1519       printf("fov: ");
1520       lib3ds_lin1Track_dump(&node->data.camera.fov_track);
1521       printf("roll: ");
1522       lib3ds_lin1Track_dump(&node->data.camera.roll_track);
1523       break;
1524     case LIB3DS_TARGET_NODE:
1525       printf("pos: ");
1526       lib3ds_lin3Track_dump(&node->data.target.pos_track);
1527       break;
1528     case LIB3DS_LIGHT_NODE:
1529       printf("pos: ");
1530       lib3ds_lin3Track_dump(&node->data.light.pos_track);
1531       printf("col: ");
1532       lib3ds_lin3Track_dump(&node->data.light.col_track);
1533       printf("hotspot: ");
1534       lib3ds_lin1Track_dump(&node->data.light.hotspot_track);
1535       printf("falloff: ");
1536       lib3ds_lin1Track_dump(&node->data.light.falloff_track);
1537       printf("roll: ");
1538       lib3ds_lin1Track_dump(&node->data.light.roll_track);
1539       break;
1540     case LIB3DS_SPOT_NODE:
1541       printf("pos: ");
1542       lib3ds_lin3Track_dump(&node->data.spot.pos_track);
1543       break;
1544
1545         default:
1546           break;
1547   }
1548 }