r_mesh_anim.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "r_local.h"
00027 #include "r_mesh_anim.h"
00028 
00029 #define LNEXT(x) ((x + 1 < MAX_ANIMLIST) ? x + 1 : 0)
00030 
00041 static const mAliasAnim_t *R_AnimGet (const model_t * mod, const char *name)
00042 {
00043     mAliasAnim_t *anim;
00044     int i;
00045 
00046     if (!mod || !mod->alias.num_anims)
00047         return NULL;
00048 
00049     for (i = 0, anim = mod->alias.animdata; i < mod->alias.num_anims; i++, anim++)
00050         if (!strcmp(name, anim->name))
00051             return anim;
00052 
00053     Com_Printf("model \"%s\" doesn't have animation \"%s\"\n", mod->name, name);
00054     return NULL;
00055 }
00056 
00057 
00068 void R_AnimAppend (animState_t * as, const model_t * mod, const char *name)
00069 {
00070     const mAliasAnim_t *anim;
00071 
00072     assert(as->ladd < MAX_ANIMLIST);
00073 
00074     if (!mod || !mod->alias.num_anims)
00075         return;
00076 
00077     /* get animation */
00078     anim = R_AnimGet(mod, name);
00079     if (!anim)
00080         return;
00081 
00082     if (as->lcur == as->ladd) {
00083         /* first animation */
00084         as->oldframe = anim->from;
00085         if (anim->to > anim->from)
00086             as->frame = anim->from + 1;
00087         else
00088             as->frame = anim->from;
00089 
00090         as->backlerp = 0.0;
00091         as->time = anim->time;
00092         as->dt = 0;
00093 
00094         as->list[as->ladd] = anim - mod->alias.animdata;
00095     } else {
00096         /* next animation */
00097         as->list[as->ladd] = anim - mod->alias.animdata;
00098     }
00099 
00100     /* advance in list (no overflow protection!) */
00101     as->ladd = LNEXT(as->ladd);
00102 }
00103 
00104 
00115 void R_AnimChange (animState_t * as, const model_t * mod, const char *name)
00116 {
00117     const mAliasAnim_t *anim;
00118 
00119     assert(as->ladd < MAX_ANIMLIST);
00120 
00121     if (!mod || !mod->alias.num_anims)
00122         return;
00123 
00124     /* get animation */
00125     anim = R_AnimGet(mod, name);
00126     if (!anim) {
00127         Com_Printf("R_AnimChange: No such animation: %s (model: %s)\n", name, mod->name);
00128         return;
00129     }
00130 
00131     if (as->lcur == as->ladd) {
00132         /* first animation */
00133         as->oldframe = anim->from;
00134         if (anim->to > anim->from)
00135             as->frame = anim->from + 1;
00136         else
00137             as->frame = anim->from;
00138 
00139         as->backlerp = 1.0;
00140         as->time = anim->time;
00141         as->dt = 0;
00142 
00143         as->list[as->ladd] = anim - mod->alias.animdata;
00144         as->change = qtrue;
00145     } else {
00146         /* next animation */
00147         as->ladd = LNEXT(as->lcur);
00148         as->list[as->ladd] = anim - mod->alias.animdata;
00149 
00150         if (anim->time < as->time)
00151             as->time = anim->time;
00152         /* don't change to the same animation */
00153         if (anim != mod->alias.animdata + as->list[as->lcur])
00154             as->change = qtrue;
00155     }
00156 
00157     /* advance in list (no overflow protection!) */
00158     as->ladd = LNEXT(as->ladd);
00159 }
00160 
00161 
00172 void R_AnimRun (animState_t * as, const model_t * mod, int msec)
00173 {
00174     assert(as->lcur < MAX_ANIMLIST);
00175 
00176     if (!mod || !mod->alias.num_anims)
00177         return;
00178 
00179     if (as->lcur == as->ladd)
00180         return;
00181 
00182     as->dt += msec;
00183 
00184     while (as->dt > as->time) {
00185         const mAliasAnim_t *anim = mod->alias.animdata + as->list[as->lcur];
00186         as->dt -= as->time;
00187 
00188         if (as->change || as->frame >= anim->to) {
00189             /* go to next animation if it isn't the last one */
00190             if (LNEXT(as->lcur) != as->ladd)
00191                 as->lcur = LNEXT(as->lcur);
00192 
00193             anim = mod->alias.animdata + as->list[as->lcur];
00194 
00195             /* prepare next frame */
00196             as->dt = 0;
00197             as->time = anim->time;
00198             as->oldframe = as->frame;
00199             as->frame = anim->from;
00200             as->change = qfalse;
00201         } else {
00202             /* next frame of the same animation */
00203             as->time = anim->time;
00204             as->oldframe = as->frame;
00205             as->frame++;
00206         }
00207     }
00208 
00209     as->backlerp = 1.0 - (float) as->dt / as->time;
00210 }
00211 
00212 
00223 const char *R_AnimGetName (const animState_t * as, const model_t * mod)
00224 {
00225     const mAliasAnim_t *anim;
00226 
00227     assert(as->lcur < MAX_ANIMLIST);
00228 
00229     if (!mod || !mod->alias.num_anims)
00230         return NULL;
00231 
00232     if (as->lcur == as->ladd)
00233         return NULL;
00234 
00235     anim = mod->alias.animdata + as->list[as->lcur];
00236     return anim->name;
00237 }
00238 
00243 void R_InterpolateTransform (animState_t * as, int numframes, const float *tag, float *interpolated)
00244 {
00245     const float *current, *old;
00246     float bl, fl;
00247     int i;
00248 
00249     /* range check */
00250     if (as->frame >= numframes || as->frame < 0)
00251         as->frame = 0;
00252     if (as->oldframe >= numframes || as->oldframe < 0)
00253         as->oldframe = 0;
00254 
00255     /* calc relevant values */
00256     current = tag + as->frame * 16;
00257     old = tag + as->oldframe * 16;
00258     bl = as->backlerp;
00259     fl = 1.0 - as->backlerp;
00260 
00261     /* right on a frame? */
00262     if (bl == 0.0) {
00263         memcpy(interpolated, current, sizeof(float) * 16);
00264         return;
00265     }
00266     if (bl == 1.0) {
00267         memcpy(interpolated, old, sizeof(float) * 16);
00268         return;
00269     }
00270 
00271     /* interpolate */
00272     for (i = 0; i < 16; i++)
00273         interpolated[i] = fl * current[i] + bl * old[i];
00274 
00275     /* normalize */
00276     for (i = 0; i < 3; i++)
00277         VectorNormalize(interpolated + i * 4);
00278 }

Generated by  doxygen 1.6.2