[scene] Move visibility management into scene code

Well, sort of: it's still really in the renderer, but now calling
R_AddEfrags automatically updates the visibility structure as necessary,
and deleting an entity cleans up the efrags automatically. I wanted this
over twenty years ago.
This commit is contained in:
Bill Currie 2022-11-13 15:08:18 +09:00
parent 88e59e72c4
commit 0e64f959e2
8 changed files with 80 additions and 127 deletions

View file

@ -146,7 +146,7 @@ Entity_Transform (entity_t ent)
struct mod_brush_s; struct mod_brush_s;
void R_AddEfrags (struct mod_brush_s *, entity_t ent); void R_AddEfrags (struct mod_brush_s *, entity_t ent);
void R_RemoveEfrags (entity_t ent); void R_ClearEfragChain (efrag_t *ef);
///@} ///@}

View file

@ -157,12 +157,10 @@ void
CL_Init_Entity (entity_t ent) CL_Init_Entity (entity_t ent)
{ {
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, cl_world.scene->reg); renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, cl_world.scene->reg);
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, cl_world.scene->reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation, cl_world.scene->reg); animation_t *animation = Ent_GetComponent (ent.id, scene_animation, cl_world.scene->reg);
byte *active = Ent_GetComponent (ent.id, scene_active, cl_world.scene->reg); byte *active = Ent_GetComponent (ent.id, scene_active, cl_world.scene->reg);
vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, cl_world.scene->reg); vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, cl_world.scene->reg);
memset (animation, 0, sizeof (*animation)); memset (animation, 0, sizeof (*animation));
memset (visibility, 0, sizeof (*visibility));
memset (renderer, 0, sizeof (*renderer)); memset (renderer, 0, sizeof (*renderer));
*active = 1; *active = 1;
*old_origin = (vec4f_t) {0, 0, 0, 1}; *old_origin = (vec4f_t) {0, 0, 0, 1};
@ -223,11 +221,6 @@ static inline void
beam_clear (beam_t *b) beam_clear (beam_t *b)
{ {
if (b->tents) { if (b->tents) {
tent_t *t;
for (t = b->tents; t; t = t->next) {
R_RemoveEfrags (t->ent);
}
free_temp_entities (b->tents); free_temp_entities (b->tents);
b->tents = 0; b->tents = 0;
} }
@ -635,11 +628,9 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx)
ent = ex->tent->ent; ent = ex->tent->ent;
f = 10 * (time - ex->start); f = 10 * (time - ex->start);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, cl_world.scene->reg); renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, cl_world.scene->reg);
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, cl_world.scene->reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation, cl_world.scene->reg); animation_t *animation = Ent_GetComponent (ent.id, scene_animation, cl_world.scene->reg);
if (f >= renderer->model->numframes) { if (f >= renderer->model->numframes) {
tent_obj_t *_to; tent_obj_t *_to;
R_RemoveEfrags (ent);
free_temp_entities (ex->tent); free_temp_entities (ex->tent);
_to = *to; _to = *to;
*to = _to->next; *to = _to->next;
@ -649,9 +640,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx)
to = &(*to)->next; to = &(*to)->next;
animation->frame = f; animation->frame = f;
if (!visibility->efrag) { R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
}
} }
} }
@ -688,11 +677,6 @@ CL_ParseParticleEffect (qmsg_t *net_message)
void void
CL_ClearProjectiles (void) CL_ClearProjectiles (void)
{ {
tent_t *tent;
for (tent = cl_projectiles; tent; tent = tent->next) {
R_RemoveEfrags (tent->ent);
}
free_temp_entities (cl_projectiles); free_temp_entities (cl_projectiles);
cl_projectiles = 0; cl_projectiles = 0;
} }

View file

