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