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