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.
This commit is contained in:
Bill Currie 2010-12-08 08:44:52 +09:00
parent a0828ddd06
commit 31cf4b0d78
5 changed files with 107 additions and 33 deletions

View file

@ -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 { struct edict_s {
qboolean free; qboolean free;
link_t area; ///< linked to a division node or leaf link_t area; ///< linked to a division node or leaf
int num_leafs; edict_leaf_t *leafs;
short leafnums[MAX_ENT_LEAFS];
float freetime; ///< sv.time when the object was freed float freetime; ///< sv.time when the object was freed
void *data; ///< external per-edict data void *data; ///< external per-edict data

View file

@ -443,6 +443,7 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
vec3_t org; vec3_t org;
edict_t *ent; edict_t *ent;
entity_state_t *baseline; entity_state_t *baseline;
edict_leaf_t *el;
// find the client's PVS // find the client's PVS
VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org); 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) && (int) SVfloat (ent, modelindex) & 0xFF00)
continue; continue;
for (i = 0; i < ent->num_leafs; i++) for (el = ent->leafs; el; el = el->next) {
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7))) unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1;
if (pvs[leafnum >> 3] & (1 << (leafnum & 7)))
break; break;
}
if (i == ent->num_leafs) if (!el)
continue; // not visible continue; // not visible
} }

View file

@ -50,6 +50,39 @@ static __attribute__ ((used)) const char rcsid[] =
#include "sv_progs.h" #include "sv_progs.h"
#include "world.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 entities never clip against themselves, or their owner
line of sight checks trace->crosscontent, but bullets don't line of sight checks trace->crosscontent, but bullets don't
@ -328,23 +361,22 @@ SV_TouchLinks (edict_t *ent, areanode_t *node)
static void static void
SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
{ {
int leafnum, sides; int sides;
mleaf_t *leaf; mleaf_t *leaf;
mplane_t *splitplane; mplane_t *splitplane;
edict_leaf_t *edict_leaf;
if (node->contents == CONTENTS_SOLID) if (node->contents == CONTENTS_SOLID)
return; return;
// add an efrag if the node is a leaf // add an efrag if the node is a leaf
if (node->contents < 0) { if (node->contents < 0) {
if (ent->num_leafs == MAX_ENT_LEAFS)
return;
leaf = (mleaf_t *) node; leaf = (mleaf_t *) node;
leafnum = leaf - sv.worldmodel->leafs - 1;
ent->leafnums[ent->num_leafs] = leafnum; edict_leaf = alloc_edict_leaf ();
ent->num_leafs++; edict_leaf->leaf = leaf;
edict_leaf->next = ent->leafs;
ent->leafs = edict_leaf;
return; return;
} }
@ -398,7 +430,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
} }
// link to PVS leafs // link to PVS leafs
ent->num_leafs = 0; free_edict_leafs (&ent->leafs);
if (SVfloat (ent, modelindex)) if (SVfloat (ent, modelindex))
SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);

View file

@ -553,12 +553,13 @@ write_player (delta_t *delta, plent_state_t *from, plent_state_t *to,
static void static void
SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg) SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg)
{ {
int i, j, k; int j, k;
client_t *cl; client_t *cl;
edict_t *clent = 0; edict_t *clent = 0;
int spec_track = 0; int spec_track = 0;
int stdver = 2, full = stdver; int stdver = 2, full = stdver;
edict_t *ent; edict_t *ent;
edict_leaf_t *el;
packet_players_t *pack; packet_players_t *pack;
client_frame_t *frame = &delta->frames[delta->in_frame]; client_frame_t *frame = &delta->frames[delta->in_frame];
packet_players_t *from_pack = 0; packet_players_t *from_pack = 0;
@ -614,11 +615,12 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg)
if (pvs) { if (pvs) {
// ignore if not touching a PV leaf // ignore if not touching a PV leaf
for (i = 0; i < ent->num_leafs; i++) for (el = ent->leafs; el; el = el->next) {
if (pvs[ent->leafnums[i] >> 3] unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1;
& (1 << (ent->leafnums[i] & 7))) if (pvs[leafnum >> 3] & (1 << (leafnum & 7)))
break; break;
if (i == ent->num_leafs) }
if (!el)
continue; // not visible continue; // not visible
} }
} }
@ -759,11 +761,12 @@ void
SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg) SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg)
{ {
byte *pvs = 0; byte *pvs = 0;
int e, i, num_edicts; int e, num_edicts;
int max_packet_entities = MAX_DEMO_PACKET_ENTITIES; int max_packet_entities = MAX_DEMO_PACKET_ENTITIES;
int stdver = 1; int stdver = 1;
client_frame_t *frame; client_frame_t *frame;
edict_t *ent; edict_t *ent;
edict_leaf_t *el;
entity_state_t *state; entity_state_t *state;
packet_entities_t *pack; packet_entities_t *pack;
@ -801,12 +804,13 @@ SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg)
if (pvs) { if (pvs) {
// ignore if not touching a PV leaf // ignore if not touching a PV leaf
for (i = 0; i < ent->num_leafs; i++) for (el = ent->leafs; el; el = el->next) {
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7))) unsigned leafnum = el->leaf - sv.worldmodel->leafs - 1;
if (pvs[leafnum >> 3] & (1 << (leafnum & 7)))
break; break;
}
if (i == ent->num_leafs) if (!el)
continue; // not visible continue; // not visible
} }
if (SV_AddNailUpdate (ent)) if (SV_AddNailUpdate (ent))

View file

@ -50,6 +50,39 @@ static __attribute__ ((used)) const char rcsid[] =
#include "sv_progs.h" #include "sv_progs.h"
#include "world.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 entities never clip against themselves, or their owner
line of sight checks trace->crosscontent, but bullets don't line of sight checks trace->crosscontent, but bullets don't
@ -316,23 +349,22 @@ SV_TouchLinks (edict_t *ent, areanode_t *node)
static void static void
SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
{ {
int leafnum, sides; int sides;
mleaf_t *leaf; mleaf_t *leaf;
mplane_t *splitplane; mplane_t *splitplane;
edict_leaf_t *edict_leaf;
if (node->contents == CONTENTS_SOLID) if (node->contents == CONTENTS_SOLID)
return; return;
// add an efrag if the node is a leaf // add an efrag if the node is a leaf
if (node->contents < 0) { if (node->contents < 0) {
if (ent->num_leafs == MAX_ENT_LEAFS)
return;
leaf = (mleaf_t *) node; leaf = (mleaf_t *) node;
leafnum = leaf - sv.worldmodel->leafs - 1;
ent->leafnums[ent->num_leafs] = leafnum; edict_leaf = alloc_edict_leaf ();
ent->num_leafs++; edict_leaf->leaf = leaf;
edict_leaf->next = ent->leafs;
ent->leafs = edict_leaf;
return; return;
} }
@ -386,7 +418,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
} }
// link to PVS leafs // link to PVS leafs
ent->num_leafs = 0; free_edict_leafs (&ent->leafs);
if (SVfloat (ent, modelindex)) if (SVfloat (ent, modelindex))
SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);