#endif
}
+static int Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3])
+{
+ double t1, t2;
+ double midf, mid[3];
+ int ret, side;
+
+ // check for empty
+ while (node->plane)
+ {
+ // find the point distances
+ mplane_t *plane = node->plane;
+ if (plane->type < 3)
+ {
+ t1 = p1[plane->type] - plane->dist;
+ t2 = p2[plane->type] - plane->dist;
+ }
+ else
+ {
+ t1 = DotProduct (plane->normal, p1) - plane->dist;
+ t2 = DotProduct (plane->normal, p2) - plane->dist;
+ }
+
+ if (t1 < 0)
+ {
+ if (t2 < 0)
+ {
+ node = node->children[1];
+ continue;
+ }
+ side = 1;
+ }
+ else
+ {
+ if (t2 >= 0)
+ {
+ node = node->children[0];
+ continue;
+ }
+ side = 0;
+ }
+
+ midf = t1 / (t1 - t2);
+ VectorLerp(p1, midf, p2, mid);
+
+ // recurse both sides, front side first
+ // return 2 if empty is followed by solid (hit something)
+ // do not return 2 if both are solid or both empty,
+ // or if start is solid and end is empty
+ // as these degenerate cases usually indicate the eye is in solid and
+ // should see the target point anyway
+ ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid);
+ if (ret != 0)
+ return ret;
+ ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2);
+ if (ret != 1)
+ return ret;
+ return 2;
+ }
+ return ((mleaf_t *)node)->clusterindex < 0;
+}
+
+static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+{
+ // this function currently only supports same size start and end
+ double tracestart[3], traceend[3];
+ VectorCopy(start, tracestart);
+ VectorCopy(end, traceend);
+ return Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend) != 2;
+}
+
static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
{
int side;
tx->skinframerate = 1;
tx->currentskinframe = tx->skinframes;
tx->skinframes[0].base = r_texture_notexture;
+ tx->backgroundcurrentskinframe = tx->backgroundskinframes;
tx->basematerialflags = 0;
if (i == loadmodel->num_textures - 1)
{
node->parent = parent;
if (node->plane)
{
+ // this is a node, recurse to children
Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
+ // combine supercontents of children
+ node->combinedsupercontents = node->children[0]->combinedsupercontents | node->children[1]->combinedsupercontents;
+ }
+ else
+ {
+ int j;
+ mleaf_t *leaf = (mleaf_t *)node;
+ // if this is a leaf, calculate supercontents mask from all collidable
+ // primitives in the leaf (brushes and collision surfaces)
+ // also flag if the leaf contains any collision surfaces
+ leaf->combinedsupercontents = 0;
+ // combine the supercontents values of all brushes in this leaf
+ for (j = 0;j < leaf->numleafbrushes;j++)
+ leaf->combinedsupercontents |= loadmodel->brush.data_brushes[leaf->firstleafbrush[j]].texture->supercontents;
+ // check if this leaf contains any collision surfaces (q3 patches)
+ for (j = 0;j < leaf->numleafsurfaces;j++)
+ {
+ msurface_t *surface = loadmodel->data_surfaces + leaf->firstleafsurface[j];
+ if (surface->num_collisiontriangles)
+ {
+ leaf->containscollisionsurfaces = true;
+ leaf->combinedsupercontents |= surface->texture->supercontents;
+ }
+ }
}
}
{
pvs = loadmodel->brush.data_pvsclusters + leaf->clusterindex * loadmodel->brush.num_pvsclusterbytes;
for (j = 0;j < loadmodel->brush.num_leafs;j++)
- if (leaf->contents == CONTENTS_EMPTY && CHECKPVSBIT(pvs, loadmodel->brush.data_leafs[j].clusterindex))
+ if (CHECKPVSBIT(pvs, loadmodel->brush.data_leafs[j].clusterindex) && loadmodel->brush.data_leafs[j].contents == CONTENTS_EMPTY)
return true;
}
}
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q1BSP_TraceBox;
+ mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight;
mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents;
mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents;
mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
mod->DrawLight = R_Q1BSP_DrawLight;
if (i != 0)
{
+ mod->brush.TraceLineOfSight = NULL;
mod->brush.GetPVS = NULL;
mod->brush.FatPVS = NULL;
mod->brush.BoxTouchingPVS = NULL;
{
int i;
layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
- layer->framerate = atoi(parameter[1]);
+ layer->framerate = atof(parameter[1]);
for (i = 0;i < layer->numframes;i++)
strlcpy(layer->texturename[i], parameter[i + 2], sizeof(layer->texturename));
}
shader->surfaceparms |= Q3SURFACEPARM_WATER;
else if (!strcasecmp(parameter[1], "pointlight"))
shader->surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
+ else if (!strcasecmp(parameter[1], "antiportal"))
+ shader->surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
else
- Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
+ Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
}
else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
{
if (!Mod_LoadSkinFrame(&out->skinframes[j], shader->primarylayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0), false, true))
Con_Printf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
}
+ if (shader->backgroundlayer && cls.state != ca_dedicated)
+ {
+ int j;
+ out->backgroundnumskinframes = shader->backgroundlayer->numframes;
+ out->backgroundskinframerate = shader->backgroundlayer->framerate;
+ for (j = 0;j < shader->backgroundlayer->numframes;j++)
+ if (!Mod_LoadSkinFrame(&out->backgroundskinframes[j], shader->backgroundlayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->backgroundlayer->clampmap ? TEXF_CLAMP : 0), false, true))
+ Con_Printf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->backgroundlayer->texturename[j], j, out->name);
+ }
}
+ else if (!strcmp(out->name, "noshader"))
+ out->surfaceparms = 0;
else
{
c++;
// init the animation variables
out->currentframe = out;
out->currentskinframe = &out->skinframes[0];
+ out->backgroundcurrentskinframe = &out->backgroundskinframes[0];
}
if (c)
Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
// walk the tree until we hit a leaf, recursing for any split cases
while (node->plane)
{
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
return;
}
}
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
// hit a leaf
nodesegmentmins[0] = min(start[0], end[0]) - 1;
nodesegmentmins[1] = min(start[1], end[1]) - 1;
}
}
// can't do point traces on curves (they have no thickness)
- if (mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
+ if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
{
// line trace the curves
for (i = 0;i < leaf->numleafsurfaces;i++)
// walk the tree until we hit a leaf, recursing for any split cases
while (node->plane)
{
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
// take whichever side the segment box is on
node = node->children[sides - 1];
}
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
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);
Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush);
}
}
- if (mod_q3bsp_curves_collisions.integer)
+ if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer)
{
for (i = 0;i < leaf->numleafsurfaces;i++)
{
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q3BSP_TraceBox;
+ mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight;
mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
// textures and memory belong to the main model
mod->texturepool = NULL;
mod->mempool = NULL;
+ mod->brush.TraceLineOfSight = NULL;
mod->brush.GetPVS = NULL;
mod->brush.FatPVS = NULL;
mod->brush.BoxTouchingPVS = NULL;
break;
if (j < mod->nummodelsurfaces)
mod->DrawSky = R_Q1BSP_DrawSky;
+ else
+ mod->DrawSky = NULL;
}
}