From 7240d2dc80197c8ba43ef43b5af1eeabf858aebb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 22 May 2022 11:18:32 +0900 Subject: [PATCH] [model] Move plane info into mnode_t, and visframe out The main goal was to get visframe out of mnode_t to make it thread-safe (each thread can have its own visframe array), but moving the plane info into mnode_t made for better data access patters when traversing the bsp tree as the plane is right there with the child indices. Nicely, the size of mnode_t is the same as before (64 bytes due to alignment), with 4 bytes wasted. Performance-wise, there seems to be very little difference. Maybe slightly slower. The unfortunate thing about the change is the plane distance is negated, possibly leading to some confusion, particularly since the box and sphere culling functions were affected. However, this is so point-plane distance calculations can be done with a single 4d dot product. --- include/QF/mathlib.h | 10 ++- include/QF/model.h | 32 ++++----- include/QF/scene/entity.h | 2 +- include/r_internal.h | 3 +- include/r_local.h | 6 +- libs/models/brush/model_brush.c | 83 ++++++++++++----------- libs/scene/light.c | 2 +- libs/scene/scene.c | 4 +- libs/util/mathlib.c | 4 +- libs/video/renderer/gl/gl_rmain.c | 4 +- libs/video/renderer/gl/gl_rmisc.c | 2 +- libs/video/renderer/gl/gl_rsurf.c | 58 +++++++++------- libs/video/renderer/glsl/glsl_bsp.c | 58 +++++++++------- libs/video/renderer/glsl/glsl_main.c | 2 +- libs/video/renderer/r_bsp.c | 13 ++-- libs/video/renderer/r_efrag.c | 41 +++++------ libs/video/renderer/r_light.c | 62 ++++++++--------- libs/video/renderer/r_main.c | 2 +- libs/video/renderer/r_screen.c | 9 ++- libs/video/renderer/sw/sw_rbsp.c | 86 +++++++++++++----------- libs/video/renderer/sw/sw_rmain.c | 39 ++++++----- libs/video/renderer/vulkan/vulkan_bsp.c | 52 ++++++++------ libs/video/renderer/vulkan/vulkan_main.c | 2 +- nq/source/cl_screen.c | 2 +- nq/source/host.c | 2 +- nq/source/sv_main.c | 28 ++++---- nq/source/sv_pr_cmds.c | 6 +- nq/source/world.c | 19 +++--- qtv/source/client.c | 27 ++++---- qtv/source/sv_parse.c | 18 ++--- qw/source/cl_main.c | 2 +- qw/source/cl_screen.c | 2 +- qw/source/sv_ents.c | 33 ++++----- qw/source/sv_pr_cmds.c | 6 +- qw/source/sv_send.c | 7 +- qw/source/world.c | 19 +++--- 36 files changed, 397 insertions(+), 350 deletions(-) diff --git a/include/QF/mathlib.h b/include/QF/mathlib.h index 5f8c900d2..645220b40 100644 --- a/include/QF/mathlib.h +++ b/include/QF/mathlib.h @@ -136,6 +136,7 @@ void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void AngleQuat (const vec3_t angles, quat_t q); void VectorVectors (const vec3_t forward, vec3_t right, vec3_t up); +// NOTE expects plane distance is -p.n int BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const plane_t *plane) __attribute__((pure)); float anglemod (float a) __attribute__((const)); @@ -143,14 +144,15 @@ float anglemod (float a) __attribute__((const)); void RotatePointAroundVector (vec3_t dst, const vec3_t axis, const vec3_t point, float degrees); +// NOTE expects plane distance is -p.n #define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ (((p)->type < 3)? \ ( \ - ((p)->dist <= (emins)[(p)->type])? \ + (-(p)->dist <= (emins)[(p)->type])? \ 1 \ : \ ( \ - ((p)->dist >= (emaxs)[(p)->type])? \ + (-(p)->dist >= (emaxs)[(p)->type])? \ 2 \ : \ 3 \ @@ -185,6 +187,7 @@ R_CullBox (const plane_t *frustum, const vec3_t mins, const vec3_t maxs) int i; for (i=0 ; i < 4 ; i++) { + // NOTE frustum distance is -p.n if (BOX_ON_PLANE_SIDE (mins, maxs, &frustum[i]) == 2) { return true; } @@ -205,7 +208,8 @@ R_CullSphere (const plane_t *frustum, const vec3_t origin, const float radius) for (i = 0; i < 4; i++) { - r = DotProduct (origin, frustum[i].normal) - frustum[i].dist; + // NOTE frustum distance is -p.n + r = DotProduct (origin, frustum[i].normal) + frustum[i].dist; if (r <= -radius) return true; } diff --git a/include/QF/model.h b/include/QF/model.h index 47a7a8baa..e8d9df66a 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -34,6 +34,8 @@ #include "QF/modelgen.h" #include "QF/zone.h" +#include "QF/simd/types.h" + extern struct vid_model_funcs_s *mod_funcs; /* @@ -174,18 +176,18 @@ typedef struct msurface_s { } msurface_t; typedef struct mnode_s { -// common with leaf - int contents; // 0, to differentiate from leafs - int visframe; // node needs to be traversed if current - - float minmaxs[6]; // for bounding box culling - -// node specific - plane_t *plane; - struct mnode_s *children[2]; - - unsigned int firstsurface; - unsigned int numsurfaces; + /// Vector representation of the plane. + /// \note the 4th component is the negative of the plane distance. This + /// makes it so a 4d dot product with a point vector (4th component = 1) + /// gives the distance of the point from the plane. + vec4f_t plane; + byte type; + byte signbits; + byte pad[2]; + int32_t children[2]; ///< Negative values = ~(leaf number) + float minmaxs[6]; + uint32_t firstsurface; + uint32_t numsurfaces; } mnode_t; typedef struct mleaf_s { @@ -267,8 +269,8 @@ typedef struct mod_brush_s { byte *lightdata; char *entities; //FIXME should not be here - mnode_t **node_parents; - mnode_t **leaf_parents; + int32_t *node_parents; + int32_t *leaf_parents; int *leaf_flags; // union of surf flags for surfs in leaf unsigned int checksum; @@ -437,7 +439,7 @@ model_t *Mod_ForName (const char *name, qboolean crash); void Mod_TouchModel (const char *name); void Mod_UnloadModel (model_t *model); // brush specific -mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) __attribute__((pure)); +mleaf_t *Mod_PointInLeaf (vec4f_t p, model_t *model) __attribute__((pure)); struct set_s *Mod_LeafPVS (const mleaf_t *leaf, const model_t *model); void Mod_LeafPVS_set (const mleaf_t *leaf, const model_t *model, byte defvis, diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index 373c81f1a..6aadfab65 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -59,7 +59,7 @@ typedef struct animation_s { typedef struct visibility_s { struct entity_s *entity; // owning entity struct efrag_s *efrag; // linked list of efrags - struct mnode_s *topnode; // bmodels, first world node that + int topnode_id; // bmodels, first world node that // splits bmodel, or NULL if not split // applies to other models, too // found in an active leaf diff --git a/include/r_internal.h b/include/r_internal.h index 95a1c26bc..35b1fda30 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -74,7 +74,8 @@ struct entity_s; struct animation_s; void R_DrawAliasModel (struct entity_s *e); -void R_MarkLeaves (struct mleaf_s *viewleaf); +void R_MarkLeaves (struct mleaf_s *viewleaf, int *node_visframes); +extern int *r_node_visframes; void GL_SetPalette (void *data, const byte *palette); void GLSL_SetPalette (void *data, const byte *palette); diff --git a/include/r_local.h b/include/r_local.h index 33ef06469..3e158fe9d 100644 --- a/include/r_local.h +++ b/include/r_local.h @@ -159,7 +159,7 @@ texture_t *R_TextureAnimation (const struct entity_s *entity, msurface_t *surf) void R_GenSkyTile (void *pdest); void R_SurfPatch (void); -void R_DrawSubmodelPolygons (struct entity_s *ent, model_t *pmodel, int clipflags, struct mnode_s *topnode); +void R_DrawSubmodelPolygons (struct entity_s *ent, model_t *pmodel, int clipflags, struct mleaf_s *topleaf); void R_DrawSolidClippedSubmodelPolygons (struct entity_s *ent, model_t *pmodel, struct mnode_s *topnode); void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel); @@ -308,8 +308,8 @@ void R_SetupFrame (void); void R_cshift_f (void); void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1); void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); -void R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, - struct dlight_s *light, int bit, mnode_t *node); +void R_RecursiveMarkLights (mod_brush_t *brush, vec4f_t lightorigin, + struct dlight_s *light, int bit, int node_id); void R_LoadSkys (const char *); //void Vulkan_R_LoadSkys (const char *, struct vulkan_ctx_s *ctx); diff --git a/libs/models/brush/model_brush.c b/libs/models/brush/model_brush.c index 0b88504ab..8e3d652e2 100644 --- a/libs/models/brush/model_brush.c +++ b/libs/models/brush/model_brush.c @@ -52,6 +52,7 @@ #include "QF/va.h" #include "QF/plugin/vid_render.h" +#include "QF/simd/vec4f.h" #include "compat.h" #include "mod_internal.h" @@ -60,25 +61,20 @@ VISIBLE int mod_sky_divide; //FIXME visibility? VISIBLE int mod_lightmap_bytes = 1; //FIXME should this be visible? VISIBLE mleaf_t * -Mod_PointInLeaf (const vec3_t p, model_t *model) +Mod_PointInLeaf (vec4f_t p, model_t *model) { float d; - mnode_t *node; - plane_t *plane; if (!model || !model->brush.nodes) Sys_Error ("Mod_PointInLeaf: bad model"); - node = model->brush.nodes; + int node_id = 0; while (1) { - if (node->contents < 0) - return (mleaf_t *) node; - plane = node->plane; - d = DotProduct (p, plane->normal) - plane->dist; - if (d >= 0) - node = node->children[0]; - else - node = node->children[1]; + if (node_id < 0) + return model->brush.leafs + ~node_id; + mnode_t *node = model->brush.nodes + node_id; + d = dotf (p, node->plane)[0]; + node_id = node->children[d < 0]; } return NULL; // never reached @@ -668,15 +664,16 @@ Mod_LoadFaces (model_t *mod, bsp_t *bsp) } static void -Mod_SetParent (mod_brush_t *brush, mnode_t *node, mnode_t *parent) +Mod_SetParent (mod_brush_t *brush, int node_id, int parent_id) { - if (node->contents < 0) { - brush->leaf_parents[(mleaf_t *)node - brush->leafs] = parent; + if (node_id < 0) { + brush->leaf_parents[~node_id] = parent_id; return; } - brush->node_parents[node - brush->nodes] = parent; - Mod_SetParent (brush, node->children[0], node); - Mod_SetParent (brush, node->children[1], node); + brush->node_parents[node_id] = parent_id; + mnode_t *node = brush->nodes + node_id; + Mod_SetParent (brush, node->children[0], node_id); + Mod_SetParent (brush, node->children[1], node_id); } static void @@ -720,8 +717,11 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) out->minmaxs[3 + j] = in->maxs[j]; } - p = in->planenum; - out->plane = brush->planes + p; + plane_t *plane = brush->planes + in->planenum; + out->plane = loadvec3f (plane->normal); + out->plane[3] = -plane->dist; + out->type = plane->type; + out->signbits = plane->signbits; out->firstsurface = in->firstface; out->numsurfaces = in->numfaces; @@ -730,28 +730,27 @@ Mod_LoadNodes (model_t *mod, bsp_t *bsp) p = in->children[j]; // this check is for extended bsp 29 files if (p >= 0) { - out->children[j] = brush->nodes + p; + out->children[j] = p; } else { - p = ~p; - if ((unsigned) p < brush->modleafs) { - out->children[j] = (mnode_t *) (brush->leafs + p); + if ((unsigned) ~p < brush->modleafs) { + out->children[j] = p; } else { Sys_Printf ("Mod_LoadNodes: invalid leaf index %i " - "(file has only %i leafs)\n", p, + "(file has only %i leafs)\n", ~p, brush->modleafs); //map it to the solid leaf - out->children[j] = (mnode_t *)(brush->leafs); + out->children[j] = ~0; } } } } - size_t size = (brush->modleafs + brush->numnodes) * sizeof (mnode_t *); + size_t size = (brush->modleafs + brush->numnodes) * sizeof (int32_t); size += brush->modleafs * sizeof (int); brush->node_parents = Hunk_AllocName (0, size, mod->name); brush->leaf_parents = brush->node_parents + brush->numnodes; brush->leaf_flags = (int *) (brush->leaf_parents + brush->modleafs); - Mod_SetParent (brush, brush->nodes, NULL); // sets nodes and leafs + Mod_SetParent (brush, 0, -1); // sets nodes and leafs Mod_SetLeafFlags (brush); } @@ -889,12 +888,12 @@ Mod_LoadClipnodes (model_t *mod, bsp_t *bsp) Replicate the drawing hull structure as a clipping hull */ static void -Mod_MakeHull0 (model_t *mod) +Mod_MakeHull0 (model_t *mod, bsp_t *bsp) { dclipnode_t *out; hull_t *hull; int count, i, j; - mnode_t *in, *child; + mnode_t *in; mod_brush_t *brush = &mod->brush; hull = &brush->hulls[0]; @@ -910,13 +909,14 @@ Mod_MakeHull0 (model_t *mod) hull->planes = brush->planes; for (i = 0; i < count; i++, out++, in++) { - out->planenum = in->plane - brush->planes; + out->planenum = bsp->nodes[i].planenum; for (j = 0; j < 2; j++) { - child = in->children[j]; - if (child->contents < 0) - out->children[j] = child->contents; - else - out->children[j] = child - brush->nodes; + int child_id = in->children[j]; + if (child_id < 0) { + out->children[j] = bsp->leafs[~child_id].contents; + } else { + out->children[j] = child_id; + } } } } @@ -1026,13 +1026,14 @@ do_checksums (const bsp_t *bsp, void *_mod) } static void -recurse_draw_tree (mod_brush_t *brush, mnode_t *node, int depth) +recurse_draw_tree (mod_brush_t *brush, int node_id, int depth) { - if (!node || node->contents < 0) { + if (node_id < 0) { if (depth > brush->depth) brush->depth = depth; return; } + mnode_t *node = &brush->nodes[node_id]; recurse_draw_tree (brush, node->children[0], depth + 1); recurse_draw_tree (brush, node->children[1], depth + 1); } @@ -1041,7 +1042,7 @@ static void Mod_FindDrawDepth (mod_brush_t *brush) { brush->depth = 0; - recurse_draw_tree (brush, brush->nodes, 1); + recurse_draw_tree (brush, 0, 1); } void @@ -1074,9 +1075,9 @@ Mod_LoadBrushModel (model_t *mod, void *buffer) Mod_LoadEntities (mod, bsp); Mod_LoadSubmodels (mod, bsp); - BSP_Free(bsp); + Mod_MakeHull0 (mod, bsp); - Mod_MakeHull0 (mod); + BSP_Free(bsp); Mod_FindDrawDepth (&mod->brush); for (i = 0; i < MAX_MAP_HULLS; i++) diff --git a/libs/scene/light.c b/libs/scene/light.c index a8e82160f..dfbd026c9 100644 --- a/libs/scene/light.c +++ b/libs/scene/light.c @@ -78,7 +78,7 @@ Light_AddLight (lightingdata_t *ldata, const light_t *light, int style) int visleaf = -1; // directional light if (light->position[3]) { // positional light - mleaf_t *leaf = Mod_PointInLeaf (&light->position[0], model); + mleaf_t *leaf = Mod_PointInLeaf (light->position, model); visleaf = leaf - model->brush.leafs - 1; } else if (!DotProduct (light->direction, light->direction)) { // ambient light diff --git a/libs/scene/scene.c b/libs/scene/scene.c index 69344f47c..bf30a92a3 100644 --- a/libs/scene/scene.c +++ b/libs/scene/scene.c @@ -57,8 +57,8 @@ static mleaf_t empty_leafs[] = { }, }; -static mnode_t *empty_leaf_parents[] = { - [1] = 0, +static int empty_leaf_parents[] = { + [1] = -1, }; static int empty_leaf_flags[] = { diff --git a/libs/util/mathlib.c b/libs/util/mathlib.c index 3846f9dd7..e5fda93b3 100644 --- a/libs/util/mathlib.c +++ b/libs/util/mathlib.c @@ -486,9 +486,9 @@ BoxOnPlaneSide (const vec3_t emins, const vec3_t emaxs, const plane_t *p) #endif sides = 0; - if (dist1 >= p->dist) + if (dist1 >= -p->dist) sides = 1; - if (dist2 < p->dist) + if (dist2 < -p->dist) sides |= 2; #ifdef PARANOID diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index 6d171ac82..e6d0bd14c 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -122,8 +122,8 @@ gl_R_RenderEntities (entqueue_t *queue) qfglEnable (GL_NORMALIZE); } - for (size_t i = 0; i < queue->ent_queues[mod_alias].size; i++) { \ - entity_t *ent = queue->ent_queues[mod_alias].a[i]; \ + for (size_t i = 0; i < queue->ent_queues[mod_alias].size; i++) { + entity_t *ent = queue->ent_queues[mod_alias].a[i]; gl_R_DrawAliasModel (ent); } qfglColor3ubv (color_white); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index 026e0eb77..96d011fa8 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -173,7 +173,7 @@ gl_R_NewScene (scene_t *scene) brush->leafs[i].efrags = NULL; // Force a vis update - R_MarkLeaves (0); + R_MarkLeaves (0, 0); R_ClearParticles (); diff --git a/libs/video/renderer/gl/gl_rsurf.c b/libs/video/renderer/gl/gl_rsurf.c index 309b95950..39bd40cb0 100644 --- a/libs/video/renderer/gl/gl_rsurf.c +++ b/libs/video/renderer/gl/gl_rsurf.c @@ -548,16 +548,16 @@ gl_R_DrawBrushModel (entity_t *e) // calculate dynamic lighting for bmodel if it's not an instanced model if (brush->firstmodelsurface != 0 && r_dlight_lightmap) { - vec3_t lightorigin; - for (unsigned k = 0; k < r_maxdlights; k++) { if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; + vec4f_t lightorigin; VectorSubtract (r_dlights[k].origin, worldMatrix[3], lightorigin); + lightorigin[3] = 1; R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, - brush->nodes + brush->hulls[0].firstclipnode); + brush->hulls[0].firstclipnode); } } @@ -597,12 +597,9 @@ static inline int get_side (mnode_t *node) { // find which side of the node we are on - plane_t *plane = node->plane; vec4f_t org = r_refdef.frame.position; - if (plane->type < 3) - return (org[plane->type] - plane->dist) < 0; - return (DotProduct (org, plane->normal) - plane->dist) < 0; + return dotf (org, node->plane)[0] < 0; } static inline void @@ -630,12 +627,13 @@ visit_node (glbspctx_t *bctx, mnode_t *node, int side) } static inline int -test_node (mnode_t *node) +test_node (glbspctx_t *bctx, int node_id) { - if (node->contents < 0) + if (node_id < 0) return 0; - if (node->visframe != r_visframecount) + if (r_node_visframes[node_id] != r_visframecount) return 0; + mnode_t *node = bctx->brush->nodes + node_id; if (R_CullBox (r_refdef.frustum, node->minmaxs, node->minmaxs + 3)) return 0; return 1; @@ -645,45 +643,55 @@ static void R_VisitWorldNodes (glbspctx_t *bctx) { typedef struct { - mnode_t *node; + int node_id; int side; } rstack_t; mod_brush_t *brush = bctx->brush; rstack_t *node_ptr; rstack_t *node_stack; - mnode_t *node; - mnode_t *front; + int node_id; + int front; int side; - node = brush->nodes; + node_id = 0; // +2 for paranoia node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { - while (test_node (node)) { + while (test_node (bctx, node_id)) { + mnode_t *node = bctx->brush->nodes + node_id; side = get_side (node); front = node->children[side]; - if (test_node (front)) { - node_ptr->node = node; + if (test_node (bctx, front)) { + node_ptr->node_id = node_id; node_ptr->side = side; node_ptr++; - node = front; + node_id = front; continue; } - if (front->contents < 0 && front->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) front); + if (front < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~front; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } + } visit_node (bctx, node, side); - node = node->children[!side]; + node_id = node->children[side ^ 1]; + } + if (node_id < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); if (node_ptr != node_stack) { node_ptr--; - node = node_ptr->node; + node_id = node_ptr->node_id; + mnode_t *node = bctx->brush->nodes + node_id; side = node_ptr->side; visit_node (bctx, node, side); - node = node->children[!side]; + node_id = node->children[side ^ 1]; continue; } break; diff --git a/libs/video/renderer/glsl/glsl_bsp.c b/libs/video/renderer/glsl/glsl_bsp.c index 39ae051c7..06d1b87a0 100644 --- a/libs/video/renderer/glsl/glsl_bsp.c +++ b/libs/video/renderer/glsl/glsl_bsp.c @@ -694,16 +694,16 @@ R_DrawBrushModel (entity_t *e) // calculate dynamic lighting for bmodel if it's not an instanced model if (brush->firstmodelsurface != 0 && r_dlight_lightmap) { - vec3_t lightorigin; - for (k = 0; k < r_maxdlights; k++) { if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) continue; + vec4f_t lightorigin; VectorSubtract (r_dlights[k].origin, mat[3], lightorigin); + lightorigin[3] = 1; R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, - brush->nodes + brush->hulls[0].firstclipnode); + brush->hulls[0].firstclipnode); } } @@ -736,12 +736,9 @@ static inline int get_side (mnode_t *node) { // find the node side on which we are - plane_t *plane = node->plane; vec4f_t org = r_refdef.frame.position; - if (plane->type < 3) - return (org[plane->type] - plane->dist) < 0; - return (DotProduct (org, plane->normal) - plane->dist) < 0; + return dotf (org, node->plane)[0] < 0; } static inline void @@ -773,12 +770,13 @@ visit_node (glslbspctx_t *bctx, mnode_t *node, int side) } static inline int -test_node (mnode_t *node) +test_node (glslbspctx_t *bctx, int node_id) { - if (node->contents < 0) + if (node_id < 0) return 0; - if (node->visframe != r_visframecount) + if (r_node_visframes[node_id] != r_visframecount) return 0; + mnode_t *node = bctx->brush->nodes + node_id; if (R_CullBox (r_refdef.frustum, node->minmaxs, node->minmaxs + 3)) return 0; return 1; @@ -788,45 +786,55 @@ static void R_VisitWorldNodes (glslbspctx_t *bctx) { typedef struct { - mnode_t *node; + int node_id; int side; } rstack_t; mod_brush_t *brush = bctx->brush; rstack_t *node_ptr; rstack_t *node_stack; - mnode_t *node; - mnode_t *front; + int node_id; + int front; int side; - node = brush->nodes; + node_id = 0; // +2 for paranoia node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { - while (test_node (node)) { + while (test_node (bctx, node_id)) { + mnode_t *node = bctx->brush->nodes + node_id; side = get_side (node); front = node->children[side]; - if (test_node (front)) { - node_ptr->node = node; + if (test_node (bctx, front)) { + node_ptr->node_id = node_id; node_ptr->side = side; node_ptr++; - node = front; + node_id = front; continue; } - if (front->contents < 0 && front->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) front); + if (front < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~front; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } + } visit_node (bctx, node, side); - node = node->children[!side]; + node_id = node->children[side ^ 1]; + } + if (node_id < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); if (node_ptr != node_stack) { node_ptr--; - node = node_ptr->node; + node_id = node_ptr->node_id; side = node_ptr->side; + mnode_t *node = bctx->brush->nodes + node_id; visit_node (bctx, node, side); - node = node->children[!side]; + node_id = node->children[side ^ 1]; continue; } break; diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 7c8d04502..fb0996427 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -199,7 +199,7 @@ glsl_R_NewScene (scene_t *scene) r_refdef.worldmodel = scene->worldmodel; // Force a vis update - R_MarkLeaves (0); + R_MarkLeaves (0, 0); R_ClearParticles (); glsl_R_RegisterTextures (scene->models, scene->num_models); diff --git a/libs/video/renderer/r_bsp.c b/libs/video/renderer/r_bsp.c index f534d4b1b..468357857 100644 --- a/libs/video/renderer/r_bsp.c +++ b/libs/video/renderer/r_bsp.c @@ -47,12 +47,11 @@ static mleaf_t *r_oldviewleaf; static set_t *solid; void -R_MarkLeaves (mleaf_t *viewleaf) +R_MarkLeaves (mleaf_t *viewleaf, int *node_visframes) { set_t *vis; int c; mleaf_t *leaf; - mnode_t *node; msurface_t **mark; mod_brush_t *brush = &r_refdef.worldmodel->brush; @@ -86,12 +85,12 @@ R_MarkLeaves (mleaf_t *viewleaf) } while (--c); } leaf->visframe = r_visframecount; - node = brush->leaf_parents[leaf - brush->leafs]; - while (node) { - if (node->visframe == r_visframecount) + int node_id = brush->leaf_parents[leaf - brush->leafs]; + while (node_id >= 0) { + if (node_visframes[node_id] == r_visframecount) break; - node->visframe = r_visframecount; - node = brush->node_parents[node - brush->nodes]; + node_visframes[node_id] = r_visframecount; + node_id = brush->node_parents[node_id]; } } } diff --git a/libs/video/renderer/r_efrag.c b/libs/video/renderer/r_efrag.c index a1d4e6ea3..8e88222f2 100644 --- a/libs/video/renderer/r_efrag.c +++ b/libs/video/renderer/r_efrag.c @@ -140,25 +140,25 @@ R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, mleaf_t *leaf; int sides; efrag_t **lastlink; - mnode_t **node_stack; - mnode_t **node_ptr; - mnode_t *node = brush->nodes; + int *node_stack; + int *node_ptr; node_stack = alloca ((brush->depth + 2) * sizeof (mnode_t *)); node_ptr = node_stack; lastlink = &ent->visibility.efrag; - *node_ptr++ = 0; + *node_ptr++ = brush->numnodes; - while (node) { + int node_id = 0; + while (node_id != (int) brush->numnodes) { // add an efrag if the node is a leaf - if (__builtin_expect (node->contents < 0, 0)) { - if (!ent->visibility.topnode) { - ent->visibility.topnode = node; + if (__builtin_expect (node_id < 0, 0)) { + if (ent->visibility.topnode_id == -1) { + ent->visibility.topnode_id = node_id; } - leaf = (mleaf_t *) node; + leaf = brush->leafs + ~node_id; ef = new_efrag (); // ensures ef->entnext is 0 @@ -172,29 +172,30 @@ R_SplitEntityOnNode (mod_brush_t *brush, entity_t *ent, ef->leafnext = leaf->efrags; leaf->efrags = ef; - node = *--node_ptr; + node_id = *--node_ptr; } else { + mnode_t *node = brush->nodes + node_id; // NODE_MIXED - splitplane = node->plane; + splitplane = (plane_t *) &node->plane; sides = BOX_ON_PLANE_SIDE (emins, emaxs, splitplane); if (sides == 3) { // split on this plane // if this is the first splitter of this bmodel, remember it - if (!ent->visibility.topnode) { - ent->visibility.topnode = node; + if (ent->visibility.topnode_id == -1) { + ent->visibility.topnode_id = node_id; } } // recurse down the contacted sides - if (sides & 1 && node->children[0]->contents != CONTENTS_SOLID) { - if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) + if (sides & 1) { + if (sides & 2) *node_ptr++ = node->children[1]; - node = node->children[0]; + node_id = node->children[0]; } else { - if (sides & 2 && node->children[1]->contents != CONTENTS_SOLID) - node = node->children[1]; + if (sides & 2) + node_id = node->children[1]; else - node = *--node_ptr; + node_id = *--node_ptr; } } } @@ -216,7 +217,7 @@ R_AddEfrags (mod_brush_t *brush, entity_t *ent) VectorAdd (org, entmodel->mins, emins); VectorAdd (org, entmodel->maxs, emaxs); - ent->visibility.topnode = 0; + ent->visibility.topnode_id = -1; // leaf 0 (solid space) R_SplitEntityOnNode (brush, ent, emins, emaxs); } diff --git a/libs/video/renderer/r_light.c b/libs/video/renderer/r_light.c index 5c805fb54..614227a92 100644 --- a/libs/video/renderer/r_light.c +++ b/libs/video/renderer/r_light.c @@ -152,7 +152,7 @@ R_AnimateLight (void) } static inline void -real_mark_surfaces (float dist, msurface_t *surf, const vec3_t lightorigin, +real_mark_surfaces (float dist, msurface_t *surf, vec4f_t lightorigin, dlight_t *light, unsigned lightnum) { float dist2, is, it; @@ -190,7 +190,7 @@ real_mark_surfaces (float dist, msurface_t *surf, const vec3_t lightorigin, } static inline void -mark_surfaces (msurface_t *surf, const vec3_t lightorigin, dlight_t *light, +mark_surfaces (msurface_t *surf, vec4f_t lightorigin, dlight_t *light, int lightnum) { float dist; @@ -208,35 +208,33 @@ mark_surfaces (msurface_t *surf, const vec3_t lightorigin, dlight_t *light, // LordHavoc: heavily modified, to eliminate unnecessary texture uploads, // and support bmodel lighting better void -R_RecursiveMarkLights (mod_brush_t *brush, const vec3_t lightorigin, - dlight_t *light, int lightnum, mnode_t *node) +R_RecursiveMarkLights (mod_brush_t *brush, vec4f_t lightorigin, + dlight_t *light, int lightnum, int node_id) { unsigned i; float ndist, maxdist; - plane_t *splitplane; msurface_t *surf; maxdist = light->radius; loc0: - if (node->contents < 0) + if (node_id < 0) return; - splitplane = node->plane; - ndist = DotProduct (lightorigin, splitplane->normal) - splitplane->dist; + mnode_t *node = brush->nodes + node_id; + ndist = dotf (lightorigin, node->plane)[0]; if (ndist > maxdist * maxdist) { // Save time by not pushing another stack frame. - if (node->children[0]->contents >= 0) { - node = node->children[0]; + if (node->children[0] >= 0) { + node_id = node->children[0]; goto loc0; } return; } if (ndist < -maxdist * maxdist) { - // Save time by not pushing another stack frame. - if (node->children[1]->contents >= 0) { - node = node->children[1]; + if (node->children[1] >= 0) { + node_id = node->children[1]; goto loc0; } return; @@ -248,29 +246,29 @@ loc0: mark_surfaces (surf, lightorigin, light, lightnum); } - if (node->children[0]->contents >= 0) { - if (node->children[1]->contents >= 0) + if (node->children[0] >= 0) { + if (node->children[1] >= 0) R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node->children[1]); - node = node->children[0]; + node_id = node->children[0]; goto loc0; - } else if (node->children[1]->contents >= 0) { - node = node->children[1]; + } else if (node->children[1] >= 0) { + node_id = node->children[1]; goto loc0; } } static void -R_MarkLights (const vec3_t lightorigin, dlight_t *light, int lightnum, +R_MarkLights (vec4f_t lightorigin, dlight_t *light, int lightnum, model_t *model) { mod_brush_t *brush = &model->brush; mleaf_t *pvsleaf = Mod_PointInLeaf (lightorigin, model); if (!pvsleaf->compressed_vis) { - mnode_t *node = brush->nodes + brush->hulls[0].firstclipnode; - R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node); + int node_id = brush->hulls[0].firstclipnode; + R_RecursiveMarkLights (brush, lightorigin, light, lightnum, node_id); } else { float radius = light->radius; vec3_t mins, maxs; @@ -321,7 +319,6 @@ R_PushDlights (const vec3_t entorigin) { unsigned int i; dlight_t *l; - vec3_t lightorigin; // because the count hasn't advanced yet for this frame r_dlightframecount = r_framecount + 1; @@ -334,14 +331,15 @@ R_PushDlights (const vec3_t entorigin) for (i = 0; i < r_maxdlights; i++, l++) { if (l->die < r_data->realtime || !l->radius) continue; + vec4f_t lightorigin; VectorSubtract (l->origin, entorigin, lightorigin); + lightorigin[3] = 1; R_MarkLights (lightorigin, l, i, r_refdef.worldmodel); } } /* LIGHT SAMPLING */ -plane_t *lightplane; vec3_t lightspot; static int @@ -408,27 +406,26 @@ calc_lighting_3 (msurface_t *surf, int ds, int dt) } static int -RecursiveLightPoint (mod_brush_t *brush, mnode_t *node, vec4f_t start, +RecursiveLightPoint (mod_brush_t *brush, int node_id, vec4f_t start, vec4f_t end) { unsigned i; int r, s, t, ds, dt, side; float front, back, frac; - plane_t *plane; msurface_t *surf; mtexinfo_t *tex; loop: - if (node->contents < 0) + if (node_id < 0) return -1; // didn't hit anything // calculate mid point - plane = node->plane; - front = DotProduct (start, plane->normal) - plane->dist; - back = DotProduct (end, plane->normal) - plane->dist; + mnode_t *node = brush->nodes + node_id; + front = dotf (start, node->plane)[0]; + back = dotf (end, node->plane)[0]; side = front < 0; if ((back < 0) == side) { - node = node->children[side]; + node_id = node->children[side]; goto loop; } @@ -445,7 +442,6 @@ loop: // check for impact on this node VectorCopy (mid, lightspot); - lightplane = plane; surf = brush->surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) { @@ -478,7 +474,7 @@ loop: } // go down back side - return RecursiveLightPoint (brush, node->children[!side], mid, end); + return RecursiveLightPoint (brush, node->children[side ^ 1], mid, end); } int @@ -491,7 +487,7 @@ R_LightPoint (mod_brush_t *brush, vec4f_t p) } vec4f_t end = p - (vec4f_t) { 0, 0, 2048, 0 }; - int r = RecursiveLightPoint (brush, brush->nodes, p, end); + int r = RecursiveLightPoint (brush, 0, p, end); if (r == -1) r = 0; diff --git a/libs/video/renderer/r_main.c b/libs/video/renderer/r_main.c index d29bcd1a4..06845c912 100644 --- a/libs/video/renderer/r_main.c +++ b/libs/video/renderer/r_main.c @@ -111,7 +111,7 @@ R_SetFrustum (plane_t *frustum, const refframe_t *frame, vec4f_t origin = frame->position; for (i = 0; i < 4; i++) { frustum[i].type = PLANE_ANYZ; - frustum[i].dist = DotProduct (origin, frustum[i].normal); + frustum[i].dist = -DotProduct (origin, frustum[i].normal); frustum[i].signbits = SignbitsForPlane (&frustum[i]); } } diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 365bb9dde..3255d88ef 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -61,6 +61,7 @@ int scr_copytop; byte *draw_chars; // 8*8 graphic characters FIXME location qboolean r_cache_thrash; // set if surface cache is thrashing +int *r_node_visframes; //FIXME per renderer qboolean scr_skipupdate; static qboolean scr_initialized;// ready to draw @@ -273,8 +274,7 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) if (scr_scene && scr_scene->worldmodel) { scr_scene->viewleaf = 0; vec4f_t position = refdef->frame.position; - scr_scene->viewleaf = Mod_PointInLeaf ((vec_t*)&position, - scr_scene->worldmodel);//FIXME + scr_scene->viewleaf = Mod_PointInLeaf (position, scr_scene->worldmodel); r_dowarpold = r_dowarp; if (r_waterwarp) { r_dowarp = scr_scene->viewleaf->contents <= CONTENTS_WATER; @@ -283,7 +283,7 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) warp_buffer = r_funcs->create_frame_buffer (r_data->vid->width, r_data->vid->height); } - R_MarkLeaves (scr_scene->viewleaf); + R_MarkLeaves (scr_scene->viewleaf, r_node_visframes); } R_PushDlights (vec3_origin); @@ -514,6 +514,9 @@ SCR_NewScene (scene_t *scene) { scr_scene = scene; if (scene) { + mod_brush_t *brush = &scr_scene->worldmodel->brush; + int size = brush->numnodes * sizeof (int); + r_node_visframes = Hunk_AllocName (0, size, "visframes"); r_funcs->set_fov (tan_fov_x, tan_fov_y); r_funcs->R_NewScene (scene); } else { diff --git a/libs/video/renderer/sw/sw_rbsp.c b/libs/video/renderer/sw/sw_rbsp.c index 1362f9436..4947dc24b 100644 --- a/libs/video/renderer/sw/sw_rbsp.c +++ b/libs/video/renderer/sw/sw_rbsp.c @@ -118,8 +118,8 @@ R_RecursiveClipBPoly (entity_t *ent, bedge_t *pedges, mnode_t *pnode, // transform the BSP plane into model space // FIXME: cache these? - splitplane = pnode->plane; - tplane.dist = splitplane->dist - + splitplane = (plane_t *) &pnode->plane; + tplane.dist = splitplane->dist + DotProduct (r_entorigin, splitplane->normal); tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); @@ -132,7 +132,7 @@ R_RecursiveClipBPoly (entity_t *ent, bedge_t *pedges, mnode_t *pnode, // set the status for the last point as the previous point // FIXME: cache this stuff somehow? plastvert = pedges->v[0]; - lastdist = DotProduct (plastvert->position, tplane.normal) - + lastdist = DotProduct (plastvert->position, tplane.normal) + tplane.dist; if (lastdist > 0) @@ -142,7 +142,7 @@ R_RecursiveClipBPoly (entity_t *ent, bedge_t *pedges, mnode_t *pnode, pvert = pedges->v[1]; - dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; + dist = DotProduct (pvert->position, tplane.normal) + tplane.dist; if (dist > 0) side = 0; @@ -228,18 +228,20 @@ R_RecursiveClipBPoly (entity_t *ent, bedge_t *pedges, mnode_t *pnode, if (psideedges[i]) { // draw if we've reached a non-solid leaf, done if all that's left // is a solid leaf, and continue down the tree if it's not a leaf - pn = pnode->children[i]; + int child_id = pnode->children[i]; + pn = r_refdef.worldmodel->brush.nodes + child_id; // we're done with this branch if the node or leaf isn't in the PVS - if (pn->visframe == r_visframecount) { - if (pn->contents < 0) { - if (pn->contents != CONTENTS_SOLID) { - r_currentbkey = ((mleaf_t *) pn)->key; - R_RenderBmodelFace (ent, psideedges[i], psurf); - } - } else { - R_RecursiveClipBPoly (ent, psideedges[i], - pnode->children[i], psurf); + if (child_id < 0) { + mleaf_t *leaf = r_refdef.worldmodel->brush.leafs + ~child_id; + if (leaf->visframe == r_visframecount + && leaf->contents != CONTENTS_SOLID) { + r_currentbkey = leaf->key; + R_RenderBmodelFace (ent, psideedges[i], psurf); + } + } else { + if (r_node_visframes[child_id] == r_visframecount) { + R_RecursiveClipBPoly (ent, psideedges[i], pn, psurf); } } } @@ -320,7 +322,7 @@ R_DrawSolidClippedSubmodelPolygons (entity_t *ent, model_t *model, void R_DrawSubmodelPolygons (entity_t *ent, model_t *model, int clipflags, - mnode_t *topnode) + mleaf_t *topleaf) { int i; vec_t dot; @@ -343,7 +345,7 @@ R_DrawSubmodelPolygons (entity_t *ent, model_t *model, int clipflags, // draw the polygon if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { - r_currentkey = ((mleaf_t *) topnode)->key; + r_currentkey = topleaf->key; // FIXME: use bounding-box-based frustum clipping info? R_RenderFace (ent, psurf, clipflags); @@ -365,12 +367,9 @@ static inline int get_side (mnode_t *node) { // find which side of the node we are on - plane_t *plane = node->plane; vec4f_t org = r_refdef.frame.position; - if (plane->type < 3) - return (org[plane->type] - plane->dist) < 0; - return (DotProduct (org, plane->normal) - plane->dist) < 0; + return dotf (org, node->plane)[0] < 0; } static void @@ -414,20 +413,21 @@ visit_node (swbspctx_t *bctx, mnode_t *node, int side, int clipflags) } static inline int -test_node (mnode_t *node, int *clipflags) +test_node (swbspctx_t *bctx, int node_id, int *clipflags) { int i, *pindex; vec3_t acceptpt, rejectpt; double d; - if (node->contents < 0) + if (node_id < 0) return 0; - if (node->visframe != r_visframecount) + if (r_node_visframes[node_id] != r_visframecount) return 0; // cull the clipping planes if not trivial accept // FIXME: the compiler is doing a lousy job of optimizing here; it could be // twice as fast in ASM if (*clipflags) { + mnode_t *node = bctx->brush->nodes + node_id; for (i = 0; i < 4; i++) { if (!(*clipflags & (1 << i))) continue; // don't need to clip against it @@ -465,50 +465,60 @@ static void R_VisitWorldNodes (swbspctx_t *bctx, int clipflags) { typedef struct { - mnode_t *node; + int node_id; int side, clipflags; } rstack_t; rstack_t *node_ptr; rstack_t *node_stack; - mnode_t *node; - mnode_t *front; + int front; int side, cf; + int node_id; mod_brush_t *brush = &bctx->entity->renderer.model->brush; - node = brush->nodes; // +2 for paranoia node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; + node_id = 0; cf = clipflags; while (1) { - while (test_node (node, &cf)) { + while (test_node (bctx, node_id, &cf)) { + mnode_t *node = bctx->brush->nodes + node_id; cf = clipflags; side = get_side (node); front = node->children[side]; - if (test_node (front, &cf)) { - node_ptr->node = node; + if (test_node (bctx, front, &cf)) { + node_ptr->node_id = node_id; node_ptr->side = side; node_ptr->clipflags = clipflags; node_ptr++; clipflags = cf; - node = front; + node_id = front; continue; } - if (front->contents < 0 && front->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) front); + if (front < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~front; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } + } visit_node (bctx, node, side, clipflags); - node = node->children[!side]; + node_id = node->children[side ^ 1]; + } + if (node_id < 0) { + mleaf_t *leaf = bctx->brush->leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); if (node_ptr != node_stack) { node_ptr--; - node = node_ptr->node; + node_id = node_ptr->node_id; + mnode_t *node = bctx->brush->nodes + node_id; side = node_ptr->side; clipflags = node_ptr->clipflags; visit_node (bctx, node, side, clipflags); - node = node->children[!side]; + node_id = node->children[side ^ 1]; continue; } break; diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 03d988965..f129b2254 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -167,7 +167,7 @@ R_NewScene (scene_t *scene) R_InitSky (brush->skytexture); // Force a vis update - R_MarkLeaves (0); + R_MarkLeaves (0, 0); R_ClearParticles (); @@ -303,8 +303,7 @@ R_DrawEntitiesOnList (entqueue_t *queue) for (size_t i = 0; i < queue->ent_queues[mod_##type_name].size; \ i++) { \ entity_t *ent = queue->ent_queues[mod_##type_name].a[i]; \ - VectorCopy (Transform_GetWorldPosition (ent->transform), \ - r_entorigin); \ + r_entorigin = Transform_GetWorldPosition (ent->transform); \ draw_##type_name##_entity (ent); \ } \ } while (0) @@ -473,19 +472,18 @@ R_DrawBrushEntitiesOnList (entqueue_t *queue) // calculate dynamic lighting for bmodel if it's not an // instanced model if (brush->firstmodelsurface != 0) { - vec3_t lightorigin; - for (k = 0; k < r_maxdlights; k++) { if ((r_dlights[k].die < vr_data.realtime) || (!r_dlights[k].radius)) { continue; } + vec4f_t lightorigin; VectorSubtract (r_dlights[k].origin, origin, lightorigin); + lightorigin[3] = 1; R_RecursiveMarkLights (brush, lightorigin, &r_dlights[k], k, - brush->nodes - + brush->hulls[0].firstclipnode); + brush->hulls[0].firstclipnode); } } // if the driver wants polygons, deliver those. @@ -494,20 +492,21 @@ R_DrawBrushEntitiesOnList (entqueue_t *queue) if (r_drawpolys | r_drawculledpolys) { R_ZDrawSubmodelPolys (ent, clmodel); } else { - if (ent->visibility.topnode) { - mnode_t *topnode = ent->visibility.topnode; + int topnode_id = ent->visibility.topnode_id; + mod_brush_t *brush = &r_refdef.worldmodel->brush; - if (topnode->contents >= 0) { - // not a leaf; has to be clipped to the world - // BSP - r_clipflags = clipflags; - R_DrawSolidClippedSubmodelPolygons (ent, clmodel, topnode); - } else { - // falls entirely in one leaf, so we just put - // all the edges in the edge list and let 1/z - // sorting handle drawing order - R_DrawSubmodelPolygons (ent, clmodel, clipflags, topnode); - } + if (topnode_id >= 0) { + // not a leaf; has to be clipped to the world + // BSP + mnode_t *node = brush->nodes + topnode_id; + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (ent, clmodel, node); + } else { + // falls entirely in one leaf, so we just put + // all the edges in the edge list and let 1/z + // sorting handle drawing order + mleaf_t *leaf = brush->leafs + ~topnode_id; + R_DrawSubmodelPolygons (ent, clmodel, clipflags, leaf); } } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index f5d0d49b6..e92f0d20e 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -648,12 +648,9 @@ static inline int get_side (mnode_t *node) { // find the node side on which we are - plane_t *plane = node->plane; vec4f_t org = r_refdef.frame.position; - if (plane->type < 3) - return (org[plane->type] - plane->dist) < 0; - return (DotProduct (org, plane->normal) - plane->dist) < 0; + return dotf (org, node->plane)[0] < 0; } static inline void @@ -685,12 +682,13 @@ visit_node (mod_brush_t *brush, mnode_t *node, int side, vulkan_ctx_t *ctx) } static inline int -test_node (mnode_t *node) +test_node (mod_brush_t *brush, int node_id) { - if (node->contents < 0) + if (node_id < 0) return 0; - if (node->visframe != r_visframecount) + if (r_node_visframes[node_id] != r_visframecount) return 0; + mnode_t *node = brush->nodes + node_id; if (R_CullBox (r_refdef.frustum, node->minmaxs, node->minmaxs + 3)) return 0; return 1; @@ -700,48 +698,58 @@ static void R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx) { typedef struct { - mnode_t *node; + int node_id; int side; } rstack_t; rstack_t *node_ptr; rstack_t *node_stack; - mnode_t *node; - mnode_t *front; + int node_id; + int front; int side; - node = brush->nodes; + node_id = 0; // +2 for paranoia node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t)); node_ptr = node_stack; while (1) { - while (test_node (node)) { + while (test_node (brush, node_id)) { + mnode_t *node = brush->nodes + node_id; side = get_side (node); front = node->children[side]; - if (test_node (front)) { - node_ptr->node = node; + if (test_node (brush, front)) { + node_ptr->node_id = node_id; node_ptr->side = side; node_ptr++; - node = front; + node_id = front; continue; } // front is either not a node (ie, is a leaf) or is not visible // if node is visible, then at least one of its child nodes // must also be visible, and a leaf child in front of the node // will be visible, so no need for vis checks on a leaf - if (front->contents < 0 && front->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) front); + if (front < 0) { + mleaf_t *leaf = brush->leafs + ~front; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } + } visit_node (brush, node, side, ctx); - node = node->children[!side]; + node_id = node->children[side ^ 1]; + } + if (node_id < 0) { + mleaf_t *leaf = brush->leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + visit_leaf (leaf); + } } - if (node->contents < 0 && node->contents != CONTENTS_SOLID) - visit_leaf ((mleaf_t *) node); if (node_ptr != node_stack) { node_ptr--; - node = node_ptr->node; + node_id = node_ptr->node_id; side = node_ptr->side; + mnode_t *node = brush->nodes + node_id; visit_node (brush, node, side, ctx); - node = node->children[!side]; + node_id = node->children[side ^ 1]; continue; } break; diff --git a/libs/video/renderer/vulkan/vulkan_main.c b/libs/video/renderer/vulkan/vulkan_main.c index 9af4c5b73..59e327df7 100644 --- a/libs/video/renderer/vulkan/vulkan_main.c +++ b/libs/video/renderer/vulkan/vulkan_main.c @@ -142,7 +142,7 @@ Vulkan_NewScene (scene_t *scene, vulkan_ctx_t *ctx) r_refdef.worldmodel = scene->worldmodel; // Force a vis update - R_MarkLeaves (0); + R_MarkLeaves (0, 0); R_ClearParticles (); Vulkan_RegisterTextures (scene->models, scene->num_models, ctx); diff --git a/nq/source/cl_screen.c b/nq/source/cl_screen.c index bd2effd81..ea3a3ab50 100644 --- a/nq/source/cl_screen.c +++ b/nq/source/cl_screen.c @@ -83,7 +83,7 @@ SCR_CShift (void) if (cls.state == ca_active && cl_world.scene->worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME + leaf = Mod_PointInLeaf (origin, cl_world.scene->worldmodel); contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/nq/source/host.c b/nq/source/host.c index da90dc94a..da393a677 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -757,7 +757,7 @@ Host_ClientFrame (void) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME + l = Mod_PointInLeaf (origin, cl_world.scene->worldmodel); if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/nq/source/sv_main.c b/nq/source/sv_main.c index e89c8c82b..f3ebcb654 100644 --- a/nq/source/sv_main.c +++ b/nq/source/sv_main.c @@ -372,30 +372,29 @@ SV_ClearDatagram (void) static set_t *fatpvs; static void -SV_AddToFatPVS (vec3_t org, mnode_t *node) +SV_AddToFatPVS (vec4f_t org, int node_id) { 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) { - set_union (fatpvs, Mod_LeafPVS ((mleaf_t *) node, - sv.worldmodel)); + if (node_id < 0) { + mleaf_t *leaf = sv.worldmodel->brush.leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + set_union (fatpvs, Mod_LeafPVS (leaf, sv.worldmodel)); } return; } + mnode_t *node = sv.worldmodel->brush.nodes + node_id; - plane = node->plane; - d = DotProduct (org, plane->normal) - plane->dist; + d = dotf (node->plane, org)[0]; if (d > 8) - node = node->children[0]; + node_id = node->children[0]; else if (d < -8) - node = node->children[1]; + node_id = node->children[1]; else { // go down both SV_AddToFatPVS (org, node->children[0]); - node = node->children[1]; + node_id = node->children[1]; } } } @@ -407,14 +406,14 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) given point. */ static set_t * -SV_FatPVS (vec3_t org) +SV_FatPVS (vec4f_t org) { if (!fatpvs) { fatpvs = set_new_size (sv.worldmodel->brush.visleafs); } set_expand (fatpvs, sv.worldmodel->brush.visleafs); set_empty (fatpvs); - SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); + SV_AddToFatPVS (org, 0); return fatpvs; } @@ -426,13 +425,14 @@ SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) pr_uint_t bits, e; set_t *pvs; float miss; - vec3_t org; + vec4f_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); + org[3] = 1; pvs = SV_FatPVS (org); // send over all entities (excpet the client) that touch the pvs diff --git a/nq/source/sv_pr_cmds.c b/nq/source/sv_pr_cmds.c index b555708ff..dfc0552fd 100644 --- a/nq/source/sv_pr_cmds.c +++ b/nq/source/sv_pr_cmds.c @@ -548,7 +548,6 @@ PF_newcheckclient (progs_t *pr, unsigned check) edict_t *ent; unsigned i; mleaf_t *leaf; - vec3_t org; // cycle to the next one if (check < 1) @@ -582,7 +581,9 @@ PF_newcheckclient (progs_t *pr, unsigned check) } // get the PVS for the entity + vec4f_t org; VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); + org[3] = 1; leaf = Mod_PointInLeaf (org, sv.worldmodel); if (!checkpvs) { checkpvs = set_new_size (sv.worldmodel->brush.visleafs); @@ -615,7 +616,6 @@ PF_checkclient (progs_t *pr, void *data) edict_t *ent, *self; int l; mleaf_t *leaf; - vec3_t view; // find a new check if on a new frame if (sv.time - sv.lastchecktime >= 0.1) { @@ -630,7 +630,9 @@ PF_checkclient (progs_t *pr, void *data) } // if current entity can't possibly see the check entity, return 0 self = PROG_TO_EDICT (pr, *sv_globals.self); + vec4f_t view; VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); + view[3] = 1; leaf = Mod_PointInLeaf (view, sv.worldmodel); l = (leaf - sv.worldmodel->brush.leafs) - 1; if (!set_is_member (checkpvs, l)) { diff --git a/nq/source/world.c b/nq/source/world.c index 9926abd26..13e6df8d0 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -410,19 +410,17 @@ SV_TouchLinks (edict_t *ent, areanode_t *node) } static void -SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) +SV_FindTouchedLeafs (edict_t *ent, int node_id) { int sides; - mleaf_t *leaf; plane_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) { - leaf = (mleaf_t *) node; + // add an efrag if the node is a non-solid leaf + if (node_id < 0) { + mleaf_t *leaf = sv.worldmodel->brush.leafs + ~node_id; + if (leaf->contents == CONTENTS_SOLID) + return; edict_leaf = alloc_edict_leaf (); edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; @@ -431,8 +429,9 @@ SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) return; } + mnode_t *node = sv.worldmodel->brush.nodes + node_id; // NODE_MIXED - splitplane = node->plane; + splitplane = (plane_t *) &node->plane; sides = BOX_ON_PLANE_SIDE (SVvector (ent, absmin), SVvector (ent, absmax), splitplane); @@ -497,7 +496,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); + SV_FindTouchedLeafs (ent, 0); if (SVfloat (ent, solid) == SOLID_NOT) return; diff --git a/qtv/source/client.c b/qtv/source/client.c index 9113d2b7d..26eda3b92 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -52,6 +52,8 @@ #include "QF/sys.h" #include "QF/va.h" +#include "QF/simd/vec4f.h" + #include "qw/bothdefs.h" #include "qw/msg_ucmd.h" #include "qw/protocol.h" @@ -978,30 +980,27 @@ emit_entities (client_t *client, packet_entities_t *to, sizebuf_t *msg) } static void -add_to_fat_pvs (vec4f_t org, mnode_t *node, server_t *sv) +add_to_fat_pvs (vec4f_t org, int node_id, server_t *sv) { - 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) { - set_union (sv->fatpvs, Mod_LeafPVS ((mleaf_t *) node, - sv->worldmodel)); + if (node_id < 0) { + mleaf_t *leaf = sv->worldmodel->brush.leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + set_union (sv->fatpvs, Mod_LeafPVS (leaf, sv->worldmodel)); } return; } - plane = node->plane; - d = DotProduct (org, plane->normal) - plane->dist; + mnode_t *node = sv->worldmodel->brush.nodes + node_id; + float d = dotf (node->plane, org)[0]; if (d > 8) - node = node->children[0]; + node_id = node->children[0]; else if (d < -8) - node = node->children[1]; + node_id = node->children[1]; else { // go down both add_to_fat_pvs (org, node->children[0], sv); - node = node->children[1]; + node_id = node->children[1]; } } } @@ -1015,7 +1014,7 @@ fat_pvs (vec4f_t org, server_t *sv) set_expand (sv->fatpvs, sv->worldmodel->brush.visleafs); set_empty (sv->fatpvs); - add_to_fat_pvs (org, sv->worldmodel->brush.nodes, sv); + add_to_fat_pvs (org, 0, sv); return sv->fatpvs; } diff --git a/qtv/source/sv_parse.c b/qtv/source/sv_parse.c index db4a8c3e7..b0a080a5a 100644 --- a/qtv/source/sv_parse.c +++ b/qtv/source/sv_parse.c @@ -116,15 +116,16 @@ sv_unlink_entity (server_t *sv, qtv_entity_t *ent) } static void -sv_find_touched_leafs (server_t *sv, qtv_entity_t *ent, mnode_t *node) +sv_find_touched_leafs (server_t *sv, qtv_entity_t *ent, int node_id) { - if (node->contents == CONTENTS_SOLID) { - return; - } // add an efrag if the node is a leaf - if (node->contents < 0) { + if (node_id < 0) { + mleaf_t *leaf = sv->worldmodel->brush.leafs + ~node_id; + if (leaf->contents == CONTENTS_SOLID) { + return; + } qtv_leaf_t *ent_leaf = alloc_qtv_leaf (); - ent_leaf->num = (mleaf_t *) node - sv->worldmodel->brush.leafs - 1; + ent_leaf->num = ~node_id - 1; ent_leaf->next = ent->leafs; ent->leafs = ent_leaf; return; @@ -134,7 +135,8 @@ sv_find_touched_leafs (server_t *sv, qtv_entity_t *ent, mnode_t *node) VectorAdd (ent->e.origin, ent->model->mins, emins); VectorAdd (ent->e.origin, ent->model->maxs, emaxs); - plane_t *splitplane = node->plane; + mnode_t *node = sv->worldmodel->brush.nodes + node_id; + plane_t *splitplane = (plane_t *) &node->plane; int sides = BOX_ON_PLANE_SIDE (emins, emaxs, splitplane); if (sides & 1) { sv_find_touched_leafs (sv, ent, node->children[0]); @@ -153,7 +155,7 @@ sv_link_entity (server_t *sv, qtv_entity_t *ent) ent->model = Mod_ForName (sv->modellist[ent->model_index - 1], false); } if (ent->model) { - sv_find_touched_leafs (sv, ent, sv->worldmodel->brush.nodes); + sv_find_touched_leafs (sv, ent, 0); } } diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index a78a46e46..3162b9b74 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1995,7 +1995,7 @@ Host_Frame (float time) vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - l = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME + l = Mod_PointInLeaf (origin, cl_world.scene->worldmodel); if (l) asl = l->ambient_sound_level; S_Update (cl.viewstate.camera_transform, asl); diff --git a/qw/source/cl_screen.c b/qw/source/cl_screen.c index 54871dac5..bbab72313 100644 --- a/qw/source/cl_screen.c +++ b/qw/source/cl_screen.c @@ -82,7 +82,7 @@ SCR_CShift (void) if (cls.state == ca_active && cl_world.scene->worldmodel) { vec4f_t origin; origin = Transform_GetWorldPosition (cl.viewstate.camera_transform); - leaf = Mod_PointInLeaf ((vec_t*)&origin, cl_world.scene->worldmodel);//FIXME + leaf = Mod_PointInLeaf (origin, cl_world.scene->worldmodel); contents = leaf->contents; } V_SetContentsColor (&cl.viewstate, contents); diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index b5c7df94c..83768fe84 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -40,6 +40,8 @@ #include "QF/set.h" #include "QF/sys.h" +#include "QF/simd/vec4f.h" + #include "compat.h" #include "qw/msg_ucmd.h" @@ -59,30 +61,29 @@ static set_t *fatpvs; static void -SV_AddToFatPVS (vec3_t org, mnode_t *node) +SV_AddToFatPVS (vec4f_t org, int node_id) { 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) { - set_union (fatpvs, Mod_LeafPVS ((mleaf_t *) node, - sv.worldmodel)); + if (node_id < 0) { + mleaf_t *leaf = sv.worldmodel->brush.leafs + ~node_id; + if (leaf->contents != CONTENTS_SOLID) { + set_union (fatpvs, Mod_LeafPVS (leaf, sv.worldmodel)); } return; } - plane = node->plane; - d = DotProduct (org, plane->normal) - plane->dist; + mnode_t *node = sv.worldmodel->brush.nodes + node_id; + d = dotf (org, node->plane)[0]; if (d > 8) - node = node->children[0]; + node_id = node->children[0]; else if (d < -8) - node = node->children[1]; + node_id = node->children[1]; else { // go down both SV_AddToFatPVS (org, node->children[0]); - node = node->children[1]; + node_id = node->children[1]; } } } @@ -94,14 +95,14 @@ SV_AddToFatPVS (vec3_t org, mnode_t *node) of the given point. */ static set_t * -SV_FatPVS (vec3_t org) +SV_FatPVS (vec4f_t org) { if (!fatpvs) { fatpvs = set_new_size (sv.worldmodel->brush.visleafs); } set_expand (fatpvs, sv.worldmodel->brush.visleafs); set_empty (fatpvs); - SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); + SV_AddToFatPVS (org, 0); return fatpvs; } @@ -710,12 +711,13 @@ static inline set_t * calc_pvs (delta_t *delta) { set_t *pvs = 0; - vec3_t org; + vec4f_t org = {}; // find the client's PVS if (delta->pvs == dt_pvs_normal) { edict_t *clent = delta->client->edict; VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org); + org[3] = 1; pvs = SV_FatPVS (org); } else if (delta->pvs == dt_pvs_fat) { // when recording a demo, send only entities that can be seen. Can help @@ -735,10 +737,11 @@ calc_pvs (delta_t *delta) VectorAdd (SVvector (cl->edict, origin), SVvector (cl->edict, view_ofs), org); + org[3] = 1; if (pvs == NULL) { pvs = SV_FatPVS (org); } else { - SV_AddToFatPVS (org, sv.worldmodel->brush.nodes); + SV_AddToFatPVS (org, 0); } } } diff --git a/qw/source/sv_pr_cmds.c b/qw/source/sv_pr_cmds.c index fe892ea7c..7075bc6cf 100644 --- a/qw/source/sv_pr_cmds.c +++ b/qw/source/sv_pr_cmds.c @@ -469,7 +469,6 @@ PF_newcheckclient (progs_t *pr, int check) edict_t *ent; int i; mleaf_t *leaf; - vec3_t org; // cycle to the next one if (check < 1) @@ -503,7 +502,9 @@ PF_newcheckclient (progs_t *pr, int check) } // get the PVS for the entity + vec4f_t org; VectorAdd (SVvector (ent, origin), SVvector (ent, view_ofs), org); + org[3] = 1; leaf = Mod_PointInLeaf (org, sv.worldmodel); if (!checkpvs) { checkpvs = set_new_size (sv.worldmodel->brush.visleafs); @@ -536,7 +537,6 @@ PF_checkclient (progs_t *pr, void *data) edict_t *ent, *self; int l; mleaf_t *leaf; - vec3_t view; // find a new check if on a new frame if (sv.time - sv.lastchecktime >= 0.1) { @@ -551,7 +551,9 @@ PF_checkclient (progs_t *pr, void *data) } // if current entity can't possibly see the check entity, return 0 self = PROG_TO_EDICT (pr, *sv_globals.self); + vec4f_t view; VectorAdd (SVvector (self, origin), SVvector (self, view_ofs), view); + view[3] = 1; leaf = Mod_PointInLeaf (view, sv.worldmodel); l = (leaf - sv.worldmodel->brush.leafs) - 1; if (!set_is_member (checkpvs, l)) { diff --git a/qw/source/sv_send.c b/qw/source/sv_send.c index 42f53169e..112e9b7e8 100644 --- a/qw/source/sv_send.c +++ b/qw/source/sv_send.c @@ -302,7 +302,8 @@ SV_Multicast (const vec3_t origin, int to) qboolean reliable; mod_brush_t *brush = &sv.worldmodel->brush; - leaf = Mod_PointInLeaf (origin, sv.worldmodel); + vec4f_t org = { VectorExpand (origin), 1 }; + leaf = Mod_PointInLeaf (org, sv.worldmodel); if (!leaf) leafnum = 0; else @@ -346,8 +347,8 @@ SV_Multicast (const vec3_t origin, int to) goto inrange; } - leaf = Mod_PointInLeaf (SVvector (client->edict, origin), - sv.worldmodel); + org = (vec4f_t) {VectorExpand (SVvector (client->edict, origin)), 1}; + leaf = Mod_PointInLeaf (org, sv.worldmodel); if (leaf) { // -1 is because pvs rows are 1 based, not 0 based like leafs leafnum = leaf - brush->leafs - 1; diff --git a/qw/source/world.c b/qw/source/world.c index 1c0de0270..f6e0fbd8b 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -410,29 +410,28 @@ SV_TouchLinks (edict_t *ent, areanode_t *node) } static void -SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) +SV_FindTouchedLeafs (edict_t *ent, int node_id) { int sides; - mleaf_t *leaf; plane_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) { - leaf = (mleaf_t *) node; + if (node_id < 0) { + mleaf_t *leaf = sv.worldmodel->brush.leafs + ~node_id; + if (leaf->contents == CONTENTS_SOLID) + return; edict_leaf = alloc_edict_leaf (); - edict_leaf->leafnum = leaf - sv.worldmodel->brush.leafs - 1; + edict_leaf->leafnum = ~node_id - 1; edict_leaf->next = SVdata (ent)->leafs; SVdata (ent)->leafs = edict_leaf; return; } + mnode_t *node = sv.worldmodel->brush.nodes + node_id; // NODE_MIXED - splitplane = node->plane; + splitplane = (plane_t *) &node->plane; sides = BOX_ON_PLANE_SIDE (SVvector (ent, absmin), SVvector (ent, absmax), splitplane); @@ -497,7 +496,7 @@ SV_LinkEdict (edict_t *ent, qboolean touch_triggers) // link to PVS leafs free_edict_leafs (&SVdata (ent)->leafs); if (SVfloat (ent, modelindex)) - SV_FindTouchedLeafs (ent, sv.worldmodel->brush.nodes); + SV_FindTouchedLeafs (ent, 0); if (SVfloat (ent, solid) == SOLID_NOT) return;