[model] Remove 64k limit on visible leafs

Modern maps can have many more leafs (eg, ad_tears has 98983 leafs).
Using set_t makes dynamic leaf counts easy to support and the code much
easier to read (though set_is_member and the iterators are a little
slower). The main thing to watch out for is the novis set and the set
returned by Mod_LeafPVS never shrink, and may have excess elements (ie,
indicate that nonexistent leafs are visible).
This commit is contained in:
Bill Currie 2021-07-26 11:15:51 +09:00
parent 03921c03c5
commit f47e03e606
16 changed files with 154 additions and 142 deletions

View file

@ -103,7 +103,7 @@ typedef struct lightingframe_s {
};
// A fat PVS of leafs visible from visible leafs so hidden lights can
// illuminate the leafs visible to the player
byte pvs[MAP_PVS_BYTES];
struct set_s *pvs;
struct mleaf_s *leaf; // the last leaf used to generate the pvs
qfv_lightvisset_t lightvis;
} lightingframe_t;
@ -124,7 +124,7 @@ typedef struct lightingctx_s {
qfv_imageset_t lightimages;
qfv_lightintset_t lightlayers;
qfv_imageviewset_t lightviews;
byte sun_pvs[MAX_MAP_LEAFS];
struct set_s *sun_pvs;
} lightingctx_t;
struct vulkan_ctx_s;

View file

@ -230,7 +230,7 @@ typedef struct mod_brush_s {
int numplanes;
plane_t *planes;
int numleafs; // number of visible leafs, not counting 0
unsigned numleafs; // number of visible leafs, not counting 0
mleaf_t *leafs;
int numvertexes;
@ -432,13 +432,12 @@ model_t *Mod_ForName (const char *name, qboolean crash);
void Mod_TouchModel (const char *name);
// brush specific
mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure));
byte *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model);
struct set_s *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model);
// NOTE: the buffer pointed to by out must be at least MAP_PVS_BYTES in size
void Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis,
byte *out);
struct set_s *pvs);
void Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis,
byte *out);
struct set_s *pvs);
void Mod_Print (void);

View file

