]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
reworked animation interpolation code - entity_render_t now has
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 30 Mar 2009 15:22:57 +0000 (15:22 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 30 Mar 2009 15:22:57 +0000 (15:22 +0000)
framegroupblend[] instead of frame1/2/1time/2time/framelerp fields
implemented csqc 4-way frame interpolation (lerpfrac2 is inferred based
on the sum of lerpfrac+lerpfrac3+lerpfrac4, so it remains compatible)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8834 d7cf8633-e32d-0410-b094-e92efae38249

15 files changed:
cl_collision.c
cl_main.c
cl_parse.c
client.h
clvm_cmds.c
csprogs.c
darkplaces.txt
gl_rmain.c
model_alias.c
model_sprite.c
progsvm.h
prvm_edict.c
r_lerpanim.c
r_sprites.c
render.h

index bad4efc21173d4fcdcaee64b04b646d7d9f1ecdd..802b8adccc6b849cf39fe1fe1f05e7e66d869d21 100644 (file)
@@ -57,7 +57,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
                        continue;
 
                //if (ent->model && ent->model->TraceBox)
-                       ent->model->TraceBox(ent->model, ent->frameblend[0].frame, &trace, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID);
+                       ent->model->TraceBox(ent->model, ent->frameblend[0].subframe, &trace, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID);
 
                if (maxrealfrac > trace.realfraction)
                {
@@ -305,7 +305,7 @@ trace_t CL_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                        entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
                        if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
                                continue;
-                       Collision_ClipToGenericEntity(&trace, ent->model, ent->frame2, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask);
+                       Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend[0].subframe, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask);
                        if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
                                *hitnetworkentity = cl.brushmodel_entities[i];
                        Collision_CombineTraces(&cliptrace, &trace, NULL, true);
index bcaec418eb2bf9a34e65b289e317b1104622b963..675c3564e9fcfcdf0b4ce10d26cb4d8f999bb634 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -441,7 +441,7 @@ static void CL_PrintEntities_f(void)
                        modelname = ent->render.model->name;
                else
                        modelname = "--no model--";
-               Con_Printf("%3i: %-25s:%4i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, modelname, ent->render.frame2, (int) ent->state_current.origin[0], (int) ent->state_current.origin[1], (int) ent->state_current.origin[2], (int) ent->state_current.angles[0] % 360, (int) ent->state_current.angles[1] % 360, (int) ent->state_current.angles[2] % 360, ent->render.scale, ent->render.alpha);
+               Con_Printf("%3i: %-25s:%4i (%5i %5i %5i) [%3i %3i %3i] %4.2f %5.3f\n", i, modelname, ent->render.framegroupblend[0].frame, (int) ent->state_current.origin[0], (int) ent->state_current.origin[1], (int) ent->state_current.origin[2], (int) ent->state_current.angles[0] % 360, (int) ent->state_current.angles[1] % 360, (int) ent->state_current.angles[2] % 360, ent->render.scale, ent->render.alpha);
        }
 }
 
