From 31cf4b0d78a39a67ccb82955ba24c8c03bbe95bc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 8 Dec 2010 08:44:52 +0900 Subject: [PATCH] Use a linked list for the leafs in which the entity is positioned. This allows the pvs to be used on an antity no matter how many leafs the entity is touching. Seems to work nicely, but it will leak memory every time a map is loaded. --- include/QF/progs.h | 9 ++++++--- nq/source/sv_main.c | 9 ++++++--- nq/source/world.c | 48 +++++++++++++++++++++++++++++++++++++-------- qw/source/sv_ents.c | 26 +++++++++++++----------- qw/source/world.c | 48 +++++++++++++++++++++++++++++++++++++-------- 5 files changed, 107 insertions(+), 33 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 7d81f415f..3c5506f39 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -214,13 +214,16 @@ void PR_BoundsCheck (progs_t *pr, int addr, etype_t type); */ //@{ -#define MAX_ENT_LEAFS 16 +typedef struct edict_leaf_s { + struct edict_leaf_s *next; + struct mleaf_s *leaf; +} edict_leaf_t; + struct edict_s { qboolean free; link_t area; ///< linked to a division node or leaf - int num_leafs; - short leafnums[MAX_ENT_LEAFS]; + edict_leaf_t *leafs; float freetime; ///< sv.time when the object was freed void *data; ///< external per-edict data diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index a8173f7d6..297c88eb5 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -443,6 +443,7 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) vec3_t org; edict_t *ent; entity_state_t *baseline; + edict_leaf_t *el; // find the client's PVS VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org); @@ -465,11 +466,13 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) && (int) SVfloat (ent, modelindex) & 0xFF00) continue; - for (i = 0; i < ent->num_leafs; i++) - if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7))) + for (el = ent->leafs; el; el = el->next) { + unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1; + if (pvs[leafnum >> 3] & (1 << (leafnum & 7))) break; + } - if (i == ent->num_leafs) + if (!el) continue; // not visible } diff --git a/nq/source/world.c b/nq/source/world.c index a88089415..98f4e44eb 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -50,6 +50,39 @@ static __attribute__ ((used)) const char rcsid[] = #include "sv_progs.h" #include "world.h" +#define EDICT_LEAFS 32 +static edict_leaf_t *free_edict_leaf_list; + +static edict_leaf_t * +alloc_edict_leaf (void) +{ + int i; + edict_leaf_t *edict_leaf; + + if (!free_edict_leaf_list) { + free_edict_leaf_list = malloc (EDICT_LEAFS * sizeof (edict_leaf_t)); + for (i = 0; i < EDICT_LEAFS - 1; i++) + free_edict_leaf_list[i].next = &free_edict_leaf_list[i + 1]; + free_edict_leaf_list[i].next = 0; + } + edict_leaf = free_edict_leaf_list; + free_edict_leaf_list = free_edict_leaf_list->next; + edict_leaf->next = 0; + return edict_leaf; +} + +static void +free_edict_leafs (edict_leaf_t **edict_leafs) +{ + edict_leaf_t **el; + + for (el = edict_leafs; *el; el = &(*el)->next) + ; + *el = free_edict_leaf_list; + free_edict_leaf_list = *edict_leafs; + *edict_leafs = 0; +} + /* entities never clip against themselves, or their owner line of sight checks trace->crosscontent, but bullets don't @@ -328,23 +361,22 @@ SV_TouchLinks (edict_t *ent, areanode_t *node) static void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) { - int leafnum, sides; + int sides; mleaf_t *leaf; mplane_t *splitplane; + edict_leaf_t *edict_leaf; if (node->contents == CONTENTS_SOLID) return; // add an efrag if the node is a leaf if (node->contents < 0) { - if (ent->num_leafs == MAX_ENT_LEAFS) - return; - leaf = (mleaf_t *) node; - leafnum = leaf - sv.worldmodel->leafs - 1; - ent->leafnums[ent->num_leafs] = leafnum; - ent->num_leafs++; + edict_leaf = alloc_edict_leaf (); + edict_leaf->leaf = leaf; + edict_leaf->next = ent->leafs; + ent->leafs = edict_leaf; return; } @@ -398,7 +430,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) } // link to PVS leafs - ent->num_leafs = 0; + free_edict_leafs (&ent->leafs); if (SVfloat (ent, modelindex)) SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index 35dbff317..ee124bfbc 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -553,12 +553,13 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to, static void SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) { - int i, j, k; + int j, k; client_t *cl; edict_t *clent = 0; int spec_track = 0; int stdver = 2, full = stdver; edict_t *ent; + edict_leaf_t *el; packet_players_t *pack; client_frame_t *frame = &delta->frames[delta->in_frame]; packet_players_t *from_pack = 0; @@ -614,11 +615,12 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) if (pvs) { // ignore if not touching a PV leaf - for (i = 0; i < ent->num_leafs; i++) - if (pvs[ent->leafnums[i] >> 3] - & (1 << (ent->leafnums[i] & 7))) + for (el = ent->leafs; el; el = el->next) { + unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1; + if (pvs[leafnum >> 3] & (1 << (leafnum & 7))) break; - if (i == ent->num_leafs) + } + if (!el) continue; // not visible } } @@ -759,11 +761,12 @@ void SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg) { byte *pvs = 0; - int e, i, num_edicts; + int e, num_edicts; int max_packet_entities = MAX_DEMO_PACKET_ENTITIES; int stdver = 1; client_frame_t *frame; edict_t *ent; + edict_leaf_t *el; entity_state_t *state; packet_entities_t *pack; @@ -801,12 +804,13 @@ SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg) if (pvs) { // ignore if not touching a PV leaf - for (i = 0; i < ent->num_leafs; i++) - if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7))) + for (el = ent->leafs; el; el = el->next) { + unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1; + if (pvs[leafnum >> 3] & (1 << (leafnum & 7))) break; - - if (i == ent->num_leafs) - continue; // not visible + } + if (!el) + continue; // not visible } if (SV_AddNailUpdate (ent)) diff --git a/qw/source/world.c b/qw/source/world.c index 4090b0d21..dbc44edd0 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -50,6 +50,39 @@ static __attribute__ ((used)) const char rcsid[] = #include "sv_progs.h" #include "world.h" +#define EDICT_LEAFS 32 +static edict_leaf_t *free_edict_leaf_list; + +static edict_leaf_t * +alloc_edict_leaf (void) +{ + int i; + edict_leaf_t *edict_leaf; + + if (!free_edict_leaf_list) { + free_edict_leaf_list = malloc (EDICT_LEAFS * sizeof (edict_leaf_t)); + for (i = 0; i < EDICT_LEAFS - 1; i++) + free_edict_leaf_list[i].next = &free_edict_leaf_list[i + 1]; + free_edict_leaf_list[i].next = 0; + } + edict_leaf = free_edict_leaf_list; + free_edict_leaf_list = free_edict_leaf_list->next; + edict_leaf->next = 0; + return edict_leaf; +} + +static void +free_edict_leafs (edict_leaf_t **edict_leafs) +{ + edict_leaf_t **el; + + for (el = edict_leafs; *el; el = &(*el)->next) + ; + *el = free_edict_leaf_list; + free_edict_leaf_list = *edict_leafs; + *edict_leafs = 0; +} + /* entities never clip against themselves, or their owner line of sight checks trace->crosscontent, but bullets don't @@ -316,23 +349,22 @@ SV_TouchLinks (edict_t *ent, areanode_t *node) static void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) { - int leafnum, sides; + int sides; mleaf_t *leaf; mplane_t *splitplane; + edict_leaf_t *edict_leaf; if (node->contents == CONTENTS_SOLID) return; // add an efrag if the node is a leaf if (node->contents < 0) { - if (ent->num_leafs == MAX_ENT_LEAFS) - return; - leaf = (mleaf_t *) node; - leafnum = leaf - sv.worldmodel->leafs - 1; - ent->leafnums[ent->num_leafs] = leafnum; - ent->num_leafs++; + edict_leaf = alloc_edict_leaf (); + edict_leaf->leaf = leaf; + edict_leaf->next = ent->leafs; + ent->leafs = edict_leaf; return; } @@ -386,7 +418,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) } // link to PVS leafs - ent->num_leafs = 0; + free_edict_leafs (&ent->leafs); if (SVfloat (ent, modelindex)) SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);