@ -259,7 +259,6 @@ bi_Scene_DestroyEntity (progs_t *pr, void *_res)
pr_ulong_t scene_id = id & 0xffffffff; pr_ulong_t scene_id = id & 0xffffffff;
rua_scene_t *scene = rua_scene_get (res, scene_id); rua_scene_t *scene = rua_scene_get (res, scene_id);
R_RemoveEfrags (ent);
// bad scene caught above // bad scene caught above
Scene_DestroyEntity (scene->scene, ent); Scene_DestroyEntity (scene->scene, ent);
} }
@ -301,8 +300,7 @@ bi_Entity_SetModel (progs_t *pr, void *_res)
// bad scene caught above // bad scene caught above
rua_scene_t *scene = rua_scene_get (res, scene_id); rua_scene_t *scene = rua_scene_get (res, scene_id);
R_RemoveEfrags (ent); renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, scene->scene->reg);
renderer->model = model; renderer->model = model;
R_AddEfrags (&scene->scene->worldmodel->brush, ent); R_AddEfrags (&scene->scene->worldmodel->brush, ent);
} }

View file

@ -59,6 +59,15 @@ create_old_origin (void *_old_origin)
*old_origin = (vec4f_t) {0, 0, 0, 1}; *old_origin = (vec4f_t) {0, 0, 0, 1};
} }
static void
destroy_visibility (void *_visibility)
{
visibility_t *visibility = _visibility;
if (visibility->efrag) {
R_ClearEfragChain (visibility->efrag);
}
}
static void static void
sw_identity_matrix (void *_mat) sw_identity_matrix (void *_mat)
{ {
@ -94,6 +103,7 @@ static const component_t scene_components[] = {
[scene_visibility] = { [scene_visibility] = {
.size = sizeof (visibility_t), .size = sizeof (visibility_t),
.create = 0,//create_visibility, .create = 0,//create_visibility,
.destroy = destroy_visibility,
.name = "visibility", .name = "visibility",
}, },
[scene_renderer] = { [scene_renderer] = {
@ -219,7 +229,6 @@ Scene_CreateEntity (scene_t *scene)
uint32_t id = trans.id; uint32_t id = trans.id;
Ent_SetComponent (id, scene_animation, scene->reg, 0); Ent_SetComponent (id, scene_animation, scene->reg, 0);
Ent_SetComponent (id, scene_visibility, scene->reg, 0);
Ent_SetComponent (id, scene_renderer, scene->reg, 0); Ent_SetComponent (id, scene_renderer, scene->reg, 0);
Ent_SetComponent (id, scene_active, scene->reg, 0); Ent_SetComponent (id, scene_active, scene->reg, 0);
Ent_SetComponent (id, scene_old_origin, scene->reg, 0); Ent_SetComponent (id, scene_old_origin, scene->reg, 0);

View file

@ -95,18 +95,10 @@ R_ClearEfrags (void)
} }
} }
/*
R_RemoveEfrags
Call when removing an object from the world or moving it to another position
*/
void void
R_RemoveEfrags (entity_t ent) R_ClearEfragChain (efrag_t *ef)
{ {
efrag_t *ef, *old, *walk, **prev; efrag_t *old, *walk, **prev;
visibility_t *vis = Ent_GetComponent (ent.id, scene_visibility, ent.reg);
ef = vis->efrag;
while (ef) { while (ef) {
prev = &ef->leaf->efrags; prev = &ef->leaf->efrags;
@ -128,8 +120,6 @@ R_RemoveEfrags (entity_t ent)
old->entnext = r_free_efrags; old->entnext = r_free_efrags;
r_free_efrags = old; r_free_efrags = old;
} }
vis->efrag = 0;
} }
static void static void
@ -210,11 +200,19 @@ R_AddEfrags (mod_brush_t *brush, entity_t ent)
vec3_t emins, emaxs; vec3_t emins, emaxs;
transform_t transform = Entity_Transform (ent); transform_t transform = Entity_Transform (ent);
renderer_t *rend = Ent_GetComponent (ent.id, scene_renderer, ent.reg); renderer_t *rend = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
visibility_t *vis = Ent_GetComponent (ent.id, scene_visibility, ent.reg);
if (!rend->model) { if (!rend->model) {
Ent_RemoveComponent (ent.id, scene_visibility, ent.reg);
return; return;
} }
visibility_t *vis;
if (Ent_HasComponent (ent.id, scene_visibility, ent.reg)) {
vis = Ent_GetComponent (ent.id, scene_visibility, ent.reg);
R_ClearEfragChain (vis->efrag);
} else {
vis = Ent_AddComponent (ent.id, scene_visibility, ent.reg);
}
vis->efrag = 0;
entmodel = rend->model; entmodel = rend->model;

View file

@ -147,8 +147,8 @@ static void
set_entity_model (int ent_ind, int modelindex) set_entity_model (int ent_ind, int modelindex)
{ {
entity_t ent = cl_entities[ent_ind]; entity_t ent = cl_entities[ent_ind];
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, cl_world.scene->reg); renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation, cl_world.scene->reg); animation_t *animation = Ent_GetComponent (ent.id, scene_animation, ent.reg);
renderer->model = cl_world.models.a[modelindex]; renderer->model = cl_world.models.a[modelindex];
// automatic animation (torches, etc) can be either all together // automatic animation (torches, etc) can be either all together
// or randomized // or randomized
@ -158,10 +158,10 @@ set_entity_model (int ent_ind, int modelindex)
} else { } else {
animation->syncbase = 0.0; animation->syncbase = 0.0;
} }
} else {
// hack to make null model players work
SET_ADD (&cl_forcelink, ent_ind);
} }
// Changing the model can change the visibility of the entity and even
// the model type
SET_ADD (&cl_forcelink, ent_ind);
animation->nolerp = 1; // don't try to lerp when the model has changed animation->nolerp = 1; // don't try to lerp when the model has changed
if (ent_ind <= cl.maxclients) { if (ent_ind <= cl.maxclients) {
renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, ent_ind); renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, ent_ind);
@ -175,7 +175,6 @@ CL_RelinkEntities (void)
entity_state_t *new, *old; entity_state_t *new, *old;
float bobjrotate, frac, f; float bobjrotate, frac, f;
int i, j; int i, j;
int entvalid;
int model_flags; int model_flags;
// determine partial update time // determine partial update time
@ -207,31 +206,23 @@ CL_RelinkEntities (void)
new = &nq_entstates.frame[0 + cl.frameIndex][i]; new = &nq_entstates.frame[0 + cl.frameIndex][i];
old = &nq_entstates.frame[1 - cl.frameIndex][i]; old = &nq_entstates.frame[1 - cl.frameIndex][i];
// if the object wasn't included in the last packet, remove it ent = CL_GetInvalidEntity (i);
entvalid = cl_msgtime[i] == cl.mtime[0]; // if the object wasn't included in the last packet, or the model
if (entvalid && !new->modelindex) { // has been removed, remove the entity
ent = CL_GetEntity (i); if (cl_msgtime[i] != cl.mtime[0] || !new->modelindex) {
CL_TransformEntity (ent, new->scale / 16.0, new->angles,
new->origin);
entvalid = 0;
}
if (!entvalid) {
ent = CL_GetInvalidEntity (i);
if (Entity_Valid (ent)) { if (Entity_Valid (ent)) {
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, ent.reg);
if (visibility->efrag) {
R_RemoveEfrags (ent); // just became empty
}
Scene_DestroyEntity (cl_world.scene, ent); Scene_DestroyEntity (cl_world.scene, ent);
} }
continue; continue;
} }
ent = CL_GetEntity (i); if (!Entity_Valid (ent)) {
ent = CL_GetEntity (i);
SET_ADD (&cl_forcelink, i);
}
transform_t transform = Entity_Transform (ent); transform_t transform = Entity_Transform (ent);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg); renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation, ent.reg); animation_t *animation = Ent_GetComponent (ent.id, scene_animation, ent.reg);
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, ent.reg);
vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, ent.reg); vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, ent.reg);
if (SET_TEST_MEMBER (&cl_forcelink, i)) { if (SET_TEST_MEMBER (&cl_forcelink, i)) {
@ -242,9 +233,6 @@ CL_RelinkEntities (void)
|| new->modelindex != old->modelindex) { || new->modelindex != old->modelindex) {
old->modelindex = new->modelindex; old->modelindex = new->modelindex;
set_entity_model (i, new->modelindex); set_entity_model (i, new->modelindex);
if (visibility->efrag) {
R_RemoveEfrags (ent);
}
} }
animation->frame = new->frame; animation->frame = new->frame;
if (SET_TEST_MEMBER (&cl_forcelink, i) if (SET_TEST_MEMBER (&cl_forcelink, i)
@ -280,9 +268,6 @@ CL_RelinkEntities (void)
CL_TransformEntity (ent, new->scale / 16.0, new->angles, CL_TransformEntity (ent, new->scale / 16.0, new->angles,
new->origin); new->origin);
if (i != cl.viewentity || chase_active) { if (i != cl.viewentity || chase_active) {
if (visibility->efrag) {
R_RemoveEfrags (ent);
}
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
} }
*old_origin = new->origin; *old_origin = new->origin;
@ -315,12 +300,7 @@ CL_RelinkEntities (void)
} }
if (i != cl.viewentity || chase_active) { if (i != cl.viewentity || chase_active) {
vec4f_t org = Transform_GetWorldPosition (transform); vec4f_t org = Transform_GetWorldPosition (transform);
if (visibility->efrag) { if (!VectorCompare (org, *old_origin)) {//FIXME
if (!VectorCompare (org, *old_origin)) {//FIXME
R_RemoveEfrags (ent);
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
}
} else {
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
} }
} }

