From 5bb512fd3cff3479e4a86b8f716e7ff6409eb1cd Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 20 Feb 2007 12:34:38 +0000 Subject: [PATCH] added model->brush.TraceLineOfSight function, this traces the rendering hull and treats leafs with no pvs as solid (meaning it traces the structural rendering hull in q3bsp, ignoring detail brushes and patches), this function is now used by sv_cullentities_trace for higher performance, and it does not stop at solid transparent surfaces such as the chainlink fences in the nexuiz map toxic.bsp git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6880 d7cf8633-e32d-0410-b094-e92efae38249 --- model_brush.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ model_shared.h | 2 ++ sv_main.c | 10 ++----- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/model_brush.c b/model_brush.c index d0c0ae6d..04cdaee9 100644 --- a/model_brush.c +++ b/model_brush.c @@ -986,6 +986,76 @@ void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cm #endif } +static int Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3]) +{ + double t1, t2; + double midf, mid[3]; + int ret, side; + + // check for empty + while (node->plane) + { + // find the point distances + mplane_t *plane = node->plane; + if (plane->type < 3) + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, p1) - plane->dist; + t2 = DotProduct (plane->normal, p2) - plane->dist; + } + + if (t1 < 0) + { + if (t2 < 0) + { + node = node->children[1]; + continue; + } + side = 1; + } + else + { + if (t2 >= 0) + { + node = node->children[0]; + continue; + } + side = 0; + } + + midf = t1 / (t1 - t2); + VectorLerp(p1, midf, p2, mid); + + // recurse both sides, front side first + // return 2 if empty is followed by solid (hit something) + // do not return 2 if both are solid or both empty, + // or if start is solid and end is empty + // as these degenerate cases usually indicate the eye is in solid and + // should see the target point anyway + ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid); + if (ret != 0) + return ret; + ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2); + if (ret != 1) + return ret; + return 2; + } + return ((mleaf_t *)node)->clusterindex < 0; +} + +static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end) +{ + // this function currently only supports same size start and end + double tracestart[3], traceend[3]; + VectorCopy(start, tracestart); + VectorCopy(end, traceend); + return Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend) != 2; +} + static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz) { int side; @@ -3276,6 +3346,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend) mod->soundfromcenter = true; mod->TraceBox = Mod_Q1BSP_TraceBox; + mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight; mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents; mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents; mod->brush.GetPVS = Mod_Q1BSP_GetPVS; @@ -3443,6 +3514,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend) mod->DrawLight = R_Q1BSP_DrawLight; if (i != 0) { + mod->brush.TraceLineOfSight = NULL; mod->brush.GetPVS = NULL; mod->brush.FatPVS = NULL; mod->brush.BoxTouchingPVS = NULL; @@ -5789,6 +5861,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend) mod->soundfromcenter = true; mod->TraceBox = Mod_Q3BSP_TraceBox; + mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight; mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents; mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents; mod->brush.GetPVS = Mod_Q1BSP_GetPVS; @@ -5898,6 +5971,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend) // textures and memory belong to the main model mod->texturepool = NULL; mod->mempool = NULL; + mod->brush.TraceLineOfSight = NULL; mod->brush.GetPVS = NULL; mod->brush.FatPVS = NULL; mod->brush.BoxTouchingPVS = NULL; diff --git a/model_shared.h b/model_shared.h index 8a2deeb8..d0406ff1 100644 --- a/model_shared.h +++ b/model_shared.h @@ -395,6 +395,8 @@ typedef struct model_brush_s // these are actually only found on brushq1, but NULL is handled gracefully void (*AmbientSoundLevelsForPoint)(struct model_s *model, const vec3_t p, unsigned char *out, int outsize); void (*RoundUpToHullSize)(struct model_s *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs); + // trace a line of sight through this model (returns false if the line if sight is definitely blocked) + qboolean (*TraceLineOfSight)(struct model_s *model, const vec3_t start, const vec3_t end); char skybox[MAX_QPATH]; diff --git a/sv_main.c b/sv_main.c index 978c58f5..0a429f09 100644 --- a/sv_main.c +++ b/sv_main.c @@ -810,7 +810,6 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) vec3_t testorigin; model_t *model; prvm_edict_t *ed; - trace_t trace; if (sententitiesconsideration[s->number] == sententitiesmark) return; sententitiesconsideration[s->number] = sententitiesmark; @@ -897,8 +896,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f; testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f; testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f; - sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID); - if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs)) + if (sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, testorigin)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; else { @@ -906,8 +904,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]); testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]); testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]); - sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID); - if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs)) + if (sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, testorigin)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; else { @@ -917,8 +914,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]); testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]); testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]); - sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID); - if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs)) + if (sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, testorigin)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; } } -- 2.39.2