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

View File

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

View File

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

View File

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

View File

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