@@ -767,39 +767,40 @@ void CL_RelinkLightFlashes(void)
 
 void CL_AddQWCTFFlagModel(entity_t *player, int skin)
 {
+       int frame = player->render.framegroupblend[0].frame;
        float f;
        entity_render_t *flagrender;
        matrix4x4_t flagmatrix;
 
        // this code taken from QuakeWorld
        f = 14;
-       if (player->render.frame2 >= 29 && player->render.frame2 <= 40)
+       if (frame >= 29 && frame <= 40)
        {
-               if (player->render.frame2 >= 29 && player->render.frame2 <= 34)
+               if (frame >= 29 && frame <= 34)
                { //axpain
-                       if      (player->render.frame2 == 29) f = f + 2;
-                       else if (player->render.frame2 == 30) f = f + 8;
-                       else if (player->render.frame2 == 31) f = f + 12;
-                       else if (player->render.frame2 == 32) f = f + 11;
-                       else if (player->render.frame2 == 33) f = f + 10;
-                       else if (player->render.frame2 == 34) f = f + 4;
+                       if      (frame == 29) f = f + 2;
+                       else if (frame == 30) f = f + 8;
+                       else if (frame == 31) f = f + 12;
+                       else if (frame == 32) f = f + 11;
+                       else if (frame == 33) f = f + 10;
+                       else if (frame == 34) f = f + 4;
                }
-               else if (player->render.frame2 >= 35 && player->render.frame2 <= 40)
+               else if (frame >= 35 && frame <= 40)
                { // pain
-                       if      (player->render.frame2 == 35) f = f + 2;
-                       else if (player->render.frame2 == 36) f = f + 10;
-                       else if (player->render.frame2 == 37) f = f + 10;
-                       else if (player->render.frame2 == 38) f = f + 8;
-                       else if (player->render.frame2 == 39) f = f + 4;
-                       else if (player->render.frame2 == 40) f = f + 2;
+                       if      (frame == 35) f = f + 2;
+                       else if (frame == 36) f = f + 10;
+                       else if (frame == 37) f = f + 10;
+                       else if (frame == 38) f = f + 8;
+                       else if (frame == 39) f = f + 4;
+                       else if (frame == 40) f = f + 2;
                }
        }
-       else if (player->render.frame2 >= 103 && player->render.frame2 <= 118)
+       else if (frame >= 103 && frame <= 118)
        {
-               if      (player->render.frame2 >= 103 && player->render.frame2 <= 104) f = f + 6;  //nailattack
-               else if (player->render.frame2 >= 105 && player->render.frame2 <= 106) f = f + 6;  //light
-               else if (player->render.frame2 >= 107 && player->render.frame2 <= 112) f = f + 7;  //rocketattack
-               else if (player->render.frame2 >= 112 && player->render.frame2 <= 118) f = f + 7;  //shotattack
+               if      (frame >= 103 && frame <= 104) f = f + 6;  //nailattack
+               else if (frame >= 105 && frame <= 106) f = f + 6;  //light
+               else if (frame >= 107 && frame <= 112) f = f + 7;  //rocketattack
+               else if (frame >= 112 && frame <= 118) f = f + 7;  //shotattack
        }
        // end of code taken from QuakeWorld
 
@@ -897,10 +898,10 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
                {
                        // blend the matrices
                        memset(&blendmatrix, 0, sizeof(blendmatrix));
-                       for (j = 0;j < 4 && t->render.frameblend[j].lerp > 0;j++)
+                       for (j = 0;j < MAX_FRAMEBLENDS && t->render.frameblend[j].lerp > 0;j++)
                        {
                                matrix4x4_t tagmatrix;
-                               Mod_Alias_GetTagMatrix(model, t->render.frameblend[j].frame, e->state_current.tagindex - 1, &tagmatrix);
+                               Mod_Alias_GetTagMatrix(model, t->render.frameblend[j].subframe, e->state_current.tagindex - 1, &tagmatrix);
                                d = t->render.frameblend[j].lerp;
                                for (l = 0;l < 4;l++)
                                        for (k = 0;k < 4;k++)
@@ -991,27 +992,29 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat
        }
 
        // animation lerp
-       if (e->render.frame2 == frame)
+       if (e->render.framegroupblend[0].frame == frame)
        {
                // update frame lerp fraction
-               e->render.framelerp = 1;
-               if (e->render.frame2time > e->render.frame1time)
+               e->render.framegroupblend[0].lerp = 1;
+               e->render.framegroupblend[1].lerp = 0;
+               if (e->render.framegroupblend[0].start > e->render.framegroupblend[1].start)
                {
                        // make sure frame lerp won't last longer than 100ms
                        // (this mainly helps with models that use framegroups and
                        // switch between them infrequently)
-                       e->render.framelerp = (cl.time - e->render.frame2time) / min(e->render.frame2time - e->render.frame1time, 0.1);
-                       e->render.framelerp = bound(0, e->render.framelerp, 1);
+                       e->render.framegroupblend[0].lerp = (cl.time - e->render.framegroupblend[0].start) / min(e->render.framegroupblend[0].start - e->render.framegroupblend[1].start, 0.1);
+                       e->render.framegroupblend[0].lerp = bound(0, e->render.framegroupblend[0].lerp, 1);
+                       e->render.framegroupblend[1].lerp = 1 - e->render.framegroupblend[0].lerp;
                }
        }
        else
        {
                // begin a new frame lerp
-               e->render.frame1 = e->render.frame2;
-               e->render.frame1time = e->render.frame2time;
-               e->render.frame2 = frame;
-               e->render.frame2time = cl.time;
-               e->render.framelerp = 0;
+               e->render.framegroupblend[1] = e->render.framegroupblend[0];
+               e->render.framegroupblend[1].lerp = 1;
+               e->render.framegroupblend[0].frame = frame;
+               e->render.framegroupblend[0].start = cl.time;
+               e->render.framegroupblend[0].lerp = 0;
        }
 
        // set up the render matrix
@@ -1246,9 +1249,9 @@ void CL_UpdateViewModel(void)
        // reset animation interpolation on weaponmodel if model changed
        if (ent->state_previous.modelindex != ent->state_current.modelindex)
        {
-               ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
-               ent->render.frame1time = ent->render.frame2time = cl.time;
-               ent->render.framelerp = 1;
+               ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame;
+               ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time;
+               ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0;
        }
        CL_UpdateNetworkEntity(ent, 32, true);
 }
@@ -1517,13 +1520,21 @@ static void CL_RelinkEffects(void)
                        if (r_draweffects.integer && (entrender = CL_NewTempEntity(e->starttime)))
                        {
                                // interpolation stuff
-                               entrender->frame1 = intframe;
-                               entrender->frame2 = intframe + 1;
-                               if (entrender->frame2 >= e->endframe)
-                                       entrender->frame2 = -1; // disappear
-                               entrender->framelerp = frame - intframe;
-                               entrender->frame1time = e->frame1time;
-                               entrender->frame2time = e->frame2time;
+                               entrender->framegroupblend[0].frame = intframe;
+                               entrender->framegroupblend[0].lerp = 1 - frame - intframe;
+                               entrender->framegroupblend[0].start = e->frame1time;
+                               if (intframe + 1 >= e->endframe)
+                               {
+                                       entrender->framegroupblend[1].frame = 0; // disappear
+                                       entrender->framegroupblend[1].lerp = 0;
+                                       entrender->framegroupblend[1].start = 0;
+                               }
+                               else
+                               {
+                                       entrender->framegroupblend[1].frame = intframe + 1;
+                                       entrender->framegroupblend[1].lerp = frame - intframe;
+                                       entrender->framegroupblend[1].start = e->frame2time;
+                               }
 
                                // normal stuff
                                if(e->modelindex < MAX_MODELS)
index 25330eec94bec2813e725ff0652344e87b0efe1c..a64e1ffd4d9fa23214da496121cf84b50d622d9b 100644 (file)
@@ -1744,9 +1744,9 @@ void CL_MoveLerpEntityStates(entity_t *ent)
                VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
                VectorCopy(ent->state_current.angles, ent->persistent.newangles);
                // reset animation interpolation as well
-               ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
-               ent->render.frame1time = ent->render.frame2time = cl.time;
-               ent->render.framelerp = 1;
+               ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame;
+               ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time;
+               ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0;
                ent->render.shadertime = cl.time;
                // reset various persistent stuff
                ent->persistent.muzzleflash = 0;
@@ -1767,9 +1767,9 @@ void CL_MoveLerpEntityStates(entity_t *ent)
                {
                        // if we ALSO changed animation frame in the process (but ONLY then!)
                        // then let's reset the animation interpolation too
-                       ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
-                       ent->render.frame1time = ent->render.frame2time = cl.time;
-                       ent->render.framelerp = 1;
+                       ent->render.framegroupblend[0].frame = ent->render.framegroupblend[1].frame = ent->state_current.frame;
+                       ent->render.framegroupblend[0].start = ent->render.framegroupblend[1].start = cl.time;
+                       ent->render.framegroupblend[0].lerp = 1;ent->render.framegroupblend[1].lerp = 0;
                }
 
                // note that this case must do everything the following case does too
@@ -2007,10 +2007,10 @@ void CL_ParseStatic (int large)
 
 // copy it to the current state
        ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
-       ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
-       ent->render.framelerp = 0;
+       ent->render.framegroupblend[0].frame = ent->state_baseline.frame;
+       ent->render.framegroupblend[0].lerp = 1;
        // make torchs play out of sync
-       ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
+       ent->render.framegroupblend[0].start = lhrandom(-10, -1);
        ent->render.skinnum = ent->state_baseline.skin;
        ent->render.effects = ent->state_baseline.effects;
        ent->render.alpha = 1;
index 73aa6e1b3455273ee5dec35a2e80e2ee3487127b..16427924bdad29d9df8fcb6bd418fbf75d37670d 100644 (file)
--- a/client.h
+++ b/client.h
@@ -222,10 +222,27 @@ typedef struct dlight_s
 }
 dlight_t;
 
-typedef struct frameblend_s
+#define MAX_FRAMEGROUPBLENDS 4
+typedef struct framegroupblend_s
 {
+       // animation number and blend factor
+       // (for most models this is the frame number)
        int frame;
        float lerp;
+       // time frame began playing (for framegroup animations)
+       double start;
+}
+framegroupblend_t;
+
+// this is derived from processing of the framegroupblend array
+// note: technically each framegroupblend can produce two of these, but that
+// never happens in practice because no one blends between more than 2
+// framegroups at once
+#define MAX_FRAMEBLENDS MAX_FRAMEGROUPBLENDS
+typedef struct frameblend_s
+{
+       int subframe;
+       float lerp;
 }
 frameblend_t;
 
@@ -271,18 +288,9 @@ typedef struct entity_render_s
        // colormod tinting of models
        float colormod[3];
 
-       // interpolated animation
+       // interpolated animation - active framegroups and blend factors
+       framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
 
-       // frame that the model is interpolating from
-       int frame1;
-       // frame that the model is interpolating to
-       int frame2;
-       // interpolation factor, usually computed from frame2time
-       float framelerp;
-       // time frame1 began playing (for framegroup animations)
-       double frame1time;
-       // time frame2 began playing (for framegroup animations)
-       double frame2time;
        // time of last model change (for shader animations)
        double shadertime;
 
@@ -290,8 +298,8 @@ typedef struct entity_render_s
 
        // calculated during R_AddModelEntities
        vec3_t mins, maxs;
-       // 4 frame numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use frame instead
-       frameblend_t frameblend[4];
+       // subframe numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use subframeblend[0].subframe
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
 
        // current lighting from map (updated ONLY by client code, not renderer)
        vec3_t modellight_ambient;
index e1969f6e4089da54e8bcbc2cefd8454bf17c9b41..4a26dd413a6d118846bc7436bd7563e10b3d57ff 100644 (file)
@@ -1415,10 +1415,10 @@ static void VM_CL_makestatic (void)
                // copy it to the current state
                memset(staticent, 0, sizeof(*staticent));
                staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
-               staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
-               staticent->render.framelerp = 0;
+               staticent->render.framegroupblend[0].frame = (int)ent->fields.client->frame;
+               staticent->render.framegroupblend[0].lerp = 1;
                // make torchs play out of sync
-               staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
+               staticent->render.framegroupblend[0].start = lhrandom(-10, -1);
                staticent->render.skinnum = (int)ent->fields.client->skin;
                staticent->render.effects = (int)ent->fields.client->effects;
                staticent->render.alpha = 1;
index 43d6c1eb70af1a0717ffb294e12120a2251580e5..7f67ecba54346f9bde86afe82c0f44759515382d 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -204,12 +204,24 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed)
        // self.frame1time is the animation base time for the interpolation target
        // self.frame2 is the interpolation start (previous frame)
        // self.frame2time is the animation base time for the interpolation start
