ref: 4044c72c4298721bfb6a6121e9ff1e2b74a5ea85
parent: 9ce925452bc4b22c27133ea3bc26ad7b191d37e0
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Nov 1 09:43:08 EDT 2023
sv: per-client pvs entity visibility check with no leafs limit (thanks super8 authors)
--- a/sv_main.c
+++ b/sv_main.c
@@ -374,7 +374,7 @@
static byte *fatpvs;
static int fatpvs_size;
-void SV_AddToFatPVS (vec3_t org, mnode_t *node)
+void SV_AddToFatPVS (vec3_t org, mnode_t *node, model_t *m)
{
int i;
byte *pvs;
@@ -388,7 +388,7 @@
{
if (node->contents != CONTENTS_SOLID)
{
- pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);
+ pvs = Mod_LeafPVS ( (mleaf_t *)node, m);
for (i=0 ; i<fatbytes ; i++)
fatpvs[i] |= pvs[i];
}
@@ -403,7 +403,7 @@
node = node->children[1];
else
{ // go down both
- SV_AddToFatPVS (org, node->children[0]);
+ SV_AddToFatPVS (org, node->children[0], m);
node = node->children[1];
}
}
@@ -417,15 +417,15 @@
given point.
=============
*/
-byte *SV_FatPVS (vec3_t org)
+byte *SV_FatPVS (vec3_t org, model_t *m)
{
- fatbytes = (sv.worldmodel->numleafs+31)>>3;
+ fatbytes = (m->numleafs+31)>>3;
if(fatpvs == nil || fatbytes > fatpvs_size){
fatpvs = realloc(fatpvs, fatbytes);
fatpvs_size = fatbytes;
}
memset(fatpvs, 0, fatbytes);
- SV_AddToFatPVS (org, sv.worldmodel->nodes);
+ SV_AddToFatPVS(org, m->nodes, m);
return fatpvs;
}
@@ -450,7 +450,7 @@
// find the client's PVS
VectorAdd (clent->v.origin, clent->v.view_ofs, org);
- pvs = SV_FatPVS (org);
+ pvs = SV_FatPVS (org, sv.worldmodel);
// send over all entities (excpet the client) that touch the pvs
ent = NEXT_EDICT(sv.edicts);
@@ -464,18 +464,14 @@
if (ent != clent) // clent is ALLWAYS sent
{
+ if((int)ent->v.effects == EF_NODRAW)
+ continue;
// ignore ents without visible models
if(!model || !*PR_Str(ent->v.model))
continue;
if(model >= sv.protocol->limit_model)
continue;
- for(i=0 ; i < ent->num_leafs ; i++)
- if(pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
- break;
- if(i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
- continue; // not visible
-
- if((int)ent->v.effects == EF_NODRAW)
+ if(!SV_FindTouchedLeafs(ent, sv.worldmodel->nodes, pvs))
continue;
if((int)ent->v.effects == 0 && zeroalpha(alpha))
continue;
--- a/world.c
+++ b/world.c
@@ -308,42 +308,26 @@
===============
*/
-void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
+int SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs)
{
mplane_t *splitplane;
- mleaf_t *leaf;
int sides;
int leafnum;
- if (node->contents == CONTENTS_SOLID)
- return;
+ if(node->contents == CONTENTS_SOLID)
+ return 0;
-// 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++;
- return;
+ if(node->contents < 0){
+ leafnum = (mleaf_t*)node - sv.worldmodel->leafs - 1;
+ return pvs[leafnum>>3] & (1<<(leafnum&7));
}
-
-// NODE_MIXED
splitplane = node->plane;
sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);
-
-// recurse down the contacted sides
- if (sides & 1)
- SV_FindTouchedLeafs (ent, node->children[0]);
-
- if (sides & 2)
- SV_FindTouchedLeafs (ent, node->children[1]);
+
+ return
+ ((sides & 1) && SV_FindTouchedLeafs(ent, node->children[0], pvs)) ||
+ ((sides & 2) && SV_FindTouchedLeafs(ent, node->children[1], pvs));
}
/*
@@ -390,11 +374,6 @@
ent->v.absmax[1] += 1;
ent->v.absmax[2] += 1;
}
-
-// link to PVS leafs
- ent->num_leafs = 0;
- if (ent->v.modelindex)
- SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
if (ent->v.solid == SOLID_NOT)
return;
--- a/world.h
+++ b/world.h
@@ -20,6 +20,7 @@
#define MOVE_NOMONSTERS 1
#define MOVE_MISSILE 2
+int SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs);
void SV_ClearWorld (void);
// called after the world model has been loaded, before linking any entities