#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)
{
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
{
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
{
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
{
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
{
}
#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];
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)
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);
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;
}
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;
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;
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
{
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;
}
}
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);
}
}
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;
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] == ':')
{
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;
+ }
}
}
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;
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))
// 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);
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;
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
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)
{
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)");
}
}
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;
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;
}
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)
{
// 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]);
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;
// 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]);
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;
{
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))
//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;
{
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;
}
}
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
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;
}
{
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;
}
}
{
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;
}
}
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;
}
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++)
{
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);
}
}
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;
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);
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++)
{
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)
{
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;
}
}
}
{
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)
// 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++)
}
}
-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;
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++)
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]);
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");
}