@ -47,6 +47,7 @@
#include "QF/qendian.h"
#include "QF/quakefs.h"
#include "QF/render.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -55,8 +56,6 @@
#include "compat.h"
#include "mod_internal.h"
static byte mod_novis[MAP_PVS_BYTES];
VISIBLE cvar_t *gl_sky_divide; //FIXME visibility?
VISIBLE int mod_lightmap_bytes = 1; //FIXME should this be visible?
@ -87,8 +86,9 @@ Mod_PointInLeaf (const vec3_t p, model_t *model)
static inline void
Mod_DecompressVis_set (const byte *in, const mod_brush_t *brush, byte defvis,
byte *out)
set_t *pvs)
{
byte *out = (byte *) pvs->map;
byte *start = out;
int row, c;
@ -119,8 +119,9 @@ Mod_DecompressVis_set (const byte *in, const mod_brush_t *brush, byte defvis,
static inline void
Mod_DecompressVis_mix (const byte *in, const mod_brush_t *brush, byte defvis,
byte *out)
set_t *pvs)
{
byte *out = (byte *) pvs->map;
byte *start = out;
int row, c;
@ -146,16 +147,30 @@ Mod_DecompressVis_mix (const byte *in, const mod_brush_t *brush, byte defvis,
} while (out - start < row);
}
VISIBLE byte *
VISIBLE set_t *
Mod_LeafPVS (const mleaf_t *leaf, const model_t *model)
{
static byte decompressed[MAP_PVS_BYTES];
static set_t *novis;
static set_t *decompressed;
unsigned numvis = model->brush.numleafs;
if (leaf == model->brush.leafs) {
if (!mod_novis[0]) {
memset (mod_novis, 0xff, sizeof (mod_novis));
if (!novis) {
novis = set_new_size (numvis);
}
return mod_novis;
if (!novis->map[0] || SET_SIZE (numvis) > novis->size) {
unsigned excess = SET_SIZE (numvis) - numvis;
set_expand (novis, numvis);
memset (novis->map, 0xff,
SET_WORDS (novis) * sizeof (*novis->map));
novis->map[SET_WORDS (novis) - 1] &= (~SET_ZERO) >> excess;
}
return novis;
}
if (!decompressed) {
decompressed = set_new ();
}
set_expand (decompressed, numvis);
Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, 0xff,
decompressed);
return decompressed;
@ -163,10 +178,14 @@ Mod_LeafPVS (const mleaf_t *leaf, const model_t *model)
VISIBLE void
Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis,
byte *out)
set_t *out)
{
unsigned numvis = model->brush.numleafs;
set_expand (out, numvis);
if (leaf == model->brush.leafs) {
memset (out, defvis, sizeof (mod_novis));
unsigned excess = SET_SIZE (numvis) - numvis;
memset (out->map, defvis, SET_WORDS (out) * sizeof (*out->map));
out->map[SET_WORDS (out) - 1] &= (~SET_ZERO) >> excess;
return;
}
Mod_DecompressVis_set (leaf->compressed_vis, &model->brush, defvis, out);
@ -174,12 +193,17 @@ Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis,
VISIBLE void
Mod_LeafPVS_mix (const mleaf_t *leaf, const model_t *model, byte defvis,
byte *out)
set_t *out)
{
unsigned numvis = model->brush.numleafs;
set_expand (out, numvis);
if (leaf == model->brush.leafs) {
for (int i = MAP_PVS_BYTES; i-- > 0; ) {
*out++ |= defvis;
unsigned excess = SET_SIZE (numvis) - numvis;
byte *o = (byte *) out->map;
for (int i = SET_WORDS (out) * sizeof (*out->map); i-- > 0; ) {
*o++ |= defvis;
}
out->map[SET_WORDS (out) - 1] &= (~SET_ZERO) >> excess;
return;
}
Mod_DecompressVis_mix (leaf->compressed_vis, &model->brush, defvis, out);
@ -431,11 +455,6 @@ Mod_LoadSubmodels (model_t *mod, bsp_t *bsp)
out = brush->submodels;
if (out->visleafs > MAX_MAP_LEAFS) {
Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s",
out->visleafs, MAX_MAP_LEAFS, mod->path);
}
if (out->visleafs > 8192)
Sys_MaskPrintf (SYS_warn,
"%i visleafs exceeds standard limit of 8192.\n",
@ -654,7 +673,7 @@ Mod_SetParent (mod_brush_t *brush, mnode_t *node, mnode_t *parent)
static void
Mod_SetLeafFlags (mod_brush_t *brush)
{
for (int i = 0; i < brush->numleafs; i++) {
for (unsigned i = 0; i < brush->numleafs; i++) {
int flags = 0;
mleaf_t *leaf = &brush->leafs[i];
for (int j = 0; j < leaf->nummarksurfaces; j++) {
@ -704,7 +723,7 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp)
out->children[j] = brush->nodes + p;
} else {
p = ~p;
if (p < brush->numleafs) {
if ((unsigned) p < brush->numleafs) {
out->children[j] = (mnode_t *) (brush->leafs + p);
} else {
Sys_Printf ("Mod_LoadNodes: invalid leaf index %i "

View file

@ -184,11 +184,10 @@ register_textures (mod_brush_t *brush)
void
gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
{
int i;
texture_t *tex;
mod_brush_t *brush;
for (i = 0; i < 256; i++)
for (int i = 0; i < 256; i++)
d_lightstylevalue[i] = 264; // normal light value
memset (&r_worldentity, 0, sizeof (r_worldentity));
@ -198,7 +197,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
R_FreeAllEntities ();
// clear out efrags in case the level hasn't been reloaded
for (i = 0; i < brush->numleafs; i++)
for (unsigned i = 0; i < brush->numleafs; i++)
brush->leafs[i].efrags = NULL;
// Force a vis update
@ -212,7 +211,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
// identify sky texture
gl_mirrortexturenum = -1;
gl_R_ClearTextures ();
for (i = 0; i < brush->numtextures; i++) {
for (int i = 0; i < brush->numtextures; i++) {
tex = brush->textures[i];
if (!tex)
continue;
@ -226,7 +225,7 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
gl_R_InitSurfaceChains (brush);
gl_R_AddTexture (r_notexture_mip);
register_textures (brush);
for (i = 0; i < num_models; i++) {
for (int i = 0; i < num_models; i++) {
if (!models[i])
continue;
if (*models[i]->path == '*')

View file

@ -36,6 +36,7 @@
#endif
#include "QF/cvar.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "r_internal.h"
@ -43,14 +44,13 @@
mvertex_t *r_pcurrentvertbase;
mleaf_t *r_viewleaf;
static mleaf_t *r_oldviewleaf;
static set_t *solid;
void
R_MarkLeaves (void)
{
byte solid[8192];
byte *vis;
set_t *vis;
int c;
unsigned int i;
mleaf_t *leaf;
mnode_t *node;
msurface_t **mark;
@ -67,13 +67,16 @@ R_MarkLeaves (void)
if (r_novis->int_val) {
r_oldviewleaf = 0; // so vis will be recalcualted when novis gets
// turned off
if (!solid) {
solid = set_new ();
set_everything (solid);
}
vis = solid;
memset (solid, 0xff, (brush->numleafs + 7) >> 3);
} else
vis = Mod_LeafPVS (r_viewleaf, r_worldentity.renderer.model);
for (i = 0; (int) i < brush->numleafs; i++) {
if (vis[i >> 3] & (1 << (i & 7))) {
for (unsigned i = 0; i < brush->numleafs; i++) {
if (set_is_member (vis, i)) {
leaf = &brush->leafs[i + 1];
if ((c = leaf->nummarksurfaces)) {
mark = leaf->firstmarksurface;

View file

@ -271,7 +271,7 @@ R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum,
} else {
float radius = light->radius;
vec3_t mins, maxs;
int leafnum = 0;
unsigned leafnum = 0;
byte *in = pvsleaf->compressed_vis;
byte vis_bits;

View file

@ -164,7 +164,6 @@ sw_R_Init (void)
void
R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
{
int i;
mod_brush_t *brush = &worldmodel->brush;
memset (&r_worldentity, 0, sizeof (r_worldentity));
@ -174,7 +173,7 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
// clear out efrags in case the level hasn't been reloaded
// FIXME: is this one short?
for (i = 0; i < brush->numleafs; i++)
for (unsigned i = 0; i < brush->numleafs; i++)
brush->leafs[i].efrags = NULL;
if (brush->skytexture)

View file

@ -179,7 +179,6 @@ sw32_R_Init (void)
void
sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
{
int i;
mod_brush_t *brush = &worldmodel->brush;
memset (&r_worldentity, 0, sizeof (r_worldentity));
@ -189,7 +188,7 @@ sw32_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models)
// clear out efrags in case the level hasn't been reloaded
// FIXME: is this one short?
for (i = 0; i < brush->numleafs; i++)
for (unsigned i = 0; i < brush->numleafs; i++)
brush->leafs[i].efrags = NULL;
if (brush->skytexture)

View file

@ -45,6 +45,7 @@
#include "QF/plist.h"
#include "QF/progs.h"
#include "QF/script.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -68,12 +69,12 @@
static vec4f_t ref_direction = { 0, 0, 1, 0 };
static void
expand_pvs (byte *pvs, model_t *model)
expand_pvs (set_t *pvs, model_t *model)
{
byte base_pvs[MAP_PVS_BYTES];
memcpy (base_pvs, pvs, sizeof (base_pvs));
for (int i = 0; i < model->brush.numleafs; i++) {
if (base_pvs[(unsigned) i / 8] & (1 << ((unsigned) i % 8))) {
set_t base_pvs = SET_STATIC_INIT (model->brush.numleafs, alloca);
set_assign (&base_pvs, pvs);
for (unsigned i = 0; i < model->brush.numleafs; i++) {
if (set_is_member (&base_pvs, i)) {
Mod_LeafPVS_mix (model->brush.leafs + i + 1, model, 0, pvs);
}
}
@ -99,13 +100,13 @@ find_visible_lights (vulkan_ctx_t *ctx)
int flags = 0;
if (leaf == model->brush.leafs) {
memset (lframe->pvs, 0xff, sizeof (lframe->pvs));
set_everything (lframe->pvs);
} else {
Mod_LeafPVS_set (leaf, model, 0, lframe->pvs);
expand_pvs (lframe->pvs, model);
}
for (int i = 0; i < model->brush.numleafs; i++) {
if (lframe->pvs[i / 8] & (1 << (i % 8))) {
for (unsigned i = 0; i < model->brush.numleafs; i++) {
if (set_is_member (lframe->pvs, i)) {
flags |= model->brush.leaf_flags[i + 1];
}
}
@ -119,7 +120,7 @@ find_visible_lights (vulkan_ctx_t *ctx)
for (size_t i = 0; i < lctx->lightleafs.size; i++) {
int l = lctx->lightleafs.a[i];
if ((l == -1 && (flags & SURF_DRAWSKY))
|| lframe->pvs[l / 8] & (1 << (l % 8))) {
|| set_is_member (lframe->pvs, l)) {
lframe->lightvis.a[i] = 1;
visible++;
}
@ -307,6 +308,8 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
DARRAY_RESIZE (&lctx->frames, frames);
lctx->frames.grow = 0;
lctx->sun_pvs = set_new ();
lctx->pipeline = Vulkan_CreatePipeline (ctx, "lighting");
lctx->layout = Vulkan_CreatePipelineLayout (ctx, "lighting_layout");
lctx->sampler = Vulkan_CreateSampler (ctx, "shadow_sampler");
@ -369,6 +372,8 @@ Vulkan_Lighting_Init (vulkan_ctx_t *ctx)
shadow_set->a[i],
va (ctx->va_ctx, "lighting:shadow_set:%zd", i));
lframe->pvs = set_new ();
DARRAY_INIT (&lframe->lightvis, 16);
lframe->leaf = 0;
@ -551,7 +556,8 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model)
//float sunlight2;
vec3_t sunangle = { 0, -90, 0 };
memset (lctx->sun_pvs, 0, MAX_MAP_LEAFS);
set_expand (lctx->sun_pvs, model->brush.numleafs);
set_empty (lctx->sun_pvs);
sunlight = parse_float (PL_String (PL_ObjectForKey (entity,
"_sunlight")), 0);
//sunlight2 = parse_float (PL_String (PL_ObjectForKey (entity,
@ -571,9 +577,9 @@ parse_sun (lightingctx_t *lctx, plitem_t *entity, model_t *model)
// Any leaf with sky surfaces can potentially see the sun, thus put
// the sun "in" every leaf with a sky surface
for (int l = 0; l < model->brush.numleafs; l++) {
for (unsigned l = 0; l < model->brush.numleafs; l++) {
if (model->brush.leaf_flags[l] & SURF_DRAWSKY) {
lctx->sun_pvs[l / 8] |= 1 << (l % 8);
set_add (lctx->sun_pvs, l);
}
}
// any leaf visible from a leaf with a sky surface (and thus the sun)

View file

@ -32,6 +32,7 @@
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/mathlib.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -388,24 +389,20 @@ SV_ClearDatagram (void)
crosses a waterline.
*/
int fatbytes;
byte fatpvs[MAP_PVS_BYTES];
static set_t *fatpvs;
static void
SV_AddToFatPVS (vec3_t org, mnode_t *node)
{
int i;
float d;
byte *pvs;
plane_t *plane;
while (1) {
// if this is a leaf, accumulate the pvs bits
if (node->contents < 0) {
if (node->contents != CONTENTS_SOLID) {
pvs = Mod_LeafPVS ((mleaf_t *) node, sv.worldmodel);
for (i = 0; i < fatbytes; i++)
fatpvs[i] |= pvs[i];
set_union (fatpvs, Mod_LeafPVS ((mleaf_t *) node,
sv.worldmodel));
}
return;
}
@ -429,11 +426,14 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node)
Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
given point.
*/
static byte *
static set_t *
SV_FatPVS (vec3_t org)
{
fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3;
memset (fatpvs, 0, fatbytes);
if (!fatpvs) {
fatpvs = set_new_size (sv.worldmodel->brush.numleafs);
}
set_expand (fatpvs, sv.worldmodel->brush.numleafs);
set_empty (fatpvs);
SV_AddToFatPVS (org, sv.worldmodel->brush.nodes);
return fatpvs;
}
@ -444,7 +444,7 @@ static void
SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
{
int bits, e, i;
byte *pvs;
set_t *pvs;
float miss;
vec3_t org;
edict_t *ent;
@ -473,7 +473,7 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
continue;
for (el = SVdata (ent)->leafs; el; el = el->next) {
if (pvs[el->leafnum >> 3] & (1 << (el->leafnum & 7)))
if (set_is_member (pvs, el->leafnum))
break;
}

View file

@ -42,6 +42,7 @@
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/ruamoko.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -539,12 +540,11 @@ PF_checkpos (progs_t *pr)
{
}
byte checkpvs[MAP_PVS_BYTES];
static set_t *checkpvs;
static int
PF_newcheckclient (progs_t *pr, int check)
{
byte *pvs;
edict_t *ent;
int i;
mleaf_t *leaf;
@ -584,8 +584,10 @@ PF_newcheckclient (progs_t *pr, int check)
// get the PVS for the entity
VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org);
leaf = Mod_PointInLeaf (org, sv.worldmodel);
pvs = Mod_LeafPVS (leaf, sv.worldmodel);
memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3);
if (!checkpvs) {
checkpvs = set_new_size (sv.worldmodel->brush.numleafs);
}
set_assign (checkpvs, Mod_LeafPVS (leaf, sv.worldmodel));
return i;
}
@ -631,7 +633,7 @@ PF_checkclient (progs_t *pr)
VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view);
leaf = Mod_PointInLeaf (view, sv.worldmodel);
l = (leaf - sv.worldmodel->brush.leafs) - 1;
if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) {
if (!set_is_member (checkpvs, l)) {
c_notvis++;
RETURN_EDICT (pr, sv.edicts);
return;

View file

@ -86,7 +86,7 @@ typedef struct {
// struct edict_s is variable sized, but can
// be used to reference the world ent
byte *pvs, *phs; // fully expanded and decompressed
struct set_s *pvs, *phs; // fully expanded and decompressed
//antilag
float lagentsfrac;

View file

@ -37,6 +37,7 @@
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "compat.h"
@ -54,25 +55,21 @@
when the bob crosses a waterline.
*/
byte fatpvs[MAP_PVS_BYTES];
int fatbytes;
static set_t *fatpvs;
static void
SV_AddToFatPVS (vec3_t org, mnode_t *node)
{
byte *pvs;
int i;
float d;
float d;
plane_t *plane;
while (1) {
// if this is a leaf, accumulate the pvs bits
if (node->contents < 0) {
if (node->contents != CONTENTS_SOLID) {
pvs = Mod_LeafPVS ((mleaf_t *) node, sv.worldmodel);
for (i = 0; i < fatbytes; i++)
fatpvs[i] |= pvs[i];
set_union (fatpvs, Mod_LeafPVS ((mleaf_t *) node,
sv.worldmodel));
}
return;
}
@ -96,11 +93,14 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node)
Calculates a PVS that is the inclusive or of all leafs within 8 pixels
of the given point.
*/
static byte *
static set_t *
SV_FatPVS (vec3_t org)
{
fatbytes = (sv.worldmodel->brush.numleafs + 31) >> 3;
memset (fatpvs, 0, fatbytes);
if (!fatpvs) {
fatpvs = set_new_size (sv.worldmodel->brush.numleafs);
}
set_expand (fatpvs, sv.worldmodel->brush.numleafs);
set_empty (fatpvs);
SV_AddToFatPVS (org, sv.worldmodel->brush.nodes);
return fatpvs;
}
@ -549,7 +549,7 @@ 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)
SV_WritePlayersToClient (delta_t *delta, set_t *pvs, sizebuf_t *msg)
{
int j, k;
client_t *cl;
@ -613,7 +613,7 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg)
if (pvs) {
// ignore if not touching a PV leaf
for (el = SVdata (ent)->leafs; el; el = el->next) {
if (pvs[el->leafnum >> 3] & (1 << (el->leafnum & 7)))
if (set_is_member (pvs, el->leafnum))
break;
}
if (!el)
@ -706,10 +706,10 @@ SV_WritePlayersToClient (delta_t *delta, byte *pvs, sizebuf_t *msg)
}
}
static inline byte *
static inline set_t *
calc_pvs (delta_t *delta)
{
byte *pvs = 0;
set_t *pvs = 0;
vec3_t org;
// find the client's PVS
@ -756,7 +756,7 @@ calc_pvs (delta_t *delta)
void
SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg)
{
byte *pvs = 0;
set_t *pvs = 0;
int e, num_edicts;
int max_packet_entities = MAX_DEMO_PACKET_ENTITIES;
int stdver = 1;
@ -801,7 +801,7 @@ SV_WriteEntitiesToClient (delta_t *delta, sizebuf_t *msg)
if (pvs) {
// ignore if not touching a PV leaf
for (el = SVdata (ent)->leafs; el; el = el->next) {
if (pvs[el->leafnum >> 3] & (1 << (el->leafnum & 7)))
if (set_is_member (pvs, el->leafnum))
break;
}
if (!el)

View file

@ -40,6 +40,7 @@
#include "QF/info.h"
#include "QF/msg.h"
#include "QF/quakefs.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -222,62 +223,45 @@ SV_SaveSpawnparms (void)
static void
SV_CalcPHS (void)
{
byte *scan;
int bitbyte, count, index, num, rowbytes, rowwords, vcount, i, j,
k, l;
unsigned int *dest, *src;
int count, num, vcount, i;
SV_Printf ("Building PHS...\n");
num = sv.worldmodel->brush.numleafs;
rowwords = (num + 31) >> 5;
rowbytes = rowwords * 4;
sv.pvs = Hunk_Alloc (rowbytes * num);
scan = sv.pvs;
sv.pvs = Hunk_Alloc (num * sizeof (set_t));
vcount = 0;
for (i = 0; i < num; i++, scan += rowbytes) {
memcpy (scan, Mod_LeafPVS (sv.worldmodel->brush.leafs + i,
sv.worldmodel),
rowbytes);
for (i = 0; i < num; i++) {
sv.pvs[i] = (set_t) SET_STATIC_INIT (num, Hunk_Alloc);
Mod_LeafPVS_set (sv.worldmodel->brush.leafs + i, sv.worldmodel, 0xff,
&sv.pvs[i]);
if (i == 0)
continue;
for (j = 0; j < num; j++) {
if (scan[j >> 3] & (1 << (j & 7))) {
vcount++;
}
for (set_iter_t *iter = set_first (&sv.pvs[i]); iter;
iter = set_next (iter)) {
vcount++;
}
}
sv.phs = Hunk_Alloc (rowbytes * num);
sv.phs = Hunk_Alloc (num * sizeof (set_t));
count = 0;
scan = sv.pvs;
dest = (unsigned int *) sv.phs;
for (i = 0; i < num; i++, dest += rowwords, scan += rowbytes) {
memcpy (dest, scan, rowbytes);
for (j = 0; j < rowbytes; j++) {
bitbyte = scan[j];
if (!bitbyte)
continue;
for (k = 0; k < 8; k++) {
if (!(bitbyte & (1 << k)))
continue;
// or this pvs row into the phs
// +1 because pvs is 1 based
index = ((j << 3) + k + 1);
if (index >= num)
continue;
src = (unsigned int *) sv.pvs + index * rowwords;
for (l = 0; l < rowwords; l++)
dest[l] |= src[l];
}
for (i = 0; i < num; i++) {
sv.phs[i] = (set_t) SET_STATIC_INIT (num, Hunk_Alloc);
set_assign (&sv.phs[i], &sv.pvs[i]);
for (set_iter_t *iter = set_first (&sv.pvs[i]); iter;
iter = set_next (iter)) {
// or this pvs row into the phs
// +1 because pvs is 1 based
set_union (&sv.phs[i], &sv.pvs[iter->element + 1]);
}
if (i == 0)
continue;
for (j = 0; j < num; j++)
if (((byte *) dest)[j >> 3] & (1 << (j & 7)))
count++;
for (set_iter_t *iter = set_first (&sv.phs[i]); iter;
iter = set_next (iter)) {
count++;
}
}
SV_Printf ("Average leafs visible / hearable / total: %i / %i / %i\n",

View file

@ -42,6 +42,7 @@
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/ruamoko.h"
#include "QF/set.h"
#include "QF/sys.h"
#include "QF/va.h"
@ -460,12 +461,11 @@ PF_checkpos (progs_t *pr)
{
}
byte checkpvs[MAP_PVS_BYTES];
set_t *checkpvs;
static int
PF_newcheckclient (progs_t *pr, int check)
{
byte *pvs;
edict_t *ent;
int i;
mleaf_t *leaf;
@ -505,8 +505,10 @@ PF_newcheckclient (progs_t *pr, int check)
// get the PVS for the entity
VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org);
leaf = Mod_PointInLeaf (org, sv.worldmodel);
pvs = Mod_LeafPVS (leaf, sv.worldmodel);
memcpy (checkpvs, pvs, (sv.worldmodel->brush.numleafs + 7) >> 3);
if (!checkpvs) {
checkpvs = set_new_size (sv.worldmodel->brush.numleafs);
}
set_assign (checkpvs, Mod_LeafPVS (leaf, sv.worldmodel));
return i;
}
@ -552,7 +554,7 @@ PF_checkclient (progs_t *pr)
VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view);
leaf = Mod_PointInLeaf (view, sv.worldmodel);
l = (leaf - sv.worldmodel->brush.leafs) - 1;
if ((l < 0) || !(checkpvs[l >> 3] & (1 << (l & 7)))) {
if (!set_is_member (checkpvs, l)) {
c_notvis++;
RETURN_EDICT (pr, sv.edicts);
return;

View file

@ -43,6 +43,7 @@
#include "QF/console.h"
#include "QF/dstring.h"
#include "QF/msg.h"
#include "QF/set.h"
#include "QF/sound.h" // FIXME: DEFAULT_SOUND_PACKET_*
#include "QF/sys.h"
@ -295,7 +296,7 @@ SV_PrintToClient (client_t *cl, int level, const char *string)
void
SV_Multicast (const vec3_t origin, int to)
{
byte *mask;
set_t *mask;
client_t *client;
int leafnum, j;
mleaf_t *leaf;
@ -314,23 +315,22 @@ SV_Multicast (const vec3_t origin, int to)
case MULTICAST_ALL_R:
reliable = true; // intentional fallthrough
case MULTICAST_ALL:
mask = sv.pvs; // leaf 0 is everything;
mask = &sv.pvs[0]; // leaf 0 is everything;
break;
case MULTICAST_PHS_R:
reliable = true; // intentional fallthrough
case MULTICAST_PHS:
mask = sv.phs + leafnum * 4 * ((brush->numleafs + 31) >> 5);
mask = &sv.phs[leafnum];
break;
case MULTICAST_PVS_R:
reliable = true; // intentional fallthrough
case MULTICAST_PVS:
mask = sv.pvs + leafnum * 4 * ((brush->numleafs + 31) >> 5);
mask = &sv.pvs[leafnum];
break;
default:
mask = NULL;
Sys_Error ("SV_Multicast: bad to:%i", to);
}
@ -352,7 +352,7 @@ SV_Multicast (const vec3_t origin, int to)
if (leaf) {
// -1 is because pvs rows are 1 based, not 0 based like leafs
leafnum = leaf - brush->leafs - 1;
if (!(mask[leafnum >> 3] & (1 << (leafnum & 7)))) {
if (!set_is_member (mask, leafnum)) {
// SV_Printf ("supressed multicast\n");
continue;
}