X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_brush.c;h=b643aa4a8e8f9c7ba2266bdea035dca9ea119a85;hp=d2fa8d488427fee4421c5674cdbe914d35900757;hb=07724ad4d6ab79f66c46e2ea2180d4efd05b3ee4;hpb=dd5644411f46bfeaf512d86eb5ae5fbc3a3b0adf diff --git a/model_brush.c b/model_brush.c index d2fa8d48..b643aa4a 100644 --- a/model_brush.c +++ b/model_brush.c @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"}; +cvar_t mod_bsp_portalize = {0, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"}; cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"}; cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"}; cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"}; @@ -62,6 +63,7 @@ static texture_t mod_q1bsp_texture_water; void Mod_BrushInit(void) { // Cvar_RegisterVariable(&r_subdivide_size); + Cvar_RegisterVariable(&mod_bsp_portalize); Cvar_RegisterVariable(&r_novis); Cvar_RegisterVariable(&r_nosurftextures); Cvar_RegisterVariable(&r_subdivisions_tolerance); @@ -1291,6 +1293,188 @@ void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536); } +static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, double mid[3]) +{ + int i; + int j; + int k; + const msurface_t *surface; + float normal[3]; + float v0[3]; + float v1[3]; + float edgedir[3]; + float edgenormal[3]; + float p[4]; + float midf; + float t1; + float t2; + VectorCopy(mid, p); + p[3] = 1; + surface = model->data_surfaces + node->firstsurface; + for (i = 0;i < node->numsurfaces;i++, surface++) + { + // skip surfaces whose bounding box does not include the point +// if (!BoxesOverlap(mid, mid, surface->mins, surface->maxs)) +// continue; + // skip faces with contents we don't care about + if (!(t->trace->hitsupercontentsmask & surface->texture->supercontents)) + continue; + // get the surface normal - since it is flat we know any vertex normal will suffice + VectorCopy(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex, normal); + // skip backfaces + if (DotProduct(t->dist, normal) > 0) + continue; + // iterate edges and see if the point is outside one of them + for (j = 0, k = surface->num_vertices - 1;j < surface->num_vertices;k = j, j++) + { + VectorCopy(model->surfmesh.data_vertex3f + 3 * (surface->num_firstvertex + k), v0); + VectorCopy(model->surfmesh.data_vertex3f + 3 * (surface->num_firstvertex + j), v1); + VectorSubtract(v0, v1, edgedir); + CrossProduct(edgedir, normal, edgenormal); + if (DotProduct(edgenormal, p) > DotProduct(edgenormal, v0)) + break; + } + // if the point is outside one of the edges, it is not within the surface + if (j < surface->num_vertices) + continue; + + // we hit a surface, this is the impact point... + VectorCopy(normal, t->trace->plane.normal); + t->trace->plane.dist = DotProduct(normal, p); + + // calculate the true fraction + t1 = DotProduct(t->start, t->trace->plane.normal) - t->trace->plane.dist; + t2 = DotProduct(t->end, t->trace->plane.normal) - t->trace->plane.dist; + midf = t1 / (t1 - t2); + t->trace->realfraction = midf; + + // calculate the return fraction which is nudged off the surface a bit + midf = (t1 - DIST_EPSILON) / (t1 - t2); + t->trace->fraction = bound(0, midf, 1); + + if (collision_prefernudgedfraction.integer) + t->trace->realfraction = t->trace->fraction; + + t->trace->hittexture = surface->texture->currentframe; + t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags; + t->trace->hitsupercontents = t->trace->hittexture->supercontents; + return surface->texture->currentframe; + } + return NULL; +} + +static int Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(RecursiveHullCheckTraceInfo_t *t, const dp_model_t *model, const mnode_t *node, const double p1[3], const double p2[3]) +{ + const mplane_t *plane; + double t1, t2; + int side; + double midf, mid[3]; + const mleaf_t *leaf; + + while (node->plane) + { + 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; + } + + // the line intersects, find intersection point + // LordHavoc: this uses the original trace for maximum accuracy + if (plane->type < 3) + { + t1 = t->start[plane->type] - plane->dist; + t2 = t->end[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, t->start) - plane->dist; + t2 = DotProduct (plane->normal, t->end) - plane->dist; + } + + midf = t1 / (t1 - t2); + VectorMA(t->start, midf, t->dist, mid); + + // recurse both sides, front side first, return if we hit a surface + if (Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side], p1, mid) == HULLCHECKSTATE_DONE) + return HULLCHECKSTATE_DONE; + + // test each surface on the node + Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(t, model, node, mid); + if (t->trace->hittexture) + return HULLCHECKSTATE_DONE; + + // recurse back side + return Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(t, model, node->children[side ^ 1], mid, p2); + } + leaf = (const mleaf_t *)node; + side = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, leaf->contents); + if (!t->trace->startfound) + { + t->trace->startfound = true; + t->trace->startsupercontents |= side; + } + if (side & SUPERCONTENTS_LIQUIDSMASK) + t->trace->inwater = true; + if (side == 0) + t->trace->inopen = true; + if (side & t->trace->hitsupercontentsmask) + { + // if the first leaf is solid, set startsolid + if (t->trace->allsolid) + t->trace->startsolid = true; + return HULLCHECKSTATE_SOLID; + } + else + { + t->trace->allsolid = false; + return HULLCHECKSTATE_EMPTY; + } +} + +static void Mod_Q1BSP_TraceLineAgainstSurfaces(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + RecursiveHullCheckTraceInfo_t rhc; + + memset(&rhc, 0, sizeof(rhc)); + memset(trace, 0, sizeof(trace_t)); + rhc.trace = trace; + rhc.trace->hitsupercontentsmask = hitsupercontentsmask; + rhc.trace->fraction = 1; + rhc.trace->realfraction = 1; + rhc.trace->allsolid = true; + rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 + VectorCopy(start, rhc.start); + VectorCopy(end, rhc.end); + VectorSubtract(rhc.end, rhc.start, rhc.dist); + Mod_Q1BSP_TraceLineAgainstSurfacesRecursiveBSPNode(&rhc, model, model->brush.data_nodes + rhc.hull->firstclipnode, rhc.start, rhc.end); + VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos); +} + static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend) { int c; @@ -2563,6 +2747,8 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) if (l->filelen % sizeof(*in)) Host_Error("Mod_Q1BSP_LoadNodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); + if (count == 0) + Host_Error("Mod_Q1BSP_LoadNodes: missing BSP tree in %s",loadmodel->name); out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); loadmodel->brush.data_nodes = out; @@ -3438,13 +3624,15 @@ static int Mod_Q1BSP_CreateShadowMesh(dp_model_t *mod) for (j = 0, surface = mod->data_surfaces;j < mod->num_surfaces;j++, surface++) if (surface->num_triangles > 0) Mod_ShadowMesh_AddMesh(mod->mempool, mod->brush.shadowmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); - mod->brush.shadowmesh = Mod_ShadowMesh_Finish(mod->mempool, mod->brush.shadowmesh, false, true, false); - if (mod->brush.shadowmesh) + mod->brush.shadowmesh = Mod_ShadowMesh_Finish(mod->mempool, mod->brush.shadowmesh, false, r_enableshadowvolumes.integer != 0, false); + if (mod->brush.shadowmesh && mod->brush.shadowmesh->neighbor3i) Mod_BuildTriangleNeighbors(mod->brush.shadowmesh->neighbor3i, mod->brush.shadowmesh->element3i, mod->brush.shadowmesh->numtriangles); return numshadowmeshtriangles; } +void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask); + void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) { int i, j, k; @@ -3502,9 +3690,10 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->soundfromcenter = true; mod->TraceBox = Mod_Q1BSP_TraceBox; - mod->TraceLine = Mod_Q1BSP_TraceLine; + mod->TraceLine = Mod_Q1BSP_TraceLineAgainstSurfaces; // LordHavoc: use the surface-hitting version of TraceLine in all cases mod->TracePoint = Mod_Q1BSP_TracePoint; mod->PointSuperContents = Mod_Q1BSP_PointSuperContents; + mod->TraceLineAgainstSurfaces = Mod_Q1BSP_TraceLineAgainstSurfaces; mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight; mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents; mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents; @@ -3573,7 +3762,8 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->brushq1.num_compressedpvs = 0; Mod_Q1BSP_MakeHull0(); - Mod_Q1BSP_MakePortals(); + if (mod_bsp_portalize.integer) + Mod_Q1BSP_MakePortals(); mod->numframes = 2; // regular and alternate animation mod->numskins = 1; @@ -3765,6 +3955,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) mod->TraceLine = Mod_CollisionBIH_TraceLine; mod->TraceBox = Mod_CollisionBIH_TraceBox; mod->TraceBrush = Mod_CollisionBIH_TraceBrush; + mod->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLineAgainstSurfaces; } // generate VBOs and other shared data before cloning submodels @@ -5496,6 +5687,8 @@ static void Mod_Q3BSP_LoadNodes(lump_t *l) if (l->filelen % sizeof(*in)) Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name); count = l->filelen / sizeof(*in); + if (count == 0) + Host_Error("Mod_Q3BSP_LoadNodes: missing BSP tree in %s",loadmodel->name); out = (mnode_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); loadmodel->brush.data_nodes = out; @@ -5621,14 +5814,26 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l) static void Mod_Q3BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal) { int i, j, k, index[3]; - float transformed[3], blend1, blend2, blend, stylescale; + float transformed[3], blend1, blend2, blend, stylescale = 1; q3dlightgrid_t *a, *s; // scale lighting by lightstyle[0] so that darkmode in dpmod works properly - if (vid.renderpath == RENDERPATH_GL20) + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + case RENDERPATH_SOFT: + case RENDERPATH_GLES2: + // LordHavoc: FIXME: is this true? stylescale = 1; // added while render - else + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: stylescale = r_refdef.scene.rtlightstylevalue[0]; + break; + } if (!model->brushq3.num_lightgrid) { @@ -5770,9 +5975,34 @@ static void Mod_CollisionBIH_TracePoint_RecursiveBIHNode(trace_t *trace, dp_mode const bih_node_t *node; const colbrushf_t *brush; int axis; - while (nodenum >= 0) + for(;;) { node = model->collision_bih.nodes + nodenum; + if (node->type == BIH_UNORDERED) + { + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = model->collision_bih.leafs + node->children[axis]; +#if 1 + if (!BoxesOverlap(point, point, leaf->mins, leaf->maxs)) + continue; +#endif + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TracePointBrushFloat(trace, point, brush); + break; + case BIH_COLLISIONTRIANGLE: + // collision triangle - skipped because they have no volume + break; + case BIH_RENDERTRIANGLE: + // render triangle - skipped because they have no volume + break; + } + } + return; + } axis = node->type - BIH_SPLITX; if (point[axis] <= node->backmax) { @@ -5785,25 +6015,9 @@ static void Mod_CollisionBIH_TracePoint_RecursiveBIHNode(trace_t *trace, dp_mode else // no overlap with either child? just return return; } - if (!model->collision_bih.leafs) - return; - leaf = model->collision_bih.leafs + (-1-nodenum); - switch(leaf->type) - { - case BIH_BRUSH: - brush = model->brush.data_brushes[leaf->itemindex].colbrushf; - Collision_TracePointBrushFloat(trace, point, brush); - break; - case BIH_COLLISIONTRIANGLE: - // collision triangle - skipped because they have no volume - break; - case BIH_RENDERTRIANGLE: - // render triangle - skipped because they have no volume - break; - } } -static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model_t *model, int nodenum, const vec3_t start, const vec3_t end, const vec3_t linestart, const vec3_t lineend) +static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model_t *model, bih_t *bih, int nodenum, const vec3_t start, const vec3_t end, const vec3_t linestart, const vec3_t lineend) { const bih_leaf_t *leaf; const bih_node_t *node; @@ -5830,19 +6044,50 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model segmentmaxs[0] = max(start[0], end[0]); segmentmaxs[1] = max(start[1], end[1]); segmentmaxs[2] = max(start[2], end[2]); - while (nodenum >= 0) + for (;;) { - node = model->collision_bih.nodes + nodenum; + node = bih->nodes + nodenum; #if 0 if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs)) return; #endif + if (node->type == BIH_UNORDERED) + { + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = model->collision_bih.leafs + node->children[axis]; +#if 1 + if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) + continue; +#endif + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush); + break; + case BIH_COLLISIONTRIANGLE: + if (!mod_q3bsp_curves_collisions.integer) + continue; + e = model->brush.data_collisionelement3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + case BIH_RENDERTRIANGLE: + e = model->surfmesh.data_element3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + } + } + return; + } axis = node->type - BIH_SPLITX; #if 0 if (segmentmins[axis] <= node->backmax) { if (segmentmaxs[axis] >= node->frontmin) - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); nodenum = node->back; } else if (segmentmaxs[axis] >= node->frontmin) @@ -5867,7 +6112,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model if (sideflags & 12) { if ((sideflags & 3) != 3) - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); nodenum = node->back; } else if ((sideflags & 3) != 3) @@ -5914,7 +6159,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model return; // line falls in gap between children case 4: // start end start END - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #ifdef BIHLINECLIP backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newend); end = newend; @@ -5932,7 +6177,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, clipped, end, linestart, lineend); backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newend); end = newend; segmentmins[0] = min(start[0], end[0]); @@ -5942,7 +6187,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model segmentmaxs[1] = max(start[1], end[1]); segmentmaxs[2] = max(start[2], end[2]); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -5951,7 +6196,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, clipped, linestart, lineend); backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newend); end = newend; segmentmins[0] = min(start[0], end[0]); @@ -5961,7 +6206,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model segmentmaxs[1] = max(start[1], end[1]); segmentmaxs[2] = max(start[2], end[2]); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -5981,7 +6226,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model break; case 8: // start end START end - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #ifdef BIHLINECLIP backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newstart); start = newstart; @@ -5999,7 +6244,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, clipped, end, linestart, lineend); backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newstart); start = newstart; segmentmins[0] = min(start[0], end[0]); @@ -6009,7 +6254,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model segmentmaxs[1] = max(start[1], end[1]); segmentmaxs[2] = max(start[2], end[2]); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -6018,7 +6263,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, clipped, linestart, lineend); backfrac = backdist1 / (backdist1 - backdist2); VectorLerp(start, backfrac, end, newstart); start = newstart; segmentmins[0] = min(start[0], end[0]); @@ -6028,7 +6273,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model segmentmaxs[1] = max(start[1], end[1]); segmentmaxs[2] = max(start[2], end[2]); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -6048,7 +6293,7 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model break; case 12: // start end start end - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); nodenum = node->back; break; case 13: @@ -6056,9 +6301,9 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, clipped, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, clipped, end, linestart, lineend); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -6067,9 +6312,9 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #ifdef BIHLINECLIP frontfrac = frontdist1 / (frontdist1 - frontdist2); VectorLerp(start, frontfrac, end, clipped); - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, clipped, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, clipped, linestart, lineend); #else - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, node->front, start, end, linestart, lineend); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, bih, node->front, start, end, linestart, lineend); #endif nodenum = node->back; break; @@ -6081,32 +6326,6 @@ static void Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace_t *trace, dp_model #endif #endif } - if (!model->collision_bih.leafs) - return; - leaf = model->collision_bih.leafs + (-1-nodenum); -#if 1 - if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) - return; -#endif - switch(leaf->type) - { - case BIH_BRUSH: - brush = model->brush.data_brushes[leaf->itemindex].colbrushf; - Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush); - break; - case BIH_COLLISIONTRIANGLE: - if (!mod_q3bsp_curves_collisions.integer) - return; - e = model->brush.data_collisionelement3i + 3*leaf->itemindex; - texture = model->data_textures + leaf->textureindex; - Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); - break; - case BIH_RENDERTRIANGLE: - e = model->surfmesh.data_element3i + 3*leaf->itemindex; - texture = model->data_textures + leaf->textureindex; - Collision_TraceLineTriangleFloat(trace, linestart, lineend, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); - break; - } } static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_model_t *model, int nodenum, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const vec3_t segmentmins, const vec3_t segmentmaxs) @@ -6117,9 +6336,40 @@ static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_mode const int *e; const texture_t *texture; int axis; - while (nodenum >= 0) + for(;;) { node = model->collision_bih.nodes + nodenum; + if (node->type == BIH_UNORDERED) + { + for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++) + { + leaf = model->collision_bih.leafs + node->children[axis]; +#if 1 + if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) + continue; +#endif + switch(leaf->type) + { + case BIH_BRUSH: + brush = model->brush.data_brushes[leaf->itemindex].colbrushf; + Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush); + break; + case BIH_COLLISIONTRIANGLE: + if (!mod_q3bsp_curves_collisions.integer) + continue; + e = model->brush.data_collisionelement3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + case BIH_RENDERTRIANGLE: + e = model->surfmesh.data_element3i + 3*leaf->itemindex; + texture = model->data_textures + leaf->textureindex; + Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); + break; + } + } + return; + } axis = node->type - BIH_SPLITX; #if 1 if (!BoxesOverlap(segmentmins, segmentmaxs, node->mins, node->maxs)) @@ -6141,32 +6391,6 @@ static void Mod_CollisionBIH_TraceBrush_RecursiveBIHNode(trace_t *trace, dp_mode else return; // trace falls between children } - if (!model->collision_bih.leafs) - return; - leaf = model->collision_bih.leafs + (-1-nodenum); -#if 1 - if (!BoxesOverlap(segmentmins, segmentmaxs, leaf->mins, leaf->maxs)) - return; -#endif - switch(leaf->type) - { - case BIH_BRUSH: - brush = model->brush.data_brushes[leaf->itemindex].colbrushf; - Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush); - break; - case BIH_COLLISIONTRIANGLE: - if (!mod_q3bsp_curves_collisions.integer) - return; - e = model->brush.data_collisionelement3i + 3*leaf->itemindex; - texture = model->data_textures + leaf->textureindex; - Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->brush.data_collisionvertex3f + e[0] * 3, model->brush.data_collisionvertex3f + e[1] * 3, model->brush.data_collisionvertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); - break; - case BIH_RENDERTRIANGLE: - e = model->surfmesh.data_element3i + 3*leaf->itemindex; - texture = model->data_textures + leaf->textureindex; - Collision_TraceBrushTriangleFloat(trace, thisbrush_start, thisbrush_end, model->surfmesh.data_vertex3f + e[0] * 3, model->surfmesh.data_vertex3f + e[1] * 3, model->surfmesh.data_vertex3f + e[2] * 3, texture->supercontents, texture->surfaceflags, texture); - break; - } } void Mod_CollisionBIH_TracePoint(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask) @@ -6190,7 +6414,7 @@ void Mod_CollisionBIH_TraceLine(dp_model_t *model, const frameblend_t *frameblen trace->fraction = 1; trace->realfraction = 1; trace->hitsupercontentsmask = hitsupercontentsmask; - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, model->collision_bih.rootnode, start, end, start, end); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, &model->collision_bih, model->collision_bih.rootnode, start, end, start, end); } void Mod_CollisionBIH_TraceBox(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) @@ -6565,7 +6789,7 @@ static void Mod_Q3BSP_TraceLine(dp_model_t *model, const frameblend_t *frameblen segmentmaxs[1] = max(start[1], end[1]) + 1; segmentmaxs[2] = max(start[2], end[2]) + 1; if (mod_collision_bih.integer) - Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, model->collision_bih.rootnode, start, end, start, end); + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, &model->collision_bih, model->collision_bih.rootnode, start, end, start, end); else if (model->brush.submodel) { for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) @@ -6715,6 +6939,16 @@ static int Mod_Q3BSP_PointSuperContents(struct model_s *model, int frame, const return supercontents; } +void Mod_CollisionBIH_TraceLineAgainstSurfaces(dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask) +{ + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + trace->realfraction = 1; + trace->hitsupercontentsmask = hitsupercontentsmask; + Mod_CollisionBIH_TraceLine_RecursiveBIHNode(trace, model, &model->render_bih, model->render_bih.rootnode, start, end, start, end); +} + + bih_t *Mod_MakeCollisionBIH(dp_model_t *model, qboolean userendersurfaces, bih_t *out) { int j; @@ -6949,6 +7183,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->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine; mod->brush.TraceLineOfSight = Mod_Q3BSP_TraceLineOfSight; mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents; mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents; @@ -7040,7 +7275,8 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->brush.numsubmodels = loadmodel->brushq3.num_models; // the MakePortals code works fine on the q3bsp data as well - Mod_Q1BSP_MakePortals(); + if (mod_bsp_portalize.integer) + Mod_Q1BSP_MakePortals(); // FIXME: shader alpha should replace r_wateralpha support in q3bsp loadmodel->brush.supportwateralpha = true; @@ -7246,6 +7482,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->TraceBrush = Mod_CollisionBIH_TraceBrush; loadmodel->TraceLine = Mod_CollisionBIH_TraceLine; loadmodel->TracePoint = Mod_CollisionBIH_TracePoint_Mesh; + loadmodel->TraceLineAgainstSurfaces = Mod_CollisionBIH_TraceLine; loadmodel->PointSuperContents = Mod_CollisionBIH_PointSuperContents_Mesh; loadmodel->brush.TraceLineOfSight = NULL; loadmodel->brush.SuperContentsFromNativeContents = NULL; @@ -7575,13 +7812,14 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) // allocate storage for final mesh data loadmodel->num_textures = numtextures * loadmodel->numskins; loadmodel->num_texturesperskin = numtextures; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(int) + loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0) + (r_enableshadowvolumes.integer ? numtriangles * sizeof(int[3]) : 0) + numvertices * sizeof(float[14]) + loadmodel->brush.numsubmodels * sizeof(dp_model_t *)); loadmodel->brush.submodels = (dp_model_t **)data;data += loadmodel->brush.numsubmodels * sizeof(dp_model_t *); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->data_textures = (texture_t *)data;data += loadmodel->num_surfaces * loadmodel->numskins * sizeof(texture_t); loadmodel->surfmesh.num_vertices = numvertices; loadmodel->surfmesh.num_triangles = numtriangles; - loadmodel->surfmesh.data_neighbor3i = (int *)data;data += numtriangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += numtriangles * sizeof(int[3]); loadmodel->surfmesh.data_vertex3f = (float *)data;data += numvertices * sizeof(float[3]); loadmodel->surfmesh.data_svector3f = (float *)data;data += numvertices * sizeof(float[3]); loadmodel->surfmesh.data_tvector3f = (float *)data;data += numvertices * sizeof(float[3]); @@ -7627,7 +7865,8 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) if (!VectorLength2(loadmodel->surfmesh.data_normal3f)) Mod_BuildNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_normal3f, r_smoothnormals_areaweighting.integer != 0); Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, r_smoothnormals_areaweighting.integer != 0); - Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); // if this is a worldmodel and has no BSP tree, create a fake one for the purpose loadmodel->brush.num_visleafs = 1; @@ -8234,6 +8473,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->TraceLine = Mod_OBJ_TraceLine; loadmodel->TracePoint = Mod_OBJ_TracePoint; loadmodel->PointSuperContents = Mod_OBJ_PointSuperContents; + loadmodel->TraceLineAgainstSurfaces = Mod_OBJ_TraceLineAgainstSurfaces; loadmodel->brush.TraceLineOfSight = Mod_OBJ_TraceLineOfSight; loadmodel->brush.SuperContentsFromNativeContents = Mod_OBJ_SuperContentsFromNativeContents; loadmodel->brush.NativeContentsFromSuperContents = Mod_OBJ_NativeContentsFromSuperContents; @@ -8527,14 +8767,15 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) loadmodel->num_surfaces = 1; loadmodel->nummodelsurfaces = loadmodel->num_surfaces; - data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + loadmodel->surfmesh.num_triangles * sizeof(int[3])); + data = (unsigned char *)Mem_Alloc(loadmodel->mempool, loadmodel->num_surfaces * sizeof(msurface_t) + loadmodel->num_surfaces * sizeof(int) + loadmodel->numframes * sizeof(animscene_t) + loadmodel->numframes * sizeof(float[6]) + loadmodel->surfmesh.num_triangles * sizeof(int[3]) + (r_enableshadowvolume.integer ? loadmodel->surfmesh.num_triangles * sizeof(int[3]) : 0)); loadmodel->data_surfaces = (msurface_t *)data;data += loadmodel->num_surfaces * sizeof(msurface_t); loadmodel->sortedmodelsurfaces = (int *)data;data += loadmodel->num_surfaces * sizeof(int); loadmodel->sortedmodelsurfaces[0] = 0; loadmodel->animscenes = (animscene_t *)data;data += loadmodel->numframes * sizeof(animscene_t); loadmodel->surfmesh.data_morphmd2framesize6f = (float *)data;data += loadmodel->numframes * sizeof(float[6]); loadmodel->surfmesh.data_element3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); - loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); + if (r_enableshadowvolumes.integer) + loadmodel->surfmesh.data_neighbor3i = (int *)data;data += loadmodel->surfmesh.num_triangles * sizeof(int[3]); loadmodel->synctype = ST_RAND; @@ -8676,7 +8917,8 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend) Mem_Free(vertremap); Mod_MakeSortedSurfaces(loadmodel); - Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); + if (loadmodel->surfmesh.data_neighbor3i) + Mod_BuildTriangleNeighbors(loadmodel->surfmesh.data_neighbor3i, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles); Mod_Alias_CalculateBoundingBox(); Mod_Alias_MorphMesh_CompileFrames();