mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 15:01:41 +00:00
Fix the ghost entities in demo playback.
Really, when cl_nodelta is in effect (eg, .qwd demo recording and thus playback). QW now uses the new shared entity state block as I'd intended. Thanks to the cleanup of ghost entities (ie, entities that have been removed but continue to be rendered), glsl overkill has gone from 157 to 163 fps :)
This commit is contained in:
parent
428d57b7e1
commit
66ef8e16c1
6 changed files with 169 additions and 82 deletions
|
@ -53,10 +53,6 @@ typedef struct entity_state_s {
|
|||
byte glow_size;
|
||||
byte glow_color;
|
||||
byte colormod;
|
||||
|
||||
struct skin_s *skin; //FIXME this should not be here, but better state
|
||||
//change tracking in the client is needed for this
|
||||
//to be moved
|
||||
} entity_state_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -306,6 +306,7 @@
|
|||
#define MAX_DEMO_PACKET_ENTITIES 196 // doesn't count nails
|
||||
typedef struct {
|
||||
int num_entities;
|
||||
int ent_nums[MAX_DEMO_PACKET_ENTITIES];
|
||||
entity_state_t *entities;
|
||||
} packet_entities_t;
|
||||
|
||||
|
|
|
@ -362,6 +362,7 @@ CL_RelinkEntities (void)
|
|||
if (cl_forcelink[i]) {
|
||||
// The entity was not updated in the last message so move to the
|
||||
// final spot
|
||||
ent->pose1 = ent->pose2 = -1;
|
||||
VectorCopy (new->origin, ent->origin);
|
||||
if (!(ent->model->flags & EF_ROTATE))
|
||||
CL_TransformEntity (ent, new->angles, true);
|
||||
|
@ -372,10 +373,10 @@ CL_RelinkEntities (void)
|
|||
}
|
||||
VectorCopy (ent->origin, ent->old_origin);
|
||||
} else {
|
||||
// If the delta is large, assume a teleport and don't lerp
|
||||
f = frac;
|
||||
VectorCopy (ent->origin, ent->old_origin);
|
||||
VectorSubtract (new->origin, old->origin, delta);
|
||||
// If the delta is large, assume a teleport and don't lerp
|
||||
if (fabs (delta[0]) > 100 || fabs (delta[1] > 100)
|
||||
|| fabs (delta[2]) > 100) {
|
||||
// assume a teleportation, not a motion
|
||||
|
@ -419,7 +420,8 @@ CL_RelinkEntities (void)
|
|||
CL_TransformEntity (ent, angles, false);
|
||||
}
|
||||
CL_EntityEffects (i, ent, new);
|
||||
CL_NewDlight (i, ent->origin, new->effects, 0, 0);
|
||||
CL_NewDlight (i, ent->origin, new->effects, new->glow_size,
|
||||
new->glow_color);
|
||||
if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256))
|
||||
VectorCopy (ent->origin, old->origin);
|
||||
if (ent->model->flags & ~EF_ROTATE)
|
||||
|
|
|
@ -203,6 +203,8 @@ typedef struct {
|
|||
// accidentally do something the first frame
|
||||
// sentcmds[cl.netchan.outgoing_sequence & UPDATE_MASK] = cmd
|
||||
frame_t frames[UPDATE_BACKUP];
|
||||
int link_sequence;
|
||||
int prev_sequence;
|
||||
|
||||
// information for local display
|
||||
int stats[MAX_CL_STATS]; // health, etc
|
||||
|
@ -340,6 +342,7 @@ extern client_state_t cl;
|
|||
|
||||
extern entity_t *cl_static_entities;
|
||||
extern entity_t cl_entities[512];
|
||||
extern byte cl_entity_valid[2][512];
|
||||
|
||||
extern qboolean nomaster;
|
||||
extern char *server_version; // version of server we connected to
|
||||
|
|
|
@ -103,12 +103,8 @@ CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits)
|
|||
if (bits & U_FRAME)
|
||||
to->frame = MSG_ReadByte (net_message);
|
||||
|
||||
if (bits & U_COLORMAP) {
|
||||
byte cmap = MSG_ReadByte (net_message);
|
||||
if (cmap != to->colormap)
|
||||
to->skin = mod_funcs->Skin_SetColormap (to->skin, cmap);
|
||||
to->colormap = cmap;
|
||||
}
|
||||
if (bits & U_COLORMAP)
|
||||
to->colormap = MSG_ReadByte (net_message);
|
||||
|
||||
if (bits & U_SKIN)
|
||||
to->skinnum = MSG_ReadByte (net_message);
|
||||
|
@ -193,22 +189,32 @@ FlushEntityPacket (void)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
copy_state (packet_entities_t *newp, packet_entities_t *oldp, int newindex,
|
||||
int oldindex, int num)
|
||||
{
|
||||
newp->entities[num] = oldp->entities[num];
|
||||
newp->ent_nums[newindex] = num;
|
||||
cl_entity_valid[0][num] = 1;
|
||||
}
|
||||
|
||||
void
|
||||
CL_ParsePacketEntities (qboolean delta)
|
||||
{
|
||||
byte from;
|
||||
int oldindex, newindex, newnum, oldnum, oldpacket, newpacket, word;
|
||||
byte from;
|
||||
int oldindex, newindex, newnum, oldnum, oldpacket, word;
|
||||
packet_entities_t *oldp, *newp, dummy;
|
||||
qboolean full;
|
||||
qboolean full;
|
||||
|
||||
newpacket = cls.netchan.incoming_sequence & UPDATE_MASK;
|
||||
newp = &cl.frames[newpacket].packet_entities;
|
||||
cl.frames[newpacket].invalid = false;
|
||||
cl.prev_sequence = cl.link_sequence;
|
||||
cl.link_sequence = cls.netchan.incoming_sequence;
|
||||
newp = &cl.frames[cl.link_sequence & UPDATE_MASK].packet_entities;
|
||||
cl.frames[cl.link_sequence & UPDATE_MASK].invalid = false;
|
||||
|
||||
if (delta) {
|
||||
from = MSG_ReadByte (net_message);
|
||||
|
||||
oldpacket = cl.frames[newpacket].delta_sequence;
|
||||
oldpacket = cl.frames[cl.link_sequence & UPDATE_MASK].delta_sequence;
|
||||
if (cls.demoplayback2)
|
||||
from = oldpacket = (cls.netchan.incoming_sequence - 1);
|
||||
if ((from & UPDATE_MASK) != (oldpacket & UPDATE_MASK))
|
||||
|
@ -217,6 +223,8 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
oldpacket = -1;
|
||||
|
||||
full = false;
|
||||
//memcpy (cl_entity_valid[1], cl_entity_valid[0],
|
||||
// sizeof (cl_entity_valid[0]));
|
||||
if (oldpacket != -1) {
|
||||
if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) {
|
||||
// we can't use this, it is too old
|
||||
|
@ -230,12 +238,14 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
dummy.num_entities = 0;
|
||||
cl.validsequence = cls.netchan.incoming_sequence;
|
||||
full = true;
|
||||
memset (cl_entity_valid[0], 0, sizeof (cl_entity_valid[0]));
|
||||
}
|
||||
|
||||
oldindex = 0;
|
||||
newindex = 0;
|
||||
newp->num_entities = 0;
|
||||
|
||||
newnum = 0;
|
||||
while (1) {
|
||||
word = MSG_ReadShort (net_message);
|
||||
if (net_message->badread) { // something didn't parse right...
|
||||
|
@ -248,15 +258,14 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
if (newindex >= MAX_DEMO_PACKET_ENTITIES)
|
||||
Host_Error ("CL_ParsePacketEntities: newindex == "
|
||||
"MAX_DEMO_PACKET_ENTITIES");
|
||||
newp->entities[newindex] = oldp->entities[oldindex];
|
||||
newindex++;
|
||||
oldindex++;
|
||||
oldnum = oldp->ent_nums[oldindex];
|
||||
copy_state (newp, oldp, newindex++, oldindex++, oldnum);
|
||||
}
|
||||
break;
|
||||
}
|
||||
newnum = word & 511;
|
||||
oldnum = oldindex >= oldp->num_entities ? 9999 :
|
||||
oldp->entities[oldindex].number;
|
||||
oldp->ent_nums[oldindex];
|
||||
|
||||
while (newnum > oldnum) {
|
||||
if (full) {
|
||||
|
@ -268,15 +277,14 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
if (newindex >= MAX_DEMO_PACKET_ENTITIES)
|
||||
Host_Error ("CL_ParsePacketEntities: newindex == "
|
||||
"MAX_DEMO_PACKET_ENTITIES");
|
||||
newp->entities[newindex] = oldp->entities[oldindex];
|
||||
newindex++;
|
||||
oldindex++;
|
||||
copy_state (newp, oldp, newindex++, oldindex++, oldnum);
|
||||
oldnum = oldindex >= oldp->num_entities ? 9999 :
|
||||
oldp->entities[oldindex].number;
|
||||
oldp->ent_nums[oldindex];
|
||||
}
|
||||
|
||||
if (newnum < oldnum) { // new from baseline
|
||||
if (word & U_REMOVE) {
|
||||
cl_entity_valid[0][newnum] = 0;
|
||||
if (full) {
|
||||
cl.validsequence = 0;
|
||||
Sys_Printf ("WARNING: U_REMOVE on full update\n");
|
||||
|
@ -290,8 +298,9 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
Host_Error ("CL_ParsePacketEntities: newindex == "
|
||||
"MAX_DEMO_PACKET_ENTITIES");
|
||||
CL_ParseDelta (&qw_entstates.baseline[newnum],
|
||||
&newp->entities[newindex],
|
||||
word);
|
||||
&newp->entities[newnum], word);
|
||||
newp->ent_nums[newindex] = newnum;
|
||||
cl_entity_valid[0][newnum] = 1;
|
||||
newindex++;
|
||||
continue;
|
||||
}
|
||||
|
@ -302,20 +311,20 @@ CL_ParsePacketEntities (qboolean delta)
|
|||
Sys_Printf ("WARNING: delta on full update");
|
||||
}
|
||||
if (word & U_REMOVE) { // Clear the entity
|
||||
entity_t *ent = &cl_entities[newnum];
|
||||
if (ent->efrag)
|
||||
r_funcs->R_RemoveEfrags (ent);
|
||||
memset (ent, 0, sizeof (entity_t));
|
||||
cl_entity_valid[0][newnum] = 0;
|
||||
oldindex++;
|
||||
continue;
|
||||
}
|
||||
CL_ParseDelta (&oldp->entities[oldindex],
|
||||
&newp->entities[newindex], word);
|
||||
CL_ParseDelta (&oldp->entities[oldnum],
|
||||
&newp->entities[newnum], word);
|
||||
newp->ent_nums[newindex] = newnum;
|
||||
cl_entity_valid[0][newnum] = 1;
|
||||
newindex++;
|
||||
oldindex++;
|
||||
}
|
||||
}
|
||||
|
||||
cl.num_entities = max (cl.num_entities, newnum);
|
||||
newp->num_entities = newindex;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "qw/msg_ucmd.h"
|
||||
|
||||
#include "qw/bothdefs.h"
|
||||
#include "chase.h"
|
||||
#include "cl_cam.h"
|
||||
#include "cl_ents.h"
|
||||
#include "cl_main.h"
|
||||
|
@ -60,6 +61,7 @@
|
|||
entity_t cl_player_ents[MAX_CLIENTS];
|
||||
entity_t cl_flag_ents[MAX_CLIENTS];
|
||||
entity_t cl_entities[512]; // FIXME: magic number
|
||||
byte cl_entity_valid[2][512];
|
||||
|
||||
void
|
||||
CL_ClearEnts (void)
|
||||
|
@ -68,6 +70,7 @@ CL_ClearEnts (void)
|
|||
|
||||
i = qw_entstates.num_frames * qw_entstates.num_entities;
|
||||
memset (qw_entstates.frame[0], 0, i * sizeof (entity_state_t));
|
||||
memset (cl_entity_valid, 0, sizeof (cl_entity_valid));
|
||||
for (i = 0; i < sizeof (cl_entities) / sizeof (cl_entities[0]); i++)
|
||||
CL_Init_Entity (&cl_entities[i]);
|
||||
for (i = 0; i < sizeof (cl_flag_ents) / sizeof (cl_flag_ents[0]); i++)
|
||||
|
@ -232,90 +235,163 @@ CL_ModelEffects (entity_t *ent, int num, int glow_color)
|
|||
r_funcs->particles->R_GlowTrail (ent, glow_color);
|
||||
}
|
||||
|
||||
static void
|
||||
set_entity_model (entity_t *ent, int modelindex)
|
||||
{
|
||||
ent->model = cl.model_precache[modelindex];
|
||||
// automatic animation (torches, etc) can be either all together
|
||||
// or randomized
|
||||
if (ent->model) {
|
||||
if (ent->model->synctype == ST_RAND)
|
||||
ent->syncbase = (float) (rand () & 0x7fff) / 0x7fff;
|
||||
else
|
||||
ent->syncbase = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CL_LinkPacketEntities (void)
|
||||
{
|
||||
int pnum;
|
||||
entity_t *ent;
|
||||
entity_state_t *s1;
|
||||
model_t *model;
|
||||
packet_entities_t *pack;
|
||||
int i, j, forcelink;
|
||||
float frac, f;
|
||||
entity_t *ent;
|
||||
entity_state_t *new, *old;
|
||||
vec3_t delta;
|
||||
|
||||
pack = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK].packet_entities;
|
||||
|
||||
for (pnum = 0; pnum < pack->num_entities; pnum++) {
|
||||
s1 = &pack->entities[pnum];
|
||||
frac = 1;
|
||||
for (i = 0; i < 512; i++) {
|
||||
new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i];
|
||||
old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i];
|
||||
ent = &cl_entities[i];
|
||||
forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i];
|
||||
cl_entity_valid[1][i] = cl_entity_valid[0][i];
|
||||
// if the object wasn't included in the last packet, remove it
|
||||
if (!cl_entity_valid[0][i]) {
|
||||
ent->model = NULL;
|
||||
ent->pose1 = ent->pose2 = -1;
|
||||
if (ent->efrag)
|
||||
r_funcs->R_RemoveEfrags (ent); // just became empty
|
||||
continue;
|
||||
}
|
||||
|
||||
// spawn light flashes, even ones coming from invisible objects
|
||||
CL_NewDlight (s1->number, s1->origin, s1->effects, s1->glow_size,
|
||||
s1->glow_color);
|
||||
|
||||
ent = &cl_entities[s1->number];
|
||||
CL_NewDlight (i, new->origin, new->effects, new->glow_size,
|
||||
new->glow_color);
|
||||
|
||||
// if set to invisible, skip
|
||||
if (!s1->modelindex
|
||||
|| (cl_deadbodyfilter->int_val && is_dead_body (s1))
|
||||
|| (cl_gibfilter->int_val && is_gib (s1))) {
|
||||
if (!new->modelindex
|
||||
|| (cl_deadbodyfilter->int_val && is_dead_body (new))
|
||||
|| (cl_gibfilter->int_val && is_gib (new))) {
|
||||
if (ent->efrag)
|
||||
r_funcs->R_RemoveEfrags (ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
ent->model = model = cl.model_precache[s1->modelindex];
|
||||
if (forcelink)
|
||||
*old = *new;
|
||||
|
||||
if (forcelink || new->modelindex != old->modelindex) {
|
||||
old->modelindex = new->modelindex;
|
||||
set_entity_model (ent, new->modelindex);
|
||||
}
|
||||
ent->frame = new->frame;
|
||||
if (forcelink || new->colormap != old->colormap
|
||||
|| new->skinnum != old->skinnum) {
|
||||
old->skinnum = new->skinnum;
|
||||
ent->skinnum = new->skinnum;
|
||||
old->colormap = new->colormap;
|
||||
if (new->colormap && (new->colormap <= MAX_CLIENTS)
|
||||
&& cl.players[new->colormap - 1].name
|
||||
&& cl.players[new->colormap - 1].name->value[0]) {
|
||||
player_info_t *player = &cl.players[new->colormap - 1];
|
||||
ent->skin = mod_funcs->Skin_SetSkin (ent->skin, new->colormap,
|
||||
player->skinname->value);
|
||||
ent->skin = mod_funcs->Skin_SetColormap (ent->skin,
|
||||
new->colormap);
|
||||
} else {
|
||||
ent->skin = mod_funcs->Skin_SetColormap (ent->skin, 0);
|
||||
}
|
||||
}
|
||||
ent->scale = new->scale / 16.0;
|
||||
|
||||
VectorCopy (ent_colormod[new->colormod], ent->colormod);
|
||||
ent->colormod[3] = new->alpha / 255.0;
|
||||
|
||||
ent->min_light = 0;
|
||||
ent->fullbright = 0;
|
||||
|
||||
if (s1->modelindex == cl_playerindex) {
|
||||
if (new->modelindex == cl_playerindex) {
|
||||
ent->min_light = min (cl.fbskins, cl_fb_players->value);
|
||||
if (ent->min_light >= 1.0)
|
||||
ent->fullbright = 1;
|
||||
}
|
||||
|
||||
// set colormap
|
||||
ent->skin = s1->skin;
|
||||
|
||||
VectorCopy (ent_colormod[s1->colormod], ent->colormod);
|
||||
ent->colormod[3] = s1->alpha / 255.0;
|
||||
ent->scale = s1->scale / 16.0;
|
||||
// Ender: Extend (Colormod) [QSG - End]
|
||||
|
||||
// set skin
|
||||
ent->skinnum = s1->skinnum;
|
||||
|
||||
// set frame
|
||||
ent->frame = s1->frame;
|
||||
|
||||
if (!ent->efrag) {
|
||||
if (forcelink) {
|
||||
ent->pose1 = ent->pose2 = -1;
|
||||
|
||||
// No trail if new this frame
|
||||
VectorCopy (s1->origin, ent->origin);
|
||||
VectorCopy (new->origin, ent->origin);
|
||||
if (!(ent->model->flags & EF_ROTATE))
|
||||
CL_TransformEntity (ent, new->angles, true);
|
||||
if (i != cl.viewentity || chase_active->int_val) {
|
||||
if (ent->efrag)
|
||||
r_funcs->R_RemoveEfrags (ent);
|
||||
r_funcs->R_AddEfrags (ent);
|
||||
}
|
||||
VectorCopy (ent->origin, ent->old_origin);
|
||||
} else {
|
||||
f = frac;
|
||||
VectorCopy (ent->origin, ent->old_origin);
|
||||
VectorCopy (s1->origin, ent->origin);
|
||||
if (!VectorCompare (ent->origin, ent->old_origin)) {
|
||||
// the entity moved, it must be relinked
|
||||
r_funcs->R_RemoveEfrags (ent);
|
||||
VectorSubtract (new->origin, old->origin, delta);
|
||||
// If the delta is large, assume a teleport and don't lerp
|
||||
if (fabs (delta[0]) > 100 || fabs (delta[1] > 100)
|
||||
|| fabs (delta[2]) > 100) {
|
||||
// assume a teleportation, not a motion
|
||||
VectorCopy (new->origin, ent->origin);
|
||||
if (!(ent->model->flags & EF_ROTATE))
|
||||
CL_TransformEntity (ent, new->angles, true);
|
||||
ent->pose1 = ent->pose2 = -1;
|
||||
} else {
|
||||
vec3_t angles, d;
|
||||
// interpolate the origin and angles
|
||||
VectorMultAdd (old->origin, f, delta, ent->origin);
|
||||
if (!(ent->model->flags & EF_ROTATE)) {
|
||||
VectorSubtract (new->angles, old->angles, d);
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (d[j] > 180)
|
||||
d[j] -= 360;
|
||||
else if (d[j] < -180)
|
||||
d[j] += 360;
|
||||
}
|
||||
VectorMultAdd (old->angles, f, d, angles);
|
||||
CL_TransformEntity (ent, angles, false);
|
||||
}
|
||||
}
|
||||
if (i != cl.viewentity || chase_active->int_val) {
|
||||
if (ent->efrag) {
|
||||
if (!VectorCompare (ent->origin, ent->old_origin)) {
|
||||
r_funcs->R_RemoveEfrags (ent);
|
||||
r_funcs->R_AddEfrags (ent);
|
||||
}
|
||||
} else {
|
||||
r_funcs->R_AddEfrags (ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ent->efrag)
|
||||
r_funcs->R_AddEfrags (ent);
|
||||
|
||||
// rotate binary objects locally
|
||||
if (model->flags & EF_ROTATE) {
|
||||
if (ent->model->flags & EF_ROTATE) {
|
||||
vec3_t angles;
|
||||
angles[PITCH] = 0;
|
||||
angles[YAW] = anglemod (100 * cl.time);
|
||||
angles[ROLL] = 0;
|
||||
CL_TransformEntity (ent, angles, false);
|
||||
} else {
|
||||
CL_TransformEntity (ent, s1->angles, false);
|
||||
}
|
||||
|
||||
if (model->flags & ~EF_ROTATE)
|
||||
CL_ModelEffects (ent, -s1->number, s1->glow_color);
|
||||
//CL_EntityEffects (i, ent, new);
|
||||
//CL_NewDlight (i, ent->origin, new->effects, 0, 0);
|
||||
if (VectorDistance_fast (old->origin, ent->origin) > (256 * 256))
|
||||
VectorCopy (ent->origin, old->origin);
|
||||
if (ent->model->flags & ~EF_ROTATE)
|
||||
CL_ModelEffects (ent, -new->number, new->glow_color);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue