Home | API | File List | Examples | Download

lib3ds_track.c

00001 /*
00002     Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
00003     All rights reserved.
00004     
00005     This program is free  software: you can redistribute it and/or modify 
00006     it under the terms of the GNU Lesser General Public License as published 
00007     by the Free Software Foundation, either version 2.1 of the License, or 
00008     (at your option) any later version.
00009 
00010     Thisprogram  is  distributed in the hope that it will be useful, 
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
00013     GNU Lesser General Public License for more details.
00014     
00015     You should  have received a copy of the GNU Lesser General Public License
00016     along with  this program; If not, see <http://www.gnu.org/licenses/>. 
00017 */
00018 #include "lib3ds_impl.h"
00019 
00020 
00021 Lib3dsTrack* 
00022 lib3ds_track_new(Lib3dsTrackType type, int nkeys) {
00023     Lib3dsTrack *track = (Lib3dsTrack*)calloc(sizeof(Lib3dsTrack), 1);
00024     track->type = type;
00025     lib3ds_track_resize(track, nkeys);
00026     return track;
00027 }
00028 
00029 
00030 void 
00031 lib3ds_track_free(Lib3dsTrack *track) {
00032     assert(track);
00033     lib3ds_track_resize(track, 0);
00034     memset(track, 0, sizeof(Lib3dsTrack));
00035     free(track);
00036 }
00037 
00038 
00039 void 
00040 lib3ds_track_resize(Lib3dsTrack *track, int nkeys) {
00041     char *p;
00042 
00043     assert(track);
00044     if (track->nkeys == nkeys)
00045         return;
00046 
00047     p = (char*)realloc(track->keys, sizeof(Lib3dsKey) * nkeys);
00048     if (nkeys > track->nkeys) {
00049         memset(p + (sizeof(Lib3dsKey)*track->nkeys), 0, sizeof(Lib3dsKey)*(nkeys - track->nkeys));
00050     }
00051     track->keys = (Lib3dsKey*)p;
00052     track->nkeys = nkeys;
00053 }
00054 
00055 
00056 static void 
00057 pos_key_setup(int n, Lib3dsKey *pp, Lib3dsKey *pc, Lib3dsKey *pn, float *dd, float *ds) {
00058     float tm, cm, cp, bm, bp, tmcm, tmcp, ksm, ksp, kdm, kdp, c;
00059     float dt, fp, fn;
00060     float delm[3], delp[3];
00061     int i;
00062 
00063     assert(pc);
00064     fp = fn = 1.0f;
00065     if (pp && pn) {
00066         dt = 0.5f * (pn->frame - pp->frame);
00067         fp = (float)(pc->frame - pp->frame) / dt;
00068         fn = (float)(pn->frame - pc->frame) / dt;
00069         c  = (float)fabs(pc->cont);
00070         fp = fp + c - c * fp;
00071         fn = fn + c - c * fn;
00072     }
00073 
00074     cm = 1.0f - pc->cont;
00075     tm = 0.5f * (1.0f - pc->tens);
00076     cp = 2.0f - cm;
00077     bm = 1.0f - pc->bias;
00078     bp = 2.0f - bm;
00079     tmcm = tm * cm;
00080     tmcp = tm * cp;
00081     ksm = tmcm * bp * fp;
00082     ksp = tmcp * bm * fp;
00083     kdm = tmcp * bp * fn;
00084     kdp = tmcm * bm * fn;
00085 
00086     for (i = 0; i < n; ++i) delm[i] = delp[i] = 0;
00087     if (pp) {
00088         for (i = 0; i < n; ++i) delm[i] = pc->value[i] - pp->value[i];
00089     }
00090     if (pn) {
00091         for (i = 0; i < n; ++i) delp[i] = pn->value[i] - pc->value[i];
00092     }
00093     if (!pp) {
00094         for (i = 0; i < n; ++i) delm[i] = delp[i];
00095     }
00096     if (!pn) {
00097         for (i = 0; i < n; ++i) delp[i] = delm[i];
00098     }
00099 
00100     for (i = 0; i < n; ++i) {
00101         ds[i] = ksm * delm[i] + ksp * delp[i];
00102         dd[i] = kdm * delm[i] + kdp * delp[i];
00103     }
00104 }
00105 
00106 
00107 static void 
00108 rot_key_setup(Lib3dsKey *prev, Lib3dsKey *cur, Lib3dsKey *next, float a[4], float b[4]) {
00109     float tm, cm, cp, bm, bp, tmcm, tmcp, ksm, ksp, kdm, kdp, c;
00110     float dt, fp, fn;
00111     float q[4], qm[4], qp[4], qa[4], qb[4];
00112     int i;
00113 
00114     assert(cur);
00115     if (prev) {
00116         if (cur->value[3] > LIB3DS_TWOPI - LIB3DS_EPSILON) {
00117             lib3ds_quat_axis_angle(qm, cur->value, 0.0f);
00118             lib3ds_quat_ln(qm);
00119         } else {
00120             lib3ds_quat_copy(q, prev->value);
00121             if (lib3ds_quat_dot(q, cur->value) < 0) lib3ds_quat_neg(q);
00122             lib3ds_quat_ln_dif(qm, q, cur->value);
00123         }
00124     }
00125     if (next) {
00126         if (next->value[3] > LIB3DS_TWOPI - LIB3DS_EPSILON) {
00127             lib3ds_quat_axis_angle(qp, next->value, 0.0f);
00128             lib3ds_quat_ln(qp);
00129         } else {
00130             lib3ds_quat_copy(q, next->value);
00131             if (lib3ds_quat_dot(q, cur->value) < 0) lib3ds_quat_neg(q);
00132             lib3ds_quat_ln_dif(qp, cur->value, q);
00133         }
00134     }
00135     if (!prev) lib3ds_quat_copy(qm, qp);
00136     if (!next) lib3ds_quat_copy(qp, qm);
00137 
00138     fp = fn = 1.0f;
00139     cm = 1.0f - cur->cont;
00140     if (prev && next) {
00141         dt = 0.5f * (next->frame - prev->frame);
00142         fp = (float)(cur->frame - prev->frame) / dt;
00143         fn = (float)(next->frame - cur->frame) / dt;
00144         c  = (float)fabs(cur->cont);
00145         fp = fp + c - c * fp;
00146         fn = fn + c - c * fn;
00147     }
00148 
00149     tm = 0.5f * (1.0f - cur->tens);
00150     cp = 2.0f - cm;
00151     bm = 1.0f - cur->bias;
00152     bp = 2.0f - bm;
00153     tmcm = tm * cm;
00154     tmcp = tm * cp;
00155     ksm = 1.0f - tmcm * bp * fp;
00156     ksp = -tmcp * bm * fp;
00157     kdm = tmcp * bp * fn;
00158     kdp = tmcm * bm * fn - 1.0f;
00159 
00160     for (i = 0; i < 4; i++) {
00161         qa[i] = 0.5f * (kdm * qm[i] + kdp * qp[i]);
00162         qb[i] = 0.5f * (ksm * qm[i] + ksp * qp[i]);
00163     }
00164     lib3ds_quat_exp(qa);
00165     lib3ds_quat_exp(qb);
00166 
00167     lib3ds_quat_mul(a, cur->value, qa);
00168     lib3ds_quat_mul(b, cur->value, qb);
00169 }
00170 
00171 
00172 static void
00173 quat_for_index(Lib3dsTrack *track, int index, float q[4]) {
00174     float p[4];
00175     int i;
00176     lib3ds_quat_identity(q);
00177     for (i = 0; i <= index; ++i) {
00178         lib3ds_quat_axis_angle(p, track->keys[i].value, track->keys[i].value[3]);
00179         lib3ds_quat_mul(q, p, q);
00180     }
00181 }
00182 
00183 
00184 static int 
00185 find_index(Lib3dsTrack *track, float t, float *u) {
00186     int i;
00187     float nt;
00188     int t0, t1;
00189 
00190     assert(track);
00191     assert(track->nkeys > 0);
00192     
00193     if (track->nkeys <= 1)
00194         return -1;
00195     
00196     t0 = track->keys[0].frame;
00197     t1 = track->keys[track->nkeys-1].frame;
00198     if (track->flags & LIB3DS_TRACK_REPEAT) {
00199         nt = (float)fmod(t - t0, t1 - t0) + t0;
00200     } else {
00201         nt = t;
00202     }
00203 
00204     if (nt <= t0) {
00205         return -1;
00206     }
00207     if (nt >= t1) {
00208         return track->nkeys;
00209     }
00210 
00211     for (i = 1; i < track->nkeys; ++i) {
00212         if (nt < track->keys[i].frame)
00213             break;
00214     }
00215 
00216     *u = nt - (float)track->keys[i-1].frame;
00217     *u /= (float)(track->keys[i].frame - track->keys[i-1].frame);
00218 
00219     assert((*u >= 0.0f) && (*u <= 1.0f));
00220     return i;
00221 }
00222 
00223 
00224 static void 
00225 setup_segment(Lib3dsTrack *track, int index, Lib3dsKey *pp, Lib3dsKey *p0, Lib3dsKey *p1, Lib3dsKey *pn) {
00226     int ip, in;
00227     
00228     pp->frame = pn->frame = -1;
00229     if (index >= 2) {
00230         ip = index - 2;
00231         *pp = track->keys[index - 2];
00232     } else {
00233         if (track->flags & LIB3DS_TRACK_SMOOTH) {
00234             ip = track->nkeys - 2;
00235             *pp = track->keys[track->nkeys - 2];
00236             pp->frame = track->keys[track->nkeys - 2].frame - (track->keys[track->nkeys - 1].frame - track->keys[0].frame);
00237         }
00238     }
00239 
00240     *p0 = track->keys[index - 1];
00241     *p1 = track->keys[index];
00242 
00243     if (index < (int)track->nkeys - 1) {
00244         in = index + 1;
00245         *pn = track->keys[index + 1];
00246     } else {
00247         if (track->flags & LIB3DS_TRACK_SMOOTH) {
00248             in = 1;
00249             *pn = track->keys[1];
00250             pn->frame = track->keys[1].frame + (track->keys[track->nkeys-1].frame - track->keys[0].frame);
00251         }
00252     }
00253 
00254     if (track->type == LIB3DS_TRACK_QUAT) {
00255         float q[4];
00256         if (pp->frame >= 0) {
00257             quat_for_index(track, ip, pp->value);
00258         } else {
00259             lib3ds_quat_identity(pp->value);
00260         }
00261 
00262         quat_for_index(track, index - 1, p0->value);
00263         lib3ds_quat_axis_angle(q, track->keys[index].value, track->keys[index].value[3]);
00264         lib3ds_quat_mul(p1->value, q, p0->value);
00265 
00266         if (pn->frame >= 0) {
00267             lib3ds_quat_axis_angle(q, track->keys[in].value, track->keys[in].value[3]);
00268             lib3ds_quat_mul(pn->value, q, p1->value);
00269         } else {
00270             lib3ds_quat_identity(pn->value);
00271         }
00272     }
00273 }
00274 
00275 
00276 void 
00277 lib3ds_track_eval_bool(Lib3dsTrack *track, int *b, float t) {
00278     *b = FALSE;
00279     if (track) {
00280         int index;
00281         float u;
00282 
00283         assert(track->type == LIB3DS_TRACK_BOOL);
00284         if (!track->nkeys) {
00285             return;
00286         }
00287 
00288         index = find_index(track, t, &u);
00289         if (index < 0) {
00290             *b = FALSE;
00291             return;
00292         }
00293         if (index >= track->nkeys) {
00294             *b = !(track->nkeys & 1);
00295             return;
00296         }
00297         *b = !(index & 1);
00298     }
00299 }
00300 
00301 
00302 static void 
00303 track_eval_linear(Lib3dsTrack *track, float *value, float t) {
00304     Lib3dsKey pp, p0, p1, pn;
00305     float u;
00306     int index;
00307     float dsp[3], ddp[3], dsn[3], ddn[3];
00308 
00309     assert(track);
00310     if (!track->nkeys) {
00311         int i;
00312         for (i = 0; i < track->type; ++i) value[i] = 0.0f;
00313         return;
00314     }
00315 
00316     index = find_index(track, t, &u);
00317 
00318     if (index < 0) {
00319         int i;
00320         for (i = 0; i < track->type; ++i) value[i] = track->keys[0].value[i];
00321         return;
00322     }
00323     if (index >= track->nkeys) {
00324         int i;
00325         for (i = 0; i < track->type; ++i) value[i] = track->keys[track->nkeys-1].value[i];
00326         return;
00327     }
00328 
00329     setup_segment(track, index, &pp, &p0, &p1, &pn);
00330 
00331     pos_key_setup(track->type, pp.frame>=0? &pp : NULL, &p0, &p1, ddp, dsp);
00332     pos_key_setup(track->type, &p0, &p1, pn.frame>=0? &pn : NULL, ddn, dsn);
00333 
00334     lib3ds_math_cubic_interp(
00335         value,
00336         p0.value,
00337         ddp,
00338         dsn,
00339         p1.value,
00340         track->type,
00341         u
00342     );
00343 }
00344 
00345 
00346 void 
00347 lib3ds_track_eval_float(Lib3dsTrack *track, float *f, float t) {
00348     *f = 0;
00349     if (track) {
00350         assert(track->type == LIB3DS_TRACK_FLOAT);
00351         track_eval_linear(track, f, t);
00352     }
00353 }
00354 
00355 
00356 void 
00357 lib3ds_track_eval_vector(Lib3dsTrack *track, float v[3], float t) {
00358     lib3ds_vector_zero(v);
00359     if (track) {
00360         assert(track->type == LIB3DS_TRACK_VECTOR);
00361         track_eval_linear(track, v, t);
00362     }
00363 }
00364 
00365 
00366 void 
00367 lib3ds_track_eval_quat(Lib3dsTrack *track, float q[4], float t) {
00368     lib3ds_quat_identity(q);
00369     if (track) {
00370         Lib3dsKey pp, p0, p1, pn;
00371         float u;
00372         int index;
00373         float ap[4], bp[4], an[4], bn[4];
00374 
00375         assert(track->type == LIB3DS_TRACK_QUAT);
00376         if (!track->nkeys) {
00377             return;
00378         }
00379 
00380         index = find_index(track, t, &u);
00381         if (index < 0) {
00382             lib3ds_quat_axis_angle(q, track->keys[0].value, track->keys[0].value[3]);
00383             return;
00384         }
00385         if (index >= track->nkeys) { 
00386             quat_for_index(track, track->nkeys - 1, q);
00387             return;
00388         }
00389 
00390         setup_segment(track, index, &pp, &p0, &p1, &pn);
00391 
00392         rot_key_setup(pp.frame>=0? &pp : NULL, &p0, &p1, ap, bp);
00393         rot_key_setup(&p0, &p1, pn.frame>=0? &pn : NULL, an, bn);
00394 
00395         lib3ds_quat_squad(q, p0.value, ap, bn, p1.value, u);
00396     }
00397 }
00398 
00399 
00400 static void 
00401 tcb_read(Lib3dsKey *key, Lib3dsIo *io) {
00402     key->flags = lib3ds_io_read_word(io);
00403     if (key->flags & LIB3DS_KEY_USE_TENS) {
00404         key->tens = lib3ds_io_read_float(io);
00405     }
00406     if (key->flags & LIB3DS_KEY_USE_CONT) {
00407         key->cont = lib3ds_io_read_float(io);
00408     }
00409     if (key->flags & LIB3DS_KEY_USE_BIAS) {
00410         key->bias = lib3ds_io_read_float(io);
00411     }
00412     if (key->flags & LIB3DS_KEY_USE_EASE_TO) {
00413         key->ease_to = lib3ds_io_read_float(io);
00414     }
00415     if (key->flags & LIB3DS_KEY_USE_EASE_FROM) {
00416         key->ease_from = lib3ds_io_read_float(io);
00417     }
00418 }
00419 
00420 
00421 void 
00422 lib3ds_track_read(Lib3dsTrack *track, Lib3dsIo *io) {
00423     unsigned nkeys;
00424     unsigned i;
00425 
00426     track->flags = lib3ds_io_read_word(io);
00427     lib3ds_io_read_dword(io);
00428     lib3ds_io_read_dword(io);
00429     nkeys = lib3ds_io_read_intd(io);
00430     lib3ds_track_resize(track, nkeys);
00431 
00432     switch (track->type) {
00433         case LIB3DS_TRACK_BOOL:
00434             for (i = 0; i < nkeys; ++i) {
00435                 track->keys[i].frame = lib3ds_io_read_intd(io);
00436                 tcb_read(&track->keys[i], io);
00437             }
00438             break;
00439 
00440         case LIB3DS_TRACK_FLOAT:
00441             for (i = 0; i < nkeys; ++i) {
00442                 track->keys[i].frame = lib3ds_io_read_intd(io);
00443                 tcb_read(&track->keys[i], io);
00444                 track->keys[i].value[0] = lib3ds_io_read_float(io);
00445             }
00446             break;
00447 
00448         case LIB3DS_TRACK_VECTOR:
00449             for (i = 0; i < nkeys; ++i) {
00450                 track->keys[i].frame = lib3ds_io_read_intd(io);
00451                 tcb_read(&track->keys[i], io);
00452                 lib3ds_io_read_vector(io, track->keys[i].value);
00453             }
00454             break;
00455 
00456         case LIB3DS_TRACK_QUAT:
00457             for (i = 0; i < nkeys; ++i) {
00458                 track->keys[i].frame = lib3ds_io_read_intd(io);
00459                 tcb_read(&track->keys[i], io);
00460                 track->keys[i].value[3] = lib3ds_io_read_float(io);
00461                 lib3ds_io_read_vector(io, track->keys[i].value);
00462             }
00463             break;
00464 
00465         /*case LIB3DS_TRACK_MORPH:
00466             for (i = 0; i < nkeys; ++i) {
00467                 track->keys[i].frame = lib3ds_io_read_intd(io);
00468                 tcb_read(&track->keys[i].tcb, io);
00469                 lib3ds_io_read_string(io, track->keys[i].data.m.name, 64);
00470             }
00471             break;*/
00472 
00473         default:
00474             break;
00475     }
00476 }
00477 
00478 
00479 void
00480 tcb_write(Lib3dsKey *key, Lib3dsIo *io) {
00481     lib3ds_io_write_word(io, key->flags);
00482     if (key->flags & LIB3DS_KEY_USE_TENS) {
00483         lib3ds_io_write_float(io, key->tens);
00484     }
00485     if (key->flags & LIB3DS_KEY_USE_CONT) {
00486         lib3ds_io_write_float(io, key->cont);
00487     }
00488     if (key->flags & LIB3DS_KEY_USE_BIAS) {
00489         lib3ds_io_write_float(io, key->bias);
00490     }
00491     if (key->flags & LIB3DS_KEY_USE_EASE_TO) {
00492         lib3ds_io_write_float(io, key->ease_to);
00493     }
00494     if (key->flags & LIB3DS_KEY_USE_EASE_FROM) {
00495         lib3ds_io_write_float(io, key->ease_from);
00496     }
00497 }
00498 
00499 
00500 void
00501 lib3ds_track_write(Lib3dsTrack *track, Lib3dsIo *io) {
00502     int i;
00503 
00504     lib3ds_io_write_word(io, (uint16_t)track->flags);
00505     lib3ds_io_write_dword(io, 0);
00506     lib3ds_io_write_dword(io, 0);
00507     lib3ds_io_write_dword(io, track->nkeys);
00508 
00509     switch (track->type) {
00510         case LIB3DS_TRACK_BOOL:
00511             for (i = 0; i < track->nkeys; ++i) {
00512                 lib3ds_io_write_intd(io, track->keys[i].frame);
00513                 tcb_write(&track->keys[i], io);
00514             }
00515             break;
00516 
00517         case LIB3DS_TRACK_FLOAT:
00518             for (i = 0; i < track->nkeys; ++i) {
00519                 lib3ds_io_write_intd(io, track->keys[i].frame);
00520                 tcb_write(&track->keys[i], io);
00521                 lib3ds_io_write_float(io, track->keys[i].value[0]);
00522             }
00523             break;
00524 
00525         case LIB3DS_TRACK_VECTOR:
00526             for (i = 0; i < track->nkeys; ++i) {
00527                 lib3ds_io_write_intd(io, track->keys[i].frame);
00528                 tcb_write(&track->keys[i], io);
00529                 lib3ds_io_write_vector(io, track->keys[i].value);
00530             }
00531             break;
00532 
00533         case LIB3DS_TRACK_QUAT:
00534             for (i = 0; i < track->nkeys; ++i) {
00535                 lib3ds_io_write_intd(io, track->keys[i].frame);
00536                 tcb_write(&track->keys[i], io);
00537                 lib3ds_io_write_float(io, track->keys[i].value[3]);
00538                 lib3ds_io_write_vector(io, track->keys[i].value);
00539             }
00540             break;
00541 
00542         /*case LIB3DS_TRACK_MORPH:
00543             for (i = 0; i < track->nkeys; ++i) {
00544                 lib3ds_io_write_intd(io, track->keys[i].frame);
00545                 tcb_write(&track->keys[i].tcb, io);
00546                 lib3ds_io_write_string(io, track->keys[i].data.m.name);
00547             }
00548             break;*/
00549     }
00550 }