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)
{
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);
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);
}
}
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
{
// 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++)
}
// 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
// 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);
}
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)
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;
{
// 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
// 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;
}
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;
// 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;
// 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;
// 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;
// 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);
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
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"};
{
// 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];
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;
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)
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)
{
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 );
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)
// 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)
{
}
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)
{
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)
// 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)
}
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)
{
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]));
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)
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]);
// 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
{
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;
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)
{
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;
}
}
loadmodel->radius = modelradius;
loadmodel->radius2 = modelradius * modelradius;
+
+ loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1;
}
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
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
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
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
int viewmodelforclient; // ssqc
int viewzoom; // ssqc
int yaw_speed; // ssqc / csqc
- int clientcamera; // ssqc
- int clientstatus; // ssqc
}
prvm_prog_fieldoffsets_t;
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");
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");
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");
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");
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");
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");
// 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;
+ }
+ }
}
}
}
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
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);
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;