From 9e10334c3d85c0ff3630fe015f40b5c5a227668a Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 30 Mar 2009 15:22:57 +0000 Subject: [PATCH] reworked animation interpolation code - entity_render_t now has 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 --- cl_collision.c | 4 +- cl_main.c | 97 ++++++++++++++------------ cl_parse.c | 18 ++--- client.h | 36 ++++++---- clvm_cmds.c | 6 +- csprogs.c | 22 ++++-- darkplaces.txt | 2 +- gl_rmain.c | 19 ++--- model_alias.c | 34 ++++----- model_sprite.c | 4 ++ progsvm.h | 12 +++- prvm_edict.c | 88 ++++++++++++----------- r_lerpanim.c | 184 ++++++++++++++++--------------------------------- r_sprites.c | 8 +-- render.h | 2 +- 15 files changed, 257 insertions(+), 279 deletions(-) diff --git a/cl_collision.c b/cl_collision.c index bad4efc2..802b8adc 100644 --- a/cl_collision.c +++ b/cl_collision.c @@ -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); diff --git a/cl_main.c b/cl_main.c index bcaec418..675c3564 100644 --- 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) diff --git a/cl_parse.c b/cl_parse.c index 25330eec..a64e1ffd 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -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; diff --git a/client.h b/client.h index 73aa6e1b..16427924 100644 --- 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; diff --git a/clvm_cmds.c b/clvm_cmds.c index e1969f6e..4a26dd41 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -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; diff --git a/csprogs.c b/csprogs.c index 43d6c1eb..7f67ecba 100644 --- 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); diff --git a/darkplaces.txt b/darkplaces.txt index 91c3d626..fc096d7f 100644 --- a/darkplaces.txt +++ b/darkplaces.txt @@ -693,7 +693,7 @@ r_hdr_range 4 how much d r_hdr_scenebrightness 1 global rendering brightness r_lerpimages 1 bilinear filters images when scaling them up to power of 2 size (mode 1), looks better than glquake (mode 0) r_lerpmodels 1 enables animation smoothing on models -r_lerpsprites 1 enables animation smoothing on sprites (requires r_lerpmodels 1) +r_lerpsprites 1 enables animation smoothing on sprites r_letterbox 0 reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes) r_lightmaprgba 1 whether to use RGBA (32bit) or RGB (24bit) lightmaps r_lightningbeam_color_blue 1 color of the lightning beam effect diff --git a/gl_rmain.c b/gl_rmain.c index 4cfbdddf..3ad23498 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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) { diff --git a/model_alias.c b/model_alias.c index ad912f96..626ef113 100644 --- a/model_alias.c +++ b/model_alias.c @@ -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) { diff --git a/model_sprite.c b/model_sprite.c index 926ea606..df70609f 100644 --- a/model_sprite.c +++ b/model_sprite.c @@ -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; } diff --git a/progsvm.h b/progsvm.h index 4a13dd56..3d9af477 100644 --- 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; diff --git a/prvm_edict.c b/prvm_edict.c index cb1509cb..be8af7c9 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -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"); diff --git a/r_lerpanim.c b/r_lerpanim.c index 9497ccf9..f384d81a 100644 --- a/r_lerpanim.c +++ b/r_lerpanim.c @@ -6,157 +6,95 @@ // 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; + } + } } } } diff --git a/r_sprites.c b/r_sprites.c index 88238522..f98eb130 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -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); diff --git a/render.h b/render.h index b6754e98..7bf72d7c 100644 --- 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; -- 2.39.2