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:
Bill Currie 2012-07-05 19:06:35 +09:00
parent 428d57b7e1
commit 66ef8e16c1
6 changed files with 169 additions and 82 deletions

View file

@ -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 {

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}
}