From d8e1f27d4b49ab8b2979b0a68e3a52ab4da9a0dd Mon Sep 17 00:00:00 2001 From: Jeff Teunissen Date: Mon, 11 Dec 2000 09:59:27 +0000 Subject: [PATCH] pr_edict.c: whitespace rest: Implement model animation interpolation for alias models. Trying to implement this has been an annoyance for some time, but IT WORKS NOW. set gl_lerp_anims to zero to disable. --- include/client.h | 4 +- include/render.h | 6 + source/cl_ents.c | 113 +++++-------- source/gl_rmain.c | 413 +++++++++++++++++++++++++++++++++------------- source/gl_rmisc.c | 4 + source/pr_edict.c | 16 +- 6 files changed, 367 insertions(+), 189 deletions(-) diff --git a/include/client.h b/include/client.h index 6b4f9da..7f776d2 100644 --- a/include/client.h +++ b/include/client.h @@ -54,8 +54,7 @@ typedef struct // player_state_t is the information needed by a player entity // to do move prediction and to generate a drawable entity -typedef struct -{ +typedef struct player_state_s { int messagenum; // all player's won't be updated each frame double state_time; // not the same as the packet time, @@ -67,6 +66,7 @@ typedef struct vec3_t velocity; int weaponframe; + int number; int modelindex; int frame; int skinnum; diff --git a/include/render.h b/include/render.h index 4d1e369..f4d35a1 100644 --- a/include/render.h +++ b/include/render.h @@ -79,6 +79,12 @@ typedef struct entity_s // FIXME: could turn these into a union int trivial_accept; struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + // Animation interpolation + float frame_start_time; + float frame_interval; + int pose1; + int pose2; } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! diff --git a/source/cl_ents.c b/source/cl_ents.c index dc62e2d..a522f44 100644 --- a/source/cl_ents.c +++ b/source/cl_ents.c @@ -355,21 +355,14 @@ CL_ParsePacketEntities (qboolean delta) full = false; if (oldpacket != -1) { - if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) { // we - // can't - // use - // this, - // it - // is - // too - // old + if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) { + // we can't use this, it is too old FlushEntityPacket (); return; } cl.validsequence = cls.netchan.incoming_sequence; oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities; - } else { // this is a full update that we can - // start delta compressing from now + } else { // a full update that we can start delta compressing from now oldp = &dummy; dummy.num_entities = 0; cl.validsequence = cls.netchan.incoming_sequence; @@ -489,8 +482,7 @@ CL_LinkPacketEntities (void) extern int cl_playerindex; extern int cl_h_playerindex, cl_gib1index, cl_gib2index, cl_gib3index; - pack = - &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].packet_entities; + pack = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].packet_entities; autorotate = anglemod (100 * cl.time); @@ -498,24 +490,19 @@ CL_LinkPacketEntities (void) for (pnum = 0; pnum < pack->num_entities; pnum++) { s1 = &pack->entities[pnum]; - s2 = s1; // FIXME: no interpolation right now + s2 = s1; // FIXME: no interpolation right now // spawn light flashes, even ones coming from invisible objects if ((s1->effects & (EF_BLUE | EF_RED)) == (EF_BLUE | EF_RED)) - CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], - s1->origin[2], 200 + (rand () & 31), 0.1, 3); + CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + (rand () & 31), 0.1, 3); else if (s1->effects & EF_BLUE) - CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], - s1->origin[2], 200 + (rand () & 31), 0.1, 1); + CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + (rand () & 31), 0.1, 1); else if (s1->effects & EF_RED) - CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], - s1->origin[2], 200 + (rand () & 31), 0.1, 2); + CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + (rand () & 31), 0.1, 2); else if (s1->effects & EF_BRIGHTLIGHT) - CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], - s1->origin[2] + 16, 400 + (rand () & 31), 0.1, 0); + CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2] + 16, 400 + (rand () & 31), 0.1, 0); else if (s1->effects & EF_DIMLIGHT) - CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], - s1->origin[2], 200 + (rand () & 31), 0.1, 0); + CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + (rand () & 31), 0.1, 0); // if set to invisible, skip if (!s1->modelindex) @@ -536,8 +523,7 @@ CL_LinkPacketEntities (void) if (cl_numvisedicts == MAX_VISEDICTS) break; // object list is full - ent = &cl_visedicts[cl_numvisedicts]; - cl_numvisedicts++; + ent = &cl_visedicts[cl_numvisedicts++]; ent->keynum = s1->number; ent->model = model = cl.model_precache[s1->modelindex]; @@ -552,36 +538,22 @@ CL_LinkPacketEntities (void) ent->scoreboard = NULL; } - // LordHavoc: cleaned up Endy's coding style, and fixed Endy's bugs // Ender: Extend (Colormod) [QSG - Begin] // N.B: All messy code below is the sole fault of LordHavoc and // his futile attempts to save bandwidth. :) - // - ent->glowsize = - s1->glowsize < - 128 ? s1->glowsize * 8.0 : (s1->glowsize - 256) * 8.0; -// if (s1->glowsize != 0) -// Con_Printf("glowsize: %d\n", s1->glowsize); + ent->glowsize = s1->glowsize < 128 ? s1->glowsize * 8.0 : (s1->glowsize - 256) * 8.0; ent->glowcolor = s1->glowcolor; -// if (s1->glowcolor != 254) -// Con_Printf("glowcolor: %d\n", s1->glowcolor); ent->alpha = s1->alpha / 255.0; -// if (s1->alpha != 255) -// Con_Printf("alpha: %d\n", s1->alpha); ent->scale = s1->scale / 16.0; -// if (s1->scale != 16) -// Con_Printf("scale: %d\n", s1->scale); - if (s1->colormod == 255) + if (s1->colormod == 255) { ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1; - else { -// Con_Printf("colormod: %d\n", s1->colormod); + } else { ent->colormod[0] = (float) ((s1->colormod >> 5) & 7) * (1.0 / 7.0); ent->colormod[1] = (float) ((s1->colormod >> 2) & 7) * (1.0 / 7.0); ent->colormod[2] = (float) (s1->colormod & 3) * (1.0 / 3.0); } - // // Ender: Extend (Colormod) [QSG - End] // set skin @@ -590,8 +562,7 @@ CL_LinkPacketEntities (void) // set frame ent->frame = s1->frame; - // rotate binary objects locally - if (model->flags & EF_ROTATE) { + if (model->flags & EF_ROTATE) { // rotate binary objects locally ent->angles[0] = 0; ent->angles[1] = autorotate; ent->angles[2] = 0; @@ -611,8 +582,7 @@ CL_LinkPacketEntities (void) // calculate origin for (i = 0; i < 3; i++) - ent->origin[i] = s2->origin[i] + - f * (s1->origin[i] - s2->origin[i]); + ent->origin[i] = s2->origin[i] + f * (s1->origin[i] - s2->origin[i]); // add automatic particle trails if (!model->flags) @@ -621,12 +591,17 @@ CL_LinkPacketEntities (void) // scan the old entity display list for a matching for (i = 0; i < cl_oldnumvisedicts; i++) { if (cl_oldvisedicts[i].keynum == ent->keynum) { + ent->frame_start_time = cl_oldvisedicts[i].frame_start_time; + ent->frame_interval = cl_oldvisedicts[i].frame_interval; + ent->pose1 = cl_oldvisedicts[i].pose1; + ent->pose2 = cl_oldvisedicts[i].pose2; VectorCopy (cl_oldvisedicts[i].origin, old_origin); break; } } - if (i == cl_oldnumvisedicts) - continue; // not in last message + + if (i == cl_oldnumvisedicts) // not in last message + continue; for (i = 0; i < 3; i++) if (abs (old_origin[i] - ent->origin[i]) > 128) { // no trail @@ -634,6 +609,7 @@ CL_LinkPacketEntities (void) VectorCopy (ent->origin, old_origin); break; } + if (model->flags & EF_ROCKET) { R_RocketTrail (old_origin, ent->origin, 0, ent); dl = CL_AllocDlight (s1->number); @@ -781,13 +757,14 @@ CL_ParsePlayerinfo (void) num = MSG_ReadByte (); if (num > MAX_CLIENTS) -// Sys_Error ("CL_ParsePlayerinfo: bad num"); +// Sys_Error ("CL_ParsePlayerinfo: bad num"); Host_EndGame ("CL_ParsePlayerinfo: bad num"); info = &cl.players[num]; state = &cl.frames[parsecountmod].playerstate[num]; + state->number = num; flags = state->flags = MSG_ReadShort (); state->messagenum = cl.parsecount; @@ -944,7 +921,6 @@ CL_LinkPlayers (void) if (state->messagenum != cl.parsecount) continue; // not present this frame - // FIXME: Use a findvar or something for gl_flashblend --KB // spawn light flashes, even ones coming from invisible objects if (!gl_flashblend->int_val || j != cl.playernum) { @@ -986,12 +962,23 @@ CL_LinkPlayers (void) continue; // grab an entity to fill in - if (cl_numvisedicts == MAX_VISEDICTS) - break; // object list is full + if (cl_numvisedicts == MAX_VISEDICTS) // object list is full + break; + ent = &cl_visedicts[cl_numvisedicts]; cl_numvisedicts++; - ent->keynum = 0; + // scan the old entity display list for a matching player + for (i = 0; i < cl_oldnumvisedicts; i++) { + if (cl_oldvisedicts[i].keynum == state->number) { + ent->frame_start_time = cl_oldvisedicts[i].frame_start_time; + ent->frame_interval = cl_oldvisedicts[i].frame_interval; + ent->pose1 = cl_oldvisedicts[i].pose1; + ent->pose2 = cl_oldvisedicts[i].pose2; + } + } + + ent->keynum = 0; ent->model = cl.model_precache[state->modelindex]; ent->skinnum = state->skinnum; ent->frame = state->frame; @@ -1019,17 +1006,10 @@ CL_LinkPlayers (void) // only predict half the move to minimize overruns msec = 500 * (playertime - state->state_time); - if (msec <= 0 - || (!cl_predict_players->int_val - && !cl_predict_players2->int_val)) { + if (msec <= 0 || (!cl_predict_players->int_val && !cl_predict_players2->int_val)) { VectorCopy (state->origin, ent->origin); -//Con_DPrintf ("nopredict\n"); - } else { - // predict players movement - if (msec > 255) - msec = 255; - state->command.msec = msec; -//Con_DPrintf ("predict: %i\n", msec); + } else { // predict players movement + state->command.msec = msec = min (msec, 255); oldphysent = pmove.numphysent; CL_SetSolidPlayers (j); @@ -1145,9 +1125,7 @@ CL_SetUpPlayerPrediction (qboolean dopred) // Con_DPrintf ("nopredict\n"); } else { // predict players movement - if (msec > 255) - msec = 255; - state->command.msec = msec; + state->command.msec = msec = min (msec, 255); // Con_DPrintf ("predict: %i\n", msec); CL_PredictUsercmd (state, &exact, &state->command, false); @@ -1221,8 +1199,7 @@ CL_EmitEntities (void) return; cl_oldnumvisedicts = cl_numvisedicts; - cl_oldvisedicts = - cl_visedicts_list[(cls.netchan.incoming_sequence - 1) & 1]; + cl_oldvisedicts = cl_visedicts_list[(cls.netchan.incoming_sequence - 1) & 1]; cl_visedicts = cl_visedicts_list[cls.netchan.incoming_sequence & 1]; cl_numvisedicts = 0; diff --git a/source/gl_rmain.c b/source/gl_rmain.c index 012fd85..615cf50 100644 --- a/source/gl_rmain.c +++ b/source/gl_rmain.c @@ -50,83 +50,83 @@ #include "va.h" #include "view.h" +entity_t r_worldentity; -entity_t r_worldentity; +vec3_t modelorg, r_entorigin; +entity_t *currententity; -vec3_t modelorg, r_entorigin; -entity_t *currententity; +int r_visframecount; // bumped when going to a new PVS +int r_framecount; // used for dlight push checking -int r_visframecount; // bumped when going to a new PVS -int r_framecount; // used for dlight push checking +mplane_t frustum[4]; -mplane_t frustum[4]; +int c_brush_polys, c_alias_polys; -int c_brush_polys, c_alias_polys; - -qboolean envmap; // true during envmap command capture +qboolean envmap; // true during envmap command capture // -int playertextures; // up to 16 color translated skins +int playertextures; // up to 16 color translated skins // // view origin // -vec3_t vup; -vec3_t vpn; -vec3_t vright; -vec3_t r_origin; +vec3_t vup; +vec3_t vpn; +vec3_t vright; +vec3_t r_origin; -float r_world_matrix[16]; -float r_base_world_matrix[16]; +float r_world_matrix[16]; +float r_base_world_matrix[16]; // // screen size info // -refdef_t r_refdef; +refdef_t r_refdef; -mleaf_t *r_viewleaf, *r_oldviewleaf; +mleaf_t *r_viewleaf, *r_oldviewleaf; -int d_lightstylevalue[256]; // 8.8 fraction of base light value +int d_lightstylevalue[256]; // 8.8 fraction of base light value -vec3_t shadecolor; // Ender (Extend) Colormod -float modelalpha; // Ender (EXtend) Alpha +vec3_t shadecolor; // Ender (Extend) Colormod +float modelalpha; // Ender (EXtend) Alpha -void R_MarkLeaves (void); +void R_MarkLeaves (void); -cvar_t *r_norefresh; -cvar_t *r_drawentities; -cvar_t *r_drawviewmodel; -cvar_t *r_speeds; -cvar_t *r_shadows; -cvar_t *r_wateralpha; -cvar_t *r_waterripple; -cvar_t *r_dynamic; -cvar_t *r_novis; -cvar_t *r_netgraph; +cvar_t *r_norefresh; +cvar_t *r_drawentities; +cvar_t *r_drawviewmodel; +cvar_t *r_speeds; +cvar_t *r_shadows; +cvar_t *r_wateralpha; +cvar_t *r_waterripple; +cvar_t *r_dynamic; +cvar_t *r_novis; +cvar_t *r_netgraph; -cvar_t *gl_clear; -cvar_t *gl_cull; -cvar_t *gl_texsort; -cvar_t *gl_smooth; -cvar_t *gl_smoothdlights; -cvar_t *gl_affinemodels; -cvar_t *gl_flashblend; -cvar_t *gl_playermip; -cvar_t *gl_nocolors; -cvar_t *gl_keeptjunctions; -cvar_t *gl_particles; +cvar_t *gl_clear; +cvar_t *gl_cull; +cvar_t *gl_texsort; +cvar_t *gl_smooth; +cvar_t *gl_smoothdlights; +cvar_t *gl_affinemodels; +cvar_t *gl_flashblend; +cvar_t *gl_playermip; +cvar_t *gl_nocolors; +cvar_t *gl_keeptjunctions; +cvar_t *gl_particles; +cvar_t *gl_lerp_anim; -cvar_t *r_skyname; -cvar_t *gl_skymultipass; -cvar_t *gl_sky_clip; +cvar_t *r_skyname; +cvar_t *gl_skymultipass; +cvar_t *gl_sky_clip; -cvar_t *gl_fb_models; -cvar_t *gl_fb_bmodels; +cvar_t *gl_fb_models; +cvar_t *gl_fb_bmodels; -cvar_t *brighten; +cvar_t *brighten; extern cvar_t *scr_fov; @@ -345,23 +345,23 @@ float r_avertexnormals[NUMVERTEXNORMALS][3] = { #include "anorms.h" }; -vec3_t shadevector; -float shadelight; +vec3_t shadevector; +float shadelight; // precalculated dot products for quantized angles #define SHADEDOT_QUANT 16 -float r_avertexnormal_dots[SHADEDOT_QUANT][256] = +float r_avertexnormal_dots[SHADEDOT_QUANT][256] = #include "anorm_dots.h" ; -float *shadedots = r_avertexnormal_dots[0]; +float *shadedots = r_avertexnormal_dots[0]; -int lastposenum; +int lastposenum, lastposenum0; /* -============= -GL_DrawAliasFrame -============= + GL_DrawAliasFrame + + Standard model drawing */ static void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum, qboolean fb) @@ -385,8 +385,9 @@ GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum, qboolean fb) if (count < 0) { count = -count; glBegin (GL_TRIANGLE_FAN); - } else + } else { glBegin (GL_TRIANGLE_STRIP); + } do { // texture coordinates come from the draw list @@ -416,11 +417,76 @@ GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum, qboolean fb) glColor3ubv (lighthalf_v); } +/* + GL_DrawAliasBlendedFrame + + Interpolated model drawing +*/ +void +GL_DrawAliasBlendedFrame (aliashdr_t *paliashdr, int pose1, int pose2, float blend, qboolean fb) +{ + float l; + trivertx_t *verts1; + trivertx_t *verts2; + int *order; + int count; + vec3_t d; + + lastposenum0 = pose1; + lastposenum = pose2; + + verts1 = (trivertx_t *) ((byte *) paliashdr + paliashdr->posedata); + verts2 = verts1; + + verts1 += pose1 * paliashdr->poseverts; + verts2 += pose2 * paliashdr->poseverts; + + order = (int *) ((byte *) paliashdr + paliashdr->commands); + + while ((count = *order++)) { + // get the vertex count and primitive type + + if (count < 0) { + count = -count; + glBegin (GL_TRIANGLE_FAN); + } else { + glBegin (GL_TRIANGLE_STRIP); + } + + do { + // texture coordinates come from the draw list + glTexCoord2f (((float *) order)[0], ((float *) order)[1]); + order += 2; + + if (fb) { + glColor4f (1, 1, 1, modelalpha); + } else { + // normals and vertexes come from the frame list + // blend the light intensity from the two frames together + d[0] = shadedots[verts2->lightnormalindex] - shadedots[verts1->lightnormalindex]; + + l = shadelight * (shadedots[verts1->lightnormalindex] + (blend * d[0])); + glColor4f (shadecolor[0] * l, shadecolor[1] * l, shadecolor[2] * l, modelalpha); + } + + VectorSubtract (verts2->v, verts1->v, d); + + // blend the vertex positions from each frame together + glVertex3f (verts1->v[0] + (blend * d[0]), + verts1->v[1] + (blend * d[1]), + verts1->v[2] + (blend * d[2])); + + verts1++; + verts2++; + } while (--count); + glEnd (); + } +} /* -============= -GL_DrawAliasShadow -============= + GL_DrawAliasShadow + + Standard shadow drawing */ extern vec3_t lightspot; @@ -442,11 +508,9 @@ GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) height = -lheight + 1.0; - while (1) { + while ((count = *order++)) { // get the vertex count and primitive type - count = *order++; - if (!count) - break; // done + if (count < 0) { count = -count; glBegin (GL_TRIANGLE_FAN); @@ -459,15 +523,9 @@ GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) order += 2; // normals and vertexes come from the frame list - point[0] = - verts->v[0] * paliashdr->mdl.scale[0] + - paliashdr->mdl.scale_origin[0]; - point[1] = - verts->v[1] * paliashdr->mdl.scale[1] + - paliashdr->mdl.scale_origin[1]; - point[2] = - verts->v[2] * paliashdr->mdl.scale[2] + - paliashdr->mdl.scale_origin[2]; + point[0] = verts->v[0] * paliashdr->mdl.scale[0] + paliashdr->mdl.scale_origin[0]; + point[1] = verts->v[1] * paliashdr->mdl.scale[1] + paliashdr->mdl.scale_origin[1]; + point[2] = verts->v[2] * paliashdr->mdl.scale[2] + paliashdr->mdl.scale_origin[2]; point[0] -= shadevector[0] * (point[2] + lheight); point[1] -= shadevector[1] * (point[2] + lheight); @@ -482,13 +540,75 @@ GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) } } +/* + GL_DrawAliasBlendedShadow + + Interpolated shadow drawing +*/ +void +GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, entity_t *e) +{ + trivertx_t *verts1, *verts2; + vec3_t point1, point2, d; + int *order, count; + float height, lheight, blend; + + blend = (realtime - e->frame_start_time) / e->frame_interval; + blend = min (blend, 1); + + lheight = e->origin[2] - lightspot[2]; + height = -lheight + 1.0; + + verts2 = verts1 = (trivertx_t *) ((byte *) paliashdr + paliashdr->posedata); + + verts1 += pose1 * paliashdr->poseverts; + verts2 += pose2 * paliashdr->poseverts; + + order = (int *) ((byte *) paliashdr + paliashdr->commands); + + while ((count = *order++)) { + // get the vertex count and primitive type + + if (count < 0) { + count = -count; + glBegin (GL_TRIANGLE_FAN); + } else { + glBegin (GL_TRIANGLE_STRIP); + } + + do { + order += 2; + + point1[0] = verts1->v[0] * paliashdr->mdl.scale[0] + paliashdr->mdl.scale_origin[0]; + point1[1] = verts1->v[1] * paliashdr->mdl.scale[1] + paliashdr->mdl.scale_origin[1]; + point1[2] = verts1->v[2] * paliashdr->mdl.scale[2] + paliashdr->mdl.scale_origin[2]; + + point1[0] -= shadevector[0] * (point1[2] + lheight); + point1[1] -= shadevector[1] * (point1[2] + lheight); + + point2[0] = verts2->v[0] * paliashdr->mdl.scale[0] + paliashdr->mdl.scale_origin[0]; + point2[1] = verts2->v[1] * paliashdr->mdl.scale[1] + paliashdr->mdl.scale_origin[1]; + point2[2] = verts2->v[2] * paliashdr->mdl.scale[2] + paliashdr->mdl.scale_origin[2]; + + point2[0] -= shadevector[0] * (point2[2] + lheight); + point2[1] -= shadevector[1] * (point2[2] + lheight); + + VectorSubtract (point2, point1, d); + + glVertex3f (point1[0] + (blend * d[0]), point1[1] + (blend * d[1]), height); + + verts1++; + verts2++; + } while (--count); + glEnd (); + } +} + /* -================= -R_SetupAliasFrame + R_SetupAliasFrame -================= */ static void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr, qboolean fb) @@ -512,6 +632,56 @@ R_SetupAliasFrame (int frame, aliashdr_t *paliashdr, qboolean fb) GL_DrawAliasFrame (paliashdr, pose, fb); } +/* + R_SetupAliasBlendedFrame + + +*/ +void +R_SetupAliasBlendedFrame (int frame, aliashdr_t *paliashdr, entity_t *e, qboolean fb) +{ + int pose, numposes; + float blend; + + if ((frame >= paliashdr->mdl.numframes) || (frame < 0)) { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + + pose = paliashdr->frames[frame].firstpose; + numposes = paliashdr->frames[frame].numposes; + + if (numposes > 1) { + e->frame_interval = paliashdr->frames[frame].interval; + pose += (int) (cl.time / e->frame_interval) % numposes; + } else { + /* One tenth of a second is a good for most Quake animations. If the + nextthink is longer then the animation is usually meant to pause + (e.g. check out the shambler magic animation in shambler.qc). If + its shorter then things will still be smoothed partly, and the + jumps will be less noticable because of the shorter time. So, + this is probably a good assumption. */ + e->frame_interval = 0.2; + } + + if (e->pose2 != pose) { + e->frame_start_time = realtime; + e->pose1 = e->pose2; + e->pose2 = pose; + blend = 0; + } else { + blend = (realtime - e->frame_start_time) / e->frame_interval; + blend = min (blend, 1); + } +// Sys_Printf ("numposes: %d, pose1: %d, pose2: %d\n", numposes, e->pose1, e->pose2); + + // wierd things start happening if blend passes 1 + if (cl.paused) + blend = 1; + + GL_DrawAliasBlendedFrame (paliashdr, e->pose1, e->pose2, blend, fb); +} + /* ================= @@ -522,15 +692,16 @@ R_DrawAliasModel static void R_DrawAliasModel (entity_t *e) { - int i; - int lnum; - vec3_t dist; - float add; - model_t *clmodel; - vec3_t mins, maxs; - aliashdr_t *paliashdr; - float an; - int anim; + int i; + int lnum; + vec3_t dist; + float add; + model_t *clmodel; + vec3_t mins, maxs; + aliashdr_t *paliashdr; + float an; + int anim; + qboolean torch = false; clmodel = currententity->model; @@ -567,10 +738,9 @@ R_DrawAliasModel (entity_t *e) for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract (currententity->origin, - cl_dlights[lnum].origin, dist); - add = - (cl_dlights[lnum].radius * cl_dlights[lnum].radius * 8) / - (DotProduct (dist, dist)); // FIXME Deek + cl_dlights[lnum].origin, + dist); + add = (cl_dlights[lnum].radius * cl_dlights[lnum].radius * 8) / (DotProduct (dist, dist)); // FIXME Deek if (add > 0) { shadelight += add; @@ -582,18 +752,19 @@ R_DrawAliasModel (entity_t *e) shadelight = min (shadelight, 100); // ZOID: never allow players to go totally black - if (!strcmp (clmodel->name, "progs/player.mdl")) { + if (strequal (clmodel->name, "progs/player.mdl")) { shadelight = max (shadelight, 8); - } else if (!gl_fb_models->int_val - && (!strcmp (clmodel->name, "progs/flame.mdl") - || !strcmp (clmodel->name, "progs/flame2.mdl"))) { - // HACK HACK HACK -- no fullbright colors, so make torches full light - shadelight = 256; + + } + + if (strnequal (clmodel->name, "progs/flame", 11)) { + torch = true; + if (!gl_fb_models->int_val) { // make torches full brightness anyway + shadelight = 256; + } } - shadedots = - r_avertexnormal_dots[((int) (e->angles[1] * (SHADEDOT_QUANT / 360.0))) & - (SHADEDOT_QUANT - 1)]; + shadedots = r_avertexnormal_dots[((int) (e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; shadelight /= 200.0; an = e->angles[1] / 180 * M_PI; @@ -616,11 +787,11 @@ R_DrawAliasModel (entity_t *e) glPushMatrix (); R_RotateForEntity (e); - if (!strcmp (clmodel->name, "progs/eyes.mdl")) { + if (strequal (clmodel->name, "progs/eyes.mdl")) { glTranslatef (paliashdr->mdl.scale_origin[0], paliashdr->mdl.scale_origin[1], paliashdr->mdl.scale_origin[2] - (22 + 8)); - // double size of eyes, since they are really hard to see in gl + // double size of eyes, since they are really hard to see in GL glScalef (paliashdr->mdl.scale[0] * 2, paliashdr->mdl.scale[1] * 2, paliashdr->mdl.scale[2] * 2); } else { @@ -650,15 +821,21 @@ R_DrawAliasModel (entity_t *e) if (gl_affinemodels->int_val) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - R_SetupAliasFrame (currententity->frame, paliashdr, false); + if (gl_lerp_anim->int_val && !torch) { + R_SetupAliasBlendedFrame (currententity->frame, paliashdr, currententity, false); + } else { + R_SetupAliasFrame (currententity->frame, paliashdr, false); + } // This block is GL fullbright support for objects... if (clmodel->hasfullbrights && gl_fb_models->int_val && paliashdr->gl_fb_texturenum[currententity->skinnum][anim]) { - glBindTexture (GL_TEXTURE_2D, - paliashdr->gl_fb_texturenum[currententity-> - skinnum][anim]); - R_SetupAliasFrame (currententity->frame, paliashdr, true); + glBindTexture (GL_TEXTURE_2D, paliashdr->gl_fb_texturenum[currententity->skinnum][anim]); + if (gl_lerp_anim->int_val && !torch) { + R_SetupAliasBlendedFrame (currententity->frame, paliashdr, currententity, true); + } else { + R_SetupAliasFrame (currententity->frame, paliashdr, true); + } } if (gl_affinemodels->int_val) @@ -667,16 +844,30 @@ R_DrawAliasModel (entity_t *e) glPopMatrix (); if (r_shadows->int_val) { + // torches, grenades, and lightning bolts do not have shadows + if (torch) + return; + if (strequal (clmodel->name, "progs/grenade.mdl")) + return; + if (strnequal (clmodel->name, "progs/bolt", 10)) + return; + glPushMatrix (); R_RotateForEntity (e); + glDisable (GL_TEXTURE_2D); glColor4f (0, 0, 0, 0.5); - GL_DrawAliasShadow (paliashdr, lastposenum); + + if (gl_lerp_anim->int_val) { + GL_DrawAliasBlendedShadow (paliashdr, lastposenum0, lastposenum, currententity); + } else { + GL_DrawAliasShadow (paliashdr, lastposenum); + } + glEnable (GL_TEXTURE_2D); glColor3ubv (lighthalf_v); glPopMatrix (); } - } //================================================================================== @@ -810,7 +1001,7 @@ R_SetupFrame static void R_SetupFrame (void) { -// don't allow cheats in multiplayer + // don't allow cheats in multiplayer if (!atoi (Info_ValueForKey (cl.serverinfo, "watervis"))) Cvar_SetValue (r_wateralpha, 1); @@ -818,12 +1009,12 @@ R_SetupFrame (void) r_framecount++; -// build the transformation matrix for the given view angles + // build the transformation matrix for the given view angles VectorCopy (r_refdef.vieworg, r_origin); AngleVectors (r_refdef.viewangles, vpn, vright, vup); -// current viewleaf + // current viewleaf r_oldviewleaf = r_viewleaf; r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); diff --git a/source/gl_rmisc.c b/source/gl_rmisc.c index 4ff7eae..b098be5 100644 --- a/source/gl_rmisc.c +++ b/source/gl_rmisc.c @@ -65,6 +65,7 @@ void R_InitBubble (); void R_FireColor_f (void); cvar_t *gl_fires; +extern cvar_t *gl_lerp_anim; qboolean allowskybox; // allow skyboxes? --KB /* @@ -252,6 +253,9 @@ R_Init_Cvars (void) gl_keeptjunctions = Cvar_Get ("gl_keeptjunctions", "1", CVAR_NONE, "None"); + gl_lerp_anim = Cvar_Get ("gl_lerp_anim", "1", CVAR_ARCHIVE, + "Toggles model animation interpolation"); + r_skyname = Cvar_Get ("r_skyname", "none", CVAR_NONE, "name of the current skybox"); gl_skymultipass = Cvar_Get ("gl_skymultipass", "1", CVAR_NONE, diff --git a/source/pr_edict.c b/source/pr_edict.c index 5b2cbc7..19b9920 100644 --- a/source/pr_edict.c +++ b/source/pr_edict.c @@ -272,7 +272,7 @@ ED_FindFunction (char *name) return NULL; } -eval_t * +eval_t * GetEdictFieldValue (edict_t *ed, char *field) { ddef_t *def = NULL; @@ -308,7 +308,7 @@ PR_ValueString Returns a string describing *data in a type specific manner ============= */ -char * +char * PR_ValueString (etype_t type, eval_t *val) { static char line[256]; @@ -362,7 +362,7 @@ Returns a string describing *data in a type specific manner Easier to parse than PR_ValueString ============= */ -char * +char * PR_UglyValueString (etype_t type, eval_t *val) { static char line[256]; @@ -413,7 +413,7 @@ Returns a string with a description and the contents of a global, padded to 20 field width ============ */ -char * +char * PR_GlobalString (int ofs) { char *s; @@ -440,7 +440,7 @@ PR_GlobalString (int ofs) return line; } -char * +char * PR_GlobalStringNoContents (int ofs) { int i; @@ -724,7 +724,7 @@ ED_ParseGlobals (char *data) ED_NewString ============= */ -char * +char * ED_NewString (char *string) { char *new, *new_p; @@ -828,7 +828,7 @@ ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ -char * +char * ED_ParseEdict (char *data, edict_t *ent) { ddef_t *key; @@ -1249,7 +1249,7 @@ PR_Init_Cvars (void) -edict_t * +edict_t * EDICT_NUM (int n) { if (n < 0 || n >= MAX_EDICTS)