]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
added model->brush.TraceLineOfSight function, this traces the rendering hull and...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Feb 2007 12:34:38 +0000 (12:34 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 20 Feb 2007 12:34:38 +0000 (12:34 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6880 d7cf8633-e32d-0410-b094-e92efae38249

model_brush.c
model_shared.h
sv_main.c

index d0c0ae6dfc1270145f438a90e2f09e2eca60e64a..04cdaee9b561d07f54aea0fc42c9822b3ac47d10 100644 (file)
@@ -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;
index 8a2deeb8227e79ccb1243ea11a95fa7516add2fc..d0406ff13cb0a9a01cb29e709a8d74d3f2800392 100644 (file)
@@ -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];
 
index 978c58f54e3d8408e9726739febbdf8c6b196ac8..0a429f0938d2b775ce44947ca5f8d1e77ff0dd34 100644 (file)
--- 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;
                                                }
                                        }