[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;
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)
{
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;
}

View file

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

View file

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

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

View file

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

View file

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

View file

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