-       entrender->frame1 = entrender->frame2 = (int) ed->fields.client->frame;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->frame2 = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->frame2time = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->frame1time = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framelerp = val->_float;
+       // self.lerpfrac is the interpolation strength for self.frame
+       // 3+ are for additional blends (the main use for this feature is lerping
+       // pitch angle on a player model where the animator set up 5 sets of
+       // animations and the csqc simply lerps between sets)
+       entrender->framegroupblend[0].frame = entrender->framegroupblend[1].frame = (int) ed->fields.client->frame;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->framegroupblend[1].frame = (int) val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) entrender->framegroupblend[2].frame = (int) val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) entrender->framegroupblend[3].frame = (int) val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->framegroupblend[0].start = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->framegroupblend[1].start = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) entrender->framegroupblend[2].start = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) entrender->framegroupblend[3].start = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framegroupblend[0].lerp = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) entrender->framegroupblend[2].lerp = val->_float;
+       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) entrender->framegroupblend[3].lerp = val->_float;
        if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.shadertime))) entrender->shadertime = val->_float;
+       // assume that the (missing) lerpfrac2 is whatever remains after lerpfrac+lerpfrac3+lerpfrac4 are summed
+       entrender->framegroupblend[1].lerp = 1 - entrender->framegroupblend[0].lerp - entrender->framegroupblend[2].lerp - entrender->framegroupblend[3].lerp;
 
        // concat the matrices to make the entity relative to its tag
        Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2);
index 91c3d6267e50396a58224aba905ff5ed4e0eb4fb..fc096d7f1f3b8ab1fa18a58d307b21d0394e8e74 100644 (file)
@@ -693,7 +693,7 @@ r_hdr_range                                       4                   how much d
 r_hdr_scenebrightness                             1                   global rendering brightness\r
 r_lerpimages                                      1                   bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0)\r
 r_lerpmodels                                      1                   enables animation smoothing on models\r
-r_lerpsprites                                     1                   enables animation smoothing on sprites (requires r_lerpmodels 1)\r
+r_lerpsprites                                     1                   enables animation smoothing on sprites\r
 r_letterbox                                       0                   reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)\r
 r_lightmaprgba                                    1                   whether to use RGBA (32bit) or RGB (24bit) lightmaps\r
 r_lightningbeam_color_blue                        1                   color of the lightning beam effect\r
index 4cfbdddfebb1a21719c26136c8b1db32f8434af0..3ad23498fb0dfa84d5c67573614109a46b68a0d4 100644 (file)
@@ -98,7 +98,7 @@ cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier"
 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
 
-cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
+cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites"};
 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
@@ -4648,7 +4648,7 @@ texture_t *R_GetCurrentTexture(texture_t *t)
                {
                        // use an alternate animation if the entity's frame is not 0,
                        // and only if the texture has an alternate animation
-                       if (ent->frame2 != 0 && t->anim_total[1])
+                       if (ent->framegroupblend[0].frame != 0 && t->anim_total[1])
                                t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[1]) : 0];
                        else
                                t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[0]) : 0];
@@ -4952,14 +4952,8 @@ void RSurf_ActiveWorldEntity(void)
        VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
        VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
        VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
-       rsurface.frameblend[0].frame = 0;
+       memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
        rsurface.frameblend[0].lerp = 1;
-       rsurface.frameblend[1].frame = 0;
-       rsurface.frameblend[1].lerp = 0;
-       rsurface.frameblend[2].frame = 0;
-       rsurface.frameblend[2].lerp = 0;
-       rsurface.frameblend[3].frame = 0;
-       rsurface.frameblend[3].lerp = 0;
        rsurface.basepolygonfactor = r_refdef.polygonfactor;
        rsurface.basepolygonoffset = r_refdef.polygonoffset;
        rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
@@ -5029,10 +5023,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
        VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
        VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
        VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
-       rsurface.frameblend[0] = ent->frameblend[0];
-       rsurface.frameblend[1] = ent->frameblend[1];
-       rsurface.frameblend[2] = ent->frameblend[2];
-       rsurface.frameblend[3] = ent->frameblend[3];
+       memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
        rsurface.basepolygonfactor = r_refdef.polygonfactor;
        rsurface.basepolygonoffset = r_refdef.polygonoffset;
        if (ent->model->brush.submodel)
