X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=model_brush.c;h=6abc8d8f6e2919c88d1a33fc219bfea2d21af6ad;hb=780934a7d98fc6f0a6d65ac8577bfc24dba3eebd;hp=8622d3d01d7561bf3dcabc4e20f7372ddb0d6929;hpb=6824d8ddc8a43cae0609be5bbe8bee01fa1a4225;p=xonotic%2Fdarkplaces.git diff --git a/model_brush.c b/model_brush.c index 8622d3d0..6abc8d8f 100644 --- a/model_brush.c +++ b/model_brush.c @@ -26,24 +26,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "wad.h" -//cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"}; -cvar_t halflifebsp = {0, "halflifebsp", "0"}; -cvar_t mcbsp = {0, "mcbsp", "0"}; -cvar_t r_novis = {0, "r_novis", "0"}; -cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"}; -cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"}; -cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"}; -cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4"}; -cvar_t r_subdivisions_mintess = {0, "r_subdivisions_mintess", "1"}; -cvar_t r_subdivisions_maxtess = {0, "r_subdivisions_maxtess", "1024"}; -cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536"}; -cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15"}; -cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "1"}; -cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024"}; -cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225"}; -cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"}; -cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"}; -cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0"}; +//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 halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"}; +cvar_t mcbsp = {0, "mcbsp", "0", "indicates the current map is mcbsp format (useful to know because of different bounding box sizes)"}; +cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"}; +cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0", "mipmaps lightmaps on upload, also expanding them to power of 2 sizes, this runs slower"}; +cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1", "whether to use RGBA (32bit) or RGB (24bit) lightmaps"}; +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)"}; +cvar_t r_subdivisions_mintess = {0, "r_subdivisions_mintess", "1", "minimum number of subdivisions (values above 1 will smooth curves that don't need it)"}; +cvar_t r_subdivisions_maxtess = {0, "r_subdivisions_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"}; +cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536", "maximum vertices allowed per subdivided curve"}; +cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15", "maximum error tolerance on curve subdivision for collision purposes (usually a larger error tolerance than for rendering)"}; +cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "1", "minimum number of subdivisions (values above 1 will smooth curves that don't need it)"}; +cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"}; +cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"}; +cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"}; +cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1", "whether to use optimized traceline code for line traces (as opposed to tracebox code)"}; +cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"}; void Mod_BrushInit(void) { @@ -116,11 +116,13 @@ static int Mod_Q1BSP_FindBoxClusters(model_t *model, const vec3_t mins, const ve if (node->plane) { // node - recurse down the BSP tree - int side = BoxOnPlaneSide(mins, maxs, node->plane) - 1; - if (side < 2) + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) { + if (sides == 0) + return -1; // ERROR: NAN bounding box! // box is on one side of plane, take that path - node = node->children[side]; + node = node->children[sides-1]; } else { @@ -179,11 +181,13 @@ static int Mod_Q1BSP_BoxTouchingPVS(model_t *model, const unsigned char *pvs, co if (node->plane) { // node - recurse down the BSP tree - int side = BoxOnPlaneSide(mins, maxs, node->plane) - 1; - if (side < 2) + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) { + if (sides == 0) + return -1; // ERROR: NAN bounding box! // box is on one side of plane, take that path - node = node->children[side]; + node = node->children[sides-1]; } else { @@ -248,11 +252,13 @@ static int Mod_Q1BSP_BoxTouchingLeafPVS(model_t *model, const unsigned char *pvs if (node->plane) { // node - recurse down the BSP tree - int side = BoxOnPlaneSide(mins, maxs, node->plane) - 1; - if (side < 2) + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) { + if (sides == 0) + return -1; // ERROR: NAN bounding box! // box is on one side of plane, take that path - node = node->children[side]; + node = node->children[sides-1]; } else { @@ -317,11 +323,13 @@ static int Mod_Q1BSP_BoxTouchingVisibleLeafs(model_t *model, const unsigned char if (node->plane) { // node - recurse down the BSP tree - int side = BoxOnPlaneSide(mins, maxs, node->plane) - 1; - if (side < 2) + int sides = BoxOnPlaneSide(mins, maxs, node->plane); + if (sides < 3) { + if (sides == 0) + return -1; // ERROR: NAN bounding box! // box is on one side of plane, take that path - node = node->children[side]; + node = node->children[sides-1]; } else { @@ -749,7 +757,7 @@ static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, i } #endif -static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask) +static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) { // this function currently only supports same size start and end double boxsize[3]; @@ -762,7 +770,7 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, rhc.trace->fraction = 1; rhc.trace->realfraction = 1; rhc.trace->allsolid = true; - VectorSubtract(boxstartmaxs, boxstartmins, boxsize); + VectorSubtract(boxmaxs, boxmins, boxsize); if (boxsize[0] < 3) rhc.hull = &model->brushq1.hulls[0]; // 0x0x0 else if (model->brush.ismcbsp) @@ -795,15 +803,15 @@ static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, else rhc.hull = &model->brushq1.hulls[2]; // 64x64x88 } - VectorSubtract(boxstartmins, rhc.hull->clip_mins, rhc.start); - VectorSubtract(boxendmins, rhc.hull->clip_mins, rhc.end); + VectorMAMAM(1, start, 1, boxmins, -1, rhc.hull->clip_mins, rhc.start); + VectorMAMAM(1, end, 1, boxmins, -1, rhc.hull->clip_mins, rhc.end); VectorSubtract(rhc.end, rhc.start, rhc.dist); #if COLLISIONPARANOID >= 2 Con_Printf("t(%f %f %f,%f %f %f,%i %f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2], rhc.hull - model->brushq1.hulls, rhc.hull->clip_mins[0], rhc.hull->clip_mins[1], rhc.hull->clip_mins[2]); Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); Con_Print("\n"); #else - if (DotProduct(rhc.dist, rhc.dist)) + if (VectorLength2(rhc.dist)) Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end); else Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode); @@ -1096,7 +1104,7 @@ void R_Q1BSP_LoadSplitSky (unsigned char *src, int width, int height, int bytesp if (width != 256 || height != 128) { loadmodel->brush.solidskytexture = R_LoadTexture2D(loadmodel->texturepool, "sky_solidtexture", width, height, src, bytesperpixel == 4 ? TEXTYPE_RGBA : TEXTYPE_PALETTE, TEXF_PRECACHE, bytesperpixel == 1 ? palette_complete : NULL); - loadmodel->brush.alphaskytexture = NULL;; + loadmodel->brush.alphaskytexture = NULL; return; } @@ -1158,7 +1166,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) texture_t *tx, *tx2, *anims[10], *altanims[10]; dmiptexlump_t *m; unsigned char *data, *mtdata; - char name[256]; + char name[MAX_QPATH]; loadmodel->data_textures = NULL; @@ -1250,67 +1258,57 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name); } - // LordHavoc: HL sky textures are entirely different than quake - if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) + if (cls.state != ca_dedicated) { - if (loadmodel->isworldmodel) + // LordHavoc: HL sky textures are entirely different than quake + if (!loadmodel->brush.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) { - data = loadimagepixels(tx->name, false, 0, 0); - if (data) + if (loadmodel->isworldmodel) { - R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); - Mem_Free(data); + data = loadimagepixels(tx->name, false, 0, 0); + if (data) + { + R_Q1BSP_LoadSplitSky(data, image_width, image_height, 4); + Mem_Free(data); + } + else if (mtdata != NULL) + R_Q1BSP_LoadSplitSky(mtdata, mtwidth, mtheight, 1); } - else if (mtdata != NULL) - R_Q1BSP_LoadSplitSky(mtdata, mtwidth, mtheight, 1); } - } - else - { - if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true)) + else { - // did not find external texture, load it from the bsp or wad3 - if (loadmodel->brush.ishlbsp) + if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true)) { - // internal texture overrides wad - unsigned char *pixels, *freepixels, *fogpixels; - pixels = freepixels = NULL; - if (mtdata) - pixels = W_ConvertWAD3Texture(dmiptex); - if (pixels == NULL) - pixels = freepixels = W_GetTexture(tx->name); - if (pixels != NULL) + // did not find external texture, load it from the bsp or wad3 + if (loadmodel->brush.ishlbsp) { - tx->width = image_width; - tx->height = image_height; - tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, NULL); - if (Image_CheckAlpha(pixels, image_width * image_height, true)) + // internal texture overrides wad + unsigned char *pixels, *freepixels; + pixels = freepixels = NULL; + if (mtdata) + pixels = W_ConvertWAD3Texture(dmiptex); + if (pixels == NULL) + pixels = freepixels = W_GetTexture(tx->name); + if (pixels != NULL) { - fogpixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4); - for (j = 0;j < image_width * image_height * 4;j += 4) - { - fogpixels[j + 0] = 255; - fogpixels[j + 1] = 255; - fogpixels[j + 2] = 255; - fogpixels[j + 3] = pixels[j + 3]; - } - tx->skin.fog = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, NULL); - Mem_Free(fogpixels); + tx->width = image_width; + tx->height = image_height; + Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, false, pixels, image_width, image_height, 32, NULL, NULL); } + if (freepixels) + Mem_Free(freepixels); } - if (freepixels) - Mem_Free(freepixels); + else if (mtdata) // texture included + Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL); } - else if (mtdata) // texture included - Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height); } - } - if (tx->skin.base == NULL) - { - // no texture found - tx->width = 16; - tx->height = 16; - tx->skin.base = r_texture_notexture; + if (tx->skin.base == NULL) + { + // no texture found + tx->width = 16; + tx->height = 16; + tx->skin.base = r_texture_notexture; + } } tx->basematerialflags = 0; @@ -1456,6 +1454,7 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) int i; unsigned char *in, *out, *data, d; char litfilename[1024]; + fs_offset_t filesize; loadmodel->brushq1.lightdata = NULL; if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight { @@ -1474,17 +1473,17 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) strlcpy (litfilename, loadmodel->name, sizeof (litfilename)); FS_StripExtension (litfilename, litfilename, sizeof (litfilename)); strlcat (litfilename, ".lit", sizeof (litfilename)); - data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false); + data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize); if (data) { - if (fs_filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + if (filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) { Con_DPrintf("loaded %s\n", litfilename); - loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, fs_filesize - 8); - memcpy(loadmodel->brushq1.lightdata, data + 8, fs_filesize - 8); + loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8); + memcpy(loadmodel->brushq1.lightdata, data + 8, filesize - 8); Mem_Free(data); return; } @@ -1496,10 +1495,10 @@ static void Mod_Q1BSP_LoadLighting(lump_t *l) } else { - if (fs_filesize == 8) + if (filesize == 8) Con_Print("Empty .lit file, ignoring\n"); else - Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", fs_filesize, 8 + l->filelen * 3); + Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", filesize, 8 + l->filelen * 3); Mem_Free(data); } } @@ -1529,7 +1528,7 @@ static void Mod_Q1BSP_LoadLightList(void) strlcpy (lightsfilename, loadmodel->name, sizeof (lightsfilename)); FS_StripExtension (lightsfilename, lightsfilename, sizeof(lightsfilename)); strlcat (lightsfilename, ".lights", sizeof (lightsfilename)); - s = lightsstring = (char *) FS_LoadFile(lightsfilename, tempmempool, false); + s = lightsstring = (char *) FS_LoadFile(lightsfilename, tempmempool, false, NULL); if (s) { numlights = 0; @@ -1619,18 +1618,18 @@ static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data) key[strlen(key)-1] = 0; if (!COM_ParseToken(&data, false)) return; // error - strcpy(value, com_token); + dpsnprintf(value, sizeof(value), "%s", com_token); if (!strcmp("wad", key)) // for HalfLife maps { if (loadmodel->brush.ishlbsp) { j = 0; - for (i = 0;i < 4096;i++) + for (i = 0;i < (int)sizeof(value);i++) if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':') break; if (value[i]) { - for (;i < 4096;i++) + for (;i < (int)sizeof(value);i++) { // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'... if (value[i] == '\\' || value[i] == '/' || value[i] == ':') @@ -1767,6 +1766,12 @@ static void Mod_Q1BSP_LoadEdges(lump_t *l) { out->v[0] = (unsigned short)LittleShort(in->v[0]); out->v[1] = (unsigned short)LittleShort(in->v[1]); + if (out->v[0] >= loadmodel->brushq1.numvertexes || out->v[1] >= loadmodel->brushq1.numvertexes) + { + Con_Printf("Mod_Q1BSP_LoadEdges: %s has invalid vertex indices in edge %i (vertices %i %i >= numvertices %i)\n", loadmodel->name, i, out->v[0], out->v[1], loadmodel->brushq1.numvertexes); + out->v[0] = 0; + out->v[1] = 0; + } } } @@ -1948,7 +1953,7 @@ static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surface) subdivpolyverts = 0; SubdividePolygon(surface->num_vertices, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex)); if (subdivpolytriangles < 1) - Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?\n"); + Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?"); surface->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t)); mesh->num_vertices = subdivpolyverts; @@ -2011,16 +2016,16 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) firstedge = LittleLong(in->firstedge); numedges = LittleShort(in->numedges); if ((unsigned int) firstedge > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges) - Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->brushq1.numsurfedges); + Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)", firstedge, numedges, loadmodel->brushq1.numsurfedges); i = LittleShort(in->texinfo); if ((unsigned int) i >= (unsigned int) loadmodel->brushq1.numtexinfo) - Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)\n", i, loadmodel->brushq1.numtexinfo); + Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)", i, loadmodel->brushq1.numtexinfo); surface->lightmapinfo->texinfo = loadmodel->brushq1.texinfo + i; surface->texture = surface->lightmapinfo->texinfo->texture; planenum = LittleShort(in->planenum); if ((unsigned int) planenum >= (unsigned int) loadmodel->brush.num_planes) - Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->brush.num_planes); + Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)", planenum, loadmodel->brush.num_planes); //surface->flags = surface->texture->flags; //if (LittleShort(in->side)) @@ -2090,8 +2095,6 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) // lighting info for (i = 0;i < MAXLIGHTMAPS;i++) surface->lightmapinfo->styles[i] = in->styles[i]; - // force lightmap upload on first time seeing the surface - surface->cached_dlight = true; surface->lightmapinfo->lightmaptexturestride = 0; surface->lightmaptexture = NULL; i = LittleLong(in->lightofs); @@ -2111,6 +2114,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) else // LordHavoc: white lighting (bsp version 29) surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (i * 3); + // check if we should apply a lightmap to this if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples) { int i, iu, iv; @@ -2118,6 +2122,8 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) if (ssize > 256 || tsize > 256) Host_Error("Bad surface extents"); + // force lightmap upload on first time seeing the surface + surface->cached_dlight = true; // stainmap for permanent marks on walls surface->lightmapinfo->stainsamples = (unsigned char *)Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); // clear to white @@ -2155,7 +2161,7 @@ static void Mod_Q1BSP_LoadFaces(lump_t *l) static void Mod_Q1BSP_LoadNodes_RecursiveSetParent(mnode_t *node, mnode_t *parent) { //if (node->parent) - // Host_Error("Mod_Q1BSP_LoadNodes_RecursiveSetParent: runaway recursion\n"); + // Host_Error("Mod_Q1BSP_LoadNodes_RecursiveSetParent: runaway recursion"); node->parent = parent; if (node->plane) { @@ -2305,7 +2311,7 @@ static void Mod_Q1BSP_LoadClipnodes(lump_t *l, hullinfo_t *hullinfo) out->children[0] = LittleShort(in->children[0]); out->children[1] = LittleShort(in->children[1]); if (out->children[0] >= count || out->children[1] >= count) - Host_Error("Corrupt clipping hull(out of range child)\n"); + Host_Error("Corrupt clipping hull(out of range child)"); } } @@ -2405,7 +2411,7 @@ static void Mod_Q1BSP_LoadMapBrushes(void) char mapfilename[MAX_QPATH]; FS_StripExtension (loadmodel->name, mapfilename, sizeof (mapfilename)); strlcat (mapfilename, ".map", sizeof (mapfilename)); - maptext = (unsigned char*) FS_LoadFile(mapfilename, tempmempool, false); + maptext = (unsigned char*) FS_LoadFile(mapfilename, tempmempool, false, NULL); if (!maptext) return; text = maptext; @@ -2784,7 +2790,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node) for (i = 0;i < nodeportal->numpoints*3;i++) frontpoints[i] = nodeportal->points[i]; - PolygonD_Divide(nodeportal->numpoints, frontpoints, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, 1.0/32.0, MAX_PORTALPOINTS, nodeportal->points, &nodeportal->numpoints, 0, NULL, NULL); + PolygonD_Divide(nodeportal->numpoints, frontpoints, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, 1.0/32.0, MAX_PORTALPOINTS, nodeportal->points, &nodeportal->numpoints, 0, NULL, NULL, NULL); if (nodeportal->numpoints <= 0 || nodeportal->numpoints >= MAX_PORTALPOINTS) break; } @@ -2822,7 +2828,7 @@ static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node) RemovePortalFromNodes(portal); // cut the portal into two portals, one on each side of the node plane - PolygonD_Divide(portal->numpoints, portal->points, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, 1.0/32.0, MAX_PORTALPOINTS, frontpoints, &numfrontpoints, MAX_PORTALPOINTS, backpoints, &numbackpoints); + PolygonD_Divide(portal->numpoints, portal->points, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, 1.0/32.0, MAX_PORTALPOINTS, frontpoints, &numfrontpoints, MAX_PORTALPOINTS, backpoints, &numbackpoints, NULL); if (!numfrontpoints) { @@ -3151,6 +3157,18 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend) // store which lightmap format to use mod->brushq1.lightmaprgba = r_lightmaprgba.integer; + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < HEADER_LUMPS;i++) + { + if (i == LUMP_ENTITIES) + continue; + mod->brush.qw_md4sum ^= LittleLong(Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen)); + if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= LittleLong(Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen)); + } + Mod_Q1BSP_LoadEntities(&header->lumps[LUMP_ENTITIES]); Mod_Q1BSP_LoadVertexes(&header->lumps[LUMP_VERTEXES]); Mod_Q1BSP_LoadEdges(&header->lumps[LUMP_EDGES]); @@ -3728,7 +3746,7 @@ void static Mod_Q2BSP_Load(model_t *mod, void *buffer, void *bufferend) int i; q2dheader_t *header; - Host_Error("Mod_Q2BSP_Load: not yet implemented\n"); + Host_Error("Mod_Q2BSP_Load: not yet implemented"); mod->type = mod_brushq2; @@ -3754,6 +3772,18 @@ void static Mod_Q2BSP_Load(model_t *mod, void *buffer, void *bufferend) // store which lightmap format to use mod->brushq1.lightmaprgba = r_lightmaprgba.integer; + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < Q2HEADER_LUMPS;i++) + { + if (i == Q2LUMP_ENTITIES) + continue; + mod->brush.qw_md4sum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + if (i == Q2LUMP_VISIBILITY || i == Q2LUMP_LEAFS || i == Q2LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + } + Mod_Q2BSP_LoadEntities(&header->lumps[Q2LUMP_ENTITIES]); Mod_Q2BSP_LoadPlanes(&header->lumps[Q2LUMP_PLANES]); Mod_Q2BSP_LoadVertices(&header->lumps[Q2LUMP_VERTEXES]); @@ -3781,7 +3811,7 @@ static int Mod_Q3BSP_NativeContentsFromSuperContents(model_t *model, int superco static void Mod_Q3BSP_LoadEntities(lump_t *l) { const char *data; - char key[128], value[4096]; + char key[128], value[MAX_INPUTLINE]; float v[3]; loadmodel->brushq3.num_lightgrid_cellsize[0] = 64; loadmodel->brushq3.num_lightgrid_cellsize[1] = 64; @@ -3855,7 +3885,7 @@ static void Mod_Q3BSP_LoadTextures(lump_t *l) { for (i = 0;i < search->numfilenames;i++) { - if ((f = (char *)FS_LoadFile(search->filenames[i], tempmempool, false))) + if ((f = (char *)FS_LoadFile(search->filenames[i], tempmempool, false, NULL))) { text = f; while (COM_ParseToken(&text, false)) @@ -4105,9 +4135,9 @@ parseerror: //if (R_TextureHasAlpha(out->skin.base)) // out->surfaceparms |= Q3SURFACEPARM_TRANS; } - if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true)) - if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true)) - if (cls.state != ca_dedicated) + if (cls.state != ca_dedicated) + if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true)) + if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true)) Con_Printf("%s: texture loading for shader \"%s\" failed (first layer \"%s\" not found either)\n", loadmodel->name, out->name, out->firstpasstexturename); // no animation out->currentframe = out; @@ -4160,11 +4190,11 @@ static void Mod_Q3BSP_LoadBrushSides(lump_t *l) { n = LittleLong(in->planeindex); if (n < 0 || n >= loadmodel->brush.num_planes) - Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)\n", n, loadmodel->brush.num_planes); + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid planeindex %i (%i planes)", n, loadmodel->brush.num_planes); out->plane = loadmodel->brush.data_planes + n; n = LittleLong(in->textureindex); if (n < 0 || n >= loadmodel->num_textures) - Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)\n", n, loadmodel->num_textures); + Host_Error("Mod_Q3BSP_LoadBrushSides: invalid textureindex %i (%i textures)", n, loadmodel->num_textures); out->texture = loadmodel->data_textures + n; } } @@ -4193,12 +4223,12 @@ static void Mod_Q3BSP_LoadBrushes(lump_t *l) n = LittleLong(in->firstbrushside); c = LittleLong(in->numbrushsides); if (n < 0 || n + c > loadmodel->brush.num_brushsides) - Host_Error("Mod_Q3BSP_LoadBrushes: invalid brushside range %i : %i (%i brushsides)\n", n, n + c, loadmodel->brush.num_brushsides); + Host_Error("Mod_Q3BSP_LoadBrushes: invalid brushside range %i : %i (%i brushsides)", n, n + c, loadmodel->brush.num_brushsides); out->firstbrushside = loadmodel->brush.data_brushsides + n; out->numbrushsides = c; n = LittleLong(in->textureindex); if (n < 0 || n >= loadmodel->num_textures) - Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)\n", n, loadmodel->num_textures); + Host_Error("Mod_Q3BSP_LoadBrushes: invalid textureindex %i (%i textures)", n, loadmodel->num_textures); out->texture = loadmodel->data_textures + n; // make a list of mplane_t structs to construct a colbrush from @@ -4696,13 +4726,13 @@ static void Mod_Q3BSP_LoadModels(lump_t *l) n = LittleLong(in->firstface); c = LittleLong(in->numfaces); if (n < 0 || n + c > loadmodel->num_surfaces) - Host_Error("Mod_Q3BSP_LoadModels: invalid face range %i : %i (%i faces)\n", n, n + c, loadmodel->num_surfaces); + Host_Error("Mod_Q3BSP_LoadModels: invalid face range %i : %i (%i faces)", n, n + c, loadmodel->num_surfaces); out->firstface = n; out->numfaces = c; n = LittleLong(in->firstbrush); c = LittleLong(in->numbrushes); if (n < 0 || n + c > loadmodel->brush.num_brushes) - Host_Error("Mod_Q3BSP_LoadModels: invalid brush range %i : %i (%i brushes)\n", n, n + c, loadmodel->brush.num_brushes); + Host_Error("Mod_Q3BSP_LoadModels: invalid brush range %i : %i (%i brushes)", n, n + c, loadmodel->brush.num_brushes); out->firstbrush = n; out->numbrushes = c; } @@ -4727,7 +4757,7 @@ static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l) { n = LittleLong(*in); if (n < 0 || n >= loadmodel->brush.num_brushes) - Host_Error("Mod_Q3BSP_LoadLeafBrushes: invalid brush index %i (%i brushes)\n", n, loadmodel->brush.num_brushes); + Host_Error("Mod_Q3BSP_LoadLeafBrushes: invalid brush index %i (%i brushes)", n, loadmodel->brush.num_brushes); *out = n; } } @@ -4751,7 +4781,7 @@ static void Mod_Q3BSP_LoadLeafFaces(lump_t *l) { n = LittleLong(*in); if (n < 0 || n >= loadmodel->num_surfaces) - Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)\n", n, loadmodel->num_surfaces); + Host_Error("Mod_Q3BSP_LoadLeafFaces: invalid face index %i (%i faces)", n, loadmodel->num_surfaces); *out = n; } } @@ -4786,13 +4816,13 @@ static void Mod_Q3BSP_LoadLeafs(lump_t *l) n = LittleLong(in->firstleafface); c = LittleLong(in->numleaffaces); if (n < 0 || n + c > loadmodel->brush.num_leafsurfaces) - Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafsurface range %i : %i (%i leafsurfaces)\n", n, n + c, loadmodel->brush.num_leafsurfaces); + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafsurface range %i : %i (%i leafsurfaces)", n, n + c, loadmodel->brush.num_leafsurfaces); out->firstleafsurface = loadmodel->brush.data_leafsurfaces + n; out->numleafsurfaces = c; n = LittleLong(in->firstleafbrush); c = LittleLong(in->numleafbrushes); if (n < 0 || n + c > loadmodel->brush.num_leafbrushes) - Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)\n", n, n + c, loadmodel->brush.num_leafbrushes); + Host_Error("Mod_Q3BSP_LoadLeafs: invalid leafbrush range %i : %i (%i leafbrushes)", n, n + c, loadmodel->brush.num_leafbrushes); out->firstleafbrush = loadmodel->brush.data_leafbrushes + n; out->numleafbrushes = c; } @@ -4818,7 +4848,7 @@ static void Mod_Q3BSP_LoadNodes(lump_t *l) out->parent = NULL; n = LittleLong(in->planeindex); if (n < 0 || n >= loadmodel->brush.num_planes) - Host_Error("Mod_Q3BSP_LoadNodes: invalid planeindex %i (%i planes)\n", n, loadmodel->brush.num_planes); + Host_Error("Mod_Q3BSP_LoadNodes: invalid planeindex %i (%i planes)", n, loadmodel->brush.num_planes); out->plane = loadmodel->brush.data_planes + n; for (j = 0;j < 2;j++) { @@ -4826,14 +4856,14 @@ static void Mod_Q3BSP_LoadNodes(lump_t *l) if (n >= 0) { if (n >= loadmodel->brush.num_nodes) - Host_Error("Mod_Q3BSP_LoadNodes: invalid child node index %i (%i nodes)\n", n, loadmodel->brush.num_nodes); + Host_Error("Mod_Q3BSP_LoadNodes: invalid child node index %i (%i nodes)", n, loadmodel->brush.num_nodes); out->children[j] = loadmodel->brush.data_nodes + n; } else { n = -1 - n; if (n >= loadmodel->brush.num_leafs) - Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)\n", n, loadmodel->brush.num_leafs); + Host_Error("Mod_Q3BSP_LoadNodes: invalid child leaf index %i (%i leafs)", n, loadmodel->brush.num_leafs); out->children[j] = (mnode_t *)(loadmodel->brush.data_leafs + n); } } @@ -4878,9 +4908,9 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) if (l->filelen) { if (l->filelen < count * (int)sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)\n", l->filelen, count * sizeof(*in), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]); + Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, count * sizeof(*in), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]); if (l->filelen != count * (int)sizeof(*in)) - Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", count * sizeof(*in), l->filelen); + Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i", count * sizeof(*in), l->filelen); out = (q3dlightgrid_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); loadmodel->brushq3.data_lightgrid = out; loadmodel->brushq3.num_lightgrid = count; @@ -4918,10 +4948,10 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l) loadmodel->brush.num_pvsclusters = LittleLong(in->numclusters); loadmodel->brush.num_pvsclusterbytes = LittleLong(in->chainlength); if (loadmodel->brush.num_pvsclusterbytes < ((loadmodel->brush.num_pvsclusters + 7) / 8)) - Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.num_pvsclusters); + Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8", loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.num_pvsclusters); totalchains = loadmodel->brush.num_pvsclusterbytes * loadmodel->brush.num_pvsclusters; if (l->filelen < totalchains + (int)sizeof(*in)) - Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)\n", loadmodel->brush.num_pvsclusters, loadmodel->brush.num_pvsclusterbytes, totalchains + sizeof(*in), l->filelen); + Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)", loadmodel->brush.num_pvsclusters, loadmodel->brush.num_pvsclusterbytes, totalchains + sizeof(*in), l->filelen); loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, totalchains); memcpy(loadmodel->brush.data_pvsclusters, (unsigned char *)(in + 1), totalchains); @@ -5012,51 +5042,54 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, model_t *model, float dist1, dist2, midfrac, mid[3], nodesegmentmins[3], nodesegmentmaxs[3]; mleaf_t *leaf; msurface_t *surface; + mplane_t *plane; colbrushf_t *brush; - if (startfrac > trace->realfraction) - return; - // note: all line fragments past first impact fraction are ignored - if (VectorCompare(start, end)) - { - // find which leaf the point is in - while (node->plane) - node = node->children[DotProduct(start, node->plane->normal) < node->plane->dist]; - } - else + // walk the tree until we hit a leaf, recursing for any split cases + while (node->plane) { - // find which nodes the line is in and recurse for them - while (node->plane) + plane = node->plane; + // axial planes are much more common than non-axial, so an optimized + // axial case pays off here + if (plane->type < 3) { - // recurse down node sides - dist1 = PlaneDiff(start, node->plane); - dist2 = PlaneDiff(end, node->plane); - startside = dist1 < 0; - endside = dist2 < 0; - if (startside == endside) - { - // most of the time the line fragment is on one side of the plane - node = node->children[startside]; - } - else - { - // line crosses node plane, split the line - midfrac = dist1 / (dist1 - dist2); - VectorLerp(start, midfrac, end, mid); - // take the near side first - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); - if (midfrac <= trace->realfraction) - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); - return; - } + dist1 = start[plane->type] - plane->dist; + dist2 = end[plane->type] - plane->dist; + } + else + { + dist1 = DotProduct(start, plane->normal) - plane->dist; + dist2 = DotProduct(end, plane->normal) - plane->dist; + } + startside = dist1 < 0; + endside = dist2 < 0; + if (startside == endside) + { + // most of the time the line fragment is on one side of the plane + node = node->children[startside]; + } + else + { + // line crosses node plane, split the line + dist1 = PlaneDiff(linestart, plane); + dist2 = PlaneDiff(lineend, plane); + midfrac = dist1 / (dist1 - dist2); + VectorLerp(linestart, midfrac, lineend, mid); + // take the near side first + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); + // if we found an impact on the front side, don't waste time + // exploring the far side + if (midfrac <= trace->realfraction) + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); + return; } } // hit a leaf - nodesegmentmins[0] = min(start[0], end[0]); - nodesegmentmins[1] = min(start[1], end[1]); - nodesegmentmins[2] = min(start[2], end[2]); - nodesegmentmaxs[0] = max(start[0], end[0]); - nodesegmentmaxs[1] = max(start[1], end[1]); - nodesegmentmaxs[2] = max(start[2], end[2]); + nodesegmentmins[0] = min(start[0], end[0]) - 1; + nodesegmentmins[1] = min(start[1], end[1]) - 1; + nodesegmentmins[2] = min(start[2], end[2]) - 1; + nodesegmentmaxs[0] = max(start[0], end[0]) + 1; + nodesegmentmaxs[1] = max(start[1], end[1]) + 1; + nodesegmentmaxs[2] = max(start[2], end[2]) + 1; // line trace the brushes leaf = (mleaf_t *)node; for (i = 0;i < leaf->numleafbrushes;i++) @@ -5066,8 +5099,6 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, model_t *model, { brush->markframe = markframe; Collision_TraceLineBrushFloat(trace, linestart, lineend, brush, brush); - if (startfrac > trace->realfraction) - return; } } // can't do point traces on curves (they have no thickness) @@ -5081,8 +5112,6 @@ static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, model_t *model, { surface->collisionmarkframe = markframe; Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs); - if (startfrac > trace->realfraction) - return; } } } @@ -5092,231 +5121,15 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, model_t *model { int i; int sides; - float nodesegmentmins[3], nodesegmentmaxs[3]; mleaf_t *leaf; colbrushf_t *brush; msurface_t *surface; - /* - // find which nodes the line is in and recurse for them - while (node->plane) - { - // recurse down node sides - int startside, endside; - float dist1near, dist1far, dist2near, dist2far; - BoxPlaneCornerDistances(thisbrush_start->mins, thisbrush_start->maxs, node->plane, &dist1near, &dist1far); - BoxPlaneCornerDistances(thisbrush_end->mins, thisbrush_end->maxs, node->plane, &dist2near, &dist2far); - startside = dist1near < 0; - startside = dist1near < 0 ? (dist1far < 0 ? 1 : 2) : (dist1far < 0 ? 2 : 0); - endside = dist2near < 0 ? (dist2far < 0 ? 1 : 2) : (dist2far < 0 ? 2 : 0); - if (startside == 2 || endside == 2) - { - // brushes cross plane - // do not clip anything, just take both sides - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - if (startside == 0) - { - if (endside == 0) - { - node = node->children[0]; - continue; - } - else - { - //midf0 = dist1near / (dist1near - dist2near); - //midf1 = dist1far / (dist1far - dist2far); - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - } - else - { - if (endside == 0) - { - //midf0 = dist1near / (dist1near - dist2near); - //midf1 = dist1far / (dist1far - dist2far); - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - else - { - node = node->children[1]; - continue; - } - } - - if (dist1near < 0 && dist2near < 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;} - if (dist1near < 0 && dist2near < 0 && dist1far < 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near < 0 && dist2near < 0 && dist1far >= 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near < 0 && dist2near < 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near < 0 && dist2near >= 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;} - if (dist1near < 0 && dist2near >= 0 && dist1far < 0 && dist2far >= 0){} - if (dist1near < 0 && dist2near >= 0 && dist1far >= 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near < 0 && dist2near >= 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near >= 0 && dist2near < 0 && dist1far < 0 && dist2far < 0){node = node->children[1];continue;} - if (dist1near >= 0 && dist2near < 0 && dist1far < 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near >= 0 && dist2near < 0 && dist1far >= 0 && dist2far < 0){} - if (dist1near >= 0 && dist2near < 0 && dist1far >= 0 && dist2far >= 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near >= 0 && dist2near >= 0 && dist1far < 0 && dist2far < 0){Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);node = node->children[1];continue;} - if (dist1near >= 0 && dist2near >= 0 && dist1far < 0 && dist2far >= 0){node = node->children[0];continue;} - if (dist1near >= 0 && dist2near >= 0 && dist1far >= 0 && dist2far < 0){node = node->children[0];continue;} - if (dist1near >= 0 && dist2near >= 0 && dist1far >= 0 && dist2far >= 0){node = node->children[0];continue;} - { - if (dist2near < 0) // d1n<0 && d2n<0 - { - if (dist2near < 0) // d1n<0 && d2n<0 - { - if (dist2near < 0) // d1n<0 && d2n<0 - { - } - else // d1n<0 && d2n>0 - { - } - } - else // d1n<0 && d2n>0 - { - if (dist2near < 0) // d1n<0 && d2n<0 - { - } - else // d1n<0 && d2n>0 - { - } - } - } - else // d1n<0 && d2n>0 - { - } - } - else // d1n>0 - { - if (dist2near < 0) // d1n>0 && d2n<0 - { - } - else // d1n>0 && d2n>0 - { - } - } - if (dist1near < 0 == dist1far < 0 == dist2near < 0 == dist2far < 0) - { - node = node->children[startside]; - continue; - } - if (dist1near < dist2near) - { - // out - if (dist1near >= 0) - { - node = node->children[0]; - continue; - } - if (dist2far < 0) - { - node = node->children[1]; - continue; - } - // dist1near < 0 && dist2far >= 0 - } - else - { - // in - } - startside = dist1near < 0 ? (dist1far < 0 ? 1 : 2) : (dist1far < 0 ? 2 : 0); - endside = dist2near < 0 ? (dist2far < 0 ? 1 : 2) : (dist2far < 0 ? 2 : 0); - if (startside == 2 || endside == 2) - { - // brushes cross plane - // do not clip anything, just take both sides - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - } - else if (startside == endside) - node = node->children[startside]; - else if (startside == 0) // endside = 1 (start infront, end behind) - { - } - else // startside == 1 endside = 0 (start behind, end infront) - { - } - == endside) - { - if (startside < 2) - node = node->children[startside]; - else - { - // start and end brush cross plane - } - } - else - { - } - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - node = node->children[1]; - else if (dist1near < 0 && dist1far < 0 && dist2near >= 0 && dist2far >= 0) - else if (dist1near >= 0 && dist1far >= 0 && dist2near < 0 && dist2far < 0) - else if (dist1near >= 0 && dist1far >= 0 && dist2near >= 0 && dist2far >= 0) - node = node->children[0]; - else - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - { - } - else if (dist1near >= 0 && dist1far >= 0) - { - } - else // mixed (lying on plane) - { - } - { - if (dist2near < 0 && dist2far < 0) - { - } - else - node = node->children[1]; - } - if (dist1near < 0 && dist1far < 0 && dist2near < 0 && dist2far < 0) - node = node->children[0]; - else if (dist1near >= 0 && dist1far >= 0 && dist2near >= 0 && dist2far >= 0) - node = node->children[1]; - else - { - // both sides - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - } - sides = dist1near || dist1near < 0 | dist1far < 0 | dist2near < 0 | dist - startside = dist1 < 0; - endside = dist2 < 0; - if (startside == endside) - { - // most of the time the line fragment is on one side of the plane - node = node->children[startside]; - } - else - { - // line crosses node plane, split the line - midfrac = dist1 / (dist1 - dist2); - VectorLerp(start, midfrac, end, mid); - // take the near side first - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); - if (midfrac <= trace->fraction) - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs); - return; - } - } - */ -#if 1 - for (;;) + mplane_t *plane; + float nodesegmentmins[3], nodesegmentmaxs[3]; + // walk the tree until we hit a leaf, recursing for any split cases + while (node->plane) { - mplane_t *plane = node->plane; - if (!plane) - break; + plane = node->plane; // axial planes are much more common than non-axial, so an optimized // axial case pays off here if (plane->type < 3) @@ -5326,172 +5139,34 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, model_t *model // recurse down node sides // use an inlined axial BoxOnPlaneSide to slightly reduce overhead //sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, plane); - sides = ((segmentmaxs[plane->type] >= plane->dist) | ((segmentmins[plane->type] < plane->dist) << 1)); - if (sides == 3) - { - // segment box crosses plane - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - sides = 2; - } - } - else - { - // this is a non-axial plane, entire trace bounding box - // comparisons against it are likely to be very sloppy, so in if - // the whole box is split by the plane we then test the start/end - // boxes against it to be sure - sides = BoxOnPlaneSide(segmentmins, segmentmaxs, plane); - if (sides == 3) - { - // segment box crosses plane - // now check start and end brush boxes to handle a lot of 'diagonal' cases more efficiently... - sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, plane); - if (sides == 3) - { - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - sides = 2; - } - } - } - // take whichever side the segment box is on - node = node->children[sides - 1]; - } - nodesegmentmins[0] = max(segmentmins[0], node->mins[0]); - nodesegmentmins[1] = max(segmentmins[1], node->mins[1]); - nodesegmentmins[2] = max(segmentmins[2], node->mins[2]); - nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]); - nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]); - nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]); -#elif 1 - for (;;) - { - nodesegmentmins[0] = max(segmentmins[0], node->mins[0]); - nodesegmentmins[1] = max(segmentmins[1], node->mins[1]); - nodesegmentmins[2] = max(segmentmins[2], node->mins[2]); - nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]); - nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]); - nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]); - if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2]) - return; - if (!node->plane) - break; - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - } -#elif 0 - // FIXME: could be made faster by copying TraceLine code and making it use - // box plane distances... (variant on the BoxOnPlaneSide code) - for (;;) - { - nodesegmentmins[0] = max(segmentmins[0], node->mins[0]); - nodesegmentmins[1] = max(segmentmins[1], node->mins[1]); - nodesegmentmins[2] = max(segmentmins[2], node->mins[2]); - nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]); - nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]); - nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]); - if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2]) - return; - if (!node->plane) - break; - if (mod_q3bsp_debugtracebrush.integer == 2) - { - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - else if (mod_q3bsp_debugtracebrush.integer == 1) - { - // recurse down node sides - sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane); - if (sides == 3) - { - // segment box crosses plane - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - // take whichever side the segment box is on - node = node->children[sides - 1]; - continue; + //sides = ((segmentmaxs[plane->type] >= plane->dist) | ((segmentmins[plane->type] < plane->dist) << 1)); + sides = ((segmentmaxs[plane->type] >= plane->dist) + ((segmentmins[plane->type] < plane->dist) * 2)); } else { - // recurse down node sides - sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane); - if (sides == 3) - { - // segment box crosses plane - // now check start and end brush boxes to handle a lot of 'diagonal' cases more efficiently... - sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, node->plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, node->plane); - if (sides == 3) - { - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - continue; - } - } - // take whichever side the segment box is on - node = node->children[sides - 1]; - continue; - } - return; - } -#else - // FIXME: could be made faster by copying TraceLine code and making it use - // box plane distances... (variant on the BoxOnPlaneSide code) - for (;;) - { - nodesegmentmins[0] = max(segmentmins[0], node->mins[0]); - nodesegmentmins[1] = max(segmentmins[1], node->mins[1]); - nodesegmentmins[2] = max(segmentmins[2], node->mins[2]); - nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0]); - nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1]); - nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2]); - if (nodesegmentmins[0] > nodesegmentmaxs[0] || nodesegmentmins[1] > nodesegmentmaxs[1] || nodesegmentmins[2] > nodesegmentmaxs[2]) - return; - if (!node->plane) - break; - if (mod_q3bsp_debugtracebrush.integer == 2) - { - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; + // this is a non-axial plane, so check if the start and end boxes + // are both on one side of the plane to handle 'diagonal' cases + sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, plane); } - else if (mod_q3bsp_debugtracebrush.integer == 1) - { - // recurse down node sides - sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane); - if (sides == 3) - { - // segment box crosses plane - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - node = node->children[1]; - } - else - { - // take whichever side the segment box is on - node = node->children[sides - 1]; - } - } - else + if (sides == 3) { - // recurse down node sides - sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane); - if (sides == 3) - { - // segment box crosses plane - // now check start and end brush boxes to handle a lot of 'diagonal' cases more efficiently... - sides = BoxOnPlaneSide(thisbrush_start->mins, thisbrush_start->maxs, node->plane) | BoxOnPlaneSide(thisbrush_end->mins, thisbrush_end->maxs, node->plane); - if (sides == 3) - { - Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); - sides = 2; - } - } - // take whichever side the segment box is on - node = node->children[sides - 1]; + // segment crosses plane + Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, node->children[0], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs); + sides = 2; } + // if sides == 0 then the trace itself is bogus (Not A Number values), + // in this case we simply pretend the trace hit nothing + if (sides == 0) + return; // ERROR: NAN bounding box! + // take whichever side the segment box is on + node = node->children[sides - 1]; } -#endif + nodesegmentmins[0] = max(segmentmins[0], node->mins[0] - 1); + nodesegmentmins[1] = max(segmentmins[1], node->mins[1] - 1); + nodesegmentmins[2] = max(segmentmins[2], node->mins[2] - 1); + nodesegmentmaxs[0] = min(segmentmaxs[0], node->maxs[0] + 1); + nodesegmentmaxs[1] = min(segmentmaxs[1], node->maxs[1] + 1); + nodesegmentmaxs[2] = min(segmentmaxs[2], node->maxs[2] + 1); // hit a leaf leaf = (mleaf_t *)node; for (i = 0;i < leaf->numleafbrushes;i++) @@ -5517,12 +5192,10 @@ static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, model_t *model } } -static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask) +static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask) { int i; float segmentmins[3], segmentmaxs[3]; - colbrushf_t *thisbrush_start, *thisbrush_end; - matrix4x4_t startmatrix, endmatrix; static int markframe = 0; msurface_t *surface; q3mbrush_t *brush; @@ -5530,50 +5203,60 @@ static void Mod_Q3BSP_TraceBox(model_t *model, int frame, trace_t *trace, const trace->fraction = 1; trace->realfraction = 1; trace->hitsupercontentsmask = hitsupercontentsmask; - Matrix4x4_CreateIdentity(&startmatrix); - Matrix4x4_CreateIdentity(&endmatrix); - segmentmins[0] = min(boxstartmins[0], boxendmins[0]); - segmentmins[1] = min(boxstartmins[1], boxendmins[1]); - segmentmins[2] = min(boxstartmins[2], boxendmins[2]); - segmentmaxs[0] = max(boxstartmaxs[0], boxendmaxs[0]); - segmentmaxs[1] = max(boxstartmaxs[1], boxendmaxs[1]); - segmentmaxs[2] = max(boxstartmaxs[2], boxendmaxs[2]); - if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs)) - { - if (VectorCompare(boxstartmins, boxendmins)) + if (mod_q3bsp_optimizedtraceline.integer && VectorLength2(boxmins) + VectorLength2(boxmaxs) == 0) + { + if (VectorCompare(start, end)) { // point trace if (model->brush.submodel) { for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) if (brush->colbrushf) - Collision_TracePointBrushFloat(trace, boxstartmins, brush->colbrushf); + Collision_TracePointBrushFloat(trace, start, brush->colbrushf); } else - Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace, model, model->brush.data_nodes, boxstartmins, ++markframe); + Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, ++markframe); } else { // line trace + segmentmins[0] = min(start[0], end[0]) - 1; + segmentmins[1] = min(start[1], end[1]) - 1; + segmentmins[2] = min(start[2], end[2]) - 1; + segmentmaxs[0] = max(start[0], end[0]) + 1; + segmentmaxs[1] = max(start[1], end[1]) + 1; + segmentmaxs[2] = max(start[2], end[2]) + 1; if (model->brush.submodel) { for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) if (brush->colbrushf) - Collision_TraceLineBrushFloat(trace, boxstartmins, boxendmins, brush->colbrushf, brush->colbrushf); + Collision_TraceLineBrushFloat(trace, start, end, 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_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs); + Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs); } else - Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, boxstartmins, boxendmins, 0, 1, boxstartmins, boxendmins, ++markframe, segmentmins, segmentmaxs); + Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs); } } else { // box trace, performed as brush trace - thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs); - thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs); + colbrushf_t *thisbrush_start, *thisbrush_end; + vec3_t boxstartmins, boxstartmaxs, boxendmins, boxendmaxs; + segmentmins[0] = min(start[0], end[0]) + boxmins[0] - 1; + segmentmins[1] = min(start[1], end[1]) + boxmins[1] - 1; + segmentmins[2] = min(start[2], end[2]) + boxmins[2] - 1; + segmentmaxs[0] = max(start[0], end[0]) + boxmaxs[0] + 1; + segmentmaxs[1] = max(start[1], end[1]) + boxmaxs[1] + 1; + segmentmaxs[2] = max(start[2], end[2]) + boxmaxs[2] + 1; + VectorAdd(start, boxmins, boxstartmins); + VectorAdd(start, boxmaxs, boxstartmaxs); + VectorAdd(end, boxmins, boxendmins); + VectorAdd(end, boxmaxs, boxendmaxs); + thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs); + thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs); if (model->brush.submodel) { for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++) @@ -5708,6 +5391,18 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend) header->lumps[i].filelen = LittleLong(header->lumps[i].filelen); } + mod->brush.qw_md4sum = 0; + mod->brush.qw_md4sum2 = 0; + for (i = 0;i < Q3HEADER_LUMPS;i++) + { + if (i == Q3LUMP_ENTITIES) + continue; + mod->brush.qw_md4sum ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + if (i == Q3LUMP_PVS || i == Q3LUMP_LEAFS || i == Q3LUMP_NODES) + continue; + mod->brush.qw_md4sum2 ^= Com_BlockChecksum(mod_base + header->lumps[i].fileofs, header->lumps[i].filelen); + } + Mod_Q3BSP_LoadEntities(&header->lumps[Q3LUMP_ENTITIES]); Mod_Q3BSP_LoadTextures(&header->lumps[Q3LUMP_TEXTURES]); Mod_Q3BSP_LoadPlanes(&header->lumps[Q3LUMP_PLANES]); @@ -5826,11 +5521,11 @@ void Mod_IBSP_Load(model_t *mod, void *buffer, void *bufferend) else if (i == Q2BSPVERSION) Mod_Q2BSP_Load(mod,buffer, bufferend); else - Host_Error("Mod_IBSP_Load: unknown/unsupported version %i\n", i); + Host_Error("Mod_IBSP_Load: unknown/unsupported version %i", i); } void Mod_MAP_Load(model_t *mod, void *buffer, void *bufferend) { - Host_Error("Mod_MAP_Load: not yet implemented\n"); + Host_Error("Mod_MAP_Load: not yet implemented"); }