From: lordhavoc Date: Thu, 26 Apr 2001 05:38:37 +0000 (+0000) Subject: a big change with a little description... X-Git-Tag: RELEASE_0_2_0_RC1~835 X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=f9605292b17719532eac0b3c7ccd6341b671d684 a big change with a little description... rearranged client entity_t structure redesigned entity update system (same protocol) added support for split entity updates in the future for rate capping glow trails and view relative entities should work now (untested) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@193 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/bspfile.h b/bspfile.h index 626c74e4..7c8d489a 100644 --- a/bspfile.h +++ b/bspfile.h @@ -308,7 +308,7 @@ typedef struct epair_t *epairs; } entity_t; -extern int num_entities; +//extern int num_entities; extern entity_t entities[MAX_MAP_ENTITIES]; void ParseEntities (void); diff --git a/cl_effects.c b/cl_effects.c index 01bea5c9..d1973b8e 100644 --- a/cl_effects.c +++ b/cl_effects.c @@ -118,21 +118,21 @@ void CL_DoEffects() vis = CL_NewTempEntity(); if (!vis) continue; - VectorCopy(e->origin, vis->origin); - vis->lerp_model = vis->model = cl.model_precache[e->modelindex]; - vis->frame1 = e->frame; - vis->frame2 = e->frame + 1; - if (vis->frame2 >= e->endframe) - vis->frame2 = -1; // disappear - vis->frame = vis->frame2; - vis->framelerp = frame - vis->frame1; - vis->frame1start = e->frame1start; - vis->frame2start = e->frame2start; - vis->lerp_starttime = -1; - vis->colormap = -1; // no special coloring - vis->scale = 1; - vis->alpha = 1; - vis->colormod[0] = vis->colormod[1] = vis->colormod[2] = 1; + VectorCopy(e->origin, vis->render.origin); + vis->render.lerp_model = vis->render.model = cl.model_precache[e->modelindex]; + vis->render.frame1 = e->frame; + vis->render.frame2 = e->frame + 1; + if (vis->render.frame2 >= e->endframe) + vis->render.frame2 = -1; // disappear + vis->render.frame = vis->render.frame2; + vis->render.framelerp = frame - vis->render.frame1; + vis->render.frame1start = e->frame1start; + vis->render.frame2start = e->frame2start; + vis->render.lerp_starttime = -1; + vis->render.colormap = -1; // no special coloring + vis->render.scale = 1; + vis->render.alpha = 1; + vis->render.colormod[0] = vis->render.colormod[1] = vis->render.colormod[2] = 1; } } } diff --git a/cl_input.c b/cl_input.c index 21f084ff..89068734 100644 --- a/cl_input.c +++ b/cl_input.c @@ -261,7 +261,7 @@ void CL_AdjustAngles (void) { cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); - cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); + cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]); } if (in_klook.state & 1) { diff --git a/cl_main.c b/cl_main.c index 40b42ebb..e0db84a6 100644 --- a/cl_main.c +++ b/cl_main.c @@ -82,11 +82,11 @@ void CL_ClearState (void) // LordHavoc: have to set up the baseline info for alpha and other stuff for (i = 0;i < MAX_EDICTS;i++) { - cl_entities[i].baseline.alpha = 255; - cl_entities[i].baseline.scale = 16; - cl_entities[i].baseline.glowsize = 0; - cl_entities[i].baseline.glowcolor = 254; - cl_entities[i].baseline.colormod = 255; + cl_entities[i].state_baseline.alpha = 255; + cl_entities[i].state_baseline.scale = 16; + cl_entities[i].state_baseline.glowsize = 0; + cl_entities[i].state_baseline.glowcolor = 254; + cl_entities[i].state_baseline.colormod = 255; } // @@ -267,15 +267,15 @@ void CL_PrintEntities_f (void) entity_t *ent; int i; - for (i=0,ent=cl_entities ; imodel) + Con_Printf ("%3i:", i); + if (!ent->render.model) { Con_Printf ("EMPTY\n"); continue; } - Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", ent->model->name, ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); + Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n", ent->render.model->name, ent->render.frame, ent->render.origin[0], ent->render.origin[1], ent->render.origin[2], ent->render.angles[0], ent->render.angles[1], ent->render.angles[2]); } } @@ -407,6 +407,26 @@ float CL_LerpPoint (void) return frac; } +float CL_EntityLerpPoint (entity_t *ent) +{ + float f; + + if (cl_nolerp.value || cls.timedemo || (sv.active && svs.maxclients == 1)) + return 1; + + f = ent->state_current.time - ent->state_previous.time; +// Con_Printf(" %g-%g=%g", ent->state_current.time, ent->state_previous.time, f); + + if (f <= 0) + return 1; + if (f >= 0.1) + f = 0.1; + +// Con_Printf(" %g-%g/%g=%f", cl.time, ent->state_previous.time, f, (cl.time - ent->state_previous.time) / f); + f = (cl.time - ent->state_previous.time) / f; + return bound(0, f, 1); +} + /* =============== @@ -421,6 +441,7 @@ void CL_RelinkEntities (void) float frac, f, d; vec3_t delta; float bobjrotate; +// float bobjoffset; vec3_t oldorg; // determine partial update time @@ -431,13 +452,13 @@ void CL_RelinkEntities (void) // // interpolate player info // - for (i=0 ; i<3 ; i++) + for (i = 0;i < 3;i++) cl.velocity[i] = cl.mvelocity[1][i] + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); if (cls.demoplayback) { // interpolate the angles - for (j=0 ; j<3 ; j++) + for (j = 0;j < 3;j++) { d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; if (d > 180) @@ -448,152 +469,180 @@ void CL_RelinkEntities (void) } } - bobjrotate = anglemod(100*cl.time); + bobjrotate = ANGLEMOD(100*cl.time); +// bobjoffset = cos(180 * cl.time * M_PI / 180) * 4.0f + 4.0f; // start on the entity after the world - for (i=1,ent=cl_entities+1 ; imodel) - { // empty slot -// if (ent->forcelink) -// R_RemoveEfrags (ent); // just became empty + // if the object wasn't included in the latest packet, remove it + if (!ent->state_current.modelindex) continue; - } - -// if the object wasn't included in the last packet, remove it - if (ent->msgtime != cl.mtime[0]) - { - ent->model = NULL; - // LordHavoc: free on the same frame, not the next -// if (ent->forcelink) -// R_RemoveEfrags (ent); // just became empty - continue; - } - VectorCopy (ent->origin, oldorg); + VectorCopy (ent->render.origin, oldorg); - if (ent->forcelink) - { // the entity was not updated in the last message - // so move to the final spot - VectorCopy (ent->msg_origins[0], ent->origin); - VectorCopy (ent->msg_angles[0], ent->angles); + if (!ent->state_previous.modelindex) + { + // only one state available + VectorCopy (ent->state_current.origin, ent->render.origin); + VectorCopy (ent->state_current.angles, ent->render.angles); +// Con_Printf(" %i", i); } else - { // if the delta is large, assume a teleport and don't lerp - f = frac; - for (j = 0;j < 3;j++) + { + // if the delta is large, assume a teleport and don't lerp + f = CL_EntityLerpPoint(ent); + if (f < 1) { - delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; - // LordHavoc: increased lerp tolerance from 100 to 200 - if (delta[j] > 200 || delta[j] < -200) - f = 1; // assume a teleportation, not a motion + for (j = 0;j < 3;j++) + { + delta[j] = ent->state_current.origin[j] - ent->state_previous.origin[j]; + // LordHavoc: increased lerp tolerance from 100 to 200 + if (delta[j] > 200 || delta[j] < -200) + f = 1; + } } - - // interpolate the origin and angles - for (j = 0;j < 3;j++) + if (f >= 1) { - ent->origin[j] = ent->msg_origins[1][j] + f*delta[j]; - - d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; - if (d > 180) - d -= 360; - else if (d < -180) - d += 360; - ent->angles[j] = ent->msg_angles[1][j] + f*d; + // no interpolation + VectorCopy (ent->state_current.origin, ent->render.origin); + VectorCopy (ent->state_current.angles, ent->render.angles); + } + else + { + // interpolate the origin and angles + for (j = 0;j < 3;j++) + { + ent->render.origin[j] = ent->state_previous.origin[j] + f*delta[j]; + + d = ent->state_current.angles[j] - ent->state_previous.angles[j]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + ent->render.angles[j] = ent->state_previous.angles[j] + f*d; + } } - } - if (ent->effects & EF_BRIGHTFIELD) - R_EntityParticles (ent); - if (ent->effects & EF_MUZZLEFLASH) + ent->render.flags = ent->state_current.flags; + ent->render.effects = ent->state_current.effects; + ent->render.model = cl.model_precache[ent->state_current.modelindex]; + ent->render.frame = ent->state_current.frame; + if (cl.scores == NULL || !ent->state_current.colormap) + ent->render.colormap = -1; // no special coloring + else + ent->render.colormap = cl.scores[ent->state_current.colormap - 1].colors; // color it + ent->render.skinnum = ent->state_current.skin; + ent->render.alpha = ent->state_current.alpha * (1.0f / 255.0f); // FIXME: interpolate? + ent->render.scale = ent->state_current.scale * (1.0f / 16.0f); // FIXME: interpolate? + ent->render.glowsize = ent->state_current.glowsize * 4.0f; // FIXME: interpolate? + ent->render.glowcolor = ent->state_current.glowcolor; + ent->render.colormod[0] = (float) ((ent->state_current.colormod >> 5) & 7) * (1.0f / 7.0f); + ent->render.colormod[1] = (float) ((ent->state_current.colormod >> 2) & 7) * (1.0f / 7.0f); + ent->render.colormod[2] = (float) (ent->state_current.colormod & 3) * (1.0f / 3.0f); + + // LordHavoc: if the entity has no effects, don't check each + if (ent->render.effects) { - vec3_t v; + if (ent->render.effects & EF_BRIGHTFIELD) + R_EntityParticles (ent); + if (ent->render.effects & EF_MUZZLEFLASH) + { + vec3_t v; - AngleVectors (ent->angles, v, NULL, NULL); + AngleVectors (ent->render.angles, v, NULL, NULL); - v[0] = v[0] * 18 + ent->origin[0]; - v[1] = v[1] * 18 + ent->origin[1]; - v[2] = v[2] * 18 + ent->origin[2] + 16; + v[0] = v[0] * 18 + ent->render.origin[0]; + v[1] = v[1] * 18 + ent->render.origin[1]; + v[2] = v[2] * 18 + ent->render.origin[2] + 16; - CL_AllocDlight (ent, v, 100, 1, 1, 1, 0, 0.1); - } - if (ent->effects & EF_BRIGHTLIGHT) - CL_AllocDlight (ent, ent->origin, 400, 1, 1, 1, 0, 0); - if (ent->effects & EF_DIMLIGHT) - CL_AllocDlight (ent, ent->origin, 200, 1, 1, 1, 0, 0); - // LordHavoc: added EF_RED and EF_BLUE - if (ent->effects & EF_RED) // red - { - if (ent->effects & EF_BLUE) // magenta - CL_AllocDlight (ent, ent->origin, 200, 1.0f, 0.2f, 1.0f, 0, 0); - else // red - CL_AllocDlight (ent, ent->origin, 200, 1.0f, 0.1f, 0.1f, 0, 0); - } - else if (ent->effects & EF_BLUE) // blue - CL_AllocDlight (ent, ent->origin, 200, 0.1f, 0.1f, 1.0f, 0, 0); - else if (ent->effects & EF_FLAME) - { - if (ent->model) + CL_AllocDlight (ent, v, 100, 1, 1, 1, 0, 0.1); + } + if (ent->render.effects & EF_BRIGHTLIGHT) + CL_AllocDlight (ent, ent->render.origin, 400, 1, 1, 1, 0, 0); + if (ent->render.effects & EF_DIMLIGHT) + CL_AllocDlight (ent, ent->render.origin, 200, 1, 1, 1, 0, 0); + // LordHavoc: added EF_RED and EF_BLUE + if (ent->render.effects & EF_RED) // red + { + if (ent->render.effects & EF_BLUE) // magenta + CL_AllocDlight (ent, ent->render.origin, 200, 1.0f, 0.2f, 1.0f, 0, 0); + else // red + CL_AllocDlight (ent, ent->render.origin, 200, 1.0f, 0.1f, 0.1f, 0, 0); + } + else if (ent->render.effects & EF_BLUE) // blue + CL_AllocDlight (ent, ent->render.origin, 200, 0.1f, 0.1f, 1.0f, 0, 0); + else if (ent->render.effects & EF_FLAME) { - vec3_t mins, maxs; - int temp; - VectorAdd(ent->origin, ent->model->mins, mins); - VectorAdd(ent->origin, ent->model->maxs, maxs); - // how many flames to make - temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300); - R_FlameCube(mins, maxs, temp); + if (ent->render.model) + { + vec3_t mins, maxs; + int temp; + VectorAdd(ent->render.origin, ent->render.model->mins, mins); + VectorAdd(ent->render.origin, ent->render.model->maxs, maxs); + // how many flames to make + temp = (int) (cl.time * 300) - (int) (cl.oldtime * 300); + R_FlameCube(mins, maxs, temp); + } + CL_AllocDlight (ent, ent->render.origin, lhrandom(200, 250), 1.0f, 0.7f, 0.3f, 0, 0); } - CL_AllocDlight (ent, ent->origin, lhrandom(200, 250), 1.0f, 0.7f, 0.3f, 0, 0); } - if (ent->model->flags) // LordHavoc: if the model has no flags, don't check each + // LordHavoc: if the model has no flags, don't check each + if (ent->render.model && ent->render.model->flags) { - // rotate binary objects locally - if (ent->model->flags & EF_ROTATE) - ent->angles[1] = bobjrotate; - if (ent->model->flags & EF_GIB) - R_RocketTrail (oldorg, ent->origin, 2, ent); - else if (ent->model->flags & EF_ZOMGIB) - R_RocketTrail (oldorg, ent->origin, 4, ent); - else if (ent->model->flags & EF_TRACER) - R_RocketTrail (oldorg, ent->origin, 3, ent); - else if (ent->model->flags & EF_TRACER2) - R_RocketTrail (oldorg, ent->origin, 5, ent); - else if (ent->model->flags & EF_ROCKET) + if (ent->render.model->flags & EF_ROTATE) { - R_RocketTrail (oldorg, ent->origin, 0, ent); - CL_AllocDlight (ent, ent->origin, 200, 1.0f, 0.8f, 0.4f, 0, 0); + ent->render.angles[1] = bobjrotate; +// ent->render.origin[2] += bobjoffset; } - else if (ent->model->flags & EF_GRENADE) + // only do trails if present in the previous frame as well + if (ent->state_previous.modelindex) { - if (ent->alpha == -1) // LordHavoc: Nehahra dem compatibility - R_RocketTrail (oldorg, ent->origin, 7, ent); - else - R_RocketTrail (oldorg, ent->origin, 1, ent); + if (ent->render.model->flags & EF_GIB) + R_RocketTrail (oldorg, ent->render.origin, 2, ent); + else if (ent->render.model->flags & EF_ZOMGIB) + R_RocketTrail (oldorg, ent->render.origin, 4, ent); + else if (ent->render.model->flags & EF_TRACER) + R_RocketTrail (oldorg, ent->render.origin, 3, ent); + else if (ent->render.model->flags & EF_TRACER2) + R_RocketTrail (oldorg, ent->render.origin, 5, ent); + else if (ent->render.model->flags & EF_ROCKET) + { + R_RocketTrail (oldorg, ent->render.origin, 0, ent); + CL_AllocDlight (ent, ent->render.origin, 200, 1.0f, 0.8f, 0.4f, 0, 0); + } + else if (ent->render.model->flags & EF_GRENADE) + { + if (ent->render.alpha == -1) // LordHavoc: Nehahra dem compatibility + R_RocketTrail (oldorg, ent->render.origin, 7, ent); + else + R_RocketTrail (oldorg, ent->render.origin, 1, ent); + } + else if (ent->render.model->flags & EF_TRACER3) + R_RocketTrail (oldorg, ent->render.origin, 6, ent); } - else if (ent->model->flags & EF_TRACER3) - R_RocketTrail (oldorg, ent->origin, 6, ent); } - if (ent->glowsize) // LordHavoc: customizable glow + if (ent->render.glowsize) // LordHavoc: customizable glow { - byte *tempcolor = (byte *)&d_8to24table[ent->glowcolor]; - CL_AllocDlight (ent, ent->origin, ent->glowsize, tempcolor[0]*(1.0/255.0), tempcolor[1]*(1.0/255.0), tempcolor[2]*(1.0/255.0), 0, 0); + byte *tempcolor = (byte *)&d_8to24table[ent->render.glowcolor]; + CL_AllocDlight (ent, ent->render.origin, ent->render.glowsize, tempcolor[0]*(1.0/255.0), tempcolor[1]*(1.0/255.0), tempcolor[2]*(1.0/255.0), 0, 0); } - if (ent->glowtrail) // LordHavoc: customizable glow and trail - R_RocketTrail2 (oldorg, ent->origin, ent->glowcolor, ent); - - ent->forcelink = false; + if (ent->render.flags & RENDER_GLOWTRAIL) // LordHavoc: customizable glow and trail + R_RocketTrail2 (oldorg, ent->render.origin, ent->render.glowcolor, ent); if (i == cl.viewentity && !chase_active.value) continue; -// LordHavoc: enabled EF_NODRAW - if (!ent->model || ent->effects & EF_NODRAW) + if (ent->render.model == NULL) + continue; + if (ent->render.effects & EF_NODRAW) continue; if (cl_numvisedicts < MAX_VISEDICTS) cl_visedicts[cl_numvisedicts++] = ent; } +// Con_Printf("\n"); } diff --git a/cl_parse.c b/cl_parse.c index d856ce11..942e2b34 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -100,16 +100,21 @@ This error checks and tracks the total number of entities */ entity_t *CL_EntityNum (int num) { + /* if (num >= cl.num_entities) { if (num >= MAX_EDICTS) Host_Error ("CL_EntityNum: %i is an invalid number",num); - while (cl.num_entities<=num) - { - cl_entities[cl.num_entities].colormap = -1; // no special coloring - cl.num_entities++; - } + cl.num_entities = num; +// while (cl.num_entities <= num) +// { +// cl_entities[cl.num_entities].colormap = -1; // no special coloring +// cl.num_entities++; +// } } + */ + if (num >= MAX_EDICTS) + Host_Error ("CL_EntityNum: %i is an invalid number",num); return &cl_entities[num]; } @@ -441,7 +446,7 @@ void CL_ParseServerInfo (void) // local state - cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; + cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); @@ -450,6 +455,24 @@ void CL_ParseServerInfo (void) noclip_anglehack = false; // noclip is turned off at start } +void CL_ValidateState(entity_state_t *s) +{ + model_t *model; + + if (s->modelindex >= MAX_MODELS) + Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS); + + // colormap is client index + 1 + if (s->colormap > cl.maxclients) + Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients); + + model = cl.model_precache[s->modelindex]; + if (model && s->frame >= model->numframes) + { + Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name); + s->frame = 0; + } +} /* ================== @@ -460,13 +483,11 @@ If an entities model or origin changes from frame to frame, it must be relinked. Other attributes can change without relinking. ================== */ +byte entkill[MAX_EDICTS]; void CL_ParseUpdate (int bits) { - int i, modnum, num, alpha, scale, glowsize, glowcolor, colormod, frame; - model_t *model; - qboolean forcelink; - entity_t *ent; - entity_state_t *baseline; + int num, deltadie; + entity_t *ent; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage @@ -476,7 +497,7 @@ void CL_ParseUpdate (int bits) if (bits & U_MOREBITS) bits |= (MSG_ReadByte()<<8); - if (bits & U_EXTEND1 && !Nehahrademcompatibility) + if ((bits & U_EXTEND1) && (!Nehahrademcompatibility)) { bits |= MSG_ReadByte() << 16; if (bits & U_EXTEND2) @@ -484,141 +505,125 @@ void CL_ParseUpdate (int bits) } if (bits & U_LONGENTITY) - num = MSG_ReadShort (); + num = (unsigned) MSG_ReadShort (); else - num = MSG_ReadByte (); + num = (unsigned) MSG_ReadByte (); - ent = CL_EntityNum (num); + if (num >= MAX_EDICTS) + Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS); + if (num < 1) + Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num); - forcelink = ent->msgtime != cl.mtime[1]; // no previous frame to lerp from + // mark as visible (no kill) + entkill[num] = 0; - ent->msgtime = cl.mtime[0]; - - // LordHavoc: new protocol stuff - baseline = &ent->baseline; - if (bits & U_DELTA) - baseline = &ent->deltabaseline; + ent = CL_EntityNum (num); - if (forcelink) + ent->state_previous = ent->state_current; + deltadie = false; + if (bits & U_DELTA) { - ent->deltabaseline.origin[0] = ent->deltabaseline.origin[1] = ent->deltabaseline.origin[2] = 0; - ent->deltabaseline.angles[0] = ent->deltabaseline.angles[1] = ent->deltabaseline.angles[2] = 0; - ent->deltabaseline.effects = 0; - ent->deltabaseline.modelindex = 0; - ent->deltabaseline.frame = 0; - ent->deltabaseline.colormap = 0; - ent->deltabaseline.skin = 0; - ent->deltabaseline.alpha = 255; - ent->deltabaseline.scale = 16; - ent->deltabaseline.glowsize = 0; - ent->deltabaseline.glowcolor = 254; - ent->deltabaseline.colormod = 255; + if (!ent->state_current.modelindex) + deltadie = true; // was not present in previous frame, leave hidden until next full update } - - modnum = bits & U_MODEL ? MSG_ReadByte() : baseline->modelindex; - if (modnum >= MAX_MODELS) - Host_Error ("CL_ParseModel: bad modnum"); - - frame = ((bits & U_FRAME) ? MSG_ReadByte() : (baseline->frame & 0xFF)); - - i = bits & U_COLORMAP ? MSG_ReadByte() : baseline->colormap; - ent->deltabaseline.colormap = i; - if (!i) - ent->colormap = -1; // no special coloring else + ent->state_current = ent->state_baseline; + + ent->state_current.time = cl.mtime[0]; + + ent->state_current.flags = 0; + if (bits & U_MODEL) ent->state_current.modelindex = (ent->state_current.modelindex & 0xFF00) | MSG_ReadByte(); + if (bits & U_FRAME) ent->state_current.frame = (ent->state_current.frame & 0xFF00) | MSG_ReadByte(); + if (bits & U_COLORMAP) ent->state_current.colormap = MSG_ReadByte(); + if (bits & U_SKIN) ent->state_current.skin = MSG_ReadByte(); + if (bits & U_EFFECTS) ent->state_current.effects = (ent->state_current.effects & 0xFF00) | MSG_ReadByte(); + if (bits & U_ORIGIN1) ent->state_current.origin[0] = MSG_ReadCoord(); + if (bits & U_ANGLE1) ent->state_current.angles[0] = MSG_ReadAngle(); + if (bits & U_ORIGIN2) ent->state_current.origin[1] = MSG_ReadCoord(); + if (bits & U_ANGLE2) ent->state_current.angles[1] = MSG_ReadAngle(); + if (bits & U_ORIGIN3) ent->state_current.origin[2] = MSG_ReadCoord(); + if (bits & U_ANGLE3) ent->state_current.angles[2] = MSG_ReadAngle(); + if (bits & U_STEP) ent->state_current.flags |= RENDER_STEP; + if (bits & U_ALPHA) ent->state_current.alpha = MSG_ReadByte(); + if (bits & U_SCALE) ent->state_current.scale = MSG_ReadByte(); + if (bits & U_EFFECTS2) ent->state_current.effects = (ent->state_current.effects & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_GLOWSIZE) ent->state_current.glowsize = MSG_ReadByte(); + if (bits & U_GLOWCOLOR) ent->state_current.glowcolor = MSG_ReadByte(); + if (bits & U_GLOWTRAIL) ent->state_current.flags |= RENDER_GLOWTRAIL; + if (bits & U_COLORMOD) ent->state_current.colormod = MSG_ReadByte(); + if (bits & U_FRAME2) ent->state_current.frame = (ent->state_current.frame & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_MODEL2) ent->state_current.modelindex = (ent->state_current.modelindex & 0x00FF) | (MSG_ReadByte() << 8); + if (bits & U_VIEWMODEL) ent->state_current.flags |= RENDER_VIEWMODEL; + + // LordHavoc: to allow playback of the Nehahra movie + if (Nehahrademcompatibility && (bits & U_EXTEND1)) { - if (i > cl.maxclients) - Host_Error ("i >= cl.maxclients"); - ent->colormap = cl.scores[i-1].colors; // color it - } - - ent->deltabaseline.skin = ent->skinnum = bits & U_SKIN ? MSG_ReadByte() : baseline->skin; - - ent->effects = ((bits & U_EFFECTS) ? MSG_ReadByte() : (baseline->effects & 0xFF)); - -// shift the known values for interpolation - VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); - VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); - VectorCopy (baseline->origin, ent->msg_origins[0]); - VectorCopy (baseline->angles, ent->msg_angles[0]); - - if (bits & U_ORIGIN1) ent->msg_origins[0][0] = MSG_ReadCoord (); - if (bits & U_ANGLE1) ent->msg_angles[0][0] = MSG_ReadAngle(); - if (bits & U_ORIGIN2) ent->msg_origins[0][1] = MSG_ReadCoord (); - if (bits & U_ANGLE2) ent->msg_angles[0][1] = MSG_ReadAngle(); - if (bits & U_ORIGIN3) ent->msg_origins[0][2] = MSG_ReadCoord (); - if (bits & U_ANGLE3) ent->msg_angles[0][2] = MSG_ReadAngle(); - - VectorCopy(ent->msg_origins[0], ent->deltabaseline.origin); - VectorCopy(ent->msg_angles[0], ent->deltabaseline.angles); - - alpha = bits & U_ALPHA ? MSG_ReadByte() : baseline->alpha; - scale = bits & U_SCALE ? MSG_ReadByte() : baseline->scale; - ent->effects |= ((bits & U_EFFECTS2) ? (MSG_ReadByte() << 8) : (baseline->effects & 0xFF00)); - glowsize = bits & U_GLOWSIZE ? MSG_ReadByte() : baseline->glowsize; - glowcolor = bits & U_GLOWCOLOR ? MSG_ReadByte() : baseline->glowcolor; - colormod = bits & U_COLORMOD ? MSG_ReadByte() : baseline->colormod; - modnum |= ((bits & U_MODEL2) ? (MSG_ReadByte() << 8) : (baseline->modelindex & 0xFF00)); - frame |= ((bits & U_FRAME2) ? (MSG_ReadByte() << 8) : (baseline->frame & 0xFF00)); - - if (modnum >= MAX_MODELS) - Host_Error("modnum (%i) >= MAX_MODELS (%i)\n", modnum, MAX_MODELS); - - model = cl.model_precache[modnum]; - if (model != ent->model) - { - ent->model = model; - // automatic animation (torches, etc) can be either all together - // or randomized - if (model) - ent->syncbase = model->synctype == ST_RAND ? (float)(rand()&0x7fff) / 0x7fff : 0.0; + // LordHavoc: evil format + int i = MSG_ReadFloat(); + int j = MSG_ReadFloat() * 255.0f; + if (i == 2) + { + if (MSG_ReadFloat()) + ent->state_current.effects |= EF_FULLBRIGHT; + } + if (j < 0) + ent->state_current.alpha = 0; + else if (j == 0 || j >= 255) + ent->state_current.alpha = 255; else - forcelink = true; // hack to make null model players work + ent->state_current.alpha = j; } - ent->frame = frame; - if (model && (unsigned) frame >= model->numframes) - Con_DPrintf("CL_ParseUpdate: no such frame %i in \"%s\"\n", frame, model->name); - - ent->deltabaseline.alpha = alpha; - ent->deltabaseline.scale = scale; - ent->deltabaseline.effects = ent->effects; - ent->deltabaseline.glowsize = glowsize; - ent->deltabaseline.glowcolor = glowcolor; - ent->deltabaseline.colormod = colormod; - ent->deltabaseline.modelindex = modnum; - ent->deltabaseline.frame = frame; - ent->alpha = (float) alpha * (1.0 / 255.0); - ent->scale = (float) scale * (1.0 / 16.0); - ent->glowsize = glowsize * 4.0; - ent->glowcolor = glowcolor; - ent->colormod[0] = (float) ((colormod >> 5) & 7) * (1.0 / 7.0); - ent->colormod[1] = (float) ((colormod >> 2) & 7) * (1.0 / 7.0); - ent->colormod[2] = (float) (colormod & 3) * (1.0 / 3.0); - if (bits & U_EXTEND1 && Nehahrademcompatibility) // LordHavoc: to allow playback of the Nehahra movie + if (deltadie) { - i = MSG_ReadFloat(); - ent->alpha = MSG_ReadFloat(); - if (i == 2 && MSG_ReadFloat() != 0.0) - ent->effects |= EF_FULLBRIGHT; - if (ent->alpha == 0) - ent->alpha = 1; + // hide the entity + ent->state_current.modelindex = 0; } + else + { + CL_ValidateState(&ent->state_current); - //if ( bits & U_NOLERP ) - // ent->forcelink = true; - //if (bits & U_STEP) // FIXME: implement clientside interpolation of monsters - - if ( forcelink ) - { // didn't have an update last message - VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); - VectorCopy (ent->msg_origins[0], ent->origin); - VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); - VectorCopy (ent->msg_angles[0], ent->angles); - ent->forcelink = true; + /* + if (!ent->state_current.modelindex) + { + if (bits & U_DELTA) + { + if (bits & U_MODEL) + Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i %i\n", num, ent->state_previous.modelindex, ent->state_current.modelindex); + else + Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i\n", num, ent->state_previous.modelindex); + } + else + { + if (bits & U_MODEL) + Con_Printf("CL_ParseUpdate: NULL model on %i: %i %i\n", num, ent->state_baseline.modelindex, ent->state_current.modelindex); + else + Con_Printf("CL_ParseUpdate: NULL model on %i: %i\n", num, ent->state_baseline.modelindex); + } + } + */ } } +int entityupdatestart; +void CL_EntityUpdateBegin(int start) +{ + if (start < 0 || start >= MAX_EDICTS) + Host_Error("CL_EntityUpdateBegin: start (%i) < 0 or >= MAX_EDICTS (%i)\n", start, MAX_EDICTS); + entityupdatestart = start; + memset(entkill, 1, MAX_EDICTS); +} + +void CL_EntityUpdateEnd(int end) +{ + int i; + if (end < 0 || end > MAX_EDICTS) + Host_Error("CL_EntityUpdateEnd: end (%i) < 0 or > MAX_EDICTS (%i)\n", end, MAX_EDICTS); + for (i = entityupdatestart;i < end;i++) + if (entkill[i]) + cl_entities[i].state_current.modelindex = 0; +} + /* ================== CL_ParseBaseline @@ -626,28 +631,29 @@ CL_ParseBaseline */ void CL_ParseBaseline (entity_t *ent, int largemodelindex) { - int i; + int i; + memset(&ent->state_baseline, 0, sizeof(entity_state_t)); if (largemodelindex) - ent->baseline.modelindex = (unsigned short) MSG_ReadShort (); + ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort (); else - ent->baseline.modelindex = MSG_ReadByte (); - ent->baseline.frame = MSG_ReadByte (); - ent->baseline.colormap = MSG_ReadByte(); - ent->baseline.skin = MSG_ReadByte(); - for (i=0 ; i<3 ; i++) + ent->state_baseline.modelindex = MSG_ReadByte (); + ent->state_baseline.frame = MSG_ReadByte (); + ent->state_baseline.colormap = MSG_ReadByte(); + ent->state_baseline.skin = MSG_ReadByte(); + for (i = 0;i < 3;i++) { - ent->baseline.origin[i] = MSG_ReadCoord (); - ent->baseline.angles[i] = MSG_ReadAngle (); + ent->state_baseline.origin[i] = MSG_ReadCoord (); + ent->state_baseline.angles[i] = MSG_ReadAngle (); } - ent->baseline.alpha = 255; - ent->baseline.scale = 16; - ent->baseline.glowsize = 0; - ent->baseline.glowcolor = 254; - ent->baseline.colormod = 255; - - if (ent->baseline.modelindex >= MAX_MODELS) - Host_Error("CL_ParseBaseline: modelindex (%i) >= MAX_MODELS (%i)\n", ent->baseline.modelindex, MAX_MODELS); + ent->state_baseline.alpha = 255; + ent->state_baseline.scale = 16; + ent->state_baseline.glowsize = 0; + ent->state_baseline.glowcolor = 254; + ent->state_baseline.colormod = 255; + ent->state_previous = ent->state_current = ent->state_baseline; + + CL_ValidateState(&ent->state_baseline); } @@ -660,7 +666,7 @@ Server information pertaining to this client only */ void CL_ParseClientdata (int bits) { - int i, j; + int i, j; bits &= 0xFFFF; if (bits & SU_EXTEND1) @@ -739,34 +745,31 @@ CL_ParseStatic void CL_ParseStatic (int largemodelindex) { entity_t *ent; - int i; - i = cl.num_statics; - if (i >= MAX_STATIC_ENTITIES) + if (cl.num_statics >= MAX_STATIC_ENTITIES) Host_Error ("Too many static entities"); - ent = &cl_static_entities[i]; - cl.num_statics++; + ent = &cl_static_entities[cl.num_statics++]; CL_ParseBaseline (ent, largemodelindex); // copy it to the current state - ent->model = cl.model_precache[ent->baseline.modelindex]; - ent->frame = ent->frame1 = ent->frame2 = ent->baseline.frame; - ent->framelerp = 0; - ent->lerp_starttime = -1; + ent->render.model = cl.model_precache[ent->state_baseline.modelindex]; + ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame; + ent->render.framelerp = 0; + ent->render.lerp_starttime = -1; // make torchs play out of sync - ent->frame1start = ent->frame2start = -(rand() & 32767); - ent->colormap = -1; // no special coloring - ent->skinnum = ent->baseline.skin; - ent->effects = ent->baseline.effects; - ent->alpha = 1; - ent->scale = 1; - ent->alpha = 1; - ent->glowsize = 0; - ent->glowcolor = 254; - ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1; - - VectorCopy (ent->baseline.origin, ent->origin); - VectorCopy (ent->baseline.angles, ent->angles); + ent->render.frame1start = ent->render.frame2start = -(rand() & 32767); + ent->render.colormap = -1; // no special coloring + ent->render.skinnum = ent->state_baseline.skin; + ent->render.effects = ent->state_baseline.effects; + ent->render.alpha = 1; + ent->render.scale = 1; + ent->render.alpha = 1; + ent->render.glowsize = 0; + ent->render.glowcolor = 254; + ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1; + + VectorCopy (ent->state_baseline.origin, ent->render.origin); + VectorCopy (ent->state_baseline.angles, ent->render.angles); R_AddEfrags (ent); } @@ -832,7 +835,7 @@ CL_ParseServerMessage void CL_ParseServerMessage (void) { int cmd; - int i; + int i, updateend; byte cmdlog[32]; char *cmdlogname[32], *temp; int cmdindex, cmdcount = 0; @@ -856,6 +859,8 @@ void CL_ParseServerMessage (void) // parse the message // MSG_BeginReading (); + + updateend = false; while (1) { @@ -867,7 +872,7 @@ void CL_ParseServerMessage (void) if (cmd == -1) { SHOWNET("END OF MESSAGE"); - return; // end of message + break; // end of message } cmdindex = cmdcount & 31; @@ -878,7 +883,7 @@ void CL_ParseServerMessage (void) if (cmd & 128) { // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer) - temp = "svc_entity"; + temp = "entity"; cmdlogname[cmdindex] = temp; SHOWNET("fast update"); CL_ParseUpdate (cmd&127); @@ -926,6 +931,9 @@ void CL_ParseServerMessage (void) break; case svc_time: + // handle old protocols which do not have entity update ranges + CL_EntityUpdateBegin(0); + updateend = true; cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; @@ -938,10 +946,7 @@ void CL_ParseServerMessage (void) case svc_version: i = MSG_ReadLong (); if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250) - { Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION); - return; - } Nehahrademcompatibility = false; if (i == 250) Nehahrademcompatibility = true; @@ -986,7 +991,7 @@ void CL_ParseServerMessage (void) case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) - Host_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); + Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES"); strncpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING - 1); cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0; cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); @@ -1131,7 +1136,19 @@ void CL_ParseServerMessage (void) case svc_showlmp: SHOWLMP_decodeshow(); break; + case svc_entitiesbegin: + // the beginning of an entity update range + CL_EntityUpdateBegin((unsigned) MSG_ReadShort()); + break; + case svc_entitiesend: + // the end of an entity update range + CL_EntityUpdateEnd((unsigned) MSG_ReadShort()); + updateend = false; + break; } } + + if (updateend) + CL_EntityUpdateEnd(MAX_EDICTS); } diff --git a/cl_tent.c b/cl_tent.c index 363ca591..22b258bc 100644 --- a/cl_tent.c +++ b/cl_tent.c @@ -443,10 +443,10 @@ entity_t *CL_NewTempEntity (void) memset (ent, 0, sizeof(*ent)); cl_visedicts[cl_numvisedicts++] = ent; - ent->colormap = -1; // no special coloring - ent->scale = 1; - ent->alpha = 1; - ent->colormod[0] = ent->colormod[1] = ent->colormod[2] = 1; + ent->render.colormap = -1; // no special coloring + ent->render.scale = 1; + ent->render.alpha = 1; + ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1; return ent; } @@ -474,13 +474,11 @@ void CL_UpdateTEnts (void) if (!b->model || b->endtime < cl.time) continue; - // if coming from the player, update the start position + // if coming from the player, update the start position if (b->entity == cl.viewentity) - { - VectorCopy (cl_entities[cl.viewentity].origin, b->start); - } + VectorCopy (cl_entities[cl.viewentity].render.origin, b->start); - // calculate pitch and yaw + // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); if (dist[1] == 0 && dist[0] == 0) @@ -503,7 +501,7 @@ void CL_UpdateTEnts (void) pitch += 360; } - // add new entities for the lightning + // add new entities for the lightning VectorCopy (b->start, org); d = VectorNormalizeLength(dist); while (d > 0) @@ -511,15 +509,15 @@ void CL_UpdateTEnts (void) ent = CL_NewTempEntity (); if (!ent) return; - VectorCopy (org, ent->origin); - ent->model = b->model; - ent->effects = EF_FULLBRIGHT; - ent->angles[0] = pitch; - ent->angles[1] = yaw; - ent->angles[2] = rand()%360; + VectorCopy (org, ent->render.origin); + ent->render.model = b->model; + ent->render.effects = EF_FULLBRIGHT; + ent->render.angles[0] = pitch; + ent->render.angles[1] = yaw; + ent->render.angles[2] = rand()%360; if (r_glowinglightning.value > 0) - CL_AllocDlight(ent, ent->origin, lhrandom(100, 120), r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, 0, 0); + CL_AllocDlight(ent, ent->render.origin, lhrandom(100, 120), r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, r_glowinglightning.value * 0.25f, 0, 0); VectorMA(org, 30, dist, org); d -= 30; diff --git a/client.h b/client.h index f7aa2af0..42845cda 100644 --- a/client.h +++ b/client.h @@ -144,7 +144,7 @@ typedef struct // information for local display int stats[MAX_CL_STATS]; // health, etc int items; // inventory bit flags - float item_gettime[32]; // cl.time of aquiring item, for blinking + float item_gettime[32]; // cl.time of acquiring item, for blinking float faceanimtime; // use anim frame if cl.time < this cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups @@ -208,7 +208,7 @@ typedef struct // refresh related state struct model_s *worldmodel; // cl_entitites[0].model struct efrag_s *free_efrags; - int num_entities; // held in cl_entities array +// int num_entities; // held in cl_entities array int num_statics; // held in cl_staticentities array entity_t viewent; // the gun model diff --git a/gl_refrag.c b/gl_refrag.c index 224899f8..ce5ba79a 100644 --- a/gl_refrag.c +++ b/gl_refrag.c @@ -52,7 +52,7 @@ void R_RemoveEfrags (entity_t *ent) { efrag_t *ef, *old, *walk, **prev; - ef = ent->efrag; + ef = ent->render.efrag; while (ef) { @@ -79,7 +79,7 @@ void R_RemoveEfrags (entity_t *ent) cl.free_efrags = old; } - ent->efrag = NULL; + ent->render.efrag = NULL; } /* @@ -181,25 +181,25 @@ void R_AddEfrags (entity_t *ent) model_t *entmodel; int i; - if (!ent->model) + if (!ent->render.model) return; r_addent = ent; - lastlink = &ent->efrag; + lastlink = &ent->render.efrag; r_pefragtopnode = NULL; - entmodel = ent->model; + entmodel = ent->render.model; for (i=0 ; i<3 ; i++) { - r_emins[i] = ent->origin[i] + entmodel->mins[i]; - r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; + r_emins[i] = ent->render.origin[i] + entmodel->mins[i]; + r_emaxs[i] = ent->render.origin[i] + entmodel->maxs[i]; } R_SplitEntityOnNode (cl.worldmodel->nodes); - ent->topnode = r_pefragtopnode; + ent->render.topnode = r_pefragtopnode; } @@ -220,7 +220,7 @@ void R_StoreEfrags (efrag_t **ppefrag) while ((pefrag = *ppefrag) != NULL) { pent = pefrag->entity; - clmodel = pent->model; + clmodel = pent->render.model; switch (clmodel->type) { @@ -229,10 +229,10 @@ void R_StoreEfrags (efrag_t **ppefrag) case mod_sprite: pent = pefrag->entity; - if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) + if ((pent->render.visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) { cl_visedicts[cl_numvisedicts++] = pent; - pent->visframe = r_framecount; // render each entity only once per frame + pent->render.visframe = r_framecount; // render each entity only once per frame } ppefrag = &pefrag->leafnext; diff --git a/gl_rmain.c b/gl_rmain.c index f3806a33..d266859e 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -344,45 +344,70 @@ void R_DrawSpriteModel (entity_t *e, frameblend_t *blend); void R_LerpUpdate(entity_t *ent) { int frame; - frame = ent->frame; - if (ent->model && ent->frame >= ent->model->numframes) + frame = ent->render.frame; + if (ent->render.model && ent->render.frame >= ent->render.model->numframes) { - Con_Printf("R_LerpUpdate: no such frame%6i in \"%s\"\n", ent->frame, ent->model->name); + Con_Printf("R_LerpUpdate: no such frame%6i in \"%s\"\n", ent->render.frame, ent->render.model->name); frame = 0; } - if (ent->lerp_model != ent->model) + if (ent->render.lerp_model != ent->render.model) { // reset all interpolation information - ent->lerp_model = ent->model; - ent->frame1 = ent->frame2 = frame; - ent->frame1start = ent->frame2start = cl.time; - ent->framelerp = 1; - ent->lerp_starttime = 0; + ent->render.lerp_model = ent->render.model; + ent->render.frame1 = ent->render.frame2 = frame; + ent->render.frame1start = ent->render.frame2start = cl.time; + ent->render.framelerp = 1; + ent->render.lerp_starttime = 0; } - else if (ent->frame2 != frame) + else if (ent->render.frame2 != frame) { // transition to new frame - ent->frame1 = ent->frame2; - ent->frame1start = ent->frame2start; - ent->frame2 = frame; - ent->frame2start = cl.time; - ent->framelerp = 0; - ent->lerp_starttime = cl.time; + ent->render.frame1 = ent->render.frame2; + ent->render.frame1start = ent->render.frame2start; + ent->render.frame2 = frame; + ent->render.frame2start = cl.time; + ent->render.framelerp = 0; + ent->render.lerp_starttime = cl.time; } else { // lerp_starttime < 0 is used to prevent changing of framelerp - if (ent->lerp_starttime >= 0) + if (ent->render.lerp_starttime >= 0) { // update transition - ent->framelerp = (cl.time - ent->lerp_starttime) * 10; - ent->framelerp = bound(0, ent->framelerp, 1); + ent->render.framelerp = (cl.time - ent->render.lerp_starttime) * 10; + ent->render.framelerp = bound(0, ent->render.framelerp, 1); } } } +void R_PrepareEntities (void) +{ + int i; + entity_t *ent; + vec3_t v; + // this updates entities that are supposed to be view relative + for (i = 0;i < cl_numvisedicts;i++) + { + ent = cl_visedicts[i]; + + if (ent->render.flags & RENDER_VIEWMODEL) + { + // remove flag so it will not be repeated incase RelinkEntities is not called again for a while + ent->render.flags -= RENDER_VIEWMODEL; + // transform origin + VectorCopy(ent->render.origin, v); + ent->render.origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_refdef.vieworg[0]; + ent->render.origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_refdef.vieworg[1]; + ent->render.origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_refdef.vieworg[2]; + // adjust angles + VectorAdd(ent->render.angles, r_refdef.viewangles, ent->render.angles); + } + } +} + /* ============= R_DrawEntitiesOnList @@ -396,12 +421,12 @@ void R_DrawEntitiesOnList1 (void) if (!r_drawentities.value) return; - for (i=0 ; imodel->type != mod_brush) + if (cl_visedicts[i]->render.model->type != mod_brush) continue; currententity = cl_visedicts[i]; - modelalpha = currententity->alpha; + modelalpha = currententity->render.alpha; R_DrawBrushModel (currententity); } @@ -415,25 +440,22 @@ void R_DrawEntitiesOnList2 (void) if (!r_drawentities.value) return; - for (i=0 ; ialpha; + modelalpha = currententity->render.alpha; - switch (currententity->model->type) + switch (currententity->render.model->type) { case mod_alias: - if (!strcmp(currententity->model->name, "progs/flame2.mdl")) - blend[0].frame = 0; - R_LerpUpdate(currententity); - R_LerpAnimation(currententity->model, currententity->frame1, currententity->frame2, currententity->frame1start, currententity->frame2start, currententity->framelerp, blend); - R_DrawAliasModel (currententity, true, modelalpha, currententity->model, blend, currententity->skinnum, currententity->origin, currententity->angles, currententity->scale, currententity->effects, currententity->model->flags, currententity->colormap); + R_LerpAnimation(currententity->render.model, currententity->render.frame1, currententity->render.frame2, currententity->render.frame1start, currententity->render.frame2start, currententity->render.framelerp, blend); + R_DrawAliasModel (currententity, true, modelalpha, currententity->render.model, blend, currententity->render.skinnum, currententity->render.origin, currententity->render.angles, currententity->render.scale, currententity->render.effects, currententity->render.model->flags, currententity->render.colormap); break; case mod_sprite: R_LerpUpdate(currententity); - R_LerpAnimation(currententity->model, currententity->frame1, currententity->frame2, currententity->frame1start, currententity->frame2start, currententity->framelerp, blend); + R_LerpAnimation(currententity->render.model, currententity->render.frame1, currententity->render.frame2, currententity->render.frame1start, currententity->render.frame2start, currententity->render.framelerp, blend); R_DrawSpriteModel (currententity, blend); break; @@ -452,21 +474,21 @@ void R_DrawViewModel (void) { frameblend_t blend[4]; - if (!r_drawviewmodel.value || chase_active.value || envmap || !r_drawentities.value || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.model) + if (!r_drawviewmodel.value || chase_active.value || envmap || !r_drawentities.value || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model) return; currententity = &cl.viewent; - currententity->alpha = modelalpha = cl_entities[cl.viewentity].alpha; // LordHavoc: if the player is transparent, so is his gun - currententity->effects = cl_entities[cl.viewentity].effects; - currententity->scale = 1; - VectorCopy(cl_entities[cl.viewentity].colormod, currententity->colormod); + currententity->render.alpha = modelalpha = cl_entities[cl.viewentity].render.alpha; // LordHavoc: if the player is transparent, so is the gun + currententity->render.effects = cl_entities[cl.viewentity].render.effects; + currententity->render.scale = 1; + VectorCopy(cl_entities[cl.viewentity].render.colormod, currententity->render.colormod); R_LerpUpdate(currententity); - R_LerpAnimation(currententity->model, currententity->frame1, currententity->frame2, currententity->frame1start, currententity->frame2start, currententity->framelerp, blend); + R_LerpAnimation(currententity->render.model, currententity->render.frame1, currententity->render.frame2, currententity->render.frame1start, currententity->render.frame2start, currententity->render.framelerp, blend); // hack the depth range to prevent view model from poking into walls glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); - R_DrawAliasModel (currententity, false, modelalpha, currententity->model, blend, currententity->skinnum, currententity->origin, currententity->angles, currententity->scale, currententity->effects, currententity->model->flags, currententity->colormap); + R_DrawAliasModel (currententity, false, modelalpha, currententity->render.model, blend, currententity->render.skinnum, currententity->render.origin, currententity->render.angles, currententity->render.scale, currententity->render.effects, currententity->render.model->flags, currententity->render.colormap); glDepthRange (gldepthmin, gldepthmax); } @@ -773,8 +795,8 @@ void R_RenderView (void) // if (r_norefresh.value) // return; - if (!r_worldentity.model || !cl.worldmodel) - Sys_Error ("R_RenderView: NULL worldmodel"); + if (!r_worldentity.render.model || !cl.worldmodel) + Host_Error ("R_RenderView: NULL worldmodel"); lighthalf = gl_lightmode.value; @@ -796,6 +818,8 @@ void R_RenderView (void) R_SetFrustum (); R_SetupGL (); + R_PrepareEntities(); + skypolyclear(); wallpolyclear(); transpolyclear(); diff --git a/gl_rmisc.c b/gl_rmisc.c index 72dc5e43..cfc884d0 100644 --- a/gl_rmisc.c +++ b/gl_rmisc.c @@ -170,7 +170,7 @@ void R_NewMap (void) d_lightstylevalue[i] = 264; // normal light value memset (&r_worldentity, 0, sizeof(r_worldentity)); - r_worldentity.model = cl.worldmodel; + r_worldentity.render.model = cl.worldmodel; currententity = &r_worldentity; // clear out efrags in case the level hasn't been reloaded diff --git a/gl_rsurf.c b/gl_rsurf.c index 9031969f..3db22309 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -121,7 +121,7 @@ int R_AddDynamicLights (msurface_t *surf) if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31)))) continue; // not lit by this light - VectorSubtract (cl_dlights[lnum].origin, currententity->origin, local); + VectorSubtract (cl_dlights[lnum].origin, currententity->render.origin, local); dist = DotProduct (local, surf->plane->normal) - surf->plane->dist; // for comparisons to minimum acceptable light @@ -280,7 +280,7 @@ void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) lightmap = surf->samples; // set to full bright if no light data - if ((currententity && (currententity->effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata) + if ((currententity && (currententity->render.effects & EF_FULLBRIGHT)) || !cl.worldmodel->lightdata) { bl = blocklights; for (i=0 ; iframe) + if (currententity->render.frame) { if (base->alternate_anims) base = base->alternate_anims; @@ -819,14 +819,14 @@ void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmod if (s->dlightframe == r_dlightframecount) RSurf_Light(s->dlightbits, s->polys); wv = wvert; - if (isbmodel && (currententity->colormod[0] != 1 || currententity->colormod[1] != 1 || currententity->colormod[2] != 1)) + if (isbmodel && (currententity->render.colormod[0] != 1 || currententity->render.colormod[1] != 1 || currententity->render.colormod[2] != 1)) { for (p = s->polys;p;p = p->next) { v = p->verts[0]; - transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); + transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6) - transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->colormod[0], wv[4] * currententity->colormod[1], wv[5] * currententity->colormod[2], alpha); + transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3] * currententity->render.colormod[0], wv[4] * currententity->render.colormod[1], wv[5] * currententity->render.colormod[2], alpha); transpolyend(); } } @@ -835,7 +835,7 @@ void RSurf_DrawWallVertex(msurface_t *s, texture_t *t, int transform, int isbmod for (p = s->polys;p;p = p->next) { v = p->verts[0]; - transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); + transpolybegin(R_GetTexture(t->texture), R_GetTexture(t->glowtexture), 0, currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); for (i = 0,v = p->verts[0];i < p->numverts;i++, v += VERTEXSIZE, wv += 6) transpolyvert(wv[0], wv[1], wv[2], v[3], v[4], wv[3], wv[4], wv[5], alpha); transpolyend(); @@ -932,22 +932,22 @@ void R_DrawBrushModel (entity_t *e) currententity = e; - clmodel = e->model; + clmodel = e->render.model; - if (e->angles[0] || e->angles[1] || e->angles[2]) + if (e->render.angles[0] || e->render.angles[1] || e->render.angles[2]) { rotated = true; for (i=0 ; i<3 ; i++) { - mins[i] = e->origin[i] - clmodel->radius; - maxs[i] = e->origin[i] + clmodel->radius; + mins[i] = e->render.origin[i] - clmodel->radius; + maxs[i] = e->render.origin[i] + clmodel->radius; } } else { rotated = false; - VectorAdd (e->origin, clmodel->mins, mins); - VectorAdd (e->origin, clmodel->maxs, maxs); + VectorAdd (e->render.origin, clmodel->mins, mins); + VectorAdd (e->render.origin, clmodel->maxs, maxs); } if (R_CullBox (mins, maxs)) @@ -955,14 +955,14 @@ void R_DrawBrushModel (entity_t *e) c_bmodels++; - VectorSubtract (r_refdef.vieworg, e->origin, modelorg); + VectorSubtract (r_refdef.vieworg, e->render.origin, modelorg); if (rotated) { vec3_t temp; vec3_t forward, right, up; VectorCopy (modelorg, temp); - AngleVectors (e->angles, forward, right, up); + AngleVectors (e->render.angles, forward, right, up); modelorg[0] = DotProduct (temp, forward); modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, up); @@ -977,14 +977,14 @@ void R_DrawBrushModel (entity_t *e) if (!cl_dlights[i].radius) continue; - VectorSubtract(cl_dlights[i].origin, currententity->origin, org); + VectorSubtract(cl_dlights[i].origin, currententity->render.origin, org); R_NoVisMarkLights (org, &cl_dlights[i], 1<<(i&31), i >> 5, clmodel); } - vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->effects & EF_FULLBRIGHT) || currententity->colormod[0] != 1 || currententity->colormod[2] != 1 || currententity->colormod[2] != 1; + vertexlit = modelalpha != 1 || clmodel->firstmodelsurface == 0 || (currententity->render.effects & EF_FULLBRIGHT) || currententity->render.colormod[0] != 1 || currententity->render.colormod[2] != 1 || currententity->render.colormod[2] != 1; -e->angles[0] = -e->angles[0]; // stupid quake bug +e->render.angles[0] = -e->render.angles[0]; // stupid quake bug softwaretransformforentity (e); -e->angles[0] = -e->angles[0]; // stupid quake bug +e->render.angles[0] = -e->render.angles[0]; // stupid quake bug // draw texture for (i = 0;i < clmodel->nummodelsurfaces;i++, s++) @@ -1298,10 +1298,10 @@ void R_DrawWorld (void) entity_t ent; memset (&ent, 0, sizeof(ent)); - ent.model = cl.worldmodel; - ent.colormod[0] = ent.colormod[1] = ent.colormod[2] = 1; - modelalpha = ent.alpha = 1; - ent.scale = 1; + ent.render.model = cl.worldmodel; + ent.render.colormod[0] = ent.render.colormod[1] = ent.render.colormod[2] = 1; + modelalpha = ent.render.alpha = 1; + ent.render.scale = 1; VectorCopy (r_refdef.vieworg, modelorg); diff --git a/mathlib.c b/mathlib.c index 9d847add..a1e79394 100644 --- a/mathlib.c +++ b/mathlib.c @@ -29,8 +29,6 @@ int nanmask = 255<<23; /*-----------------------------------------------------------------*/ -#define DEG2RAD( a ) ( a * M_PI ) / 180.0F - float m_bytenormals[NUMVERTEXNORMALS][3] = { {-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188}, @@ -465,18 +463,6 @@ void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, /*-----------------------------------------------------------------*/ -float anglemod(float a) -{ -#if 0 - if (a >= 0) - a -= 360*(int)(a/360); - else - a += 360*( 1 + (int)(-a/360) ); -#endif - a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - // LordHavoc note 1: // BoxOnPlaneSide did a switch on a 'signbits' value and had optimized // assembly in an attempt to accelerate it further, very inefficient diff --git a/mathlib.h b/mathlib.h index fde3d3e5..4b613ba9 100644 --- a/mathlib.h +++ b/mathlib.h @@ -36,6 +36,10 @@ typedef int fixed16_t; #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h #endif +#define DEG2RAD(a) ((a) * ((float) M_PI / 180.0f)) +#define RAD2DEG(a) ((a) * (180.0f / (float) M_PI)) +#define ANGLEMOD(a) (((int) ((a) * (65536.0f / 360.0f)) & 65535) * (360.0f / 65536.0f)) + struct mplane_s; extern vec3_t vec3_origin; @@ -90,7 +94,6 @@ void FloorDivMod (double numer, double denom, int *quotient, int *rem); int GreatestCommonDivisor (int i1, int i2); void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -float anglemod(float a); // LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful! void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up); diff --git a/model_alias.c b/model_alias.c index f29d3a9e..9e1c0351 100644 --- a/model_alias.c +++ b/model_alias.c @@ -36,12 +36,11 @@ int posenum; float aliasbboxmin[3], aliasbboxmax[3]; // LordHavoc: proper bounding box considerations -#define MAXVERTS 8192 -float vertst[MAXVERTS][2]; -int vertusage[MAXVERTS]; -int vertonseam[MAXVERTS]; -int vertremap[MAXVERTS]; -unsigned short temptris[MAXVERTS][3]; +float vertst[MAXALIASVERTS][2]; +int vertusage[MAXALIASVERTS]; +int vertonseam[MAXALIASVERTS]; +int vertremap[MAXALIASVERTS]; +unsigned short temptris[MAXALIASTRIS][3]; void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivertx_t *v, trivertx_t *out) { @@ -85,7 +84,7 @@ void Mod_ConvertAliasVerts (int inverts, vec3_t scale, vec3_t translate, trivert } } if (invalidnormals) - Con_Printf("Mod_ConvertAliasVerts: %i invalid normal indices found\n", invalidnormals); + Con_Printf("Mod_ConvertAliasVerts: \"%s\", %i invalid normal indices found\n", loadname, invalidnormals); } /* @@ -532,7 +531,7 @@ void Mod_LoadAliasModel (model_t *mod, void *buffer) numverts = LittleLong(pinmodel->numverts); BOUNDI(numverts,0,MAXALIASVERTS); numtris = LittleLong(pinmodel->numtris); - BOUNDI(numtris,0,65536); + BOUNDI(numtris,0,MAXALIASTRIS); numskins = LittleLong(pinmodel->numskins); BOUNDI(numskins,0,256); skinwidth = LittleLong (pinmodel->skinwidth); @@ -722,7 +721,7 @@ void Mod_ConvertQ2AliasVerts (int numverts, vec3_t scale, vec3_t translate, triv } } if (invalidnormals) - Con_Printf("Mod_ConvertQ2AliasVerts: %i invalid normal indices found\n", invalidnormals); + Con_Printf("Mod_ConvertQ2AliasVerts: \"%s\", %i invalid normal indices found\n", loadname, invalidnormals); } /* diff --git a/pr_cmds.c b/pr_cmds.c index e4ba51a9..4d312c73 100644 --- a/pr_cmds.c +++ b/pr_cmds.c @@ -1619,7 +1619,7 @@ void PF_changeyaw (void) float ideal, current, move, speed; ent = PROG_TO_EDICT(pr_global_struct->self); - current = anglemod( ent->v.angles[1] ); + current = ANGLEMOD(ent->v.angles[1]); ideal = ent->v.ideal_yaw; speed = ent->v.yaw_speed; @@ -1647,7 +1647,7 @@ void PF_changeyaw (void) move = -speed; } - ent->v.angles[1] = anglemod (current + move); + ent->v.angles[1] = ANGLEMOD (current + move); } /* @@ -1662,7 +1662,7 @@ void PF_changepitch (void) eval_t *val; ent = G_EDICT(OFS_PARM0); - current = anglemod( ent->v.angles[0] ); + current = ANGLEMOD( ent->v.angles[0] ); if ((val = GETEDICTFIELDVALUE(ent, eval_idealpitch))) ideal = val->_float; else @@ -1702,7 +1702,7 @@ void PF_changepitch (void) move = -speed; } - ent->v.angles[0] = anglemod (current + move); + ent->v.angles[0] = ANGLEMOD (current + move); } /* diff --git a/protocol.h b/protocol.h index edad508f..b7cf55c6 100644 --- a/protocol.h +++ b/protocol.h @@ -46,6 +46,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EF_FULLBRIGHT 512 // LordHavoc: fullbright #define EF_FLAME 1024 // LordHavoc: on fire +#define EF_STEP 0x80000000 // internal client use only - present on MOVETYPE_STEP entities, not QC accessible (too many bits) + // if the high bit of the servercmd is set, the low bits are fast update flags: #define U_MOREBITS (1<<0) #define U_ORIGIN1 (1<<1) @@ -206,6 +208,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define svc_sound2 54 // short soundindex instead of byte #define svc_spawnbaseline2 55 // short modelindex instead of byte #define svc_spawnstatic2 56 // short modelindex instead of byte +#define svc_entitiesbegin 57 // [short] entitynum +#define svc_entitiesend 58 // [short] entitynum // // client to server diff --git a/quakedef.h b/quakedef.h index db706ec7..7b67999a 100644 --- a/quakedef.h +++ b/quakedef.h @@ -187,24 +187,6 @@ extern int buildnumber; #include "zone.h" #include "mathlib.h" -// LordHavoc: made this more compact, and added some more fields -typedef struct -{ - vec3_t origin; - vec3_t angles; - int effects; - short modelindex; - short frame; - byte colormap; - byte skin; - byte alpha; - byte scale; - byte glowsize; - byte glowcolor; - byte colormod; -} entity_state_t; - - #include "r_textures.h" #include "wad.h" diff --git a/r_light.c b/r_light.c index 37a2a0fd..2c4d2d0d 100644 --- a/r_light.c +++ b/r_light.c @@ -817,17 +817,17 @@ void R_LightModel(entity_t *ent, int numverts, vec3_t center, vec3_t basecolor) a = (byte) bound((int) 0, (int) (modelalpha * 255.0f), (int) 255); if (lighthalf) { - mod[0] = ent->colormod[0] * 0.5f; - mod[1] = ent->colormod[1] * 0.5f; - mod[2] = ent->colormod[2] * 0.5f; + mod[0] = ent->render.colormod[0] * 0.5f; + mod[1] = ent->render.colormod[1] * 0.5f; + mod[2] = ent->render.colormod[2] * 0.5f; } else { - mod[0] = ent->colormod[0]; - mod[1] = ent->colormod[1]; - mod[2] = ent->colormod[2]; + mod[0] = ent->render.colormod[0]; + mod[1] = ent->render.colormod[1]; + mod[2] = ent->render.colormod[2]; } - if (ent->effects & EF_FULLBRIGHT) + if (ent->render.effects & EF_FULLBRIGHT) { ((byte *)&color)[0] = (byte) (255.0f * mod[0]); ((byte *)&color)[1] = (byte) (255.0f * mod[1]); diff --git a/r_part.c b/r_part.c index 2e3f8f36..ed53ba2c 100644 --- a/r_part.c +++ b/r_part.c @@ -65,6 +65,7 @@ rtexture_t *smokeparticletexture[8]; rtexture_t *rainparticletexture; rtexture_t *bubbleparticletexture; rtexture_t *bulletholetexture[8]; +rtexture_t *rocketglowparticletexture; particle_t *particles; int r_numparticles; @@ -245,6 +246,21 @@ void R_InitParticleTexture (void) bulletholetexture[i] = R_LoadTexture (va("bulletholetexture%d", i), 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE); } + + for (y = 0;y < 32;y++) + { + dy = y - 16; + for (x = 0;x < 32;x++) + { + dx = x - 16; + d = (2048.0f / (dx*dx+dy*dy+1)) - 8.0f; + data[y][x][0] = bound(0, d * 1.0f, 255); + data[y][x][1] = bound(0, d * 0.8f, 255); + data[y][x][2] = bound(0, d * 0.5f, 255); + data[y][x][3] = bound(0, d * 1.0f, 255); + } + } + rocketglowparticletexture = R_LoadTexture ("glowparticletexture", 32, 32, &data[0][0][0], TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE); } void r_part_start() @@ -444,7 +460,7 @@ void R_EntityParticles (entity_t *ent) forward[1] = cp*sy; forward[2] = -sp; - particle(pt_oneframe, 0x6f, particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 9999, 0, ent->origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0); + particle(pt_oneframe, 0x6f, particletexture, TPOLYTYPE_ALPHA, false, 2, 255, 9999, 0, ent->render.origin[0] + m_bytenormals[i][0]*dist + forward[0]*beamlength, ent->render.origin[1] + m_bytenormals[i][1]*dist + forward[1]*beamlength, ent->render.origin[2] + m_bytenormals[i][2]*dist + forward[2]*beamlength, 0, 0, 0); } } @@ -837,12 +853,10 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) VectorSubtract(end, start, dir); VectorNormalize(dir); - /* if (type == 0) // rocket glow - particle(pt_glow, 254, particletexture, TPOLYTYPE_ADD, false, 10, 160, 9999, 0, start[0] - 12 * dir[0], start[1] - 12 * dir[1], start[2] - 12 * dir[2], 0, 0, 0); - */ + particle(pt_oneframe, 254, rocketglowparticletexture, TPOLYTYPE_ADD, false, 24, 255, 9999, 0, end[0] - 12 * dir[0], end[1] - 12 * dir[1], end[2] - 12 * dir[2], 0, 0, 0); - t = ent->trail_time; + t = ent->render.trail_time; if (t >= cl.time) return; // no particles to spawn this frame (sparse trail) @@ -854,7 +868,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) if (len <= 0.01f) { // advance the trail time - ent->trail_time = cl.time; + ent->render.trail_time = cl.time; return; } speed = len / (cl.time - cl.oldtime); @@ -869,14 +883,14 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) if (contents == CONTENTS_SKY || contents == CONTENTS_LAVA) { // advance the trail time - ent->trail_time = cl.time; + ent->render.trail_time = cl.time; return; } bubbles = (contents == CONTENTS_WATER || contents == CONTENTS_SLIME); polytype = TPOLYTYPE_ALPHA; - if (ent->effects & EF_ADDITIVE) + if (ent->render.effects & EF_ADDITIVE) polytype = TPOLYTYPE_ADD; while (t < cl.time) @@ -974,7 +988,7 @@ void R_RocketTrail (vec3_t start, vec3_t end, int type, entity_t *ent) dec *= speed; VectorMA (start, dec, vec, start); } - ent->trail_time = t; + ent->render.trail_time = t; } void R_RocketTrail2 (vec3_t start, vec3_t end, int color, entity_t *ent) diff --git a/r_sprites.c b/r_sprites.c index db8e90e9..95facc3c 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -4,7 +4,7 @@ void GL_DrawSpriteImage (mspriteframe_t *frame, vec3_t origin, vec3_t up, vec3_t { byte alphaub; alphaub = bound(0, alpha, 255); - transpolybegin(R_GetTexture(frame->texture), 0, R_GetTexture(frame->fogtexture), currententity->effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); + transpolybegin(R_GetTexture(frame->texture), 0, R_GetTexture(frame->fogtexture), currententity->render.effects & EF_ADDITIVE ? TPOLYTYPE_ADD : TPOLYTYPE_ALPHA); transpolyvertub(origin[0] + frame->down * up[0] + frame->left * right[0], origin[1] + frame->down * up[1] + frame->left * right[1], origin[2] + frame->down * up[2] + frame->left * right[2], 0, 1, red, green, blue, alphaub); transpolyvertub(origin[0] + frame->up * up[0] + frame->left * right[0], origin[1] + frame->up * up[1] + frame->left * right[1], origin[2] + frame->up * up[2] + frame->left * right[2], 0, 0, red, green, blue, alphaub); transpolyvertub(origin[0] + frame->up * up[0] + frame->right * right[0], origin[1] + frame->up * up[1] + frame->right * right[1], origin[2] + frame->up * up[2] + frame->right * right[2], 1, 0, red, green, blue, alphaub); @@ -29,34 +29,34 @@ void R_DrawSpriteModel (entity_t *e, frameblend_t *blend) c_sprites++; - psprite = Mod_Extradata(e->model); + psprite = Mod_Extradata(e->render.model); //psprite = e->model->cache.data; if (psprite->type == SPR_ORIENTED) { // bullet marks on walls - AngleVectors (e->angles, NULL, right, up); - VectorSubtract(e->origin, vpn, org); + AngleVectors (e->render.angles, NULL, right, up); + VectorSubtract(e->render.origin, vpn, org); } else { // normal sprite VectorCopy(vup, up); VectorCopy(vright, right); - VectorCopy(e->origin, org); + VectorCopy(e->render.origin, org); } - if (e->scale != 1) + if (e->render.scale != 1) { - VectorScale(up, e->scale, up); - VectorScale(right, e->scale, right); + VectorScale(up, e->render.scale, up); + VectorScale(right, e->render.scale, right); } - if (e->model->flags & EF_FULLBRIGHT || e->effects & EF_FULLBRIGHT) + if (e->render.model->flags & EF_FULLBRIGHT || e->render.effects & EF_FULLBRIGHT) { - color[0] = e->colormod[0] * 255; - color[1] = e->colormod[1] * 255; - color[2] = e->colormod[2] * 255; + color[0] = e->render.colormod[0] * 255; + color[1] = e->render.colormod[1] * 255; + color[2] = e->render.colormod[2] * 255; } else - R_CompleteLightPoint(color, e->origin, true); + R_CompleteLightPoint(color, e->render.origin, true); colorub[0] = bound(0, color[0], 255); colorub[1] = bound(0, color[1], 255); @@ -64,12 +64,12 @@ void R_DrawSpriteModel (entity_t *e, frameblend_t *blend) // LordHavoc: interpolated sprite rendering if (blend[0].lerp) - GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[0].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->alpha*255*blend[0].lerp); + GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[0].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->render.alpha*255*blend[0].lerp); if (blend[1].lerp) - GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[1].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->alpha*255*blend[1].lerp); + GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[1].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->render.alpha*255*blend[1].lerp); if (blend[2].lerp) - GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[2].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->alpha*255*blend[2].lerp); + GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[2].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->render.alpha*255*blend[2].lerp); if (blend[3].lerp) - GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[3].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->alpha*255*blend[3].lerp); + GL_DrawSpriteImage(((mspriteframe_t *)(psprite->ofs_frames + (int) psprite)) + blend[3].frame, org, up, right, colorub[0],colorub[1],colorub[2], e->render.alpha*255*blend[3].lerp); } diff --git a/render.h b/render.h index e69a5bdd..d67134d3 100644 --- a/render.h +++ b/render.h @@ -35,57 +35,77 @@ typedef struct efrag_s struct efrag_s *entnext; } efrag_t; +#define RENDER_STEP 1 +#define RENDER_GLOWTRAIL 2 +#define RENDER_VIEWMODEL 4 + +// LordHavoc: made this more compact, and added some more fields +typedef struct +{ + double time; // time this state was updated + vec3_t origin; + vec3_t angles; + int effects; + unsigned short modelindex; + unsigned short frame; + byte colormap; + byte skin; + byte alpha; + byte scale; + byte glowsize; + byte glowcolor; + byte colormod; + byte flags; +} entity_state_t; typedef struct entity_s { - qboolean forcelink; // model changed - - int update_type; - - entity_state_t baseline; // to fill in defaults in updates - entity_state_t deltabaseline; // LordHavoc: previous frame - - double msgtime; // time of last update - vec3_t msg_origins[2]; // last two updates (0 is newest) - vec3_t origin; - vec3_t msg_angles[2]; // last two updates (0 is newest) - vec3_t angles; - - // LordHavoc: added support for alpha transprency and other effects - float alpha; // opacity (alpha) of the model - float colormod[3]; // color tint for model - float scale; // size the model is shown - float trail_time; - float glowsize; // how big the glow is - byte glowcolor; // color of glow and particle trail (paletted) - byte glowtrail; // leaves a trail of particles - byte isviewmodel; // attached to view - - struct model_s *model; // NULL = no model - struct efrag_s *efrag; // linked list of efrags - int frame; // current desired frame (usually identical to frame2, but frame2 is not always used) - struct model_s *lerp_model; // lerp resets when model changes - float lerp_starttime; // start of this transition - int frame1; // frame that the model is interpolating from - int frame2; // frame that the model is interpolating to - double framelerp; // interpolation factor, usually computed from lerp_starttime - double frame1start; // time frame1 began playing (for framegroup animations) - double frame2start; // time frame2 began playing (for framegroup animations) - float syncbase; // for client-side animations - int colormap; - int effects; // light, particles, etc - int skinnum; // for Alias models - int visframe; // last frame this entity was - // found in an active leaf - - int dlightframe; // dynamic lighting - int dlightbits[8]; - -// 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 + entity_state_t state_baseline; // baseline for entity + entity_state_t state_previous; // previous state (interpolating from this) + entity_state_t state_current; // current state (interpolating to this) + + struct + { + vec3_t origin; + vec3_t angles; + + // LordHavoc: added support for alpha transprency and other effects + float alpha; // opacity (alpha) of the model + float colormod[3]; // color tint for model + float scale; // size the model is shown + float glowsize; // how big the glow is + byte glowcolor; // color of glow and particle trail (paletted) + byte flags; // render flags + + struct model_s *model; // NULL = no model + int frame; // current desired frame (usually identical to frame2, but frame2 is not always used) + struct efrag_s *efrag; // linked list of efrags + int colormap; + int effects; // light, particles, etc + int skinnum; // for Alias models + + int visframe; // last frame this entity was found in an active leaf + + struct model_s *lerp_model; // lerp resets when model changes + float lerp_starttime; // start of this transition + int frame1; // frame that the model is interpolating from + int frame2; // frame that the model is interpolating to + double framelerp; // interpolation factor, usually computed from lerp_starttime + double frame1start; // time frame1 began playing (for framegroup animations) + double frame2start; // time frame2 began playing (for framegroup animations) +// float syncbase; // for client-side animations + + int dlightframe; // dynamic lighting + int dlightbits[8]; + + float trail_time; + // 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 + } + render; } entity_t; // !!! if this is changed, it must be changed in asm_draw.h too !!! diff --git a/sbar.c b/sbar.c index fd63c133..32e1db6d 100644 --- a/sbar.c +++ b/sbar.c @@ -783,6 +783,9 @@ void Sbar_DrawFace (void) f = 4; else f = cl.stats[STAT_HEALTH] / 20; + // LordHavoc: I don't even know how the game didn't crash without this + if (f < 0) + f = 0; if (cl.time <= cl.faceanimtime) { diff --git a/sv_main.c b/sv_main.c index 330a9ba7..59da2be2 100644 --- a/sv_main.c +++ b/sv_main.c @@ -483,6 +483,8 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) MSG_WriteFloat(msg, org[2]); } */ + MSG_WriteByte(msg, svc_entitiesbegin); + MSG_WriteShort(msg, 1); clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes // send over all entities (except the client) that touch the pvs @@ -744,6 +746,9 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) if (bits & U_FRAME2) MSG_WriteByte(msg, (int)ent->v.frame >> 8); if (bits & U_MODEL2) MSG_WriteByte(msg, (int)ent->v.modelindex >> 8); } + + MSG_WriteByte(msg, svc_entitiesend); + MSG_WriteShort(msg, MAX_EDICTS); } /* diff --git a/sv_move.c b/sv_move.c index 87f3ed43..8bf64f62 100644 --- a/sv_move.c +++ b/sv_move.c @@ -287,8 +287,8 @@ void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) float d[3]; float tdir, olddir, turnaround; - olddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 ); - turnaround = anglemod(olddir - 180); + olddir = ANGLEMOD((int)(actor->v.ideal_yaw/45)*45); + turnaround = ANGLEMOD(olddir - 180); deltax = enemy->v.origin[0] - actor->v.origin[0]; deltay = enemy->v.origin[1] - actor->v.origin[1]; diff --git a/transform.c b/transform.c index e025c7f3..52107efc 100644 --- a/transform.c +++ b/transform.c @@ -151,8 +151,8 @@ void softwaretransformset (vec3_t origin, vec3_t angles, vec_t scale) void softwaretransformforentity (entity_t *e) { vec3_t angles; - angles[0] = -e->angles[0]; - angles[1] = e->angles[1]; - angles[2] = e->angles[2]; - softwaretransformset(e->origin, angles, e->scale); + angles[0] = -e->render.angles[0]; + angles[1] = e->render.angles[1]; + angles[2] = e->render.angles[2]; + softwaretransformset(e->render.origin, angles, e->render.scale); } diff --git a/view.c b/view.c index 5eddbe63..793fec63 100644 --- a/view.c +++ b/view.c @@ -312,10 +312,10 @@ void V_ParseDamage (void) // ent = &cl_entities[cl.viewentity]; - VectorSubtract (from, ent->origin, from); + VectorSubtract (from, ent->render.origin, from); VectorNormalize (from); - AngleVectors (ent->angles, forward, right, NULL); + AngleVectors (ent->render.angles, forward, right, NULL); side = DotProduct (from, right); v_dmg_roll = count*side*v_kickroll.value; @@ -555,7 +555,7 @@ void V_UpdateBlends (void) float angledelta (float a) { - a = anglemod(a); + a = ANGLEMOD(a); if (a > 180) a -= 360; return a; @@ -615,12 +615,12 @@ void CalcGunAngle (void) cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch); */ - cl.viewent.angles[YAW] = r_refdef.viewangles[YAW]; - cl.viewent.angles[PITCH] = -r_refdef.viewangles[PITCH]; + cl.viewent.render.angles[YAW] = r_refdef.viewangles[YAW]; + cl.viewent.render.angles[PITCH] = -r_refdef.viewangles[PITCH]; - cl.viewent.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; - cl.viewent.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; - cl.viewent.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; + cl.viewent.render.angles[ROLL] -= v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value; + cl.viewent.render.angles[PITCH] -= v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value; + cl.viewent.render.angles[YAW] -= v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value; } /* @@ -634,21 +634,21 @@ void V_BoundOffsets (void) ent = &cl_entities[cl.viewentity]; -// absolutely bound refresh reletive to entity clipping hull +// absolutely bound refresh relative to entity clipping hull // so the view can never be inside a solid wall - if (r_refdef.vieworg[0] < ent->origin[0] - 14) - r_refdef.vieworg[0] = ent->origin[0] - 14; - else if (r_refdef.vieworg[0] > ent->origin[0] + 14) - r_refdef.vieworg[0] = ent->origin[0] + 14; - if (r_refdef.vieworg[1] < ent->origin[1] - 14) - r_refdef.vieworg[1] = ent->origin[1] - 14; - else if (r_refdef.vieworg[1] > ent->origin[1] + 14) - r_refdef.vieworg[1] = ent->origin[1] + 14; - if (r_refdef.vieworg[2] < ent->origin[2] - 22) - r_refdef.vieworg[2] = ent->origin[2] - 22; - else if (r_refdef.vieworg[2] > ent->origin[2] + 30) - r_refdef.vieworg[2] = ent->origin[2] + 30; + if (r_refdef.vieworg[0] < ent->render.origin[0] - 14) + r_refdef.vieworg[0] = ent->render.origin[0] - 14; + else if (r_refdef.vieworg[0] > ent->render.origin[0] + 14) + r_refdef.vieworg[0] = ent->render.origin[0] + 14; + if (r_refdef.vieworg[1] < ent->render.origin[1] - 14) + r_refdef.vieworg[1] = ent->render.origin[1] - 14; + else if (r_refdef.vieworg[1] > ent->render.origin[1] + 14) + r_refdef.vieworg[1] = ent->render.origin[1] + 14; + if (r_refdef.vieworg[2] < ent->render.origin[2] - 22) + r_refdef.vieworg[2] = ent->render.origin[2] - 22; + else if (r_refdef.vieworg[2] > ent->render.origin[2] + 30) + r_refdef.vieworg[2] = ent->render.origin[2] + 30; } /* @@ -677,7 +677,7 @@ void V_CalcViewRoll (void) { float side; - side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity); + side = V_CalcRoll (cl_entities[cl.viewentity].render.angles, cl.velocity); r_refdef.viewangles[ROLL] += side; if (v_dmg_time > 0) @@ -712,9 +712,9 @@ void V_CalcIntermissionRefdef (void) // view is the weapon model (only visible from inside body) view = &cl.viewent; - VectorCopy (ent->origin, r_refdef.vieworg); - VectorCopy (ent->angles, r_refdef.viewangles); - view->model = NULL; + VectorCopy (ent->render.origin, r_refdef.vieworg); + VectorCopy (ent->render.angles, r_refdef.viewangles); + view->render.model = NULL; // always idle in intermission old = v_idlescale.value; @@ -747,67 +747,64 @@ void V_CalcRefdef (void) view = &cl.viewent; -// transform the view offset by the model's matrix to get the offset from -// model origin for the view +// transform the view offset by the model's matrix to get the offset from model origin for the view if (!chase_active.value) // LordHavoc: get rid of angle problems in chase_active mode { - ent->angles[YAW] = cl.viewangles[YAW]; // the model should face the view dir - ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face the view dir + ent->render.angles[YAW] = cl.viewangles[YAW]; // the model should face the view dir + ent->render.angles[PITCH] = -cl.viewangles[PITCH]; // the model should face the view dir } bob = V_CalcBob (); // refresh position - VectorCopy (ent->origin, r_refdef.vieworg); + VectorCopy (ent->render.origin, r_refdef.vieworg); r_refdef.vieworg[2] += cl.viewheight + bob; + // LordHavoc: the protocol has changed... so this is an obsolete approach // never let it sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis - r_refdef.vieworg[0] += 1.0/32; - r_refdef.vieworg[1] += 1.0/32; - r_refdef.vieworg[2] += 1.0/32; +// r_refdef.vieworg[0] += 1.0/32; +// r_refdef.vieworg[1] += 1.0/32; +// r_refdef.vieworg[2] += 1.0/32; if (!intimerefresh) - { VectorCopy (cl.viewangles, r_refdef.viewangles); - } V_CalcViewRoll (); V_AddIdle (); // offsets - angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are - // actually backward - angles[YAW] = ent->angles[YAW]; - angles[ROLL] = ent->angles[ROLL]; + angles[PITCH] = -ent->render.angles[PITCH]; // because entity pitches are actually backward + angles[YAW] = ent->render.angles[YAW]; + angles[ROLL] = ent->render.angles[ROLL]; AngleVectors (angles, forward, NULL, NULL); V_BoundOffsets (); // set up gun position - VectorCopy (cl.viewangles, view->angles); + VectorCopy (cl.viewangles, view->render.angles); CalcGunAngle (); - VectorCopy (ent->origin, view->origin); - view->origin[2] += cl.viewheight; + VectorCopy (ent->render.origin, view->render.origin); + view->render.origin[2] += cl.viewheight; for (i=0 ; i<3 ; i++) { - view->origin[i] += forward[i]*bob*0.4; + view->render.origin[i] += forward[i]*bob*0.4; // view->origin[i] += right[i]*bob*0.4; // view->origin[i] += up[i]*bob*0.8; } - view->origin[2] += bob; + view->render.origin[2] += bob; // fudge position around to keep amount of weapon visible // roughly equal with different FOV - view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; - view->frame = cl.stats[STAT_WEAPONFRAME]; - view->colormap = -1; // no special coloring + view->render.model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->render.frame = cl.stats[STAT_WEAPONFRAME]; + view->render.colormap = -1; // no special coloring // set up the refresh position if (!intimerefresh) @@ -817,7 +814,7 @@ void V_CalcRefdef (void) } // smooth out stair step ups -if (cl.onground && ent->origin[2] - oldz > 0) +if (cl.onground && ent->render.origin[2] - oldz > 0) { float steptime; @@ -827,15 +824,15 @@ if (cl.onground && ent->origin[2] - oldz > 0) steptime = 0; oldz += steptime * 80; - if (oldz > ent->origin[2]) - oldz = ent->origin[2]; - if (ent->origin[2] - oldz > 12) - oldz = ent->origin[2] - 12; - r_refdef.vieworg[2] += oldz - ent->origin[2]; - view->origin[2] += oldz - ent->origin[2]; + if (oldz > ent->render.origin[2]) + oldz = ent->render.origin[2]; + if (ent->render.origin[2] - oldz > 12) + oldz = ent->render.origin[2] - 12; + r_refdef.vieworg[2] += oldz - ent->render.origin[2]; + view->render.origin[2] += oldz - ent->render.origin[2]; } else - oldz = ent->origin[2]; + oldz = ent->render.origin[2]; // LordHavoc: origin view kick VectorAdd(r_refdef.vieworg, cl.punchvector, r_refdef.vieworg);