@@ -5040,7 +5031,7 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q
                rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
                rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
        }
-       if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
+       if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
        {
                if (wanttangents)
                {
index ad912f96f658c2a156be83c65f099e03941f2e38..626ef113b2ddc641b983ddc9eaec76d8eb5fe0a2 100644 (file)
@@ -62,9 +62,9 @@ void Mod_Skeletal_AnimateVertices(const dp_model_t *model, const frameblend_t *f
                for (k = 0;k < 12;k++)
                        m[k] = 0;
                VectorClear(desiredscale);
-               for (blends = 0;blends < 4 && frameblend[blends].lerp > 0;blends++)
+               for (blends = 0;blends < MAX_FRAMEBLENDS && frameblend[blends].lerp > 0;blends++)
                {
-                       matrix = model->data_poses + (frameblend[blends].frame * model->num_bones + i) * 12;
+                       matrix = model->data_poses + (frameblend[blends].subframe * model->num_bones + i) * 12;
                        for (k = 0;k < 12;k++)
                                m[k] += matrix[k] * frameblend[blends].lerp;
                        desiredscale[0] += frameblend[blends].lerp * VectorLength(matrix    );
@@ -233,7 +233,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        int i, numblends, blendnum;
        int numverts = model->surfmesh.num_vertices;
        numblends = 0;
-       for (blendnum = 0;blendnum < 4;blendnum++)
+       for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
        {
                //VectorMA(translate, model->surfmesh.num_morphmdlframetranslate, frameblend[blendnum].lerp, translate);
                if (frameblend[blendnum].lerp > 0)
@@ -242,7 +242,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        // special case for the first blend because it avoids some adds and the need to memset the arrays first
        for (blendnum = 0;blendnum < numblends;blendnum++)
        {
-               const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].frame;
+               const md3vertex_t *verts = model->surfmesh.data_morphmd3vertex + numverts * frameblend[blendnum].subframe;
                float scale = frameblend[blendnum].lerp * (1.0f / 64.0f);
                if (blendnum == 0)
                {
@@ -291,7 +291,7 @@ void Mod_MD3_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
                }
                if (svector3f)
                {
-                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
+                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
                        float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
                        if (blendnum == 0)
                        {
@@ -323,10 +323,10 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        numblends = 0;
        // blend the frame translates to avoid redundantly doing so on each vertex
        // (a bit of a brain twister but it works)
-       for (blendnum = 0;blendnum < 4;blendnum++)
+       for (blendnum = 0;blendnum < MAX_FRAMEBLENDS;blendnum++)
        {
                if (model->surfmesh.data_morphmd2framesize6f)
-                       VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6 + 3, translate);
+                       VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6 + 3, translate);
                else
                        VectorMA(translate, frameblend[blendnum].lerp, model->surfmesh.num_morphmdlframetranslate, translate);
                if (frameblend[blendnum].lerp > 0)
@@ -335,10 +335,10 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
        // special case for the first blend because it avoids some adds and the need to memset the arrays first
        for (blendnum = 0;blendnum < numblends;blendnum++)
        {
-               const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].frame;
+               const trivertx_t *verts = model->surfmesh.data_morphmdlvertex + numverts * frameblend[blendnum].subframe;
                float scale[3];
                if (model->surfmesh.data_morphmd2framesize6f)
-                       VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].frame * 6, frameblend[blendnum].lerp, scale);
+                       VectorScale(model->surfmesh.data_morphmd2framesize6f + frameblend[blendnum].subframe * 6, frameblend[blendnum].lerp, scale);
                else
                        VectorScale(model->surfmesh.num_morphmdlframescale, frameblend[blendnum].lerp, scale);
                if (blendnum == 0)
@@ -385,7 +385,7 @@ void Mod_MDL_AnimateVertices(const dp_model_t *model, const frameblend_t *frameb
                }
                if (svector3f)
                {
-                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].frame;
+                       const texvecvertex_t *texvecvert = model->surfmesh.data_morphtexvecvertex + numverts * frameblend[blendnum].subframe;
                        float f = frameblend[blendnum].lerp * (1.0f / 127.0f);
                        if (blendnum == 0)
                        {
@@ -545,7 +545,7 @@ static void Mod_Alias_CalculateBoundingBox(void)
        float dist, yawradius, radius;
        float *v;
        float *vertex3f;
-       frameblend_t frameblend[4];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        memset(frameblend, 0, sizeof(frameblend));
        frameblend[0].lerp = 1;
        vertex3f = (float *) Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * sizeof(float[3]));
@@ -553,7 +553,7 @@ static void Mod_Alias_CalculateBoundingBox(void)
        VectorClear(loadmodel->normalmaxs);
        yawradius = 0;
        radius = 0;
-       for (frameblend[0].frame = 0;frameblend[0].frame < loadmodel->num_poses;frameblend[0].frame++)
+       for (frameblend[0].subframe = 0;frameblend[0].subframe < loadmodel->num_poses;frameblend[0].subframe++)
        {
                loadmodel->AnimateVertices(loadmodel, frameblend, vertex3f, NULL, NULL, NULL);
                for (vnum = 0, v = vertex3f;vnum < loadmodel->surfmesh.num_vertices;vnum++, v += 3)
@@ -597,8 +597,10 @@ static void Mod_Alias_CalculateBoundingBox(void)
 static void Mod_Alias_MorphMesh_CompileFrames(void)
 {
        int i, j;
-       frameblend_t frameblend[4] = {{0, 1}, {0, 0}, {0, 0}, {0, 0}};
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        unsigned char *datapointer;
+       memset(frameblend, 0, sizeof(frameblend));
+       frameblend[0].lerp = 1;
        datapointer = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->surfmesh.num_vertices * (sizeof(float[3]) * 4 + loadmodel->surfmesh.num_morphframes * sizeof(texvecvertex_t)));
        loadmodel->surfmesh.data_vertex3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
        loadmodel->surfmesh.data_svector3f = (float *)datapointer;datapointer += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
@@ -608,7 +610,7 @@ static void Mod_Alias_MorphMesh_CompileFrames(void)
        // this counts down from the last frame to the first so that the final data in surfmesh is for frame zero (which is what the renderer expects to be there)
        for (i = loadmodel->surfmesh.num_morphframes-1;i >= 0;i--)
        {
-               frameblend[0].frame = i;
+               frameblend[0].subframe = i;
                loadmodel->AnimateVertices(loadmodel, frameblend, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_normal3f, NULL, NULL);
                Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer);
                // encode the svector and tvector in 3 byte format for permanent storage
@@ -624,7 +626,7 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace,
 {
        int i;
        float segmentmins[3], segmentmaxs[3];
-       frameblend_t frameblend[4];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        msurface_t *surface;
        static int maxvertices = 0;
        static float *vertex3f = NULL;
@@ -633,7 +635,7 @@ static void Mod_MDLMD2MD3_TraceBox(dp_model_t *model, int frame, trace_t *trace,
        trace->realfraction = 1;
        trace->hitsupercontentsmask = hitsupercontentsmask;
        memset(frameblend, 0, sizeof(frameblend));
-       frameblend[0].frame = frame;
+       frameblend[0].subframe = frame;
        frameblend[0].lerp = 1;
        if (maxvertices < model->surfmesh.num_vertices)
        {
index 926ea606aa00bda659c4141c6b4c7e8a91d11e5f..df70609f6dba352efde24d8e7c7eeb00e1bafab8 100644 (file)
@@ -340,6 +340,8 @@ void Mod_IDSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        else
                Host_Error("Mod_IDSP_Load: %s has wrong version number (%i). Only %i (quake), %i (HalfLife), and %i (sprite32) supported",
                                        loadmodel->name, version, SPRITE_VERSION, SPRITEHL_VERSION, SPRITE32_VERSION);
+
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
 }
 
 
@@ -445,4 +447,6 @@ void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        }
        loadmodel->radius = modelradius;
        loadmodel->radius2 = modelradius * modelradius;
+
+       loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
 }
index 4a13dd56586c5b9a3867b7bf6597d2c8c06c612b..3d9af47730cd0bd79a1576bd97ed4399ff3aaf37 100644 (file)
--- a/progsvm.h
+++ b/progsvm.h
@@ -157,7 +157,9 @@ typedef struct prvm_prog_fieldoffsets_s
        int buttonuse; // ssqc
        int chain; // common - used by find builtins
        int classname; // common
+       int clientcamera; // ssqc
        int clientcolors; // ssqc
+       int clientstatus; // ssqc
        int color; // ssqc
        int colormod; // ssqc / csqc
        int contentstransition; // ssqc
@@ -179,7 +181,10 @@ typedef struct prvm_prog_fieldoffsets_s
        int frame1time; // csqc
        int frame2; // csqc
        int frame2time; // csqc
-       int shadertime; // csqc
+       int frame3; // csqc
+       int frame3time; // csqc
+       int frame4; // csqc
+       int frame4time; // csqc
        int frame; // common - used by OP_STATE
        int fullbright; // ssqc - Nehahra support
        int glow_color; // ssqc
@@ -191,6 +196,8 @@ typedef struct prvm_prog_fieldoffsets_s
        int ideal_yaw; // ssqc / csqc
        int idealpitch; // ssqc / csqc
        int items2; // ssqc
+       int lerpfrac3; // csqc
+       int lerpfrac4; // csqc
        int lerpfrac; // csqc
        int light_lev; // ssqc
        int message; // csqc
@@ -211,6 +218,7 @@ typedef struct prvm_prog_fieldoffsets_s
        int renderflags; // csqc
        int rendermode; // ssqc - HalfLife support
        int scale; // ssqc / csqc
+       int shadertime; // csqc
        int style; // ssqc
        int tag_entity; // ssqc / csqc
        int tag_index; // ssqc / csqc
@@ -218,8 +226,6 @@ typedef struct prvm_prog_fieldoffsets_s
        int viewmodelforclient; // ssqc
        int viewzoom; // ssqc
        int yaw_speed; // ssqc / csqc
-       int clientcamera; // ssqc
-       int clientstatus; // ssqc
 }
 prvm_prog_fieldoffsets_t;
 
index cb1509cb18dc1954e4914332e0cd0e0dc4f5c210..be8af7c9daf2c94e3e56f0429fdc42adc1b4ccc4 100644 (file)
@@ -1445,7 +1445,9 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.buttonuse                      = PRVM_ED_FindFieldOffset("buttonuse");
        prog->fieldoffsets.chain                          = PRVM_ED_FindFieldOffset("chain");
        prog->fieldoffsets.classname                      = PRVM_ED_FindFieldOffset("classname");
+       prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
        prog->fieldoffsets.clientcolors                   = PRVM_ED_FindFieldOffset("clientcolors");
+       prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
        prog->fieldoffsets.color                          = PRVM_ED_FindFieldOffset("color");
        prog->fieldoffsets.colormod                       = PRVM_ED_FindFieldOffset("colormod");
        prog->fieldoffsets.contentstransition             = PRVM_ED_FindFieldOffset("contentstransition");
@@ -1467,7 +1469,10 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.frame1time                     = PRVM_ED_FindFieldOffset("frame1time");
        prog->fieldoffsets.frame2                         = PRVM_ED_FindFieldOffset("frame2");
        prog->fieldoffsets.frame2time                     = PRVM_ED_FindFieldOffset("frame2time");
-       prog->fieldoffsets.shadertime                     = PRVM_ED_FindFieldOffset("shadertime");
+       prog->fieldoffsets.frame3                         = PRVM_ED_FindFieldOffset("frame3");
+       prog->fieldoffsets.frame3time                     = PRVM_ED_FindFieldOffset("frame3time");
+       prog->fieldoffsets.frame4                         = PRVM_ED_FindFieldOffset("frame4");
+       prog->fieldoffsets.frame4time                     = PRVM_ED_FindFieldOffset("frame4time");
        prog->fieldoffsets.fullbright                     = PRVM_ED_FindFieldOffset("fullbright");
        prog->fieldoffsets.glow_color                     = PRVM_ED_FindFieldOffset("glow_color");
        prog->fieldoffsets.glow_size                      = PRVM_ED_FindFieldOffset("glow_size");
@@ -1479,6 +1484,8 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.idealpitch                     = PRVM_ED_FindFieldOffset("idealpitch");
        prog->fieldoffsets.items2                         = PRVM_ED_FindFieldOffset("items2");
        prog->fieldoffsets.lerpfrac                       = PRVM_ED_FindFieldOffset("lerpfrac");
+       prog->fieldoffsets.lerpfrac3                      = PRVM_ED_FindFieldOffset("lerpfrac3");
+       prog->fieldoffsets.lerpfrac4                      = PRVM_ED_FindFieldOffset("lerpfrac4");
        prog->fieldoffsets.light_lev                      = PRVM_ED_FindFieldOffset("light_lev");
        prog->fieldoffsets.message                        = PRVM_ED_FindFieldOffset("message");
        prog->fieldoffsets.modelflags                     = PRVM_ED_FindFieldOffset("modelflags");
@@ -1498,6 +1505,7 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.renderflags                    = PRVM_ED_FindFieldOffset("renderflags");
        prog->fieldoffsets.rendermode                     = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
        prog->fieldoffsets.scale                          = PRVM_ED_FindFieldOffset("scale");
+       prog->fieldoffsets.shadertime                     = PRVM_ED_FindFieldOffset("shadertime");
        prog->fieldoffsets.style                          = PRVM_ED_FindFieldOffset("style");
        prog->fieldoffsets.tag_entity                     = PRVM_ED_FindFieldOffset("tag_entity");
        prog->fieldoffsets.tag_index                      = PRVM_ED_FindFieldOffset("tag_index");
@@ -1505,12 +1513,10 @@ void PRVM_FindOffsets(void)
        prog->fieldoffsets.viewmodelforclient             = PRVM_ED_FindFieldOffset("viewmodelforclient");
        prog->fieldoffsets.viewzoom                       = PRVM_ED_FindFieldOffset("viewzoom");
        prog->fieldoffsets.yaw_speed                      = PRVM_ED_FindFieldOffset("yaw_speed");
-       prog->fieldoffsets.clientcamera                   = PRVM_ED_FindFieldOffset("clientcamera");
-       prog->fieldoffsets.clientstatus                   = PRVM_ED_FindFieldOffset("clientstatus");
        prog->funcoffsets.CSQC_ConsoleCommand             = PRVM_ED_FindFunctionOffset("CSQC_ConsoleCommand");
        prog->funcoffsets.CSQC_Ent_Remove                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Remove");
-       prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
        prog->funcoffsets.CSQC_Ent_Spawn                  = PRVM_ED_FindFunctionOffset("CSQC_Ent_Spawn");
+       prog->funcoffsets.CSQC_Ent_Update                 = PRVM_ED_FindFunctionOffset("CSQC_Ent_Update");
        prog->funcoffsets.CSQC_Event                      = PRVM_ED_FindFunctionOffset("CSQC_Event");
        prog->funcoffsets.CSQC_Event_Sound                = PRVM_ED_FindFunctionOffset("CSQC_Event_Sound");
        prog->funcoffsets.CSQC_Init                       = PRVM_ED_FindFunctionOffset("CSQC_Init");
@@ -1521,59 +1527,59 @@ void PRVM_FindOffsets(void)
        prog->funcoffsets.CSQC_Parse_TempEntity           = PRVM_ED_FindFunctionOffset("CSQC_Parse_TempEntity");
        prog->funcoffsets.CSQC_Shutdown                   = PRVM_ED_FindFunctionOffset("CSQC_Shutdown");
        prog->funcoffsets.CSQC_UpdateView                 = PRVM_ED_FindFunctionOffset("CSQC_UpdateView");
-       prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
        prog->funcoffsets.EndFrame                        = PRVM_ED_FindFunctionOffset("EndFrame");
+       prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
+       prog->funcoffsets.Gecko_Query                     = PRVM_ED_FindFunctionOffset("Gecko_Query");
        prog->funcoffsets.RestoreGame                     = PRVM_ED_FindFunctionOffset("RestoreGame");
        prog->funcoffsets.SV_ChangeTeam                   = PRVM_ED_FindFunctionOffset("SV_ChangeTeam");
-       prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
-       prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
        prog->funcoffsets.SV_OnEntityNoSpawnFunction      = PRVM_ED_FindFunctionOffset("SV_OnEntityNoSpawnFunction");
-       prog->funcoffsets.SV_OnEntityPreSpawnFunction     = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
        prog->funcoffsets.SV_OnEntityPostSpawnFunction    = PRVM_ED_FindFunctionOffset("SV_OnEntityPostSpawnFunction");
-       prog->funcoffsets.GameCommand                     = PRVM_ED_FindFunctionOffset("GameCommand");
+       prog->funcoffsets.SV_OnEntityPreSpawnFunction     = PRVM_ED_FindFunctionOffset("SV_OnEntityPreSpawnFunction");
+       prog->funcoffsets.SV_ParseClientCommand           = PRVM_ED_FindFunctionOffset("SV_ParseClientCommand");
+       prog->funcoffsets.SV_PausedTic                    = PRVM_ED_FindFunctionOffset("SV_PausedTic");
+       prog->funcoffsets.SV_PlayerPhysics                = PRVM_ED_FindFunctionOffset("SV_PlayerPhysics");
        prog->funcoffsets.SV_Shutdown                     = PRVM_ED_FindFunctionOffset("SV_Shutdown");
        prog->funcoffsets.URI_Get_Callback                = PRVM_ED_FindFunctionOffset("URI_Get_Callback");
-       prog->funcoffsets.SV_PausedTic                    = PRVM_ED_FindFunctionOffset("SV_PausedTic");
        prog->globaloffsets.SV_InitCmd                    = PRVM_ED_FindGlobalOffset("SV_InitCmd");
-       prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
-       prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
-       prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
-       prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
-       prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
-       prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
-       prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
-       prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
-       prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
-       prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
-       prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
-       prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
-       prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
-       prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
-       prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
-       prog->globaloffsets.trace_networkentity           = PRVM_ED_FindGlobalOffset("trace_networkentity");
-       prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
-       prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
-       prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
-       prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
-       prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
        prog->globaloffsets.coop                          = PRVM_ED_FindGlobalOffset("coop");
        prog->globaloffsets.deathmatch                    = PRVM_ED_FindGlobalOffset("deathmatch");
-       prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
-       prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
        prog->globaloffsets.dmg_origin                    = PRVM_ED_FindGlobalOffset("dmg_origin");
-       prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
+       prog->globaloffsets.dmg_save                      = PRVM_ED_FindGlobalOffset("dmg_save");
+       prog->globaloffsets.dmg_take                      = PRVM_ED_FindGlobalOffset("dmg_take");
        prog->globaloffsets.drawfont                      = PRVM_ED_FindGlobalOffset("drawfont");
-       prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
-       prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
-       prog->globaloffsets.servertime                    = PRVM_ED_FindGlobalOffset("servertime");
-       prog->globaloffsets.serverprevtime                = PRVM_ED_FindGlobalOffset("serverprevtime");
-       prog->globaloffsets.serverdeltatime               = PRVM_ED_FindGlobalOffset("serverdeltatime");
+       prog->globaloffsets.gettaginfo_forward            = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
        prog->globaloffsets.gettaginfo_name               = PRVM_ED_FindGlobalOffset("gettaginfo_name");
-       prog->globaloffsets.gettaginfo_parent             = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
        prog->globaloffsets.gettaginfo_offset             = PRVM_ED_FindGlobalOffset("gettaginfo_offset");
-       prog->globaloffsets.gettaginfo_forward            = PRVM_ED_FindGlobalOffset("gettaginfo_forward");
+       prog->globaloffsets.gettaginfo_parent             = PRVM_ED_FindGlobalOffset("gettaginfo_parent");
        prog->globaloffsets.gettaginfo_right              = PRVM_ED_FindGlobalOffset("gettaginfo_right");
        prog->globaloffsets.gettaginfo_up                 = PRVM_ED_FindGlobalOffset("gettaginfo_up");
+       prog->globaloffsets.intermission                  = PRVM_ED_FindGlobalOffset("intermission");
+       prog->globaloffsets.require_spawnfunc_prefix      = PRVM_ED_FindGlobalOffset("require_spawnfunc_prefix");
+       prog->globaloffsets.sb_showscores                 = PRVM_ED_FindGlobalOffset("sb_showscores");
+       prog->globaloffsets.self                          = PRVM_ED_FindGlobalOffset("self");
+       prog->globaloffsets.serverdeltatime               = PRVM_ED_FindGlobalOffset("serverdeltatime");
+       prog->globaloffsets.serverprevtime                = PRVM_ED_FindGlobalOffset("serverprevtime");
+       prog->globaloffsets.servertime                    = PRVM_ED_FindGlobalOffset("servertime");
+       prog->globaloffsets.time                          = PRVM_ED_FindGlobalOffset("time");
+       prog->globaloffsets.trace_allsolid                = PRVM_ED_FindGlobalOffset("trace_allsolid");
+       prog->globaloffsets.trace_dphitcontents           = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
+       prog->globaloffsets.trace_dphitq3surfaceflags     = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
+       prog->globaloffsets.trace_dphittexturename        = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
+       prog->globaloffsets.trace_dpstartcontents         = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
+       prog->globaloffsets.trace_endpos                  = PRVM_ED_FindGlobalOffset("trace_endpos");
+       prog->globaloffsets.trace_ent                     = PRVM_ED_FindGlobalOffset("trace_ent");
+       prog->globaloffsets.trace_fraction                = PRVM_ED_FindGlobalOffset("trace_fraction");
+       prog->globaloffsets.trace_inopen                  = PRVM_ED_FindGlobalOffset("trace_inopen");
+       prog->globaloffsets.trace_inwater                 = PRVM_ED_FindGlobalOffset("trace_inwater");
+       prog->globaloffsets.trace_networkentity           = PRVM_ED_FindGlobalOffset("trace_networkentity");
+       prog->globaloffsets.trace_plane_dist              = PRVM_ED_FindGlobalOffset("trace_plane_dist");
+       prog->globaloffsets.trace_plane_normal            = PRVM_ED_FindGlobalOffset("trace_plane_normal");
+       prog->globaloffsets.trace_startsolid              = PRVM_ED_FindGlobalOffset("trace_startsolid");
+       prog->globaloffsets.v_forward                     = PRVM_ED_FindGlobalOffset("v_forward");
+       prog->globaloffsets.v_right                       = PRVM_ED_FindGlobalOffset("v_right");
+       prog->globaloffsets.v_up                          = PRVM_ED_FindGlobalOffset("v_up");
+       prog->globaloffsets.view_angles                   = PRVM_ED_FindGlobalOffset("view_angles");
+       prog->globaloffsets.worldstatus                   = PRVM_ED_FindGlobalOffset("worldstatus");
 
        // menu qc only uses some functions, nothing else
        prog->funcoffsets.m_draw                          = PRVM_ED_FindFunctionOffset("m_draw");
index 9497ccf9a3c7d0a7137f41b295bfbcea35390f8e..f384d81af0eb39c67af64157fb3c565e70e413ed 100644 (file)
 // LordHavoc: later note: made FRAMEBLENDINSERT macro
 void R_LerpAnimation(entity_render_t *r)
 {
-       int sub1, sub2, numframes, f, i, dolerp;
+       int sub2, numframes, f, i, k;
+       int isfirstframegroup = true;
+       int nolerp;
        double sublerp, lerp, d;
        animscene_t *scene;
+       framegroupblend_t *g;
        frameblend_t *blend;
        dp_model_t *model = r->model;
 
-       blend = r->frameblend;
-       blend[0].frame = blend[1].frame = blend[2].frame = blend[3].frame = 0;
-       blend[0].lerp = blend[1].lerp = blend[2].lerp = blend[3].lerp = 0;
-
-       if (!model || !model->type)
-               return;
+       memset(r->frameblend, 0, sizeof(r->frameblend));
 
-       numframes = model->numframes;
-
-       if (r->frame1 >= numframes)
+       if (!model || !model->surfmesh.isanimated)
        {
-               Con_DPrintf("CL_LerpAnimation: no such frame %d\n", r->frame1);
-               r->frame1 = 0;
-       }
-
-       if (r->frame2 >= numframes)
-       {
-               Con_DPrintf("CL_LerpAnimation: no such frame %d\n", r->frame2);
-               r->frame2 = 0;
-       }
-
-       // note: this could be removed, if the rendering code allows an empty blend array
-       if (r->frame1 < 0)
-       {
-               Con_Printf ("CL_LerpAnimation: frame1 is NULL\n");
-               r->frame1 = 0;
+               r->frameblend[0].lerp = 1;
+               return;
        }
 
-       // check r_lerpmodels and round off very close blend percentages
-       dolerp = (model->type == mod_sprite) ? r_lerpsprites.integer : r_lerpmodels.integer;
-
-       if (!dolerp || r->framelerp >= (65535.0f / 65536.0f))
-               r->framelerp = 1;
-       else if (r->framelerp < (1.0f / 65536.0f))
-               r->framelerp = 0;
-
-       if (model->animscenes)
+       blend = r->frameblend;
+       nolerp = (model->type == mod_sprite) ? !r_lerpsprites.integer : !r_lerpmodels.integer;
+       numframes = model->numframes;
+       for (k = 0, g = r->framegroupblend;k < MAX_FRAMEGROUPBLENDS;k++, g++)
        {
-               if (r->framelerp < 1 && r->frame1 >= 0)
+               if ((unsigned int)g->frame >= (unsigned int)numframes)
                {
-                       scene = model->animscenes + r->frame1;
-                       lerp = 1 - r->framelerp;
-
-                       if (scene->framecount > 1)
+                       Con_DPrintf("CL_LerpAnimation: no such frame %d\n", g->frame);
+                       g->frame = 0;
+               }
+               f = g->frame;
+               d = lerp = g->lerp;
+               if (lerp <= 0)
+                       continue;
+               if (nolerp)
+               {
+                       if (isfirstframegroup)
                        {
-                               sublerp = scene->framerate * (cl.time - r->frame1time);
-                               sub1 = (int) (sublerp);
-                               sub2 = sub1 + 1;
-                               sublerp -= sub1;
-                               if (!dolerp)
-                                       sublerp = 0;
-                               else if (sublerp >= (65535.0f / 65536.0f))
-                                       sublerp = 1;
-                               else if (sublerp < (1.0f / 65536.0f))
-                                       sublerp = 0;
-                               if (scene->loop)
-                               {
-                                       sub1 = (sub1 % scene->framecount);
-                                       sub2 = (sub2 % scene->framecount);
-                               }
-                               sub1 = bound(0, sub1, (scene->framecount - 1)) + scene->firstframe;
-                               sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
-                               f = sub1;
-                               d = (1 - sublerp) * lerp;
-#define FRAMEBLENDINSERT\
-                               if (d > 0)\
-                               {\
-                                       for (i = 0;i < 4;i++)\
-                                       {\
-                                               if (blend[i].frame == f)\
-                                               {\
-                                                       blend[i].lerp += d;\
-                                                       break;\
-                                               }\
-                                               if (blend[i].lerp <= 0)\
-                                               {\
-                                                       blend[i].frame = f;\
-                                                       blend[i].lerp = d;\
-                                                       break;\
-                                               }\
-                                       }\
-                               }
-                               FRAMEBLENDINSERT
-                               f = sub2;
-                               d = sublerp * lerp;
+                               d = lerp = 1;
+                               isfirstframegroup = false;
                        }
                        else
-                       {
-                               f = scene->firstframe;
-                               d = lerp;
-                       }
-                       FRAMEBLENDINSERT
+                               continue;
                }
-               if (r->framelerp > 0 && r->frame2 >= 0)
+               if (model->animscenes)
                {
-                       scene = model->animscenes + r->frame2;
-                       lerp = r->framelerp;
-
+                       scene = model->animscenes + f;
+                       f = scene->firstframe;
                        if (scene->framecount > 1)
                        {
-                               sublerp = scene->framerate * (cl.time - r->frame2time);
-                               sub1 = (int) (sublerp);
-                               sub2 = sub1 + 1;
-                               sublerp -= sub1;
-                               if (!dolerp)
-                                       sublerp = 0;
-                               else if (sublerp >= (65535.0f / 65536.0f))
-                                       sublerp = 1;
-                               else if (sublerp < (1.0f / 65536.0f))
+                               // this code path is only used on .zym models and torches
+                               sublerp = scene->framerate * (cl.time - g->start);
+                               f = (int) floor(sublerp);
+                               sublerp -= f;
+                               sub2 = f + 1;
+                               if (nolerp)
                                        sublerp = 0;
                                if (scene->loop)
                                {
-                                       sub1 = (sub1 % scene->framecount);
+                                       f = (f % scene->framecount);
                                        sub2 = (sub2 % scene->framecount);
                                }
-                               sub1 = bound(0, sub1, (scene->framecount - 1)) + scene->firstframe;
+                               f = bound(0, f, (scene->framecount - 1)) + scene->firstframe;
                                sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
-                               f = sub1;
-                               d = (1 - sublerp) * lerp;
-                               FRAMEBLENDINSERT
-                               f = sub2;
                                d = sublerp * lerp;
+                               // two framelerps produced from one animation
+                               if (f != sub2 && d > 0)
+                               {
+                                       for (i = 0;i < MAX_FRAMEBLENDS;i++)
+                                       {
+                                               if (blend[i].lerp <= 0 || blend[i].subframe == sub2)
+                                               {
+                                                       blend[i].subframe = sub2;
+                                                       blend[i].lerp += d;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               d = (1 - sublerp) * lerp;
                        }
-                       else
-                       {
-                               f = scene->firstframe;
-                               d = lerp;
-                       }
-                       FRAMEBLENDINSERT
-               }
-       }
-       else
-       {
-               // if there are no scenes, assume it is all single-frame groups
-               if (r->framelerp < 1 && r->frame1 >= 0)
-               {
-                       f = r->frame1;
-                       d = 1 - r->framelerp;
-                       FRAMEBLENDINSERT
                }
-               if (r->framelerp > 0 && r->frame2 >= 0)
+               if (d > 0)
                {
-                       f = r->frame2;
-                       d = r->framelerp;
-                       FRAMEBLENDINSERT
+                       for (i = 0;i < MAX_FRAMEBLENDS;i++)
+                       {
+                               if (blend[i].lerp <= 0 || blend[i].subframe == f)
+                               {
+                                       blend[i].subframe = f;
+                                       blend[i].lerp += d;
+                                       break;
+                               }
+                       }
                }
        }
 }
index 88238522e24e2ac4a19e88eb0af990d201024427..f98eb130656637d304f0b6e89cf270ffccf8fb6e 100644 (file)
@@ -355,12 +355,12 @@ void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const r
        R_Mesh_Matrix(&identitymatrix);
 
        // LordHavoc: interpolated sprite rendering
-       for (i = 0;i < 4;i++)
+       for (i = 0;i < MAX_FRAMEBLENDS;i++)
        {
                if (ent->frameblend[i].lerp >= 0.01f)
                {
-                       mspriteframe_t *frame = model->sprite.sprdata_frames + ent->frameblend[i].frame;
-                       texture_t *texture = R_GetCurrentTexture(model->data_textures + ent->frameblend[i].frame);
+                       mspriteframe_t *frame = model->sprite.sprdata_frames + ent->frameblend[i].subframe;
+                       texture_t *texture = R_GetCurrentTexture(model->data_textures + ent->frameblend[i].subframe);
 #if 0
                        vec3_t o, l, u;
 #endif
@@ -400,7 +400,7 @@ void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const r
 void R_Model_Sprite_Draw(entity_render_t *ent)
 {
        vec3_t org;
-       if (ent->frameblend[0].frame < 0)
+       if (ent->frameblend[0].subframe < 0)
                return;
 
        Matrix4x4_OriginFromMatrix(&ent->matrix, org);
index b6754e98036ee5152cab5ac74ba6c6d84d6313e2..7bf72d7cae249ef28e59ab91bf56ca9a7031b052 100644 (file)
--- a/render.h
+++ b/render.h
@@ -301,7 +301,7 @@ typedef struct rsurfacestate_s
        matrix4x4_t matrix;
        matrix4x4_t inversematrix;
        // animation blending state from entity
-       frameblend_t frameblend[4];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
        // directional model shading state from entity
        vec3_t modellight_ambient;
        vec3_t modellight_diffuse;