123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- /*!
- \file lib/ogsf/gk.c
- \brief OGSF library - setting and manipulating keyframes animation (lower level functions)
- GRASS OpenGL gsurf OGSF Library
- (C) 1999-2008 by the GRASS Development Team
- This program is free software under the
- GNU General Public License (>=v2).
- Read the file COPYING that comes with GRASS
- for details.
- \author Bill Brown USACERL, GMSL/University of Illinois
- \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
- */
- #include <stdlib.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- #include <grass/ogsf.h>
- static float spl3(float, double, double, double, double, double, double,
- double);
- static float spl3(float tension, double data0, double data1, double x,
- double x2, double x3, double lderiv, double rderiv)
- {
- return ((float)
- (data0 * (2 * x3 - 3 * x2 + 1) + data1 * (-2 * x3 + 3 * x2) +
- (double)tension * lderiv * (x3 - 2 * x2 + x) +
- (double)tension * rderiv * (x3 - x2)));
- }
- /*!
- \brief Copy keyframes
- \param k source keyframes
- \return pointer to Keylist struct (target)
- */
- Keylist *gk_copy_key(Keylist * k)
- {
- Keylist *newk;
- int i;
- newk = (Keylist *) G_malloc(sizeof(Keylist)); /* G_fatal_error */
- if (!newk) {
- return (NULL);
- }
- for (i = 0; i < KF_NUMFIELDS; i++) {
- newk->fields[i] = k->fields[i];
- }
- newk->pos = k->pos;
- newk->look_ahead = k->look_ahead;
- newk->fieldmask = k->fieldmask;
- newk->next = newk->prior = NULL;
- return (newk);
- }
- /*!
- \brief Get mask value
- Get begin & end pos, AND all masks in keys <= pos
- Time must be between 0.0 & 1.0
- \param time timestamp
- \param keys list of keyframes
- \return mask value
- */
- unsigned long gk_get_mask_sofar(float time, Keylist * keys)
- {
- Keylist *k;
- float startpos, endpos, curpos;
- unsigned long mask = 0xFFFFFFFF;
- if (keys) {
- /* find end key */
- for (k = keys; k->next; k = k->next) ;
- startpos = keys->pos;
- endpos = k->pos;
- curpos = startpos + time * (endpos - startpos);
- for (k = keys; k->next; k = k->next) {
- if (k->pos <= curpos) {
- mask &= k->fieldmask; /* (else break) */
- }
- }
- }
- return (mask);
- }
- /*!
- \brief ADD
- \param mask mask value
- \param keys list of keyframes
- \param[out] keyret output list of keyframes
- \return number of output keyframes
- */
- int gk_viable_keys_for_mask(unsigned long mask, Keylist * keys,
- Keylist ** keyret)
- {
- Keylist *k;
- int cnt = 0;
- for (k = keys; k; k = k->next) {
- if ((mask & k->fieldmask) == mask) {
- keyret[cnt++] = k;
- }
- }
- return (cnt);
- }
- /*!
- \brief Checks key masks
- Because if they're masked up until the current position,
- pre-existing (or current) field should be used.
- \param view pointer to Viewmode struct
- \param numsteps number of steps
- \param keys list of keyframes
- \param step step value
- \param onestep
- \param render
- \param mode
- */
- void gk_follow_frames(Viewnode * view, int numsteps, Keylist * keys, int step,
- int onestep, int render, unsigned long mode)
- {
- Viewnode *v;
- int frame; /* frame is index into viewnode array */
- float tmp[3];
- float x, y, z;
- int num, w;
- unsigned long mask;
- for (frame = step - 1; frame < numsteps; frame++) {
- v = &view[frame];
- mask = gk_get_mask_sofar((float)frame / numsteps, keys);
- /* TODO?: set view field to current settings if not set,
- thereby keeping view structure up to date for easier saving of
- animation? */
- GS_get_from(tmp);
- if ((mask & KF_FROMX_MASK)) {
- tmp[X] = v->fields[KF_FROMX];
- }
- if ((mask & KF_FROMY_MASK)) {
- tmp[Y] = v->fields[KF_FROMY];
- }
- if ((mask & KF_FROMZ_MASK)) {
- tmp[Z] = v->fields[KF_FROMZ];
- }
- GS_moveto(tmp);
- GS_get_from(tmp);
- G_debug(3, "gk_follow_frames():");
- G_debug(3, " MASK: %lx", mask);
- G_debug(3, " FROM: %f %f %f", tmp[X], tmp[Y], tmp[Z]);
- /* ACS 1 line: was GS_get_focus(tmp);
- with this kanimator works also for flythrough navigation
- also changed in GK2.c
- */
- GS_get_viewdir(tmp);
- if ((mask & KF_DIRX_MASK)) {
- tmp[X] = v->fields[KF_DIRX];
- }
- if ((mask & KF_DIRY_MASK)) {
- tmp[Y] = v->fields[KF_DIRY];
- }
- if ((mask & KF_DIRZ_MASK)) {
- tmp[Z] = v->fields[KF_DIRZ];
- }
- /* ACS 1 line: was GS_set_focus(tmp);
- with this kanimator works also for flythrough navigation
- also changed in GK2.c
- */
- GS_set_viewdir(tmp);
- G_debug(3, "gk_follow_frames():");
- GS_get_viewdir(tmp);
- G_debug(3, " DIR: %f %f %f\n", tmp[X], tmp[Y], tmp[Z]);
- if ((mask & KF_TWIST_MASK)) {
- GS_set_twist((int)v->fields[KF_TWIST]);
- }
- if ((mask & KF_FOV_MASK)) {
- GS_set_fov((int)v->fields[KF_FOV]);
- }
- /* Initilaize lights before drawing */
- num = 1;
- GS_getlight_position(num, &x, &y, &z, &w);
- GS_setlight_position(num, x, y, z, w);
- num = 2; /* Top light */
- GS_setlight_position(num, 0., 0., 1., 0);
- if (render) {
- GS_set_draw(GSD_FRONT);
- }
- else {
- GS_set_draw(GSD_BACK);
- }
- GS_ready_draw();
- GS_clear(GS_background_color());
- if (render) {
- GS_alldraw_surf();
- }
- else {
- GS_alldraw_wire();
- }
- GS_alldraw_cplane_fences();
- if (mode & FM_PATH) {
- gk_draw_path(view, numsteps, keys);
- }
- if (mode & FM_VECT) {
- GV_alldraw_vect();
- }
- if (mode & FM_SITE) {
- GP_alldraw_site();
- }
- if (mode & FM_VOL) {
- GVL_alldraw_vol();
- }
- GS_done_draw();
- if (mode & FM_LABEL) {
- GS_draw_all_list(); /* draw labels and legend */
- }
- if (onestep) {
- return;
- }
- }
- return;
- }
- /*!
- \brief Free keyframe list
- \param ok pointer to Keylist struct
- */
- void gk_free_key(Keylist * ok)
- {
- Keylist *k, *prev;
- if (ok) {
- k = ok;
- while (k) {
- prev = k;
- k = k->next;
- G_free(prev);
- }
- }
- return;
- }
- /*!
- \brief Generate viewnode from keyframes
- Here we use a cardinal cubic spline
- \param keys list of keyframes
- \param keysteps keyframe step
- \param newsteps new step value
- \param loop loop indicator
- \param t
- \return pointer to Viewnode
- \return NULL on failure
- */
- Viewnode *gk_make_framesfromkeys(Keylist * keys, int keysteps, int newsteps,
- int loop, float t)
- {
- int i;
- Viewnode *v, *newview;
- Keylist *k, *kp1, *kp2, *km1, **tkeys;
- float startpos, endpos;
- double dt1, dt2, x, x2, x3, range, time, time_step, len, rderiv, lderiv;
- /* allocate tmp keys to hold valid keys for fields */
- tkeys = (Keylist **) G_malloc(keysteps * sizeof(Keylist *)); /* G_fatal_error */
- if (!tkeys) {
- return (NULL);
- }
- correct_twist(keys);
- if (keys && keysteps) {
- if (keysteps < 3) {
- G_warning(_("Need at least 3 keyframes for spline"));
- G_free(tkeys);
- return (NULL);
- }
- /* find end key */
- for (k = keys; k->next; k = k->next) ;
- startpos = keys->pos;
- endpos = k->pos;
- range = endpos - startpos;
- time_step = range / (newsteps - 1);
- newview = (Viewnode *) G_malloc(newsteps * sizeof(Viewnode)); /* G_fatal_error */
- if (!newview) { /* not used */
- G_free(tkeys);
- return (NULL);
- }
- for (i = 0; i < newsteps; i++) {
- int field = 0;
- v = &newview[i];
- time = startpos + i * time_step;
- if (i == newsteps - 1) {
- time = endpos; /*to ensure no roundoff errors */
- }
- for (field = 0; field < KF_NUMFIELDS; field++) {
- int nvk = 0; /* number of viable keyframes for this field */
- /* now need to do for each field to look at mask */
- k = kp1 = kp2 = km1 = NULL;
- nvk = gk_viable_keys_for_mask((unsigned long)(1 << field),
- keys, tkeys);
- if (nvk) {
- len = get_key_neighbors(nvk, time, range,
- loop, tkeys, &k, &kp1, &kp2, &km1,
- &dt1, &dt2);
- }
- /* ACS 1 line: was if (len == 0.0) {
- when disabling a channel no calculation must be made at all (otherwise core dump)
- */
- if (len == 0.0 || nvk == 0) {
- if (!k) {
- /* none valid - use first.
- (when showing , will be ignored anyway) */
- v->fields[field] = keys->fields[field];
- }
- else if (!kp1) {
- /* none on right - use left */
- v->fields[field] = k->fields[field];
- }
- continue;
- }
- else if (!km1 && !kp2) {
- /* only two valid - use linear */
- v->fields[field] = lin_interp((time - k->pos) / len,
- k->fields[field],
- kp1->fields[field]);
- continue;
- }
- x = (time - k->pos) / len;
- x2 = x * x;
- x3 = x2 * x;
- if (!km1) {
- /* leftmost interval */
- rderiv = (kp2->fields[field] - k->fields[field]) / dt2;
- lderiv = (3 * (kp1->fields[field] -
- k->fields[field]) / dt1 - rderiv) / 2.0;
- v->fields[field] = spl3(t, k->fields[field],
- kp1->fields[field], x, x2, x3,
- lderiv, rderiv);
- }
- else if (!kp2) {
- /* rightmost interval */
- lderiv = (kp1->fields[field] - km1->fields[field]) / dt1;
- rderiv = (3 * (kp1->fields[field] -
- k->fields[field]) / dt2 - lderiv) / 2.0;
- v->fields[field] = spl3(t, k->fields[field],
- kp1->fields[field], x, x2, x3,
- lderiv, rderiv);
- }
- else {
- /* not on ends */
- lderiv = (kp1->fields[field] - km1->fields[field]) / dt1;
- rderiv = (kp2->fields[field] - k->fields[field]) / dt2;
- v->fields[field] = spl3(t, k->fields[field],
- kp1->fields[field], x, x2, x3,
- lderiv, rderiv);
- }
- }
- }
- G_free(tkeys);
- return (newview);
- }
- else {
- G_free(tkeys);
- return (NULL);
- }
- }
- /*!
- \brief Find interval containing time
- Changed June 94 to handle masks - now need to have called get_viable_keys
- for appropriate mask first to build the ARRAY of viable keyframes.
- Putting left (or equal) key
- at km1, right at kp1, 2nd to right at kp2, and second to left at km2.
- dt1 is given the length of the current + left intervals
- dt2 is given the length of the current + right intervals
- \param nvk
- \param time
- \param range
- \param loop
- \param karray
- \param km1
- \param kp1
- \param kp2
- \param km2
- \param dt1
- \param dt2
- \return the length of the current interval
- \return 0 on error
- */
- double get_key_neighbors(int nvk, double time, double range, int loop,
- Keylist * karray[], Keylist ** km1, Keylist ** kp1,
- Keylist ** kp2, Keylist ** km2, double *dt1,
- double *dt2)
- {
- int i;
- double len;
- *km1 = *kp1 = *kp2 = *km2 = NULL;
- *dt1 = *dt2 = 0.0;
- for (i = 0; i < nvk; i++) {
- if (time < karray[i]->pos) {
- break;
- }
- }
- if (!i) {
- return (0.0); /* before first keyframe or nvk == 0 */
- }
- if (i == nvk) {
- /* past or == last keyframe! */
- *km1 = karray[nvk - 1];
- return (0.0);
- }
- /* there's at least 2 */
- *km1 = karray[i - 1];
- *kp1 = karray[i];
- len = karray[i]->pos - karray[i - 1]->pos;
- if (i == 1) {
- /* first interval */
- if (loop) {
- *km2 = karray[nvk - 2];
- *kp2 = karray[(i + 1) % nvk];
- }
- else {
- if (nvk > 2) {
- *kp2 = karray[i + 1];
- }
- }
- }
- else if (i == nvk - 1) {
- /* last interval */
- if (loop) {
- *km2 = nvk > 2 ? karray[i - 2] : karray[1];
- *kp2 = karray[1];
- }
- else {
- if (nvk > 2) {
- *km2 = karray[i - 2];
- }
- }
- }
- else {
- *km2 = karray[i - 2];
- *kp2 = karray[i + 1];
- }
- *dt1 = (*km2) ? (*kp1)->pos - (*km2)->pos : len;
- *dt2 = (*kp2) ? (*kp2)->pos - (*km1)->pos : len;
- if (i == 1 && loop) {
- *dt1 += range;
- }
- if (i == nvk - 1 && loop) {
- *dt2 += range;
- }
- return (len);
- }
- /*!
- \brief Linear interpolation
- \param dt coeficient
- \param val2 value 2
- \param val1 value 1
- \return val1 + dt * (val2 - val1)
- */
- double lin_interp(float dt, float val1, float val2)
- {
- return ((double)(val1 + dt * (val2 - val1)));
- }
- /*!
- \brief Finds interval containing time, putting left (or equal) key
- at km1, right at kp1
- \param nvk
- \param time
- \param range
- \param loop
- \param karray
- \param km1
- \param km2
- \return interval value
- */
- double get_2key_neighbors(int nvk, float time, float range, int loop,
- Keylist * karray[], Keylist ** km1, Keylist ** kp1)
- {
- int i;
- double len;
- *km1 = *kp1 = NULL;
- for (i = 0; i < nvk; i++) {
- if (time < karray[i]->pos) {
- break;
- }
- }
- if (!i) {
- return (0.0); /* before first keyframe or nvk == 0 */
- }
- if (i == nvk) {
- /* past or == last keyframe! */
- *km1 = karray[nvk - 1];
- return (0.0);
- }
- /* there's at least 2 */
- *km1 = karray[i - 1];
- *kp1 = karray[i];
- len = karray[i]->pos - karray[i - 1]->pos;
- return (len);
- }
- /*!
- \brief Generate viewnode from keyframe list (linear interpolation)
- Here we use linear interpolation. Loop variable isn't used, but left
- in for use in possible "linear interp with smoothing" version.
- \param kesy keyframe list
- \param keysteps step value
- \param newsteps new step value
- \param loop loop indicator
- \param pointer to viewnode struct
- \param NULL on failure
- */
- Viewnode *gk_make_linear_framesfromkeys(Keylist * keys, int keysteps,
- int newsteps, int loop)
- {
- int i, nvk;
- Viewnode *v, *newview;
- Keylist *k, *k1, *k2, **tkeys;
- float startpos, endpos, dt, range, time, time_step, len;
- /* allocate tmp keys to hold valid keys for fields */
- tkeys = (Keylist **) G_malloc(keysteps * sizeof(Keylist *)); /* G_fatal_error */
- if (!tkeys) {
- return (NULL);
- }
- correct_twist(keys);
- if (keys && keysteps) {
- if (keysteps < 2) {
- G_warning(_("Need at least 2 keyframes for interpolation"));
- G_free(tkeys);
- return (NULL);
- }
- /* find end key */
- for (k = keys; k->next; k = k->next) ;
- startpos = keys->pos;
- endpos = k->pos;
- range = endpos - startpos;
- time_step = range / (newsteps - 1);
- newview = (Viewnode *) G_malloc(newsteps * sizeof(Viewnode)); /* G_fatal_error */
- if (!newview) { /* not used */
- G_free(tkeys);
- return (NULL);
- }
- for (i = 0; i < newsteps; i++) {
- int field = 0;
- v = &newview[i];
- time = startpos + i * time_step;
- if (i == newsteps - 1) {
- time = endpos; /*to ensure no roundoff errors */
- }
- for (field = 0; field < KF_NUMFIELDS; field++) {
- nvk = gk_viable_keys_for_mask((unsigned long)(1 << field),
- keys, tkeys);
- if (!nvk) {
- v->fields[field] = keys->fields[field]; /*default-not used */
- }
- else {
- len = get_2key_neighbors(nvk, time, range, loop,
- tkeys, &k1, &k2);
- }
- /* ACS 1 line: was if (len == 0.0) {
- when disabling a channel no calculation must be made at all (otherwise core dump)
- */
- if (len == 0.0 || nvk == 0) {
- if (!k1) {
- /* none valid - use first.
- (when showing , will be ignored anyway) */
- v->fields[field] = keys->fields[field];
- }
- else if (!k2) {
- /* none on right - use left */
- v->fields[field] = k1->fields[field];
- }
- }
- else {
- dt = (time - k1->pos) / len;
- v->fields[field] = lin_interp(dt,
- k1->fields[field],
- k2->fields[field]);
- }
- }
- }
- G_free(tkeys);
- return (newview);
- }
- else {
- G_free(tkeys);
- return (NULL);
- }
- }
- /*!
- \brief Correct twist value
- \param k keyframe list
- */
- void correct_twist(Keylist * k)
- {
- Keylist *c, *p, *t;
- int cnt, j;
- p = NULL;
- cnt = 0;
- for (c = k; c; c = c->next) {
- if (p) {
- if ((c->fields[KF_TWIST] - p->fields[KF_TWIST]) > 1800.) {
- for (t = c; t; t = t->next) {
- t->fields[KF_TWIST] -= 3600.;
- }
- }
- else if ((p->fields[KF_TWIST] - c->fields[KF_TWIST]) > 1800.) {
- for (t = k, j = 0; j < cnt; j++, t = t->next) {
- t->fields[KF_TWIST] -= 3600.;
- }
- }
- }
- p = c;
- ++cnt;
- }
- return;
- }
- /*!
- \brief Draw path
- \param views Viewnode struct
- \param steps step value
- \param keys keyframe list
- \return 0 on failure
- \return 1 on success
- */
- int gk_draw_path(Viewnode * views, int steps, Keylist * keys)
- {
- Viewnode *v;
- Keylist *k;
- int frame;
- float siz, from[3];
- if (!views || !keys) {
- return (0);
- }
- GS_get_longdim(&siz);
- siz /= 200.;
- gsd_colormode(CM_COLOR);
- gsd_linewidth(2);
- gsd_color_func(GS_default_draw_color());
- gsd_zwritemask(0);
- gsd_bgnline();
- for (frame = 0; frame < steps; frame++) {
- v = &views[frame];
- gsd_vert_func(&(v->fields[KF_FROMX]));
- }
- gsd_endline();
- gsd_linewidth(1);
- for (k = keys; k; k = k->next) {
- gsd_x(NULL, &(k->fields[KF_FROMX]),
- ~(GS_background_color() | 0xFF0000), siz);
- }
- /* draw viewer position for inset images */
- GS_get_from(from);
- gsd_x(NULL, from, ~(GS_default_draw_color() | 0xFFFF00), 3.0 * siz);
- gsd_zwritemask(0xffffffff);
- return (1);
- }
|