View file

@ -234,10 +234,9 @@ CL_ClearMemory (void)
cl.viewstate.demoplayback = cls.demoplayback; cl.viewstate.demoplayback = cls.demoplayback;
CL_ClearTEnts (); CL_ClearTEnts ();
CL_ClearEnts ();
SCR_NewScene (0); SCR_NewScene (0);
CL_ClearEnts ();
} }
void void

View file

@ -89,6 +89,12 @@ CL_ClearEnts (void)
memset (cl_entity_valid, 0, sizeof (cl_entity_valid)); memset (cl_entity_valid, 0, sizeof (cl_entity_valid));
} }
static entity_t
CL_GetInvalidEntity (int num)
{
return cl_entities[num];
}
entity_t entity_t
CL_GetEntity (int num) CL_GetEntity (int num)
{ {
@ -163,42 +169,37 @@ CL_LinkPacketEntities (void)
for (i = MAX_CLIENTS + 1; i < 512; i++) { for (i = MAX_CLIENTS + 1; i < 512; i++) {
new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i]; new = &qw_entstates.frame[cl.link_sequence & UPDATE_MASK][i];
old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i]; old = &qw_entstates.frame[cl.prev_sequence & UPDATE_MASK][i];
ent = CL_GetEntity (i);
transform_t transform = Entity_Transform (ent); ent = CL_GetInvalidEntity (i);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer,
cl_world.scene->reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
cl_world.scene->reg);
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility,
cl_world.scene->reg);
vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin,
cl_world.scene->reg);
forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i]; forcelink = cl_entity_valid[0][i] != cl_entity_valid[1][i];
cl_entity_valid[1][i] = cl_entity_valid[0][i]; cl_entity_valid[1][i] = cl_entity_valid[0][i];
// if the object wasn't included in the last packet, remove it // if the object wasn't included in the last packet, or set
if (!cl_entity_valid[0][i]) { // to invisible, remove it
renderer->model = NULL; if (!cl_entity_valid[0][i]
animation->pose1 = animation->pose2 = -1; || !new->modelindex
if (visibility->efrag) { || (cl_deadbodyfilter && is_dead_body (new))
R_RemoveEfrags (ent); // just became empty || (cl_gibfilter && is_gib (new))) {
if (Entity_Valid (ent)) {
Scene_DestroyEntity (cl_world.scene, ent);
} }
continue; continue;
} }
if (!Entity_Valid (ent)) {
ent = CL_GetEntity (i);
forcelink = true;
}
transform_t transform = Entity_Transform (ent);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer,
ent.reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
ent.reg);
vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin,
ent.reg);
// spawn light flashes, even ones coming from invisible objects // spawn light flashes, even ones coming from invisible objects
CL_NewDlight (i, new->origin, new->effects, new->glow_size, CL_NewDlight (i, new->origin, new->effects, new->glow_size,
new->glow_color, cl.time); new->glow_color, cl.time);
// if set to invisible, skip
if (!new->modelindex
|| (cl_deadbodyfilter && is_dead_body (new))
|| (cl_gibfilter && is_gib (new))) {
if (visibility->efrag) {
R_RemoveEfrags (ent);
}
continue;
}
if (forcelink) if (forcelink)
*old = *new; *old = *new;
@ -246,9 +247,6 @@ CL_LinkPacketEntities (void)
CL_TransformEntity (ent, new->scale / 16, new->angles, CL_TransformEntity (ent, new->scale / 16, new->angles,
new->origin); new->origin);
if (i != cl.viewentity || chase_active) { if (i != cl.viewentity || chase_active) {
if (visibility->efrag) {
R_RemoveEfrags (ent);
}
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
} }
} else { } else {
@ -277,19 +275,11 @@ CL_LinkPacketEntities (void)
} }
if (i != cl.viewentity || chase_active) { if (i != cl.viewentity || chase_active) {
vec4f_t org = Transform_GetWorldPosition (transform); vec4f_t org = Transform_GetWorldPosition (transform);
if (visibility->efrag) { if (!VectorCompare (org, *old_origin)) {//FIXME
if (!VectorCompare (org, *old_origin)) {//FIXME
R_RemoveEfrags (ent);
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
}
} else {
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
} }
} }
} }
if (!visibility->efrag) {
R_AddEfrags (&cl_world.scene->worldmodel->brush, ent);
}
// rotate binary objects locally // rotate binary objects locally
if (renderer->model->flags & EF_ROTATE) { if (renderer->model->flags & EF_ROTATE) {
@ -420,28 +410,23 @@ CL_LinkPlayers (void)
for (j = 0, player = cl.players, state = frame->playerstate; for (j = 0, player = cl.players, state = frame->playerstate;
j < MAX_CLIENTS; j++, player++, state++) { j < MAX_CLIENTS; j++, player++, state++) {
ent = CL_GetEntity (j + 1); ent = CL_GetInvalidEntity (j + 1);
visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, if (state->messagenum != cl.parsecount
cl_world.scene->reg); || !player->name || !player->name->value[0]) {
// not present this frame
if (Entity_Valid (ent)) {
Scene_DestroyEntity (cl_world.scene, ent);
}
continue;
}
if (!Entity_Valid (ent)) {
ent = CL_GetEntity (j + 1);
}
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer,
cl_world.scene->reg); cl_world.scene->reg);
animation_t *animation = Ent_GetComponent (ent.id, scene_animation, animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
cl_world.scene->reg); cl_world.scene->reg);
if (visibility->efrag)
R_RemoveEfrags (ent);
if (Entity_Valid (player->flag_ent)) {
visibility_t *fvis = Ent_GetComponent (player->flag_ent.id,
scene_visibility,
cl_world.scene->reg);
if (fvis->efrag) {
R_RemoveEfrags (player->flag_ent);
}
}
if (state->messagenum != cl.parsecount)
continue; // not present this frame
if (!player->name || !player->name->value[0])
continue;
// spawn light flashes, even ones coming from invisible objects // spawn light flashes, even ones coming from invisible objects
if (j == cl.playernum) { if (j == cl.playernum) {