1 /*
2     Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
3     All rights reserved.
4 
5     This program is free  software: you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published
7     by the Free Software Foundation, either version 2.1 of the License, or
8     (at your option) any later version.
9 
10     Thisprogram  is  distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU Lesser General Public License for more details.
14 
15     You should  have received a copy of the GNU Lesser General Public License
16     along with  this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "lib3ds_impl.h"
19 
20 
21 Lib3dsTrack*
lib3ds_track_new(Lib3dsTrackType type,int nkeys)22 lib3ds_track_new(Lib3dsTrackType type, int nkeys) {
23     Lib3dsTrack *track = (Lib3dsTrack*)calloc(sizeof(Lib3dsTrack), 1);
24     track->type = type;
25     lib3ds_track_resize(track, nkeys);
26     return track;
27 }
28 
29 
30 void
lib3ds_track_free(Lib3dsTrack * track)31 lib3ds_track_free(Lib3dsTrack *track) {
32     assert(track);
33     lib3ds_track_resize(track, 0);
34     memset(track, 0, sizeof(Lib3dsTrack));
35     free(track);
36 }
37 
38 
39 void
lib3ds_track_resize(Lib3dsTrack * track,int nkeys)40 lib3ds_track_resize(Lib3dsTrack *track, int nkeys) {
41     char *p;
42 
43     assert(track);
44     if (track->nkeys == nkeys)
45         return;
46 
47     p = (char*)realloc(track->keys, sizeof(Lib3dsKey) * nkeys);
48     if (nkeys > track->nkeys) {
49         memset(p + (sizeof(Lib3dsKey)*track->nkeys), 0, sizeof(Lib3dsKey)*(nkeys - track->nkeys));
50     }
51     track->keys = (Lib3dsKey*)p;
52     track->nkeys = nkeys;
53 }
54 
55 
56 static void
pos_key_setup(int n,Lib3dsKey * pp,Lib3dsKey * pc,Lib3dsKey * pn,float * dd,float * ds)57 pos_key_setup(int n, Lib3dsKey *pp, Lib3dsKey *pc, Lib3dsKey *pn, float *dd, float *ds) {
58     float tm, cm, cp, bm, bp, tmcm, tmcp, ksm, ksp, kdm, kdp, c;
59     float dt, fp, fn;
60     float delm[3], delp[3];
61     int i;
62 
63     assert(pc);
64     fp = fn = 1.0f;
65     if (pp && pn) {
66         dt = 0.5f * (pn->frame - pp->frame);
67         fp = (float)(pc->frame - pp->frame) / dt;
68         fn = (float)(pn->frame - pc->frame) / dt;
69         c  = (float)fabs(pc->cont);
70         fp = fp + c - c * fp;
71         fn = fn + c - c * fn;
72     }
73 
74     cm = 1.0f - pc->cont;
75     tm = 0.5f * (1.0f - pc->tens);
76     cp = 2.0f - cm;
77     bm = 1.0f - pc->bias;
78     bp = 2.0f - bm;
79     tmcm = tm * cm;
80     tmcp = tm * cp;
81     ksm = tmcm * bp * fp;
82     ksp = tmcp * bm * fp;
83     kdm = tmcp * bp * fn;
84     kdp = tmcm * bm * fn;
85 
86     for (i = 0; i < n; ++i) delm[i] = delp[i] = 0;
87     if (pp) {
88         for (i = 0; i < n; ++i) delm[i] = pc->value[i] - pp->value[i];
89     }
90     if (pn) {
91         for (i = 0; i < n; ++i) delp[i] = pn->value[i] - pc->value[i];
92     }
93     if (!pp) {
94         for (i = 0; i < n; ++i) delm[i] = delp[i];
95     }
96     if (!pn) {
97         for (i = 0; i < n; ++i) delp[i] = delm[i];
98     }
99 
100     for (i = 0; i < n; ++i) {
101         ds[i] = ksm * delm[i] + ksp * delp[i];
102         dd[i] = kdm * delm[i] + kdp * delp[i];
103     }
104 }
105 
106 
107 static void
rot_key_setup(Lib3dsKey * prev,Lib3dsKey * cur,Lib3dsKey * next,float a[4],float b[4])108 rot_key_setup(Lib3dsKey *prev, Lib3dsKey *cur, Lib3dsKey *next, float a[4], float b[4]) {
109     float tm, cm, cp, bm, bp, tmcm, tmcp, ksm, ksp, kdm, kdp, c;
110     float dt, fp, fn;
111     float q[4], qm[4], qp[4], qa[4], qb[4];
112     int i;
113 
114     assert(cur);
115     assert(prev || next);
116 
117     if (!prev && !next) return;
118 
119     if (prev) {
120         if (cur->value[3] > LIB3DS_TWOPI - LIB3DS_EPSILON) {
121             lib3ds_quat_axis_angle(qm, cur->value, 0.0f);
122             lib3ds_quat_ln(qm);
123         } else {
124             lib3ds_quat_copy(q, prev->value);
125             if (lib3ds_quat_dot(q, cur->value) < 0) lib3ds_quat_neg(q);
126             lib3ds_quat_ln_dif(qm, q, cur->value);
127         }
128     }
129     if (next) {
130         if (next->value[3] > LIB3DS_TWOPI - LIB3DS_EPSILON) {
131             lib3ds_quat_axis_angle(qp, next->value, 0.0f);
132             lib3ds_quat_ln(qp);
133         } else {
134             lib3ds_quat_copy(q, next->value);
135             if (lib3ds_quat_dot(q, cur->value) < 0) lib3ds_quat_neg(q);
136             lib3ds_quat_ln_dif(qp, cur->value, q);
137         }
138     }
139     if (!prev) lib3ds_quat_copy(qm, qp);
140     if (!next) lib3ds_quat_copy(qp, qm);
141 
142     fp = fn = 1.0f;
143     cm = 1.0f - cur->cont;
144     if (prev && next) {
145         dt = 0.5f * (next->frame - prev->frame);
146         fp = (float)(cur->frame - prev->frame) / dt;
147         fn = (float)(next->frame - cur->frame) / dt;
148         c  = (float)fabs(cur->cont);
149         fp = fp + c - c * fp;
150         fn = fn + c - c * fn;
151     }
152 
153     tm = 0.5f * (1.0f - cur->tens);
154     cp = 2.0f - cm;
155     bm = 1.0f - cur->bias;
156     bp = 2.0f - bm;
157     tmcm = tm * cm;
158     tmcp = tm * cp;
159     ksm = 1.0f - tmcm * bp * fp;
160     ksp = -tmcp * bm * fp;
161     kdm = tmcp * bp * fn;
162     kdp = tmcm * bm * fn - 1.0f;
163 
164     for (i = 0; i < 4; i++) {
165         qa[i] = 0.5f * (kdm * qm[i] + kdp * qp[i]);
166         qb[i] = 0.5f * (ksm * qm[i] + ksp * qp[i]);
167     }
168     lib3ds_quat_exp(qa);
169     lib3ds_quat_exp(qb);
170 
171     lib3ds_quat_mul(a, cur->value, qa);
172     lib3ds_quat_mul(b, cur->value, qb);
173 }
174 
175 
176 static void
quat_for_index(Lib3dsTrack * track,int index,float q[4])177 quat_for_index(Lib3dsTrack *track, int index, float q[4]) {
178     float p[4];
179     int i;
180     lib3ds_quat_identity(q);
181     for (i = 0; i <= index; ++i) {
182         lib3ds_quat_axis_angle(p, track->keys[i].value, track->keys[i].value[3]);
183         lib3ds_quat_mul(q, p, q);
184     }
185 }
186 
187 
188 static int
find_index(Lib3dsTrack * track,float t,float * u)189 find_index(Lib3dsTrack *track, float t, float *u) {
190     int i;
191     float nt;
192     int t0, t1;
193 
194     assert(track);
195     assert(track->nkeys > 0);
196 
197     if (track->nkeys <= 1)
198         return -1;
199 
200     t0 = track->keys[0].frame;
201     t1 = track->keys[track->nkeys-1].frame;
202     if (track->flags & LIB3DS_TRACK_REPEAT) {
203         nt = (float)fmod(t - t0, t1 - t0) + t0;
204     } else {
205         nt = t;
206     }
207 
208     if (nt <= t0) {
209         return -1;
210     }
211     if (nt >= t1) {
212         return track->nkeys;
213     }
214 
215     for (i = 1; i < track->nkeys; ++i) {
216         if (nt < track->keys[i].frame)
217             break;
218     }
219 
220     *u = nt - (float)track->keys[i-1].frame;
221     *u /= (float)(track->keys[i].frame - track->keys[i-1].frame);
222 
223     assert((*u >= 0.0f) && (*u <= 1.0f));
224     return i;
225 }
226 
227 
228 static void
setup_segment(Lib3dsTrack * track,int index,Lib3dsKey * pp,Lib3dsKey * p0,Lib3dsKey * p1,Lib3dsKey * pn)229 setup_segment(Lib3dsTrack *track, int index, Lib3dsKey *pp, Lib3dsKey *p0, Lib3dsKey *p1, Lib3dsKey *pn) {
230     int ip, in;
231 
232     pp->frame = pn->frame = -1;
233     if (index >= 2) {
234         ip = index - 2;
235         *pp = track->keys[index - 2];
236     } else {
237         if (track->flags & LIB3DS_TRACK_SMOOTH) {
238             ip = track->nkeys - 2;
239             *pp = track->keys[track->nkeys - 2];
240             pp->frame = track->keys[track->nkeys - 2].frame - (track->keys[track->nkeys - 1].frame - track->keys[0].frame);
241         }
242 	else ip = -1;		// Avoids a compiler warning
243     }
244 
245     *p0 = track->keys[index - 1];
246     *p1 = track->keys[index];
247 
248     if (index < (int)track->nkeys - 1) {
249         in = index + 1;
250         *pn = track->keys[index + 1];
251     } else {
252         if (track->flags & LIB3DS_TRACK_SMOOTH) {
253             in = 1;
254             *pn = track->keys[1];
255             pn->frame = track->keys[1].frame + (track->keys[track->nkeys-1].frame - track->keys[0].frame);
256         }
257         else in = -1; // Avoids a compiler warning
258     }
259 
260     if (track->type == LIB3DS_TRACK_QUAT) {
261         float q[4];
262         if (pp->frame >= 0) {
263             quat_for_index(track, ip, pp->value);
264         } else {
265             lib3ds_quat_identity(pp->value);
266         }
267 
268         quat_for_index(track, index - 1, p0->value);
269         lib3ds_quat_axis_angle(q, track->keys[index].value, track->keys[index].value[3]);
270         lib3ds_quat_mul(p1->value, q, p0->value);
271 
272         if (pn->frame >= 0) {
273             lib3ds_quat_axis_angle(q, track->keys[in].value, track->keys[in].value[3]);
274             lib3ds_quat_mul(pn->value, q, p1->value);
275         } else {
276             lib3ds_quat_identity(pn->value);
277         }
278     }
279 }
280 
281 
282 void
lib3ds_track_eval_bool(Lib3dsTrack * track,int * b,float t)283 lib3ds_track_eval_bool(Lib3dsTrack *track, int *b, float t) {
284     *b = FALSE;
285     if (track) {
286         int index;
287         float u;
288 
289         assert(track->type == LIB3DS_TRACK_BOOL);
290         if (!track->nkeys) {
291             return;
292         }
293 
294         index = find_index(track, t, &u);
295         if (index < 0) {
296             *b = FALSE;
297             return;
298         }
299         if (index >= track->nkeys) {
300             *b = !(track->nkeys & 1);
301             return;
302         }
303         *b = !(index & 1);
304     }
305 }
306 
307 
308 static void
track_eval_linear(Lib3dsTrack * track,float * value,float t)309 track_eval_linear(Lib3dsTrack *track, float *value, float t) {
310     Lib3dsKey pp, p0, p1, pn;
311     float u;
312     int index;
313     float dsp[3], ddp[3], dsn[3], ddn[3];
314 
315     assert(track);
316     if (!track->nkeys) {
317         if (track->type==LIB3DS_TRACK_FLOAT)
318         {
319             *value = 0.0f;
320         }
321         else
322         {
323             int i;
324             for (i = 0; i < track->type; ++i) value[i] = 0.0f;
325         }
326         return;
327     }
328 
329     index = find_index(track, t, &u);
330 
331     if (index < 0) {
332         int i;
333         for (i = 0; i < track->type; ++i) value[i] = track->keys[0].value[i];
334         return;
335     }
336     if (index >= track->nkeys) {
337         int i;
338         for (i = 0; i < track->type; ++i) value[i] = track->keys[track->nkeys-1].value[i];
339         return;
340     }
341 
342     setup_segment(track, index, &pp, &p0, &p1, &pn);
343 
344     pos_key_setup(track->type, pp.frame>=0? &pp : NULL, &p0, &p1, ddp, dsp);
345     pos_key_setup(track->type, &p0, &p1, pn.frame>=0? &pn : NULL, ddn, dsn);
346 
347     lib3ds_math_cubic_interp(
348         value,
349         p0.value,
350         ddp,
351         dsn,
352         p1.value,
353         track->type,
354         u
355     );
356 }
357 
358 
359 void
lib3ds_track_eval_float(Lib3dsTrack * track,float * f,float t)360 lib3ds_track_eval_float(Lib3dsTrack *track, float *f, float t) {
361     *f = 0;
362     if (track) {
363         assert(track->type == LIB3DS_TRACK_FLOAT);
364         track_eval_linear(track, f, t);
365     }
366 }
367 
368 
369 void
lib3ds_track_eval_vector(Lib3dsTrack * track,float v[3],float t)370 lib3ds_track_eval_vector(Lib3dsTrack *track, float v[3], float t) {
371     lib3ds_vector_zero(v);
372     if (track) {
373         assert(track->type == LIB3DS_TRACK_VECTOR);
374         track_eval_linear(track, v, t);
375     }
376 }
377 
378 
379 void
lib3ds_track_eval_quat(Lib3dsTrack * track,float q[4],float t)380 lib3ds_track_eval_quat(Lib3dsTrack *track, float q[4], float t) {
381     lib3ds_quat_identity(q);
382     if (track) {
383         Lib3dsKey pp, p0, p1, pn;
384         float u;
385         int index;
386         float ap[4], bp[4], an[4], bn[4];
387 
388         assert(track->type == LIB3DS_TRACK_QUAT);
389         if (!track->nkeys) {
390             return;
391         }
392 
393         index = find_index(track, t, &u);
394         if (index < 0) {
395             lib3ds_quat_axis_angle(q, track->keys[0].value, track->keys[0].value[3]);
396             return;
397         }
398         if (index >= track->nkeys) {
399             quat_for_index(track, track->nkeys - 1, q);
400             return;
401         }
402 
403         setup_segment(track, index, &pp, &p0, &p1, &pn);
404 
405         rot_key_setup(pp.frame>=0? &pp : NULL, &p0, &p1, ap, bp);
406         rot_key_setup(&p0, &p1, pn.frame>=0? &pn : NULL, an, bn);
407 
408         lib3ds_quat_squad(q, p0.value, ap, bn, p1.value, u);
409     }
410 }
411 
412 
413 static void
tcb_read(Lib3dsKey * key,Lib3dsIo * io)414 tcb_read(Lib3dsKey *key, Lib3dsIo *io) {
415     key->flags = lib3ds_io_read_word(io);
416     if (key->flags & LIB3DS_KEY_USE_TENS) {
417         key->tens = lib3ds_io_read_float(io);
418     }
419     if (key->flags & LIB3DS_KEY_USE_CONT) {
420         key->cont = lib3ds_io_read_float(io);
421     }
422     if (key->flags & LIB3DS_KEY_USE_BIAS) {
423         key->bias = lib3ds_io_read_float(io);
424     }
425     if (key->flags & LIB3DS_KEY_USE_EASE_TO) {
426         key->ease_to = lib3ds_io_read_float(io);
427     }
428     if (key->flags & LIB3DS_KEY_USE_EASE_FROM) {
429         key->ease_from = lib3ds_io_read_float(io);
430     }
431 }
432 
433 
434 void
lib3ds_track_read(Lib3dsTrack * track,Lib3dsIo * io)435 lib3ds_track_read(Lib3dsTrack *track, Lib3dsIo *io) {
436     unsigned nkeys;
437     unsigned i;
438 
439     track->flags = lib3ds_io_read_word(io);
440     lib3ds_io_read_dword(io);
441     lib3ds_io_read_dword(io);
442     nkeys = lib3ds_io_read_intd(io);
443     lib3ds_track_resize(track, nkeys);
444 
445     switch (track->type) {
446         case LIB3DS_TRACK_BOOL:
447             for (i = 0; i < nkeys; ++i) {
448                 track->keys[i].frame = lib3ds_io_read_intd(io);
449                 tcb_read(&track->keys[i], io);
450             }
451             break;
452 
453         case LIB3DS_TRACK_FLOAT:
454             for (i = 0; i < nkeys; ++i) {
455                 track->keys[i].frame = lib3ds_io_read_intd(io);
456                 tcb_read(&track->keys[i], io);
457                 track->keys[i].value[0] = lib3ds_io_read_float(io);
458             }
459             break;
460 
461         case LIB3DS_TRACK_VECTOR:
462             for (i = 0; i < nkeys; ++i) {
463                 track->keys[i].frame = lib3ds_io_read_intd(io);
464                 tcb_read(&track->keys[i], io);
465                 lib3ds_io_read_vector(io, track->keys[i].value);
466             }
467             break;
468 
469         case LIB3DS_TRACK_QUAT:
470             for (i = 0; i < nkeys; ++i) {
471                 track->keys[i].frame = lib3ds_io_read_intd(io);
472                 tcb_read(&track->keys[i], io);
473                 track->keys[i].value[3] = lib3ds_io_read_float(io);
474                 lib3ds_io_read_vector(io, track->keys[i].value);
475             }
476             break;
477 
478         /*case LIB3DS_TRACK_MORPH:
479             for (i = 0; i < nkeys; ++i) {
480                 track->keys[i].frame = lib3ds_io_read_intd(io);
481                 tcb_read(&track->keys[i].tcb, io);
482                 lib3ds_io_read_string(io, track->keys[i].data.m.name, 64);
483             }
484             break;*/
485 
486         default:
487             break;
488     }
489 }
490 
491 
492 void
tcb_write(Lib3dsKey * key,Lib3dsIo * io)493 tcb_write(Lib3dsKey *key, Lib3dsIo *io) {
494     lib3ds_io_write_word(io, (uint16_t)key->flags);
495     if (key->flags & LIB3DS_KEY_USE_TENS) {
496         lib3ds_io_write_float(io, key->tens);
497     }
498     if (key->flags & LIB3DS_KEY_USE_CONT) {
499         lib3ds_io_write_float(io, key->cont);
500     }
501     if (key->flags & LIB3DS_KEY_USE_BIAS) {
502         lib3ds_io_write_float(io, key->bias);
503     }
504     if (key->flags & LIB3DS_KEY_USE_EASE_TO) {
505         lib3ds_io_write_float(io, key->ease_to);
506     }
507     if (key->flags & LIB3DS_KEY_USE_EASE_FROM) {
508         lib3ds_io_write_float(io, key->ease_from);
509     }
510 }
511 
512 
513 void
lib3ds_track_write(Lib3dsTrack * track,Lib3dsIo * io)514 lib3ds_track_write(Lib3dsTrack *track, Lib3dsIo *io) {
515     int i;
516 
517     lib3ds_io_write_word(io, (uint16_t)track->flags);
518     lib3ds_io_write_dword(io, 0);
519     lib3ds_io_write_dword(io, 0);
520     lib3ds_io_write_dword(io, track->nkeys);
521 
522     switch (track->type) {
523         case LIB3DS_TRACK_BOOL:
524             for (i = 0; i < track->nkeys; ++i) {
525                 lib3ds_io_write_intd(io, track->keys[i].frame);
526                 tcb_write(&track->keys[i], io);
527             }
528             break;
529 
530         case LIB3DS_TRACK_FLOAT:
531             for (i = 0; i < track->nkeys; ++i) {
532                 lib3ds_io_write_intd(io, track->keys[i].frame);
533                 tcb_write(&track->keys[i], io);
534                 lib3ds_io_write_float(io, track->keys[i].value[0]);
535             }
536             break;
537 
538         case LIB3DS_TRACK_VECTOR:
539             for (i = 0; i < track->nkeys; ++i) {
540                 lib3ds_io_write_intd(io, track->keys[i].frame);
541                 tcb_write(&track->keys[i], io);
542                 lib3ds_io_write_vector(io, track->keys[i].value);
543             }
544             break;
545 
546         case LIB3DS_TRACK_QUAT:
547             for (i = 0; i < track->nkeys; ++i) {
548                 lib3ds_io_write_intd(io, track->keys[i].frame);
549                 tcb_write(&track->keys[i], io);
550                 lib3ds_io_write_float(io, track->keys[i].value[3]);
551                 lib3ds_io_write_vector(io, track->keys[i].value);
552             }
553             break;
554 
555         /*case LIB3DS_TRACK_MORPH:
556             for (i = 0; i < track->nkeys; ++i) {
557                 lib3ds_io_write_intd(io, track->keys[i].frame);
558                 tcb_write(&track->keys[i].tcb, io);
559                 lib3ds_io_write_string(io, track->keys[i].data.m.name);
560             }
561             break;*/
562     }
563 }
564