]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - model_brush.c
implemented a new preallocated "boxbrush" type for use with
[xonotic/darkplaces.git] / model_brush.c
index da1585caa72c2ff8d3bbffe0fe10fad7a29cf56b..69792ce28d593be543d4f516e32d9d6c465097b1 100644 (file)
@@ -45,6 +45,7 @@ cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1", "
 cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"};
 cvar_t mod_q3bsp_lightmapmergepower = {CVAR_SAVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."};
 cvar_t mod_q3bsp_nolightmaps = {CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"};
+cvar_t mod_q3bsp_tracelineofsight_brushes = {0, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"};
 
 static texture_t mod_q1bsp_texture_solid;
 static texture_t mod_q1bsp_texture_sky;
@@ -73,6 +74,7 @@ void Mod_BrushInit(void)
        Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
        Cvar_RegisterVariable(&mod_q3bsp_lightmapmergepower);
        Cvar_RegisterVariable(&mod_q3bsp_nolightmaps);
+       Cvar_RegisterVariable(&mod_q3bsp_tracelineofsight_brushes);
 
        memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid));
        strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name));
@@ -142,7 +144,7 @@ static int Mod_Q1BSP_FindBoxClusters(dp_model_t *model, const vec3_t mins, const
        mnode_t *node, *nodestack[1024];
        if (!model->brush.num_pvsclusters)
                return -1;
-       node = model->brush.data_nodes;
+       node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
        for (;;)
        {
 #if 1
@@ -207,7 +209,7 @@ static int Mod_Q1BSP_BoxTouchingPVS(dp_model_t *model, const unsigned char *pvs,
        mnode_t *node, *nodestack[1024];
        if (!model->brush.num_pvsclusters)
                return true;
-       node = model->brush.data_nodes;
+       node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
        for (;;)
        {
 #if 1
@@ -278,7 +280,7 @@ static int Mod_Q1BSP_BoxTouchingLeafPVS(dp_model_t *model, const unsigned char *
        mnode_t *node, *nodestack[1024];
        if (!model->brush.num_leafs)
                return true;
-       node = model->brush.data_nodes;
+       node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
        for (;;)
        {
 #if 1
@@ -349,7 +351,7 @@ static int Mod_Q1BSP_BoxTouchingVisibleLeafs(dp_model_t *model, const unsigned c
        mnode_t *node, *nodestack[1024];
        if (!model->brush.num_leafs)
                return true;
-       node = model->brush.data_nodes;
+       node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
        for (;;)
        {
 #if 1
@@ -1020,6 +1022,8 @@ void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cm
 #if 1
        colbrushf_t cbox;
        colplanef_t cbox_planes[6];
+       cbox.isaabb = true;
+       cbox.hasaabbplanes = true;
        cbox.supercontents = boxsupercontents;
        cbox.numplanes = 6;
        cbox.numpoints = 0;
@@ -1135,74 +1139,11 @@ void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t
        }
 }
 
-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;
+       trace_t trace;
+       model->TraceLine(model, 0, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
+       return trace.fraction == 1;
 }
 
 static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
@@ -3200,7 +3141,7 @@ static void Mod_Q1BSP_FinalizePortals(void)
                p = pnext;
        }
        // now recalculate the node bounding boxes from the leafs
-       Mod_Q1BSP_RecursiveRecalcNodeBBox(loadmodel->brush.data_nodes);
+       Mod_Q1BSP_RecursiveRecalcNodeBBox(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode);
 }
 
 /*
@@ -3412,7 +3353,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
 static void Mod_Q1BSP_MakePortals(void)
 {
        portalchain = NULL;
-       Mod_Q1BSP_RecursiveNodePortals(loadmodel->brush.data_nodes);
+       Mod_Q1BSP_RecursiveNodePortals(loadmodel->brush.data_nodes + loadmodel->brushq1.hulls[0].firstclipnode);
        Mod_Q1BSP_FinalizePortals();
 }
 
@@ -3421,7 +3362,7 @@ static void Mod_Q1BSP_MakePortals(void)
 static unsigned char *Mod_Q1BSP_GetPVS(dp_model_t *model, const vec3_t p)
 {
        mnode_t *node;
-       node = model->brush.data_nodes;
+       node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
        while (node->plane)
                node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
        if (((mleaf_t *)node)->clusterindex >= 0)
@@ -3469,7 +3410,7 @@ static int Mod_Q1BSP_FatPVS(dp_model_t *model, const vec3_t org, vec_t radius, u
        }
        if (!merge)
                memset(pvsbuffer, 0, bytes);
-       Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brush.data_nodes);
+       Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode);
        return bytes;
 }
 
@@ -3707,7 +3648,6 @@ void Mod_Q1BSP_Load(dp_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;
@@ -3735,6 +3675,9 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
                mod->firstmodelsurface = bm->firstface;
                mod->nummodelsurfaces = bm->numfaces;
 
+               // set node/leaf parents for this submodel
+               Mod_Q1BSP_LoadNodes_RecursiveSetParent(mod->brush.data_nodes + mod->brushq1.hulls[0].firstclipnode, NULL);
+
                // make the model surface list (used by shadowing/lighting)
                mod->sortedmodelsurfaces = (int *)datapointer;datapointer += mod->nummodelsurfaces * sizeof(int);
                Mod_MakeSortedSurfaces(mod);
@@ -4444,7 +4387,7 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
 {
        q3dbrush_t *in;
        q3mbrush_t *out;
-       int i, j, n, c, count, maxplanes;
+       int i, j, n, c, count, maxplanes, q3surfaceflags;
        colplanef_t *planes;
 
        in = (q3dbrush_t *)(mod_base + l->fileofs);
@@ -4480,15 +4423,17 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l)
                                Mem_Free(planes);
                        planes = (colplanef_t *)Mem_Alloc(tempmempool, sizeof(colplanef_t) * maxplanes);
                }
+               q3surfaceflags = 0;
                for (j = 0;j < out->numbrushsides;j++)
                {
                        VectorCopy(out->firstbrushside[j].plane->normal, planes[j].normal);
                        planes[j].dist = out->firstbrushside[j].plane->dist;
                        planes[j].q3surfaceflags = out->firstbrushside[j].texture->surfaceflags;
                        planes[j].texture = out->firstbrushside[j].texture;
+                       q3surfaceflags |= planes[j].q3surfaceflags;
                }
                // make the colbrush from the planes
-               out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents);
+               out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents, q3surfaceflags, out->texture, true);
 
                // this whole loop can take a while (e.g. on redstarrepublic4)
                CL_KeepaliveMessage(false);
@@ -5643,6 +5588,84 @@ static void Mod_Q3BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambie
        //Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]);
 }
 
+static int Mod_Q3BSP_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_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side    ], p1, mid);
+               if (ret != 0)
+                       return ret;
+               ret = Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2);
+               if (ret != 1)
+                       return ret;
+               return 2;
+       }
+       return ((mleaf_t *)node)->clusterindex < 0;
+}
+
+static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+{
+       if (model->brush.submodel || mod_q3bsp_tracelineofsight_brushes.integer)
+       {
+               trace_t trace;
+               model->TraceLine(model, 0, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK);
+               return trace.fraction == 1;
+       }
+       else
+       {
+               double tracestart[3], traceend[3];
+               VectorCopy(start, tracestart);
+               VectorCopy(end, traceend);
+               return !Mod_Q3BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend);
+       }
+}
+
 static void Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace_t *trace, dp_model_t *model, mnode_t *node, const vec3_t point, int markframe)
 {
        int i;
@@ -5896,7 +5919,7 @@ static void Mod_Q3BSP_TraceBox(dp_model_t *model, int frame, trace_t *trace, con
        float segmentmins[3], segmentmaxs[3];
        msurface_t *surface;
        q3mbrush_t *brush;
-       colbrushf_t *thisbrush_start, *thisbrush_end;
+       colboxbrushf_t thisbrush_start, thisbrush_end;
        vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs;
 
        if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(boxmins, boxmaxs))
@@ -5929,20 +5952,20 @@ static void Mod_Q3BSP_TraceBox(dp_model_t *model, int frame, trace_t *trace, con
        VectorAdd(start, boxmaxs, boxstartmaxs);
        VectorAdd(end, boxmins, boxendmins);
        VectorAdd(end, boxmaxs, boxendmaxs);
-       thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
-       thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
+       Collision_BrushForBox(&thisbrush_start, boxstartmins, boxstartmaxs, 0, 0, NULL);
+       Collision_BrushForBox(&thisbrush_end, boxendmins, boxendmaxs, 0, 0, NULL);
        if (model->brush.submodel)
        {
                for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
                        if (brush->colbrushf)
-                               Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush->colbrushf, brush->colbrushf);
+                               Collision_TraceBrushBrushFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, brush->colbrushf, brush->colbrushf);
                if (mod_q3bsp_curves_collisions.integer)
                        for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
                                if (surface->num_collisiontriangles)
-                                       Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->num_collisionbboxstride, surface->data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
+                                       Collision_TraceBrushTriangleMeshFloat(trace, &thisbrush_start.brush, &thisbrush_end.brush, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->num_collisionbboxstride, surface->data_collisionbbox6f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
        }
        else
-               Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
+               Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, &thisbrush_start.brush, &thisbrush_end.brush, ++markframe, segmentmins, segmentmaxs);
 }
 
 static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const vec3_t point)
@@ -6076,7 +6099,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->TraceLine = Mod_Q3BSP_TraceLine;
        mod->TracePoint = Mod_Q3BSP_TracePoint;
        mod->PointSuperContents = Mod_Q3BSP_PointSuperContents;
-       mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight;
+       mod->brush.TraceLineOfSight = Mod_Q3BSP_TraceLineOfSight;
        mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
        mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
        mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
@@ -6208,7 +6231,6 @@ void Mod_Q3BSP_Load(dp_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;