From 0e64f959e2b50418417b01930704e0318504bc58 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 13 Nov 2022 15:08:18 +0900 Subject: [PATCH] [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. --- include/QF/scene/entity.h | 2 +- libs/client/cl_temp_entities.c | 18 +------ libs/ruamoko/rua_scene.c | 4 +- libs/scene/scene.c | 11 +++- libs/video/renderer/r_efrag.c | 24 ++++----- nq/source/cl_ents.c | 48 +++++------------ nq/source/cl_main.c | 3 +- qw/source/cl_ents.c | 97 ++++++++++++++-------------------- 8 files changed, 80 insertions(+), 127 deletions(-) diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index 950c8b322..488d9ed02 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -146,7 +146,7 @@ Entity_Transform (entity_t ent) struct mod_brush_s; void R_AddEfrags (struct mod_brush_s *, entity_t ent); -void R_RemoveEfrags (entity_t ent); +void R_ClearEfragChain (efrag_t *ef); ///@} diff --git a/libs/client/cl_temp_entities.c b/libs/client/cl_temp_entities.c index aa25e33ba..9cd834d2b 100644 --- a/libs/client/cl_temp_entities.c +++ b/libs/client/cl_temp_entities.c @@ -157,12 +157,10 @@ void CL_Init_Entity (entity_t ent) { 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); 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); memset (animation, 0, sizeof (*animation)); - memset (visibility, 0, sizeof (*visibility)); memset (renderer, 0, sizeof (*renderer)); *active = 1; *old_origin = (vec4f_t) {0, 0, 0, 1}; @@ -223,11 +221,6 @@ static inline void beam_clear (beam_t *b) { if (b->tents) { - tent_t *t; - - for (t = b->tents; t; t = t->next) { - R_RemoveEfrags (t->ent); - } free_temp_entities (b->tents); b->tents = 0; } @@ -635,11 +628,9 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) ent = ex->tent->ent; f = 10 * (time - ex->start); 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); if (f >= renderer->model->numframes) { tent_obj_t *_to; - R_RemoveEfrags (ent); free_temp_entities (ex->tent); _to = *to; *to = _to->next; @@ -649,9 +640,7 @@ CL_UpdateExplosions (double time, TEntContext_t *ctx) to = &(*to)->next; 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 CL_ClearProjectiles (void) { - tent_t *tent; - - for (tent = cl_projectiles; tent; tent = tent->next) { - R_RemoveEfrags (tent->ent); - } free_temp_entities (cl_projectiles); cl_projectiles = 0; } diff --git a/libs/ruamoko/rua_scene.c b/libs/ruamoko/rua_scene.c index 210e19be5..0993480a2 100644 --- a/libs/ruamoko/rua_scene.c +++ b/libs/ruamoko/rua_scene.c @@ -259,7 +259,6 @@ bi_Scene_DestroyEntity (progs_t *pr, void *_res) pr_ulong_t scene_id = id & 0xffffffff; rua_scene_t *scene = rua_scene_get (res, scene_id); - R_RemoveEfrags (ent); // bad scene caught above Scene_DestroyEntity (scene->scene, ent); } @@ -301,8 +300,7 @@ bi_Entity_SetModel (progs_t *pr, void *_res) // bad scene caught above rua_scene_t *scene = rua_scene_get (res, scene_id); - R_RemoveEfrags (ent); - renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, scene->scene->reg); + renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg); renderer->model = model; R_AddEfrags (&scene->scene->worldmodel->brush, ent); } diff --git a/libs/scene/scene.c b/libs/scene/scene.c index 3dabbe941..90266d160 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -59,6 +59,15 @@ create_old_origin (void *_old_origin) *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 sw_identity_matrix (void *_mat) { @@ -94,6 +103,7 @@ static const component_t scene_components[] = { [scene_visibility] = { .size = sizeof (visibility_t), .create = 0,//create_visibility, + .destroy = destroy_visibility, .name = "visibility", }, [scene_renderer] = { @@ -219,7 +229,6 @@ Scene_CreateEntity (scene_t *scene) uint32_t id = trans.id; 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_active, scene->reg, 0); Ent_SetComponent (id, scene_old_origin, scene->reg, 0); diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index 3c9845906..89f919358 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -95,18 +95,10 @@ R_ClearEfrags (void) } } -/* - R_RemoveEfrags - - Call when removing an object from the world or moving it to another position -*/ void -R_RemoveEfrags (entity_t ent) +R_ClearEfragChain (efrag_t *ef) { - efrag_t *ef, *old, *walk, **prev; - visibility_t *vis = Ent_GetComponent (ent.id, scene_visibility, ent.reg); - - ef = vis->efrag; + efrag_t *old, *walk, **prev; while (ef) { prev = &ef->leaf->efrags; @@ -128,8 +120,6 @@ R_RemoveEfrags (entity_t ent) old->entnext = r_free_efrags; r_free_efrags = old; } - - vis->efrag = 0; } static void @@ -210,11 +200,19 @@ R_AddEfrags (mod_brush_t *brush, entity_t ent) vec3_t emins, emaxs; transform_t transform = Entity_Transform (ent); 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) { + Ent_RemoveComponent (ent.id, scene_visibility, ent.reg); 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; diff --git a/nq/source/cl_ents.c b/nq/source/cl_ents.c index a5db5d3e6..2545ec02e 100644 --- a/nq/source/cl_ents.c +++ b/nq/source/cl_ents.c @@ -147,8 +147,8 @@ static void set_entity_model (int ent_ind, int modelindex) { entity_t ent = cl_entities[ent_ind]; - 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); + renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg); + animation_t *animation = Ent_GetComponent (ent.id, scene_animation, ent.reg); renderer->model = cl_world.models.a[modelindex]; // automatic animation (torches, etc) can be either all together // or randomized @@ -158,10 +158,10 @@ set_entity_model (int ent_ind, int modelindex) } else { 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 if (ent_ind <= cl.maxclients) { renderer->skin = mod_funcs->Skin_SetColormap (renderer->skin, ent_ind); @@ -175,7 +175,6 @@ CL_RelinkEntities (void) entity_state_t *new, *old; float bobjrotate, frac, f; int i, j; - int entvalid; int model_flags; // determine partial update time @@ -207,31 +206,23 @@ CL_RelinkEntities (void) new = &nq_entstates.frame[0 + cl.frameIndex][i]; old = &nq_entstates.frame[1 - cl.frameIndex][i]; - // if the object wasn't included in the last packet, remove it - entvalid = cl_msgtime[i] == cl.mtime[0]; - if (entvalid && !new->modelindex) { - ent = CL_GetEntity (i); - CL_TransformEntity (ent, new->scale / 16.0, new->angles, - new->origin); - entvalid = 0; - } - if (!entvalid) { - ent = CL_GetInvalidEntity (i); + ent = CL_GetInvalidEntity (i); + // if the object wasn't included in the last packet, or the model + // has been removed, remove the entity + if (cl_msgtime[i] != cl.mtime[0] || !new->modelindex) { 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); } continue; } - ent = CL_GetEntity (i); + if (!Entity_Valid (ent)) { + ent = CL_GetEntity (i); + SET_ADD (&cl_forcelink, i); + } 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); - visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, ent.reg); vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, ent.reg); if (SET_TEST_MEMBER (&cl_forcelink, i)) { @@ -242,9 +233,6 @@ CL_RelinkEntities (void) || new->modelindex != old->modelindex) { old->modelindex = new->modelindex; set_entity_model (i, new->modelindex); - if (visibility->efrag) { - R_RemoveEfrags (ent); - } } animation->frame = new->frame; if (SET_TEST_MEMBER (&cl_forcelink, i) @@ -280,9 +268,6 @@ CL_RelinkEntities (void) CL_TransformEntity (ent, new->scale / 16.0, new->angles, new->origin); if (i != cl.viewentity || chase_active) { - if (visibility->efrag) { - R_RemoveEfrags (ent); - } R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } *old_origin = new->origin; @@ -315,12 +300,7 @@ CL_RelinkEntities (void) } if (i != cl.viewentity || chase_active) { vec4f_t org = Transform_GetWorldPosition (transform); - if (visibility->efrag) { - if (!VectorCompare (org, *old_origin)) {//FIXME - R_RemoveEfrags (ent); - R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); - } - } else { + if (!VectorCompare (org, *old_origin)) {//FIXME R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 267438cf3..e51f0884b 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -234,10 +234,9 @@ CL_ClearMemory (void) cl.viewstate.demoplayback = cls.demoplayback; CL_ClearTEnts (); + CL_ClearEnts (); SCR_NewScene (0); - - CL_ClearEnts (); } void diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index ef8eb3ec6..467fcce23 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -89,6 +89,12 @@ CL_ClearEnts (void) memset (cl_entity_valid, 0, sizeof (cl_entity_valid)); } +static entity_t +CL_GetInvalidEntity (int num) +{ + return cl_entities[num]; +} + entity_t CL_GetEntity (int num) { @@ -163,42 +169,37 @@ CL_LinkPacketEntities (void) for (i = MAX_CLIENTS + 1; 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_GetEntity (i); - transform_t transform = Entity_Transform (ent); - 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); + + ent = CL_GetInvalidEntity (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]) { - renderer->model = NULL; - animation->pose1 = animation->pose2 = -1; - if (visibility->efrag) { - R_RemoveEfrags (ent); // just became empty + // if the object wasn't included in the last packet, or set + // to invisible, remove it + if (!cl_entity_valid[0][i] + || !new->modelindex + || (cl_deadbodyfilter && is_dead_body (new)) + || (cl_gibfilter && is_gib (new))) { + if (Entity_Valid (ent)) { + Scene_DestroyEntity (cl_world.scene, ent); } 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 CL_NewDlight (i, new->origin, new->effects, new->glow_size, 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) *old = *new; @@ -246,9 +247,6 @@ CL_LinkPacketEntities (void) CL_TransformEntity (ent, new->scale / 16, new->angles, new->origin); if (i != cl.viewentity || chase_active) { - if (visibility->efrag) { - R_RemoveEfrags (ent); - } R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } else { @@ -277,19 +275,11 @@ CL_LinkPacketEntities (void) } if (i != cl.viewentity || chase_active) { vec4f_t org = Transform_GetWorldPosition (transform); - if (visibility->efrag) { - if (!VectorCompare (org, *old_origin)) {//FIXME - R_RemoveEfrags (ent); - R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); - } - } else { + if (!VectorCompare (org, *old_origin)) {//FIXME R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); } } } - if (!visibility->efrag) { - R_AddEfrags (&cl_world.scene->worldmodel->brush, ent); - } // rotate binary objects locally if (renderer->model->flags & EF_ROTATE) { @@ -420,28 +410,23 @@ CL_LinkPlayers (void) for (j = 0, player = cl.players, state = frame->playerstate; j < MAX_CLIENTS; j++, player++, state++) { - ent = CL_GetEntity (j + 1); - visibility_t *visibility = Ent_GetComponent (ent.id, scene_visibility, - cl_world.scene->reg); + ent = CL_GetInvalidEntity (j + 1); + if (state->messagenum != cl.parsecount + || !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, cl_world.scene->reg); animation_t *animation = Ent_GetComponent (ent.id, scene_animation, 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 if (j == cl.playernum) {