cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
cvar_t mod_q3bsp_curves_subdivide_level = {0, "mod_q3bsp_curves_subdivide_level", "2"};
cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1"};
-cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "0"};
+cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1"};
+cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0"};
static void Mod_Q1BSP_Collision_Init (void);
void Mod_BrushInit(void)
Cvar_RegisterVariable(&mod_q3bsp_curves_subdivide_level);
Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
+ Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
memset(mod_q1bsp_novis, 0xff, sizeof(mod_q1bsp_novis));
Mod_Q1BSP_Collision_Init();
}
memset(out, 0, outsize);
}
-
-static int Mod_Q1BSP_BoxTouchingPVS_RecursiveBSPNode(const model_t *model, const mnode_t *node, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
+static int Mod_Q1BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
{
- int leafnum;
-loc0:
- if (node->contents < 0)
- {
- // leaf
- if (node->contents == CONTENTS_SOLID)
- return false;
- leafnum = (mleaf_t *)node - model->brushq1.leafs - 1;
- return pvs[leafnum >> 3] & (1 << (leafnum & 7));
- }
-
- // node - recurse down the BSP tree
- switch (BoxOnPlaneSide(mins, maxs, node->plane))
+ int clusterindex, side, nodestackindex = 0;
+ mnode_t *node, *nodestack[1024];
+ node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode;
+ for (;;)
{
- case 1: // front
- node = node->children[0];
- goto loc0;
- case 2: // back
- node = node->children[1];
- goto loc0;
- default: // crossing
- if (node->children[0]->contents != CONTENTS_SOLID)
- if (Mod_Q1BSP_BoxTouchingPVS_RecursiveBSPNode(model, node->children[0], pvs, mins, maxs))
+ if (node->plane)
+ {
+ // node - recurse down the BSP tree
+ side = BoxOnPlaneSide(mins, maxs, node->plane) - 1;
+ if (side < 2)
+ {
+ // box is on one side of plane, take that path
+ node = node->children[side];
+ }
+ else
+ {
+ // box crosses plane, take one path and remember the other
+ nodestack[nodestackindex++] = node->children[0];
+ node = node->children[1];
+ }
+ }
+ else
+ {
+ // leaf - check cluster bit
+ clusterindex = ((mleaf_t *)node)->clusterindex;
+ if (CHECKPVSBIT(pvs, clusterindex))
+ {
+ // it is visible, return immediately with the news
return true;
- node = node->children[1];
- goto loc0;
+ }
+ else
+ {
+ // nothing to see here, try another path we didn't take earlier
+ if (nodestackindex == 0)
+ break;
+ node = nodestack[--nodestackindex];
+ }
+ }
}
- // never reached
+ // it is not visible
return false;
}
-int Mod_Q1BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
-{
- return Mod_Q1BSP_BoxTouchingPVS_RecursiveBSPNode(model, model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode, pvs, mins, maxs);
-}
-
/*
static int Mod_Q1BSP_PointContents(model_t *model, const vec3_t p)
{
VectorCopy (plane->normal, t->trace->plane.normal);
}
- // bias away from surface a bit
- t1 = DotProduct(t->trace->plane.normal, t->start) - (t->trace->plane.dist + DIST_EPSILON);
- t2 = DotProduct(t->trace->plane.normal, t->end) - (t->trace->plane.dist + DIST_EPSILON);
-
+ // calculate the true fraction
+ t1 = DotProduct(t->trace->plane.normal, t->start) - t->trace->plane.dist;
+ t2 = DotProduct(t->trace->plane.normal, t->end) - t->trace->plane.dist;
midf = t1 / (t1 - t2);
- t->trace->fraction = bound(0.0f, midf, 1.0);
+ t->trace->realfraction = bound(0, midf, 1);
+
+ // calculate the return fraction which is nudged off the surface a bit
+ midf = (t1 - DIST_EPSILON) / (t1 - t2);
+ t->trace->fraction = bound(0, midf, 1);
#if COLLISIONPARANOID >= 3
Con_Printf("D");
rhc.trace = trace;
rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
rhc.trace->fraction = 1;
+ rhc.trace->realfraction = 1;
rhc.trace->allsolid = true;
VectorSubtract(boxstartmaxs, boxstartmins, boxsize);
if (boxsize[0] < 3)
memset(trace, 0, sizeof(trace_t));
trace->hitsupercontentsmask = hitsupercontentsmask;
trace->fraction = 1;
+ trace->realfraction = 1;
Collision_TraceLineBrushFloat(trace, start, end, &cbox, &cbox);
#else
RecursiveHullCheckTraceInfo_t rhc;
rhc.trace = trace;
rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
rhc.trace->fraction = 1;
+ rhc.trace->realfraction = 1;
rhc.trace->allsolid = true;
VectorCopy(start, rhc.start);
VectorCopy(end, rhc.end);
VectorSubtract(rhc.end, rhc.start, rhc.dist);
Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos);
+ //VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos);
if (rhc.trace->startsupercontents)
rhc.trace->startsupercontents = boxsupercontents;
#endif
static void Mod_Q1BSP_DecompressVis(const qbyte *in, const qbyte *inend, qbyte *out, qbyte *outend)
{
int c;
+ qbyte *outstart = out;
while (out < outend)
{
if (in == inend)
{
- Con_DPrintf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\"\n", loadmodel->name);
+ Con_DPrintf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
return;
}
c = *in++;
{
if (in == inend)
{
- Con_DPrintf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\"\n", loadmodel->name);
+ Con_DPrintf("Mod_Q1BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
return;
}
for (c = *in++;c > 0;c--)
{
if (out == outend)
{
- Con_DPrintf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\"\n", loadmodel->name);
+ Con_DPrintf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
return;
}
*out++ = 0;
if (p >= 0)
out->children[j] = loadmodel->brushq1.nodes + p;
else
- out->children[j] = (mnode_t *)(loadmodel->brushq1.leafs + (-1 - p));
+ out->children[j] = (mnode_t *)(loadmodel->brushq1.data_leafs + (-1 - p));
}
}
{
dleaf_t *in;
mleaf_t *out;
- int i, j, count, p, pvschainbytes;
- qbyte *pvs;
+ int i, j, count, p;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
count = l->filelen / sizeof(*in);
out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
- loadmodel->brushq1.leafs = out;
- loadmodel->brushq1.numleafs = count;
- pvschainbytes = ((loadmodel->brushq1.numleafs - 1)+7)>>3;
- loadmodel->brushq1.data_decompressedpvs = pvs = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numleafs * pvschainbytes);
+ loadmodel->brushq1.data_leafs = out;
+ loadmodel->brushq1.num_leafs = count;
+ // get visleafs from the submodel data
+ loadmodel->brushq1.num_pvsclusters = loadmodel->brushq1.submodels[0].visleafs;
+ loadmodel->brushq1.num_pvsclusterbytes = (loadmodel->brushq1.num_pvsclusters+7)>>3;
+ loadmodel->brushq1.data_pvsclusters = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.num_pvsclusters * loadmodel->brushq1.num_pvsclusterbytes);
+ memset(loadmodel->brushq1.data_pvsclusters, 0xFF, loadmodel->brushq1.num_pvsclusters * loadmodel->brushq1.num_pvsclusterbytes);
for ( i=0 ; i<count ; i++, in++, out++)
{
out->nummarksurfaces = 0;
}
- out->pvsdata = pvs;
- memset(out->pvsdata, 0xFF, pvschainbytes);
- pvs += pvschainbytes;
+ out->clusterindex = i - 1;
+ if (out->clusterindex >= loadmodel->brushq1.num_pvsclusters)
+ out->clusterindex = -1;
p = LittleLong(in->visofs);
- if (p >= 0 && i > 0) // ignore visofs errors on leaf 0 (solid)
+ // ignore visofs errors on leaf 0 (solid)
+ if (p >= 0 && out->clusterindex >= 0)
{
if (p >= loadmodel->brushq1.num_compressedpvs)
Con_Printf("Mod_Q1BSP_LoadLeafs: invalid visofs\n");
else
- Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, out->pvsdata, out->pvsdata + pvschainbytes);
+ Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brushq1.data_pvsclusters + out->clusterindex * loadmodel->brushq1.num_pvsclusterbytes, loadmodel->brushq1.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brushq1.num_pvsclusterbytes);
}
for (j = 0;j < 4;j++)
winding_t *w;
// recalculate bounding boxes for all leafs(because qbsp is very sloppy)
- leaf = loadmodel->brushq1.leafs;
- endleaf = leaf + loadmodel->brushq1.numleafs;
+ leaf = loadmodel->brushq1.data_leafs;
+ endleaf = leaf + loadmodel->brushq1.num_leafs;
for (;leaf < endleaf;leaf++)
{
VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
loadmodel->brushq1.portalpoints = (void *)((qbyte *) loadmodel->brushq1.portals + numportals * sizeof(mportal_t));
loadmodel->brushq1.numportalpoints = numpoints;
// clear all leaf portal chains
- for (i = 0;i < loadmodel->brushq1.numleafs;i++)
- loadmodel->brushq1.leafs[i].portals = NULL;
+ for (i = 0;i < loadmodel->brushq1.num_leafs;i++)
+ loadmodel->brushq1.data_leafs[i].portals = NULL;
// process all portals in the global portal chain, while freeing them
portal = loadmodel->brushq1.portals;
point = loadmodel->brushq1.portalpoints;
static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node)
{
- int i;
- float d;
-
- while (node->contents >= 0)
+ while (node->plane)
{
- d = PlaneDiff(org, node->plane);
+ float d = PlaneDiff(org, node->plane);
if (d > radius)
node = node->children[0];
else if (d < -radius)
node = node->children[1];
}
}
- // FIXME: code!
- // if this is a leaf, accumulate the pvs bits
- if (node->contents != CONTENTS_SOLID && ((mleaf_t *)node)->pvsdata)
+ // if this leaf is in a cluster, accumulate the pvs bits
+ if (((mleaf_t *)node)->clusterindex >= 0)
+ {
+ int i;
+ qbyte *pvs = model->brushq1.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes;
for (i = 0;i < pvsbytes;i++)
- pvsbuffer[i] |= ((mleaf_t *)node)->pvsdata[i];
+ pvsbuffer[i] |= pvs[i];
+ }
}
//Calculates a PVS that is the inclusive or of all leafs within radius pixels
//of the given point.
static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
{
- int bytes = ((model->brushq1.numleafs - 1) + 7) >> 3;
+ int bytes = ((model->brushq1.num_leafs - 1) + 7) >> 3;
bytes = min(bytes, pvsbufferlength);
+ if (r_novis.integer)
+ {
+ memset(pvsbuffer, 0xFF, bytes);
+ return bytes;
+ }
memset(pvsbuffer, 0, bytes);
Mod_Q1BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brushq1.nodes);
return bytes;
}
//Returns PVS data for a given point
-//(note: always returns valid data, never NULL)
+//(note: can return NULL)
static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p)
{
mnode_t *node;
Mod_CheckLoaded(model);
- // LordHavoc: modified to start at first clip node,
- // in other words: first node of the (sub)model
- node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode;
- while (node->contents == 0)
+ node = model->brushq1.nodes;
+ while (node->plane)
node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
- return ((mleaf_t *)node)->pvsdata;
+ if (((mleaf_t *)node)->clusterindex >= 0)
+ return model->brushq1.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes;
+ else
+ return NULL;
}
static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs)
extern void R_Model_Brush_DrawSky(entity_render_t *ent);
extern void R_Model_Brush_Draw(entity_render_t *ent);
extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
+extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap);
void Mod_Q1BSP_Load(model_t *mod, void *buffer)
{
int i, j, k;
Mod_Q1BSP_LoadFaces(&header->lumps[LUMP_FACES]);
Mod_Q1BSP_LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]);
Mod_Q1BSP_LoadVisibility(&header->lumps[LUMP_VISIBILITY]);
+ // load submodels before leafs because they contain the number of vis leafs
+ Mod_Q1BSP_LoadSubmodels(&header->lumps[LUMP_MODELS]);
Mod_Q1BSP_LoadLeafs(&header->lumps[LUMP_LEAFS]);
Mod_Q1BSP_LoadNodes(&header->lumps[LUMP_NODES]);
Mod_Q1BSP_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]);
- Mod_Q1BSP_LoadSubmodels(&header->lumps[LUMP_MODELS]);
if (mod->brushq1.data_compressedpvs)
Mem_Free(mod->brushq1.data_compressedpvs);
Mod_Q1BSP_MakeHull0();
Mod_Q1BSP_MakePortals();
- if (developer.integer)
- Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.numleafs, loadmodel->brushq1.numleafs - 1, loadmodel->brushq1.numportals);
-
mod->numframes = 2; // regular and alternate animation
mainmempool = mod->mempool;
mod->Draw = R_Model_Brush_Draw;
mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
mod->DrawLight = R_Model_Brush_DrawLight;
+ if (i != 0)
+ {
+ mod->brush.GetPVS = NULL;
+ mod->brush.FatPVS = NULL;
+ mod->brush.BoxTouchingPVS = NULL;
+ mod->brush.LightPoint = NULL;
+ mod->brush.AmbientSoundLevelsForPoint = NULL;
+ }
mod->brushq1.pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(msurface_t **));
mod->brushq1.pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool,(mod->brushq1.nummodelsurfaces + mod->brushq1.numtextures) * sizeof(msurface_t *));
mod->brushq1.pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(int));
}
Mod_Q1BSP_BuildSurfaceNeighbors(mod->brushq1.surfaces + mod->brushq1.firstmodelsurface, mod->brushq1.nummodelsurfaces, originalloadmodel->mempool);
- mod->brushq1.visleafs = bm->visleafs;
+ mod->brushq1.num_visleafs = bm->visleafs;
// LordHavoc: only register submodels if it is the world
// (prevents bsp models from replacing world submodels)
loadmodel = originalloadmodel;
//Mod_Q1BSP_ProcessLightList();
+
+ if (developer.integer)
+ Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.num_leafs, loadmodel->brushq1.num_visleafs, loadmodel->brushq1.numportals);
}
static void Mod_Q2BSP_LoadEntities(lump_t *l)
{
snprintf(shadername, sizeof(shadername), "%s", com_token);
flags = 0;
- if (COM_ParseToken(&text, false) && !strcmp(com_token, "{"))
+ if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{"))
{
while (COM_ParseToken(&text, false))
{
- if (!strcmp(com_token, "}"))
+ if (!strcasecmp(com_token, "}"))
break;
- else if (!strcmp(com_token, "{"))
+ else if (!strcasecmp(com_token, "{"))
{
while (COM_ParseToken(&text, false))
{
- if (!strcmp(com_token, "}"))
+ if (!strcasecmp(com_token, "}"))
break;
}
}
- else if (!strcmp(com_token, "surfaceparm"))
+ else if (!strcasecmp(com_token, "surfaceparm"))
{
- if (COM_ParseToken(&text, true) && strcmp(com_token, "\n"))
+ if (COM_ParseToken(&text, true) && strcasecmp(com_token, "\n"))
{
- if (!strcmp(com_token, "alphashadow"))
+ if (!strcasecmp(com_token, "alphashadow"))
flags |= Q3SURFACEPARM_ALPHASHADOW;
- else if (!strcmp(com_token, "areaportal"))
+ else if (!strcasecmp(com_token, "areaportal"))
flags |= Q3SURFACEPARM_AREAPORTAL;
- else if (!strcmp(com_token, "clusterportal"))
+ else if (!strcasecmp(com_token, "clusterportal"))
flags |= Q3SURFACEPARM_CLUSTERPORTAL;
- else if (!strcmp(com_token, "detail"))
+ else if (!strcasecmp(com_token, "detail"))
flags |= Q3SURFACEPARM_DETAIL;
- else if (!strcmp(com_token, "donotenter"))
+ else if (!strcasecmp(com_token, "donotenter"))
flags |= Q3SURFACEPARM_DONOTENTER;
- else if (!strcmp(com_token, "fog"))
+ else if (!strcasecmp(com_token, "fog"))
flags |= Q3SURFACEPARM_FOG;
- else if (!strcmp(com_token, "lava"))
+ else if (!strcasecmp(com_token, "lava"))
flags |= Q3SURFACEPARM_LAVA;
- else if (!strcmp(com_token, "lightfilter"))
+ else if (!strcasecmp(com_token, "lightfilter"))
flags |= Q3SURFACEPARM_LIGHTFILTER;
- else if (!strcmp(com_token, "metalsteps"))
+ else if (!strcasecmp(com_token, "metalsteps"))
flags |= Q3SURFACEPARM_METALSTEPS;
- else if (!strcmp(com_token, "nodamage"))
+ else if (!strcasecmp(com_token, "nodamage"))
flags |= Q3SURFACEPARM_NODAMAGE;
- else if (!strcmp(com_token, "nodlight"))
+ else if (!strcasecmp(com_token, "nodlight"))
flags |= Q3SURFACEPARM_NODLIGHT;
- else if (!strcmp(com_token, "nodraw"))
+ else if (!strcasecmp(com_token, "nodraw"))
flags |= Q3SURFACEPARM_NODRAW;
- else if (!strcmp(com_token, "nodrop"))
+ else if (!strcasecmp(com_token, "nodrop"))
flags |= Q3SURFACEPARM_NODROP;
- else if (!strcmp(com_token, "noimpact"))
+ else if (!strcasecmp(com_token, "noimpact"))
flags |= Q3SURFACEPARM_NOIMPACT;
- else if (!strcmp(com_token, "nolightmap"))
+ else if (!strcasecmp(com_token, "nolightmap"))
flags |= Q3SURFACEPARM_NOLIGHTMAP;
- else if (!strcmp(com_token, "nomarks"))
+ else if (!strcasecmp(com_token, "nomarks"))
flags |= Q3SURFACEPARM_NOMARKS;
- else if (!strcmp(com_token, "nomipmaps"))
+ else if (!strcasecmp(com_token, "nomipmaps"))
flags |= Q3SURFACEPARM_NOMIPMAPS;
- else if (!strcmp(com_token, "nonsolid"))
+ else if (!strcasecmp(com_token, "nonsolid"))
flags |= Q3SURFACEPARM_NONSOLID;
- else if (!strcmp(com_token, "origin"))
+ else if (!strcasecmp(com_token, "origin"))
flags |= Q3SURFACEPARM_ORIGIN;
- else if (!strcmp(com_token, "playerclip"))
+ else if (!strcasecmp(com_token, "playerclip"))
flags |= Q3SURFACEPARM_PLAYERCLIP;
- else if (!strcmp(com_token, "sky"))
+ else if (!strcasecmp(com_token, "sky"))
flags |= Q3SURFACEPARM_SKY;
- else if (!strcmp(com_token, "slick"))
+ else if (!strcasecmp(com_token, "slick"))
flags |= Q3SURFACEPARM_SLICK;
- else if (!strcmp(com_token, "slime"))
+ else if (!strcasecmp(com_token, "slime"))
flags |= Q3SURFACEPARM_SLIME;
- else if (!strcmp(com_token, "structural"))
+ else if (!strcasecmp(com_token, "structural"))
flags |= Q3SURFACEPARM_STRUCTURAL;
- else if (!strcmp(com_token, "trans"))
+ else if (!strcasecmp(com_token, "trans"))
flags |= Q3SURFACEPARM_TRANS;
- else if (!strcmp(com_token, "water"))
+ else if (!strcasecmp(com_token, "water"))
flags |= Q3SURFACEPARM_WATER;
else
Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], com_token);
- if (!COM_ParseToken(&text, true) || strcmp(com_token, "\n"))
+ if (!COM_ParseToken(&text, true) || strcasecmp(com_token, "\n"))
{
Con_Printf("%s parsing error: surfaceparm only takes one parameter.\n", search->filenames[i]);
goto parseerror;
else
{
// look for linebreak or }
- while(COM_ParseToken(&text, true) && strcmp(com_token, "\n") && strcmp(com_token, "}"));
+ while(COM_ParseToken(&text, true) && strcasecmp(com_token, "\n") && strcasecmp(com_token, "}"));
// break out to top level if it was }
- if (!strcmp(com_token, "}"))
+ if (!strcasecmp(com_token, "}"))
break;
}
}
// add shader to list (shadername and flags)
// actually here we just poke into the texture settings
for (j = 0, out = loadmodel->brushq3.data_textures;j < loadmodel->brushq3.num_textures;j++, out++)
- if (!strcmp(out->name, shadername))
+ if (!strcasecmp(out->name, shadername))
out->surfaceparms = flags;
}
else
&& out->type != Q3FACETYPE_MESH
&& out->type != Q3FACETYPE_FLARE)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, out->type);
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, out->type);
out->num_vertices = 0;
out->num_triangles = 0;
out->type = 0; // error
n = LittleLong(in->textureindex);
if (n < 0 || n >= loadmodel->brushq3.num_textures)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures);
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->brushq3.num_textures);
out->num_vertices = 0;
out->num_triangles = 0;
out->type = 0; // error
n = LittleLong(in->effectindex);
if (n < -1 || n >= loadmodel->brushq3.num_effects)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
n = -1;
}
if (n == -1)
n = LittleLong(in->lightmapindex);
if (n < -1 || n >= loadmodel->brushq3.num_lightmaps)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
n = -1;
}
if (n == -1)
for (i = 0;i < count;i++, in++, out++)
{
- out->isnode = false;
out->parent = NULL;
+ out->plane = NULL;
out->clusterindex = LittleLong(in->clusterindex);
out->areaindex = LittleLong(in->areaindex);
for (j = 0;j < 3;j++)
{
// yes the mins/maxs are ints
- out->mins[j] = LittleLong(in->mins[j]);
- out->maxs[j] = LittleLong(in->maxs[j]);
+ out->mins[j] = LittleLong(in->mins[j]) - 1;
+ out->maxs[j] = LittleLong(in->maxs[j]) + 1;
}
n = LittleLong(in->firstleafface);
c = LittleLong(in->numleaffaces);
if (node->parent)
Host_Error("Mod_Q3BSP_LoadNodes_RecursiveSetParent: runaway recursion\n");
node->parent = parent;
- if (node->isnode)
+ if (node->plane)
{
Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
Mod_Q3BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
for (i = 0;i < count;i++, in++, out++)
{
- out->isnode = true;
out->parent = NULL;
n = LittleLong(in->planeindex);
if (n < 0 || n >= loadmodel->brushq3.num_planes)
for (j = 0;j < 3;j++)
{
// yes the mins/maxs are ints
- out->mins[j] = LittleLong(in->mins[j]);
- out->maxs[j] = LittleLong(in->maxs[j]);
+ out->mins[j] = LittleLong(in->mins[j]) - 1;
+ out->maxs[j] = LittleLong(in->maxs[j]) + 1;
}
}
q3dlightgrid_t *out;
int count;
- if (l->filelen == 0)
- return;
-
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name);
loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1;
loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1;
count = loadmodel->brushq3.num_lightgrid_isize[0] * loadmodel->brushq3.num_lightgrid_isize[1] * loadmodel->brushq3.num_lightgrid_isize[2];
- 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]);
- 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);
+ 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]);
+ 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);
+ }
out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
loadmodel->brushq3.data_lightgrid = out;
loadmodel->brushq3.num_lightgrid = count;
// no swapping or validation necessary
- memcpy(out, in, count * (int)sizeof(*out));
+ if (l->filelen)
+ memcpy(out, in, count * (int)sizeof(*out));
+ else
+ {
+ // no data, fill with white
+ int i;
+ for (i = 0;i < count;i++)
+ {
+ out[i].ambientrgb[0] = 128;
+ out[i].ambientrgb[1] = 128;
+ out[i].ambientrgb[2] = 128;
+ out[i].diffusergb[0] = 0;
+ out[i].diffusergb[1] = 0;
+ out[i].diffusergb[2] = 0;
+ out[i].diffusepitch = 0;
+ out[i].diffuseyaw = 0;
+ }
+ }
Matrix4x4_CreateScale3(&loadmodel->brushq3.num_lightgrid_indexfromworld, loadmodel->brushq3.num_lightgrid_scale[0], loadmodel->brushq3.num_lightgrid_scale[1], loadmodel->brushq3.num_lightgrid_scale[2]);
Matrix4x4_ConcatTranslate(&loadmodel->brushq3.num_lightgrid_indexfromworld, -loadmodel->brushq3.num_lightgrid_imins[0] * loadmodel->brushq3.num_lightgrid_cellsize[0], -loadmodel->brushq3.num_lightgrid_imins[1] * loadmodel->brushq3.num_lightgrid_cellsize[1], -loadmodel->brushq3.num_lightgrid_imins[2] * loadmodel->brushq3.num_lightgrid_cellsize[2]);
int totalchains;
if (l->filelen == 0)
+ {
+ int i;
+ // unvised maps often have cluster indices even without pvs, so check
+ // leafs to find real number of clusters
+ loadmodel->brushq3.num_pvsclusters = 1;
+ for (i = 0;i < loadmodel->brushq3.num_leafs;i++)
+ loadmodel->brushq3.num_pvsclusters = min(loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.data_leafs[i].clusterindex + 1);
+
+ // create clusters
+ loadmodel->brushq3.num_pvsclusterbytes = (loadmodel->brushq3.num_pvsclusters + 7) / 8;
+ totalchains = loadmodel->brushq3.num_pvsclusterbytes * loadmodel->brushq3.num_pvsclusters;
+ loadmodel->brushq3.data_pvsclusters = Mem_Alloc(loadmodel->mempool, totalchains);
+ memset(loadmodel->brushq3.data_pvsclusters, 0xFF, totalchains);
return;
+ }
in = (void *)(mod_base + l->fileofs);
if (l->filelen < 9)
Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name);
loadmodel->brushq3.num_pvsclusters = LittleLong(in->numclusters);
- loadmodel->brushq3.num_pvschainlength = LittleLong(in->chainlength);
- if (loadmodel->brushq3.num_pvschainlength < ((loadmodel->brushq3.num_pvsclusters + 7) / 8))
- Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvschainlength, loadmodel->brushq3.num_pvsclusters);
- totalchains = loadmodel->brushq3.num_pvschainlength * loadmodel->brushq3.num_pvsclusters;
+ loadmodel->brushq3.num_pvsclusterbytes = LittleLong(in->chainlength);
+ if (loadmodel->brushq3.num_pvsclusterbytes < ((loadmodel->brushq3.num_pvsclusters + 7) / 8))
+ Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvsclusterbytes, loadmodel->brushq3.num_pvsclusters);
+ totalchains = loadmodel->brushq3.num_pvsclusterbytes * loadmodel->brushq3.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->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvschainlength, 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)\n", loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvsclusterbytes, totalchains + sizeof(*in), l->filelen);
- loadmodel->brushq3.data_pvschains = Mem_Alloc(loadmodel->mempool, totalchains);
- memcpy(loadmodel->brushq3.data_pvschains, (qbyte *)(in + 1), totalchains);
+ loadmodel->brushq3.data_pvsclusters = Mem_Alloc(loadmodel->mempool, totalchains);
+ memcpy(loadmodel->brushq3.data_pvsclusters, (qbyte *)(in + 1), totalchains);
}
static void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, vec_t radius)
//Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]);
}
-static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe)
+static void Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const vec3_t point, int markframe)
+{
+ int i;
+ q3mleaf_t *leaf;
+ colbrushf_t *brush;
+ // find which leaf the point is in
+ while (node->plane)
+ node = node->children[DotProduct(point, node->plane->normal) < node->plane->dist];
+ // point trace the brushes
+ leaf = (q3mleaf_t *)node;
+ for (i = 0;i < leaf->numleafbrushes;i++)
+ {
+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe && BoxesOverlap(point, point, brush->mins, brush->maxs))
+ {
+ brush->markframe = markframe;
+ Collision_TracePointBrushFloat(trace, point, leaf->firstleafbrush[i]->colbrushf);
+ }
+ }
+ // can't do point traces on curves (they have no thickness)
+}
+
+static void Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const vec3_t start, const vec3_t end, vec_t startfrac, vec_t endfrac, const vec3_t linestart, const vec3_t lineend, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs)
{
int i, startside, endside;
- float dist1, dist2, midfrac, mid[3], segmentmins[3], segmentmaxs[3];
+ float dist1, dist2, midfrac, mid[3], nodesegmentmins[3], nodesegmentmaxs[3];
q3mleaf_t *leaf;
q3mface_t *face;
colbrushf_t *brush;
- if (startfrac >= trace->fraction)
+ if (startfrac > trace->realfraction)
return;
// note: all line fragments past first impact fraction are ignored
- while (node->isnode)
- {
- // 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
+ 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
+ {
+ // find which nodes the line is in and recurse for them
+ while (node->plane)
{
- // line crosses node plane, split the line
- midfrac = dist1 / (dist1 - dist2);
- VectorLerp(linestart, midfrac, lineend, mid);
- // take the near side first
- Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe);
- if (midfrac < trace->fraction)
- Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe);
- return;
+ // 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, node->children[startside], start, mid, startfrac, midfrac, linestart, lineend, markframe, segmentmins, segmentmaxs);
+ if (midfrac <= trace->realfraction)
+ Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, node->children[endside], mid, end, midfrac, endfrac, linestart, lineend, markframe, segmentmins, segmentmaxs);
+ return;
+ }
}
}
// hit a leaf
- segmentmins[0] = min(start[0], end[0]);
- segmentmins[1] = min(start[1], end[1]);
- segmentmins[2] = min(start[2], end[2]);
- segmentmaxs[0] = max(start[0], end[0]);
- segmentmaxs[1] = max(start[1], end[1]);
- segmentmaxs[2] = max(start[2], end[2]);
+ 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]);
+ // line trace the brushes
leaf = (q3mleaf_t *)node;
for (i = 0;i < leaf->numleafbrushes;i++)
{
- if (startfrac >= trace->fraction)
- return;
brush = leaf->firstleafbrush[i]->colbrushf;
- if (brush && brush->markframe != markframe)
+ if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
{
brush->markframe = markframe;
- if (BoxesOverlap(segmentmins, segmentmaxs, brush->mins, brush->maxs))
- Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ if (startfrac > trace->realfraction)
+ return;
}
}
- if (mod_q3bsp_curves_collisions.integer)
+ // can't do point traces on curves (they have no thickness)
+ if (mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
{
+ // line trace the curves
for (i = 0;i < leaf->numleaffaces;i++)
{
- if (startfrac >= trace->fraction)
- return;
face = leaf->firstleafface[i];
- if (face->collisions && face->collisionmarkframe != markframe)
+ if (face->collisions && face->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
face->collisionmarkframe = markframe;
- if (BoxesOverlap(segmentmins, segmentmaxs, face->mins, face->maxs))
- Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ if (startfrac > trace->realfraction)
+ return;
}
}
}
static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int markframe, const vec3_t segmentmins, const vec3_t segmentmaxs)
{
- int i, sides;
+ int i;
+ //int sides;
float nodesegmentmins[3], nodesegmentmaxs[3];
q3mleaf_t *leaf;
colbrushf_t *brush;
q3mface_t *face;
- 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->isnode)
- {
- // recurse down node sides
- sides = BoxOnPlaneSide(segmentmins, segmentmaxs, node->plane);
- if (sides == 3)
+ /*
+ // find which nodes the line is in and recurse for them
+ while (node->plane)
{
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
+ // 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;
+ }
}
- else if (sides == 2)
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
- else // sides == 1
+ */
+#if 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, 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);
- /*
- dist = node->plane->dist - (1.0f / 8.0f);
- for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
+ node = node->children[1];
+ continue;
+ }
+ else if (mod_q3bsp_debugtracebrush.integer == 1)
{
- if (DotProduct(ps->v, node->plane->normal) >= dist || DotProduct(pe->v, node->plane->normal) >= dist)
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
{
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
- break;
+ // 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;
}
- */
- /*
- dist = node->plane->dist + (1.0f / 8.0f);
- for (i = 0, ps = thisbrush_start->points, pe = thisbrush_end->points;i < thisbrush_start->numpoints;i++, ps++, pe++)
+ else
{
- if (DotProduct(ps->v, node->plane->normal) <= dist || DotProduct(pe->v, node->plane->normal) <= dist)
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
{
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
- break;
+ // 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;
}
- */
- /*
- sides = BoxOnPlaneSide(boxstartmins, boxstartmaxs, node->plane) | BoxOnPlaneSide(boxendmins, boxendmaxs, node->plane);
- if (sides & 1)
- Mod_Q3BSP_TraceBox_RecursiveBSPNode(trace, node->children[0], boxstartmins, boxstartmaxs, boxendmins, boxendmaxs);
- if (sides & 2)
- Mod_Q3BSP_TraceBox_RecursiveBSPNode(trace, node->children[1], boxstartmins, boxstartmaxs, boxendmins, boxendmaxs);
- */
+ return;
}
- else
- {
- // hit a leaf
- leaf = (q3mleaf_t *)node;
- for (i = 0;i < leaf->numleafbrushes;i++)
+#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
+ {
+ // take whichever side the segment box is on
+ node = node->children[sides - 1];
+ }
+ }
+ else
{
- brush = leaf->firstleafbrush[i]->colbrushf;
- if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
+ // recurse down node sides
+ sides = BoxOnPlaneSide(nodesegmentmins, nodesegmentmaxs, node->plane);
+ if (sides == 3)
{
- brush->markframe = markframe;
- Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ // 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];
+ }
+ }
+#endif
+ // hit a leaf
+ leaf = (q3mleaf_t *)node;
+ for (i = 0;i < leaf->numleafbrushes;i++)
+ {
+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
+ {
+ brush->markframe = markframe;
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
}
- if (mod_q3bsp_curves_collisions.integer)
+ }
+ if (mod_q3bsp_curves_collisions.integer)
+ {
+ for (i = 0;i < leaf->numleaffaces;i++)
{
- for (i = 0;i < leaf->numleaffaces;i++)
+ face = leaf->firstleafface[i];
+ if (face->collisions && face->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
{
- face = leaf->firstleafface[i];
- // note: this can not be optimized with a face->collisionmarkframe because each triangle of the face would need to be marked as done individually (because each one is bbox culled individually), and if all are marked, then the face could be marked as done
- if (face->collisions && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, face->mins, face->maxs))
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ face->markframe = markframe;
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
}
}
}
q3mface_t *face;
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
+ trace->realfraction = 1;
trace->hitsupercontentsmask = hitsupercontentsmask;
Matrix4x4_CreateIdentity(&startmatrix);
Matrix4x4_CreateIdentity(&endmatrix);
segmentmaxs[2] = max(boxstartmaxs[2], boxendmaxs[2]);
if (mod_q3bsp_optimizedtraceline.integer && VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs))
{
- // line trace
- if (model->brushq3.submodel)
+ if (VectorCompare(boxstartmins, boxendmins))
{
- for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
- if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
- Collision_TraceLineBrushFloat(trace, boxstartmins, boxendmins, model->brushq3.data_thismodel->firstbrush[i].colbrushf, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
- if (mod_q3bsp_curves_collisions.integer)
+ // point trace
+ if (model->brushq3.submodel)
{
- for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++)
+ for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+ if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
+ Collision_TracePointBrushFloat(trace, boxstartmins, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+ }
+ else
+ Mod_Q3BSP_TracePoint_RecursiveBSPNode(trace, model->brushq3.data_nodes, boxstartmins, ++markframe);
+ }
+ else
+ {
+ // line trace
+ if (model->brushq3.submodel)
+ {
+ for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+ if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
+ Collision_TraceLineBrushFloat(trace, boxstartmins, boxendmins, model->brushq3.data_thismodel->firstbrush[i].colbrushf, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+ if (mod_q3bsp_curves_collisions.integer)
{
- face = model->brushq3.data_thismodel->firstface + i;
- if (face->collisions)
- Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++)
+ {
+ face = model->brushq3.data_thismodel->firstface + i;
+ if (face->collisions)
+ Collision_TraceLineTriangleMeshFloat(trace, boxstartmins, boxendmins, face->num_triangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ }
}
}
+ else
+ Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model->brushq3.data_nodes, boxstartmins, boxendmins, 0, 1, boxstartmins, boxendmins, ++markframe, segmentmins, segmentmaxs);
}
- else
- Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model->brushq3.data_nodes, boxstartmins, boxendmins, 0, 1, boxstartmins, boxendmins, ++markframe);
}
else
{
}
}
-
-static int Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(const model_t *model, const q3mnode_t *node, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
+static int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
{
- int clusterindex;
-loc0:
- if (!node->isnode)
- {
- // leaf
- clusterindex = ((q3mleaf_t *)node)->clusterindex;
- return pvs[clusterindex >> 3] & (1 << (clusterindex & 7));
- }
-
- // node - recurse down the BSP tree
- switch (BoxOnPlaneSide(mins, maxs, node->plane))
+ int clusterindex, side, nodestackindex = 0;
+ q3mnode_t *node, *nodestack[1024];
+ node = model->brushq3.data_nodes;
+ if (!loadmodel->brushq3.num_pvsclusters)
+ return true;
+ for (;;)
{
- case 1: // front
- node = node->children[0];
- goto loc0;
- case 2: // back
- node = node->children[1];
- goto loc0;
- default: // crossing
- if (Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, node->children[0], pvs, mins, maxs))
- return true;
- node = node->children[1];
- goto loc0;
+ if (node->plane)
+ {
+ // node - recurse down the BSP tree
+ side = BoxOnPlaneSide(mins, maxs, node->plane) - 1;
+ if (side < 2)
+ {
+ // box is on one side of plane, take that path
+ node = node->children[side];
+ }
+ else
+ {
+ // box crosses plane, take one path and remember the other
+ nodestack[nodestackindex++] = node->children[0];
+ node = node->children[1];
+ }
+ }
+ else
+ {
+ // leaf - check cluster bit
+ clusterindex = ((q3mleaf_t *)node)->clusterindex;
+#if 0
+ if (clusterindex >= loadmodel->brushq3.num_pvsclusters)
+ {
+ Con_Printf("%i >= %i\n", clusterindex, loadmodel->brushq3.num_pvsclusters);
+ return true;
+ }
+#endif
+ if (CHECKPVSBIT(pvs, clusterindex))
+ {
+ // it is visible, return immediately with the news
+ return true;
+ }
+ else
+ {
+ // nothing to see here, try another path we didn't take earlier
+ if (nodestackindex == 0)
+ break;
+ node = nodestack[--nodestackindex];
+ }
+ }
}
- // never reached
+ // it is not visible
return false;
}
-static int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3_t mins, const vec3_t maxs)
-{
- return Mod_Q3BSP_BoxTouchingPVS_RecursiveBSPNode(model, model->brushq3.data_nodes, pvs, mins, maxs);
-}
-
//Returns PVS data for a given point
//(note: can return NULL)
static qbyte *Mod_Q3BSP_GetPVS(model_t *model, const vec3_t p)
q3mnode_t *node;
Mod_CheckLoaded(model);
node = model->brushq3.data_nodes;
- while (node->isnode)
+ while (node->plane)
node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
if (((q3mleaf_t *)node)->clusterindex >= 0)
- return model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength;
+ return model->brushq3.data_pvsclusters + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvsclusterbytes;
else
return NULL;
}
static void Mod_Q3BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, q3mnode_t *node)
{
- int i;
- float d;
- qbyte *pvs;
-
- while (node->isnode)
+ while (node->plane)
{
- d = PlaneDiff(org, node->plane);
+ float d = PlaneDiff(org, node->plane);
if (d > radius)
node = node->children[0];
else if (d < -radius)
node = node->children[1];
}
}
- // if this is a leaf with a pvs, accumulate the pvs bits
+ // if this leaf is in a cluster, accumulate the pvs bits
if (((q3mleaf_t *)node)->clusterindex >= 0)
{
- pvs = model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength;
+ int i;
+ qbyte *pvs = model->brushq1.data_pvsclusters + ((q3mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes;
for (i = 0;i < pvsbytes;i++)
pvsbuffer[i] |= pvs[i];
}
- return;
}
//Calculates a PVS that is the inclusive or of all leafs within radius pixels
//of the given point.
static int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength)
{
- int bytes = model->brushq3.num_pvschainlength;
+ int bytes = model->brushq3.num_pvsclusterbytes;
bytes = min(bytes, pvsbufferlength);
+ if (r_novis.integer || !loadmodel->brushq3.num_pvsclusters)
+ {
+ memset(pvsbuffer, 0xFF, bytes);
+ return bytes;
+ }
memset(pvsbuffer, 0, bytes);
Mod_Q3BSP_FatPVS_RecursiveBSPNode(model, org, radius, pvsbuffer, bytes, model->brushq3.data_nodes);
return bytes;
extern void R_Q3BSP_DrawSky(struct entity_render_s *ent);
extern void R_Q3BSP_Draw(struct entity_render_s *ent);
extern void R_Q3BSP_DrawShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius);
-extern void R_Q3BSP_DrawLight(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
+extern void R_Q3BSP_DrawLight(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap);
void Mod_Q3BSP_Load(model_t *mod, void *buffer)
{
int i, j;