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 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)"};
+static texture_t mod_q1bsp_texture_solid;
+static texture_t mod_q1bsp_texture_sky;
+static texture_t mod_q1bsp_texture_lava;
+static texture_t mod_q1bsp_texture_slime;
+static texture_t mod_q1bsp_texture_water;
+
void Mod_BrushInit(void)
{
// Cvar_RegisterVariable(&r_subdivide_size);
Cvar_RegisterVariable(&halflifebsp);
Cvar_RegisterVariable(&mcbsp);
Cvar_RegisterVariable(&r_novis);
- Cvar_RegisterVariable(&r_miplightmaps);
Cvar_RegisterVariable(&r_lightmaprgba);
Cvar_RegisterVariable(&r_nosurftextures);
Cvar_RegisterVariable(&r_subdivisions_tolerance);
Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
+
+ memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid));
+ strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name));
+ mod_q1bsp_texture_solid.surfaceflags = 0;
+ mod_q1bsp_texture_solid.supercontents = SUPERCONTENTS_SOLID;
+
+ mod_q1bsp_texture_sky = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_sky.name, "sky", sizeof(mod_q1bsp_texture_sky.name));
+ mod_q1bsp_texture_sky.surfaceflags = Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT | Q3SURFACEFLAG_NOMARKS | Q3SURFACEFLAG_NODLIGHT | Q3SURFACEFLAG_NOLIGHTMAP;
+ mod_q1bsp_texture_sky.supercontents = SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP;
+
+ mod_q1bsp_texture_lava = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_lava.name, "*lava", sizeof(mod_q1bsp_texture_lava.name));
+ mod_q1bsp_texture_lava.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_lava.supercontents = SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
+
+ mod_q1bsp_texture_slime = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_slime.name, "*slime", sizeof(mod_q1bsp_texture_slime.name));
+ mod_q1bsp_texture_slime.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_slime.supercontents = SUPERCONTENTS_SLIME;
+
+ mod_q1bsp_texture_water = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_water.name, "*water", sizeof(mod_q1bsp_texture_water.name));
+ mod_q1bsp_texture_water.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_water.supercontents = SUPERCONTENTS_WATER;
}
static mleaf_t *Mod_Q1BSP_PointInLeaf(model_t *model, const vec3_t p)
case CONTENTS_SLIME:
return SUPERCONTENTS_SLIME;
case CONTENTS_LAVA:
- return SUPERCONTENTS_LAVA;
+ return SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
case CONTENTS_SKY:
- return SUPERCONTENTS_SKY;
+ return SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP;
}
return 0;
}
t->trace->inwater = true;
if (num == 0)
t->trace->inopen = true;
+ if (num & SUPERCONTENTS_SOLID)
+ t->trace->hittexture = &mod_q1bsp_texture_solid;
+ else if (num & SUPERCONTENTS_SKY)
+ t->trace->hittexture = &mod_q1bsp_texture_sky;
+ else if (num & SUPERCONTENTS_LAVA)
+ t->trace->hittexture = &mod_q1bsp_texture_lava;
+ else if (num & SUPERCONTENTS_SLIME)
+ t->trace->hittexture = &mod_q1bsp_texture_slime;
+ else
+ t->trace->hittexture = &mod_q1bsp_texture_water;
+ t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
+ t->trace->hitsupercontents = num;
if (num & t->trace->hitsupercontentsmask)
{
// if the first leaf is solid, set startsolid
}
#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);
#endif
+ if (trace->fraction == 1)
+ {
+ trace->hitsupercontents = 0;
+ trace->hitq3surfaceflags = 0;
+ trace->hittexture = NULL;
+ }
}
-void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents)
+void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, texture_t *boxtexture)
{
#if 1
colbrushf_t cbox;
cbox_planes[3].normal[0] = 0;cbox_planes[3].normal[1] = -1;cbox_planes[3].normal[2] = 0;cbox_planes[3].dist = maxs[1] - cmins[1];
cbox_planes[4].normal[0] = 0;cbox_planes[4].normal[1] = 0;cbox_planes[4].normal[2] = 1;cbox_planes[4].dist = cmaxs[2] - mins[2];
cbox_planes[5].normal[0] = 0;cbox_planes[5].normal[1] = 0;cbox_planes[5].normal[2] = -1;cbox_planes[5].dist = maxs[2] - cmins[2];
+ cbox_planes[0].supercontents = boxsupercontents;cbox_planes[0].q3surfaceflags = boxq3surfaceflags;cbox_planes[0].texture = boxtexture;
+ cbox_planes[1].supercontents = boxsupercontents;cbox_planes[1].q3surfaceflags = boxq3surfaceflags;cbox_planes[1].texture = boxtexture;
+ cbox_planes[2].supercontents = boxsupercontents;cbox_planes[2].q3surfaceflags = boxq3surfaceflags;cbox_planes[2].texture = boxtexture;
+ cbox_planes[3].supercontents = boxsupercontents;cbox_planes[3].q3surfaceflags = boxq3surfaceflags;cbox_planes[3].texture = boxtexture;
+ cbox_planes[4].supercontents = boxsupercontents;cbox_planes[4].q3surfaceflags = boxq3surfaceflags;cbox_planes[4].texture = boxtexture;
+ cbox_planes[5].supercontents = boxsupercontents;cbox_planes[5].q3surfaceflags = boxq3surfaceflags;cbox_planes[5].texture = boxtexture;
memset(trace, 0, sizeof(trace_t));
trace->hitsupercontentsmask = hitsupercontentsmask;
trace->fraction = 1;
void Mod_Q1BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
{
Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2], p[2] - 65536);
+ VectorSet(diffusenormal, 0, 0, -1);
}
static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend)
if (i == loadmodel->num_textures - 1)
{
tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
- tx->supercontents = SUPERCONTENTS_WATER;
+ tx->supercontents = mod_q1bsp_texture_water.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
}
else
{
tx->basematerialflags |= MATERIALFLAG_WALL;
- tx->supercontents = SUPERCONTENTS_SOLID;
+ tx->supercontents = mod_q1bsp_texture_solid.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags;
}
tx->currentframe = tx;
}
}
else
{
- if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
+ if (!Mod_LoadSkinFrame(&tx->skin, gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
{
// did not find external texture, load it from the bsp or wad3
if (loadmodel->brush.ishlbsp)
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);
+ Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL);
}
}
if (tx->skin.base == NULL)
tx->basematerialflags = 0;
if (tx->name[0] == '*')
{
- // turb does not block movement
- tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
- // LordHavoc: some turbulent textures should be fullbright and solid
- if (!strncmp(tx->name,"*lava",5)
- || !strncmp(tx->name,"*teleport",9)
- || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
- tx->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
- else
+ // LordHavoc: some turbulent textures should not be affected by wateralpha
+ if (strncmp(tx->name,"*lava",5)
+ && strncmp(tx->name,"*teleport",9)
+ && strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
tx->basematerialflags |= MATERIALFLAG_WATERALPHA;
if (!strncmp(tx->name, "*lava", 5))
- tx->supercontents = SUPERCONTENTS_LAVA;
+ {
+ tx->supercontents = mod_q1bsp_texture_lava.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_lava.surfaceflags;
+ }
else if (!strncmp(tx->name, "*slime", 6))
- tx->supercontents = SUPERCONTENTS_SLIME;
+ {
+ tx->supercontents = mod_q1bsp_texture_slime.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_slime.surfaceflags;
+ }
else
- tx->supercontents = SUPERCONTENTS_WATER;
+ {
+ tx->supercontents = mod_q1bsp_texture_water.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
+ }
+ tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
}
else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
{
- tx->supercontents = SUPERCONTENTS_SKY;
+ tx->supercontents = mod_q1bsp_texture_sky.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags;
tx->basematerialflags |= MATERIALFLAG_SKY;
}
else
{
- tx->supercontents = SUPERCONTENTS_SOLID;
+ tx->supercontents = mod_q1bsp_texture_solid.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags;
tx->basematerialflags |= MATERIALFLAG_WALL;
}
if (tx->skin.fog)
}
}
-static void Mod_Q1BSP_LoadLightList(void)
-{
- int a, n, numlights;
- char tempchar, *s, *t, *lightsstring, lightsfilename[1024];
- mlight_t *e;
-
- 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, NULL);
- if (s)
- {
- numlights = 0;
- while (*s)
- {
- while (*s && *s != '\n' && *s != '\r')
- s++;
- if (!*s)
- {
- Mem_Free(lightsstring);
- Con_Printf("lights file must end with a newline\n");
- return;
- }
- s++;
- numlights++;
- }
- loadmodel->brushq1.lights = (mlight_t *)Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
- s = lightsstring;
- n = 0;
- while (*s && n < numlights)
- {
- t = s;
- while (*s && *s != '\n' && *s != '\r')
- s++;
- if (!*s)
- {
- Con_Printf("misparsed lights file!\n");
- break;
- }
- e = loadmodel->brushq1.lights + n;
- tempchar = *s;
- *s = 0;
- a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
- *s = tempchar;
- if (a != 14)
- {
- Con_Printf("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
- break;
- }
- if (*s == '\r')
- s++;
- if (*s == '\n')
- s++;
- n++;
- }
- if (*s)
- Con_Printf("misparsed lights file!\n");
- loadmodel->brushq1.numlights = numlights;
- Mem_Free(lightsstring);
- }
-}
-
static void Mod_Q1BSP_LoadVisibility(lump_t *l)
{
loadmodel->brushq1.num_compressedpvs = 0;
}
#endif
+static qboolean Mod_Q1BSP_AllocLightmapBlock(int *lineused, int totalwidth, int totalheight, int blockwidth, int blockheight, int *outx, int *outy)
+{
+ int y, x2, y2;
+ int bestx = totalwidth, besty = 0;
+ // find the left-most space we can find
+ for (y = 0;y <= totalheight - blockheight;y++)
+ {
+ x2 = 0;
+ for (y2 = 0;y2 < blockheight;y2++)
+ x2 = max(x2, lineused[y+y2]);
+ if (bestx > x2)
+ {
+ bestx = x2;
+ besty = y;
+ }
+ }
+ // if the best was not good enough, return failure
+ if (bestx > totalwidth - blockwidth)
+ return false;
+ // we found a good spot
+ if (outx)
+ *outx = bestx;
+ if (outy)
+ *outy = besty;
+ // now mark the space used
+ for (y2 = 0;y2 < blockheight;y2++)
+ lineused[besty+y2] = bestx + blockwidth;
+ // return success
+ return true;
+}
+
static void Mod_Q1BSP_LoadFaces(lump_t *l)
{
dface_t *in;
msurface_t *surface;
- int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris;
- float texmins[2], texmaxs[2], val;
+ int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber;
+ float texmins[2], texmaxs[2], val, lightmaptexcoordscale;
+#define LIGHTMAPSIZE 256
+ rtexture_t *lightmaptexture;
+ int lightmap_lineused[LIGHTMAPSIZE];
in = (dface_t *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *));
loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false);
+ lightmaptexture = NULL;
+ lightmapnumber = 1;
+ lightmaptexcoordscale = 1.0f / (float)LIGHTMAPSIZE;
+
totalverts = 0;
totaltris = 0;
for (surfacenum = 0, in = (dface_t *)(mod_base + l->fileofs), surface = loadmodel->data_surfaces;surfacenum < count;surfacenum++, in++, surface++)
// lighting info
for (i = 0;i < MAXLIGHTMAPS;i++)
surface->lightmapinfo->styles[i] = in->styles[i];
- surface->lightmapinfo->lightmaptexturestride = 0;
surface->lightmaptexture = NULL;
+ surface->deluxemaptexture = r_texture_blanknormalmap;
i = LittleLong(in->lightofs);
if (i == -1)
{
// check if we should apply a lightmap to this
if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples)
{
- int i, iu, iv;
+ int i, iu, iv, lightmapx, lightmapy;
float u, v, ubase, vbase, uscale, vscale;
if (ssize > 256 || tsize > 256)
// clear to white
memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
- if (r_miplightmaps.integer)
+ // find a place for this lightmap
+ if (!lightmaptexture || !Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy))
{
- surface->lightmapinfo->lightmaptexturestride = ssize;
- surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ // could not find room, make a new lightmap
+ lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber++), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ memset(lightmap_lineused, 0, sizeof(lightmap_lineused));
+ Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy);
}
- else
- {
- surface->lightmapinfo->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
- surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
- }
- R_FragmentLocation(surface->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
- uscale = (uscale - ubase) / ssize;
- vscale = (vscale - vbase) / tsize;
+
+ surface->lightmaptexture = lightmaptexture;
+ surface->deluxemaptexture = r_texture_blanknormalmap;
+ surface->lightmapinfo->lightmaporigin[0] = lightmapx;
+ surface->lightmapinfo->lightmaporigin[1] = lightmapy;
+
+ ubase = lightmapx * lightmaptexcoordscale;
+ vbase = lightmapy * lightmaptexcoordscale;
+ uscale = lightmaptexcoordscale;
+ vscale = lightmaptexcoordscale;
for (i = 0;i < surface->num_vertices;i++)
{
out->planenum = LittleLong(in->planenum);
out->children[0] = LittleShort(in->children[0]);
out->children[1] = LittleShort(in->children[1]);
+ if (out->planenum < 0 || out->planenum >= loadmodel->brush.num_planes)
+ Host_Error("Corrupt clipping hull(out of range planenum)");
if (out->children[0] >= count || out->children[1] >= count)
Host_Error("Corrupt clipping hull(out of range child)");
}
mainmempool = mod->mempool;
- Mod_Q1BSP_LoadLightList();
-
// make a single combined shadow mesh to allow optimized shadow volume creation
numshadowmeshtriangles = 0;
for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
//Mod_Q1BSP_ProcessLightList();
- if (developer.integer)
+ if (developer.integer >= 10)
Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals);
}
if (!COM_ParseToken(&text, true))
break;
}
- if (developer.integer >= 2)
+ if (developer.integer >= 100)
{
Con_Printf("%s %i: ", shadername, passnumber);
for (j = 0;j < numparameters;j++)
}
if (i == 0 && !strcasecmp(com_token, "}"))
break;
- if (developer.integer >= 2)
+ if (developer.integer >= 100)
{
Con_Printf("%s: ", shadername);
for (j = 0;j < numparameters;j++)
q3dbrush_t *in;
q3mbrush_t *out;
int i, j, n, c, count, maxplanes;
- mplane_t *planes;
+ colplanef_t *planes;
in = (q3dbrush_t *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
maxplanes = out->numbrushsides;
if (planes)
Mem_Free(planes);
- planes = (mplane_t *)Mem_Alloc(tempmempool, sizeof(mplane_t) * maxplanes);
+ planes = (colplanef_t *)Mem_Alloc(tempmempool, sizeof(colplanef_t) * maxplanes);
}
for (j = 0;j < out->numbrushsides;j++)
{
VectorCopy(out->firstbrushside[j].plane->normal, planes[j].normal);
planes[j].dist = out->firstbrushside[j].plane->dist;
+ planes[j].supercontents = out->firstbrushside[j].texture->supercontents;
+ planes[j].q3surfaceflags = out->firstbrushside[j].texture->surfaceflags;
+ planes[j].texture = out->firstbrushside[j].texture;
}
// make the colbrush from the planes
- out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents);
+ out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes);
}
if (planes)
Mem_Free(planes);
loadmodel->brushq3.data_lightmaps = out;
loadmodel->brushq3.num_lightmaps = count;
+ loadmodel->brushq3.deluxemapping_modelspace = false;
for (i = 0;i < count;i++, in++, out++)
+ {
+ // if this may be a deluxemap, check if it's in modelspace or not
+ if ((i & 1) && !loadmodel->brushq3.deluxemapping_modelspace)
+ {
+ int j;
+ unsigned char *b = in->rgb;
+ for (j = 2;j < 128*128*3;j += 3)
+ {
+ // if this is definitely negative Z, it is not facing outward,
+ // and thus must be in modelspace, as negative Z would never
+ // occur in tangentspace
+ if (b[j] < 120)
+ {
+ loadmodel->brushq3.deluxemapping_modelspace = true;
+ break;
+ }
+ }
+ }
*out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ }
}
static void Mod_Q3BSP_LoadFaces(lump_t *l)
loadmodel->data_surfaces = out;
loadmodel->num_surfaces = count;
+ // deluxemapped q3bsp files have an even number of lightmaps, and surfaces
+ // always index even numbered ones (0, 2, 4, ...), the odd numbered
+ // lightmaps are the deluxemaps (light direction textures), so if we
+ // encounter any odd numbered lightmaps it is not a deluxemapped bsp, it
+ // is also not a deluxemapped bsp if it has an odd number of lightmaps or
+ // less than 2
+ loadmodel->brushq3.deluxemapping = true;
+ if (count >= 2 && !(count & 1))
+ {
+ for (i = 0;i < count;i++)
+ {
+ n = LittleLong(in[i].lightmapindex);
+ if (n >= 0 && ((n & 1) || n + 1 >= loadmodel->brushq3.num_lightmaps))
+ {
+ loadmodel->brushq3.deluxemapping = false;
+ break;
+ }
+ }
+ }
+ else
+ loadmodel->brushq3.deluxemapping = false;
+ Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
+
i = 0;
for (meshnum = 0;i < count;meshnum++)
{
n = LittleLong(in->effectindex);
if (n < -1 || n >= loadmodel->brushq3.num_effects)
{
- if (developer.integer >= 2)
+ if (developer.integer >= 100)
Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
n = -1;
}
else if (n < 0)
n = -1;
if (n == -1)
+ {
out->lightmaptexture = NULL;
+ out->deluxemaptexture = r_texture_blanknormalmap;
+ }
else
+ {
out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+ if (loadmodel->brushq3.deluxemapping)
+ out->deluxemaptexture = loadmodel->brushq3.data_lightmaps[n+1];
+ else
+ out->deluxemaptexture = r_texture_blanknormalmap;
+ }
firstvertex = LittleLong(in->firstvertex);
numvertices = LittleLong(in->numvertices);
numtriangles = (finalwidth - 1) * (finalheight - 1) * 2;
break;
case Q3FACETYPE_FLARE:
- if (developer.integer >= 2)
+ if (developer.integer >= 100)
Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
// don't render it
continue;
Q3PatchTesselateFloat(4, sizeof(float[4]), (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
Q3PatchTriangleElements((out->groupmesh->data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex);
out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), out->groupmesh->data_vertex3f);
- if (developer.integer >= 2)
+ if (developer.integer >= 100)
{
if (out->num_triangles < finaltriangles)
Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
oldnumtriangles = out->num_triangles;
oldnumtriangles2 = out->num_collisiontriangles;
out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
- if (developer.integer)
+ if (developer.integer >= 100)
Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
break;
default:
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)
if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
{
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;
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
}
}
msurface_t *surface;
mplane_t *plane;
float nodesegmentmins[3], nodesegmentmaxs[3];
-#if 1
- for (;;)
+ // walk the tree until we hit a leaf, recursing for any split cases
+ while (node->plane)
{
plane = node->plane;
- if (!plane)
- break;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
- // we must handle sides == 0 because of NANs (crashing is far worse than recursing the entire tree!)
if (plane->type < 3)
{
// this is an axial plane, compare bounding box directly to it and
//sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, plane);
//sides = ((segmentmaxs[plane->type] >= plane->dist) | ((segmentmins[plane->type] < plane->dist) << 1));
sides = ((segmentmaxs[plane->type] >= plane->dist) + ((segmentmins[plane->type] < plane->dist) * 2));
- 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;
- }
- }
+ // 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);
+ }
+ if (sides == 3)
+ {
+ // 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
- //if (sides < 1 || sides > 2)
- // Sys_Error("Mod_Q3BSP_TraceBrush_RecursiveBSPNode: side > 2\n");
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;
- }
- if (sides == 0)
- return; // ERROR: NAN bounding box!
- // take whichever side the segment box is on
- node = node->children[sides - 1];
- continue;
- }
- 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;
- }
- }
- if (sides == 0)
- return; // ERROR: NAN bounding box!
- // 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];
- }
- 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
- {
- if (sides == 0)
- return; // ERROR: NAN bounding box!
- // take whichever side the segment box is on
- node = node->children[sides - 1];
- }
- }
- 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);
- sides = 2;
- }
- }
- 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++)
if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
{
surface->collisionmarkframe = markframe;
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
}
}
}
-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;
- startmatrix = identitymatrix;
- endmatrix = identitymatrix;
- 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, surface->texture->surfaceflags, surface->texture, 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, 0, 0, NULL);
+ thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
if (model->brush.submodel)
{
for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
if (mod_q3bsp_curves_collisions.integer)
for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
if (surface->num_collisiontriangles)
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
else
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);