float tempnormal[3], starttransformed[3], endtransformed[3];
if (hitent)
- *hitent = NULL;
+ *hitent = &cl_entities[0].render;
Mod_CheckLoaded(cl.worldmodel);
if (cl.worldmodel && cl.worldmodel->brush.TraceBox)
cl.worldmodel->brush.TraceBox(cl.worldmodel, &trace, start, start, end, end, hitsupercontentsmask);
VectorCopy(trace.plane.normal, normal);
cl_traceline_startsupercontents = trace.startsupercontents;
maxfrac = trace.fraction;
- if (hitent && trace.fraction < 1)
- *hitent = &cl_entities[0].render;
if (hitbmodels && cl_num_brushmodel_entities)
{
if (ent->model && ent->model->brush.TraceBox)
ent->model->brush.TraceBox(ent->model, &trace, starttransformed, starttransformed, endtransformed, endtransformed, hitsupercontentsmask);
- if (trace.allsolid || trace.startsolid || maxfrac > trace.fraction)
+ cl_traceline_startsupercontents |= trace.startsupercontents;
+ if (maxfrac > trace.fraction)
{
- cl_traceline_startsupercontents = trace.startsupercontents;
if (hitent)
*hitent = ent;
- if (maxfrac > trace.fraction)
+ maxfrac = trace.fraction;
+ if (impact)
+ VectorLerp(start, trace.fraction, end, impact);
+ if (normal)
{
- maxfrac = trace.fraction;
- if (impact)
- VectorLerp(start, trace.fraction, end, impact);
- if (normal)
- {
- VectorCopy(trace.plane.normal, tempnormal);
- Matrix4x4_Transform3x3(&matrix, tempnormal, normal);
- }
+ VectorCopy(trace.plane.normal, tempnormal);
+ Matrix4x4_Transform3x3(&matrix, tempnormal, normal);
}
}
}
void Collision_ValidateBrush(colbrushf_t *brush)
{
- int j, k;
+ int j, k, pointsoffplanes, printbrush;
+ float d;
+ printbrush = false;
if (!brush->numpoints)
{
Con_Printf("Collision_ValidateBrush: brush with no points!\n");
- Collision_PrintBrushAsQHull(brush, "unnamed");
- return;
+ printbrush = true;
}
+#if 0
// it's ok for a brush to have one point and no planes...
if (brush->numplanes == 0 && brush->numpoints != 1)
{
Con_Printf("Collision_ValidateBrush: brush with no planes and more than one point!\n");
- Collision_PrintBrushAsQHull(brush, "unnamed");
- return;
+ printbrush = true;
}
- for (k = 0;k < brush->numplanes;k++)
+#endif
+ if (brush->numplanes)
{
- for (j = 0;j < brush->numpoints;j++)
+ pointsoffplanes = 0;
+ for (k = 0;k < brush->numplanes;k++)
{
- if (DotProduct(brush->points[j].v, brush->planes[k].normal) - brush->planes[k].dist > (1.0f / 8.0f))
+ if (DotProduct(brush->planes[k].normal, brush->planes[k].normal) < 0.0001f)
+ Con_Printf("Collision_ValidateBrush: plane #%i (%f %f %f %f) is degenerate\n", k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist);
+ for (j = 0;j < brush->numpoints;j++)
{
- Con_Printf("Collision_NewBrushFromPlanes: point #%i (%f %f %f) infront of plane #%i (%f %f %f %f)\n", j, brush->points[j].v[0], brush->points[j].v[1], brush->points[j].v[2], k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist);
- Collision_PrintBrushAsQHull(brush, "unnamed");
- return;
+ d = DotProduct(brush->points[j].v, brush->planes[k].normal) - brush->planes[k].dist;
+ if (d > (1.0f / 8.0f))
+ {
+ Con_Printf("Collision_ValidateBrush: point #%i (%f %f %f) infront of plane #%i (%f %f %f %f)\n", j, brush->points[j].v[0], brush->points[j].v[1], brush->points[j].v[2], k, brush->planes[k].normal[0], brush->planes[k].normal[1], brush->planes[k].normal[2], brush->planes[k].dist);
+ printbrush = true;
+ }
+ if (fabs(d) > 0.01f)
+ pointsoffplanes++;
}
}
+ if (pointsoffplanes == 0) // all points are on all planes
+ {
+ Con_Printf("Collision_ValidateBrush: all points lie on all planes (degenerate, no brush volume!)\n");
+ printbrush = true;
+ }
+ }
+ if (printbrush)
+ Collision_PrintBrushAsQHull(brush, "unnamed");
+}
+
+float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
+{
+ float dist, bestdist;
+ bestdist = DotProduct(points->v, normal);
+ points++;
+ while(--numpoints)
+ {
+ dist = DotProduct(points->v, normal);
+ bestdist = min(bestdist, dist);
+ points++;
+ }
+ return bestdist;
+}
+
+float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
+{
+ float dist, bestdist;
+ bestdist = DotProduct(points->v, normal);
+ points++;
+ while(--numpoints)
+ {
+ dist = DotProduct(points->v, normal);
+ bestdist = max(bestdist, dist);
+ points++;
}
+ return bestdist;
}
colplanef_t planesbuf[256];
int elementsbuf[1024];
int polypointbuf[256];
+ float mins[3], maxs[3];
// construct a collision brush (points, planes, and renderable mesh) from
// a set of planes, this also optimizes out any unnecessary planes (ones
// whose polygon is clipped away by the other planes)
numplanes++;
}
+ // recalc distances
+ for (j = 0;j < numplanes;j++)
+ planesbuf[j].dist = furthestplanedist_float(planesbuf[j].normal, pointsbuf, numpoints);
+
+ if (numpoints)
+ {
+ VectorCopy(pointsbuf[0].v, mins);
+ VectorCopy(pointsbuf[0].v, maxs);
+ for (j = 1;j < numpoints;j++)
+ {
+ mins[0] = min(mins[0], pointsbuf[j].v[0]);
+ mins[1] = min(mins[1], pointsbuf[j].v[1]);
+ mins[2] = min(mins[2], pointsbuf[j].v[2]);
+ maxs[0] = max(maxs[0], pointsbuf[j].v[0]);
+ maxs[1] = max(maxs[1], pointsbuf[j].v[1]);
+ maxs[2] = max(maxs[2], pointsbuf[j].v[2]);
+ }
+ }
+
// if nothing is left, there's nothing to allocate
if (numtriangles < 4 || numplanes < 4 || numpoints < 4)
return NULL;
memcpy(brush->points, pointsbuf, numpoints * sizeof(colpointf_t));
memcpy(brush->planes, planesbuf, numplanes * sizeof(colplanef_t));
memcpy(brush->elements, elementsbuf, numtriangles * sizeof(int[3]));
+ VectorCopy(mins, brush->mins);
+ VectorCopy(maxs, brush->maxs);
Collision_ValidateBrush(brush);
return brush;
}
void Collision_CalcPlanesForPolygonBrushFloat(colbrushf_t *brush)
{
int i;
- float edge0[3], edge1[3], normal[3], dist, bestdist;
+ float edge0[3], edge1[3], edge2[3], normal[3], dist, bestdist, temp[3];
colpointf_t *p, *p2;
- // choose best surface normal for polygon's plane
- bestdist = 0;
- for (i = 0, p = brush->points + 1;i < brush->numpoints - 2;i++, p++)
+ if (brush->numpoints == 3)
{
- VectorSubtract(p[-1].v, p[0].v, edge0);
- VectorSubtract(p[1].v, p[0].v, edge1);
- CrossProduct(edge0, edge1, normal);
- dist = DotProduct(normal, normal);
- if (i == 0 || bestdist < dist)
+ // optimized triangle case
+ TriangleNormal(brush->points[0].v, brush->points[1].v, brush->points[2].v, brush->planes[0].normal);
+ if (DotProduct(brush->planes[0].normal, brush->planes[0].normal) < 0.0001f)
{
- bestdist = dist;
- VectorCopy(normal, brush->planes->normal);
+ // there's no point in processing a degenerate triangle (GIGO - Garbage In, Garbage Out)
+ brush->numplanes = 0;
+ return;
+ }
+ else
+ {
+ brush->numplanes = 5;
+ VectorNormalize(brush->planes[0].normal);
+ brush->planes[0].dist = DotProduct(brush->points->v, brush->planes[0].normal);
+ VectorNegate(brush->planes[0].normal, brush->planes[1].normal);
+ brush->planes[1].dist = -brush->planes[0].dist;
+ VectorSubtract(brush->points[2].v, brush->points[0].v, edge0);
+ VectorSubtract(brush->points[0].v, brush->points[1].v, edge1);
+ VectorSubtract(brush->points[1].v, brush->points[2].v, edge2);
+ CrossProduct(edge0, brush->planes->normal, brush->planes[2].normal);
+ CrossProduct(edge1, brush->planes->normal, brush->planes[3].normal);
+ CrossProduct(edge2, brush->planes->normal, brush->planes[4].normal);
+ VectorNormalize(brush->planes[2].normal);
+ VectorNormalize(brush->planes[3].normal);
+ VectorNormalize(brush->planes[4].normal);
+ brush->planes[2].dist = DotProduct(brush->points[2].v, brush->planes[2].normal);
+ brush->planes[3].dist = DotProduct(brush->points[0].v, brush->planes[3].normal);
+ brush->planes[4].dist = DotProduct(brush->points[1].v, brush->planes[4].normal);
+
+ if (developer.integer)
+ {
+ // validation code
+ //VectorSubtract(brush->points[0].v, brush->points[1].v, edge0);
+ //VectorSubtract(brush->points[2].v, brush->points[1].v, edge1);
+ CrossProduct(edge1, edge0, normal);
+ VectorNormalize(normal);
+ VectorSubtract(normal, brush->planes[0].normal, temp);
+ if (VectorLength(temp) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: TriangleNormal gave wrong answer (%f %f %f != correct answer %f %f %f)\n", brush->planes->normal[0], brush->planes->normal[1], brush->planes->normal[2], normal[0], normal[1], normal[2]);
+ if (fabs(DotProduct(brush->planes[1].normal, brush->planes[0].normal) - -1.0f) > 0.01f || fabs(brush->planes[1].dist - -brush->planes[0].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 1 (%f %f %f %f) is not opposite plane 0 (%f %f %f %f)\n", brush->planes[1].normal[0], brush->planes[1].normal[1], brush->planes[1].normal[2], brush->planes[1].dist, brush->planes[0].normal[0], brush->planes[0].normal[1], brush->planes[0].normal[2], brush->planes[0].dist);
+ if (fabs(DotProduct(brush->planes[2].normal, brush->planes[0].normal)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 2 (%f %f %f %f) is not perpendicular to plane 0 (%f %f %f %f)\n", brush->planes[2].normal[0], brush->planes[2].normal[1], brush->planes[2].normal[2], brush->planes[2].dist, brush->planes[0].normal[0], brush->planes[0].normal[1], brush->planes[0].normal[2], brush->planes[2].dist);
+ if (fabs(DotProduct(brush->planes[3].normal, brush->planes[0].normal)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 3 (%f %f %f %f) is not perpendicular to plane 0 (%f %f %f %f)\n", brush->planes[3].normal[0], brush->planes[3].normal[1], brush->planes[3].normal[2], brush->planes[3].dist, brush->planes[0].normal[0], brush->planes[0].normal[1], brush->planes[0].normal[2], brush->planes[3].dist);
+ if (fabs(DotProduct(brush->planes[4].normal, brush->planes[0].normal)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 4 (%f %f %f %f) is not perpendicular to plane 0 (%f %f %f %f)\n", brush->planes[4].normal[0], brush->planes[4].normal[1], brush->planes[4].normal[2], brush->planes[4].dist, brush->planes[0].normal[0], brush->planes[0].normal[1], brush->planes[0].normal[2], brush->planes[4].dist);
+ if (fabs(DotProduct(brush->planes[2].normal, edge0)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 2 (%f %f %f %f) is not perpendicular to edge 0 (%f %f %f to %f %f %f)\n", brush->planes[2].normal[0], brush->planes[2].normal[1], brush->planes[2].normal[2], brush->planes[2].dist, brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2], brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2]);
+ if (fabs(DotProduct(brush->planes[3].normal, edge1)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 3 (%f %f %f %f) is not perpendicular to edge 1 (%f %f %f to %f %f %f)\n", brush->planes[3].normal[0], brush->planes[3].normal[1], brush->planes[3].normal[2], brush->planes[3].dist, brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2], brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2]);
+ if (fabs(DotProduct(brush->planes[4].normal, edge2)) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: plane 4 (%f %f %f %f) is not perpendicular to edge 2 (%f %f %f to %f %f %f)\n", brush->planes[4].normal[0], brush->planes[4].normal[1], brush->planes[4].normal[2], brush->planes[4].dist, brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2], brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2]);
+ if (fabs(DotProduct(brush->points[0].v, brush->planes[0].normal) - brush->planes[0].dist) > 0.01f || fabs(DotProduct(brush->points[1].v, brush->planes[0].normal) - brush->planes[0].dist) > 0.01f || fabs(DotProduct(brush->points[2].v, brush->planes[0].normal) - brush->planes[0].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: edges (%f %f %f to %f %f %f to %f %f %f) off front plane 0 (%f %f %f %f)\n", brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2], brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2], brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2], brush->planes[0].normal[0], brush->planes[0].normal[1], brush->planes[0].normal[2], brush->planes[0].dist);
+ if (fabs(DotProduct(brush->points[0].v, brush->planes[1].normal) - brush->planes[1].dist) > 0.01f || fabs(DotProduct(brush->points[1].v, brush->planes[1].normal) - brush->planes[1].dist) > 0.01f || fabs(DotProduct(brush->points[2].v, brush->planes[1].normal) - brush->planes[1].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: edges (%f %f %f to %f %f %f to %f %f %f) off back plane 1 (%f %f %f %f)\n", brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2], brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2], brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2], brush->planes[1].normal[0], brush->planes[1].normal[1], brush->planes[1].normal[2], brush->planes[1].dist);
+ if (fabs(DotProduct(brush->points[2].v, brush->planes[2].normal) - brush->planes[2].dist) > 0.01f || fabs(DotProduct(brush->points[0].v, brush->planes[2].normal) - brush->planes[2].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: edge 0 (%f %f %f to %f %f %f) off front plane 2 (%f %f %f %f)\n", brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2], brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2], brush->planes[2].normal[0], brush->planes[2].normal[1], brush->planes[2].normal[2], brush->planes[2].dist);
+ if (fabs(DotProduct(brush->points[0].v, brush->planes[3].normal) - brush->planes[3].dist) > 0.01f || fabs(DotProduct(brush->points[1].v, brush->planes[3].normal) - brush->planes[3].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: edge 0 (%f %f %f to %f %f %f) off front plane 2 (%f %f %f %f)\n", brush->points[0].v[0], brush->points[0].v[1], brush->points[0].v[2], brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2], brush->planes[3].normal[0], brush->planes[3].normal[1], brush->planes[3].normal[2], brush->planes[3].dist);
+ if (fabs(DotProduct(brush->points[1].v, brush->planes[4].normal) - brush->planes[4].dist) > 0.01f || fabs(DotProduct(brush->points[2].v, brush->planes[4].normal) - brush->planes[4].dist) > 0.01f)
+ Con_Printf("Collision_CalcPlanesForPolygonBrushFloat: edge 0 (%f %f %f to %f %f %f) off front plane 2 (%f %f %f %f)\n", brush->points[1].v[0], brush->points[1].v[1], brush->points[1].v[2], brush->points[2].v[0], brush->points[2].v[1], brush->points[2].v[2], brush->planes[4].normal[0], brush->planes[4].normal[1], brush->planes[4].normal[2], brush->planes[4].dist);
+ }
}
}
-
- VectorNormalize(brush->planes->normal);
- brush->planes->dist = DotProduct(brush->points->v, brush->planes->normal);
-
- // negate plane to create other side
- VectorNegate(brush->planes[0].normal, brush->planes[1].normal);
- brush->planes[1].dist = -brush->planes[0].dist;
- for (i = 0, p = brush->points + (brush->numpoints - 1), p2 = brush->points;i < brush->numpoints;i++, p = p2, p2++)
+ else
{
- VectorSubtract(p->v, p2->v, edge0);
- CrossProduct(edge0, brush->planes->normal, brush->planes[i + 2].normal);
- VectorNormalize(brush->planes[i + 2].normal);
- brush->planes[i + 2].dist = DotProduct(p->v, brush->planes[i + 2].normal);
+ // choose best surface normal for polygon's plane
+ bestdist = 0;
+ for (i = 0, p = brush->points + 1;i < brush->numpoints - 2;i++, p++)
+ {
+ VectorSubtract(p[-1].v, p[0].v, edge0);
+ VectorSubtract(p[1].v, p[0].v, edge1);
+ CrossProduct(edge0, edge1, normal);
+ //TriangleNormal(p[-1].v, p[0].v, p[1].v, normal);
+ dist = DotProduct(normal, normal);
+ if (i == 0 || bestdist < dist)
+ {
+ bestdist = dist;
+ VectorCopy(normal, brush->planes->normal);
+ }
+ }
+ if (bestdist < 0.0001f)
+ {
+ // there's no point in processing a degenerate triangle (GIGO - Garbage In, Garbage Out)
+ brush->numplanes = 0;
+ return;
+ }
+ else
+ {
+ brush->numplanes = brush->numpoints + 2;
+ VectorNormalize(brush->planes->normal);
+ brush->planes->dist = DotProduct(brush->points->v, brush->planes->normal);
+
+ // negate plane to create other side
+ VectorNegate(brush->planes[0].normal, brush->planes[1].normal);
+ brush->planes[1].dist = -brush->planes[0].dist;
+ for (i = 0, p = brush->points + (brush->numpoints - 1), p2 = brush->points;i < brush->numpoints;i++, p = p2, p2++)
+ {
+ VectorSubtract(p->v, p2->v, edge0);
+ CrossProduct(edge0, brush->planes->normal, brush->planes[i + 2].normal);
+ VectorNormalize(brush->planes[i + 2].normal);
+ brush->planes[i + 2].dist = DotProduct(p->v, brush->planes[i + 2].normal);
+ }
+ }
}
-#if 1
- // validity check - will be disabled later
- for (i = 0;i < brush->numplanes;i++)
+ if (developer.integer)
{
- int j;
- for (j = 0, p = brush->points;j < brush->numpoints;j++, p++)
- if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + (1.0 / 32.0))
- Con_Printf("Error in brush plane generation, plane %i\n", i);
+ // validity check - will be disabled later
+ Collision_ValidateBrush(brush);
+ for (i = 0;i < brush->numplanes;i++)
+ {
+ int j;
+ for (j = 0, p = brush->points;j < brush->numpoints;j++, p++)
+ if (DotProduct(p->v, brush->planes[i].normal) > brush->planes[i].dist + (1.0 / 32.0))
+ Con_Printf("Error in brush plane generation, plane %i\n", i);
+ }
}
-#endif
}
colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents)
return brush;
}
-float nearestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
-{
- float dist, bestdist;
- bestdist = DotProduct(points->v, normal);
- points++;
- while(--numpoints)
- {
- dist = DotProduct(points->v, normal);
- bestdist = min(bestdist, dist);
- points++;
- }
- return bestdist;
-}
-
-float furthestplanedist_float(const float *normal, const colpointf_t *points, int numpoints)
-{
- float dist, bestdist;
- bestdist = DotProduct(points->v, normal);
- points++;
- while(--numpoints)
- {
- dist = DotProduct(points->v, normal);
- bestdist = max(bestdist, dist);
- points++;
- }
- return bestdist;
-}
-
#define COLLISIONEPSILON (1.0f / 32.0f)
#define COLLISIONEPSILON2 0//(1.0f / 32.0f)
nplane2 -= thatbrush_start->numplanes;
startplane = thisbrush_start->planes + nplane2;
endplane = thisbrush_end->planes + nplane2;
+ if (developer.integer)
+ {
+ // any brush with degenerate planes is not worth handling
+ if (DotProduct(startplane->normal, startplane->normal) < 0.9f || DotProduct(endplane->normal, endplane->normal) < 0.9f)
+ {
+ Con_Printf("Collision_TraceBrushBrushFloat: degenerate thisbrush plane!\n");
+ return;
+ }
+ f = furthestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints);
+ if (fabs(f - startplane->dist) > 0.01f)
+ Con_Printf("startplane->dist %f != calculated %f (thisbrush_start)\n", startplane->dist, f);
+ }
+ d1 = nearestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
+ d2 = nearestplanedist_float(endplane->normal, thisbrush_end->points, thisbrush_end->numpoints) - furthestplanedist_float(endplane->normal, thatbrush_end->points, thatbrush_end->numpoints) - COLLISIONEPSILON2;
}
else
{
startplane = thatbrush_start->planes + nplane2;
endplane = thatbrush_end->planes + nplane2;
+ if (developer.integer)
+ {
+ // any brush with degenerate planes is not worth handling
+ if (DotProduct(startplane->normal, startplane->normal) < 0.9f || DotProduct(endplane->normal, endplane->normal) < 0.9f)
+ {
+ Con_Printf("Collision_TraceBrushBrushFloat: degenerate thatbrush plane!\n");
+ return;
+ }
+ f = furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
+ if (fabs(f - startplane->dist) > 0.01f)
+ Con_Printf("startplane->dist %f != calculated %f (thatbrush_start)\n", startplane->dist, f);
+ }
+ d1 = nearestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - startplane->dist;
+ d2 = nearestplanedist_float(endplane->normal, thisbrush_end->points, thisbrush_end->numpoints) - startplane->dist - COLLISIONEPSILON2;
}
- d1 = nearestplanedist_float(startplane->normal, thisbrush_start->points, thisbrush_start->numpoints) - furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
- d2 = nearestplanedist_float(endplane->normal, thisbrush_end->points, thisbrush_end->numpoints) - furthestplanedist_float(endplane->normal, thatbrush_end->points, thatbrush_end->numpoints) - COLLISIONEPSILON2;
//Con_Printf("%c%i: d1 = %f, d2 = %f, d1 / (d1 - d2) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, d1, d2, d1 / (d1 - d2));
f = d1 - d2;
if (enterfrac < f)
{
enterfrac = f;
- VectorBlend(startplane->normal, endplane->normal, enterfrac, newimpactnormal);
+ VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
}
}
- else if (f < 0)
+ else
{
// moving out of brush
if (d1 > 0)
}
}
-// NOTE: start and end of brush pair must have same numplanes/numpoints
+// NOTE: start and end brush pair must have same numplanes/numpoints
void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end)
{
int nplane, fstartsolid, fendsolid, brushsolid;
startplane = thatbrush_start->planes + nplane;
endplane = thatbrush_end->planes + nplane;
d1 = DotProduct(startplane->normal, linestart) - startplane->dist;
- d2 = DotProduct(endplane->normal, lineend) - endplane->dist;
+ d2 = DotProduct(endplane->normal, lineend) - endplane->dist - COLLISIONEPSILON2;
+ if (developer.integer)
+ {
+ // any brush with degenerate planes is not worth handling
+ if (DotProduct(startplane->normal, startplane->normal) < 0.9f || DotProduct(endplane->normal, endplane->normal) < 0.9f)
+ {
+ Con_Printf("Collision_TraceLineBrushFloat: degenerate plane!\n");
+ return;
+ }
+ f = furthestplanedist_float(startplane->normal, thatbrush_start->points, thatbrush_start->numpoints);
+ if (fabs(f - startplane->dist) > 0.01f)
+ Con_Printf("startplane->dist %f != calculated %f\n", startplane->dist, f);
+ }
f = d1 - d2;
if (f >= 0)
if (enterfrac < f)
{
enterfrac = f;
- VectorBlend(startplane->normal, endplane->normal, enterfrac, newimpactnormal);
+ VectorLerp(startplane->normal, enterfrac, endplane->normal, newimpactnormal);
}
}
- else if (f < 0)
+ else
{
// moving out of brush
if (d1 > 0)
}
}
+static colpointf_t polyf_points[256];
static colplanef_t polyf_planes[256 + 2];
static colbrushf_t polyf_brush;
-void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points)
+void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, int supercontents)
{
if (numpoints > 256)
{
polyf_brush.numplanes = numpoints + 2;
polyf_brush.points = (colpointf_t *)points;
polyf_brush.planes = polyf_planes;
+ polyf_brush.supercontents = supercontents;
Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
//Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &polyf_brush, &polyf_brush);
}
+void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numtriangles, const int *element3i, const float *vertex3f, int supercontents, const vec3_t segmentmins, const vec3_t segmentmaxs)
+{
+ int i;
+ float facemins[3], facemaxs[3];
+ polyf_brush.numpoints = 3;
+ polyf_brush.numplanes = 5;
+ polyf_brush.points = polyf_points;
+ polyf_brush.planes = polyf_planes;
+ polyf_brush.supercontents = supercontents;
+ for (i = 0;i < numtriangles;i++, element3i += 3)
+ {
+ VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
+ VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
+ VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
+ facemins[0] = min(polyf_points[0].v[0], min(polyf_points[1].v[0], polyf_points[2].v[0]));
+ facemins[1] = min(polyf_points[0].v[1], min(polyf_points[1].v[1], polyf_points[2].v[1]));
+ facemins[2] = min(polyf_points[0].v[2], min(polyf_points[1].v[2], polyf_points[2].v[2]));
+ facemaxs[0] = max(polyf_points[0].v[0], max(polyf_points[1].v[0], polyf_points[2].v[0]));
+ facemaxs[1] = max(polyf_points[0].v[1], max(polyf_points[1].v[1], polyf_points[2].v[1]));
+ facemaxs[2] = max(polyf_points[0].v[2], max(polyf_points[1].v[2], polyf_points[2].v[2]));
+ if (BoxesOverlap(segmentmins, segmentmaxs, facemins, facemaxs))
+ {
+ Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
+ //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
+ Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, &polyf_brush, &polyf_brush);
+ }
+ }
+}
+
+void Collision_TraceLinePolygonFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numpoints, const float *points, int supercontents)
+{
+ if (numpoints > 256)
+ {
+ Con_Printf("Polygon with more than 256 points not supported yet (fixme!)\n");
+ return;
+ }
+ polyf_brush.numpoints = numpoints;
+ polyf_brush.numplanes = numpoints + 2;
+ polyf_brush.points = (colpointf_t *)points;
+ polyf_brush.planes = polyf_planes;
+ polyf_brush.supercontents = supercontents;
+ Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
+ //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, &polyf_brush, &polyf_brush);
+}
+
+void Collision_TraceLineTriangleMeshFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numtriangles, const int *element3i, const float *vertex3f, int supercontents, const vec3_t segmentmins, const vec3_t segmentmaxs)
+{
+ int i;
+ float facemins[3], facemaxs[3];
+ polyf_brush.numpoints = 3;
+ polyf_brush.numplanes = 5;
+ polyf_brush.points = polyf_points;
+ polyf_brush.planes = polyf_planes;
+ polyf_brush.supercontents = supercontents;
+ for (i = 0;i < numtriangles;i++, element3i += 3)
+ {
+ VectorCopy(vertex3f + element3i[0] * 3, polyf_points[0].v);
+ VectorCopy(vertex3f + element3i[1] * 3, polyf_points[1].v);
+ VectorCopy(vertex3f + element3i[2] * 3, polyf_points[2].v);
+ facemins[0] = min(polyf_points[0].v[0], min(polyf_points[1].v[0], polyf_points[2].v[0]));
+ facemins[1] = min(polyf_points[0].v[1], min(polyf_points[1].v[1], polyf_points[2].v[1]));
+ facemins[2] = min(polyf_points[0].v[2], min(polyf_points[1].v[2], polyf_points[2].v[2]));
+ facemaxs[0] = max(polyf_points[0].v[0], max(polyf_points[1].v[0], polyf_points[2].v[0]));
+ facemaxs[1] = max(polyf_points[0].v[1], max(polyf_points[1].v[1], polyf_points[2].v[1]));
+ facemaxs[2] = max(polyf_points[0].v[2], max(polyf_points[1].v[2], polyf_points[2].v[2]));
+ if (BoxesOverlap(segmentmins, segmentmaxs, facemins, facemaxs))
+ {
+ Collision_CalcPlanesForPolygonBrushFloat(&polyf_brush);
+ //Collision_PrintBrushAsQHull(&polyf_brush, "polyf_brush");
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, &polyf_brush, &polyf_brush);
+ }
+ }
+}
+
+
static colpointf_t polyf_pointsstart[256], polyf_pointsend[256];
static colplanef_t polyf_planesstart[256 + 2], polyf_planesend[256 + 2];
static colbrushf_t polyf_brushstart, polyf_brushend;
-void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, const matrix4x4_t *polygonmatrixstart, const matrix4x4_t *polygonmatrixend)
+void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, const matrix4x4_t *polygonmatrixstart, const matrix4x4_t *polygonmatrixend, int supercontents)
{
int i;
if (numpoints > 256)
polyf_brushstart.numplanes = numpoints + 2;
polyf_brushstart.points = polyf_pointsstart;//(colpointf_t *)points;
polyf_brushstart.planes = polyf_planesstart;
+ polyf_brushstart.supercontents = supercontents;
for (i = 0;i < numpoints;i++)
Matrix4x4_Transform(polygonmatrixstart, points + i * 3, polyf_brushstart.points[i].v);
polyf_brushend.numpoints = numpoints;
polyf_brushend.numplanes = numpoints + 2;
polyf_brushend.points = polyf_pointsend;//(colpointf_t *)points;
polyf_brushend.planes = polyf_planesend;
+ polyf_brushend.supercontents = supercontents;
for (i = 0;i < numpoints;i++)
Matrix4x4_Transform(polygonmatrixend, points + i * 3, polyf_brushend.points[i].v);
Collision_CalcPlanesForPolygonBrushFloat(&polyf_brushstart);
static colpointf_t brushforbox_point[MAX_BRUSHFORBOX*8];
static colplanef_t brushforbox_plane[MAX_BRUSHFORBOX*6];
static colbrushf_t brushforbox_brush[MAX_BRUSHFORBOX];
+static colbrushf_t brushforpoint_brush[MAX_BRUSHFORBOX];
void Collision_InitBrushForBox(void)
{
brushforbox_brush[i].numplanes = 6;
brushforbox_brush[i].points = brushforbox_point + i * 8;
brushforbox_brush[i].planes = brushforbox_plane + i * 6;
+ brushforpoint_brush[i].supercontents = SUPERCONTENTS_SOLID;
+ brushforpoint_brush[i].numpoints = 1;
+ brushforpoint_brush[i].numplanes = 0;
+ brushforpoint_brush[i].points = brushforbox_point + i * 8;
+ brushforpoint_brush[i].planes = brushforbox_plane + i * 6;
}
}
colbrushf_t *brush;
if (brushforbox_brush[0].numpoints == 0)
Collision_InitBrushForBox();
- brush = brushforbox_brush + ((brushforbox_index++) % MAX_BRUSHFORBOX);
- // FIXME: optimize
- for (i = 0;i < 8;i++)
+ if (VectorCompare(mins, maxs))
{
- v[0] = i & 1 ? maxs[0] : mins[0];
- v[1] = i & 2 ? maxs[1] : mins[1];
- v[2] = i & 4 ? maxs[2] : mins[2];
- Matrix4x4_Transform(matrix, v, brush->points[i].v);
+ // point brush
+ brush = brushforpoint_brush + ((brushforbox_index++) % MAX_BRUSHFORBOX);
+ VectorCopy(mins, brush->points->v);
}
- // FIXME: optimize!
- for (i = 0;i < 6;i++)
+ else
{
- VectorClear(v);
- v[i >> 1] = i & 1 ? 1 : -1;
- Matrix4x4_Transform3x3(matrix, v, brush->planes[i].normal);
- VectorNormalize(brush->planes[i].normal);
- brush->planes[i].dist = furthestplanedist_float(brush->planes[i].normal, brush->points, brush->numpoints);
+ brush = brushforbox_brush + ((brushforbox_index++) % MAX_BRUSHFORBOX);
+ // FIXME: optimize
+ for (i = 0;i < 8;i++)
+ {
+ v[0] = i & 1 ? maxs[0] : mins[0];
+ v[1] = i & 2 ? maxs[1] : mins[1];
+ v[2] = i & 4 ? maxs[2] : mins[2];
+ Matrix4x4_Transform(matrix, v, brush->points[i].v);
+ }
+ // FIXME: optimize!
+ for (i = 0;i < 6;i++)
+ {
+ VectorClear(v);
+ v[i >> 1] = i & 1 ? 1 : -1;
+ Matrix4x4_Transform3x3(matrix, v, brush->planes[i].normal);
+ VectorNormalize(brush->planes[i].normal);
+ brush->planes[i].dist = furthestplanedist_float(brush->planes[i].normal, brush->points, brush->numpoints);
+ }
}
Collision_ValidateBrush(brush);
return brush;
return impactdist / linelength;
}
+typedef struct colbspnode_s
+{
+ mplane_t plane;
+ struct colbspnode_s *children[2];
+ // the node is reallocated or split if max is reached
+ int numcolbrushf;
+ int maxcolbrushf;
+ colbrushf_t **colbrushflist;
+ //int numcolbrushd;
+ //int maxcolbrushd;
+ //colbrushd_t **colbrushdlist;
+}
+colbspnode_t;
+
+typedef struct colbsp_s
+{
+ mempool_t *mempool;
+ colbspnode_t *nodes;
+}
+colbsp_t;
+
+colbsp_t *Collision_CreateCollisionBSP(mempool_t *mempool)
+{
+ colbsp_t *bsp;
+ bsp = Mem_Alloc(mempool, sizeof(colbsp_t));
+ bsp->mempool = mempool;
+ bsp->nodes = Mem_Alloc(bsp->mempool, sizeof(colbspnode_t));
+ return bsp;
+}
+
+void Collision_FreeCollisionBSPNode(colbspnode_t *node)
+{
+ if (node->children[0])
+ Collision_FreeCollisionBSPNode(node->children[0]);
+ if (node->children[1])
+ Collision_FreeCollisionBSPNode(node->children[1]);
+ while (--node->numcolbrushf)
+ Mem_Free(node->colbrushflist[node->numcolbrushf]);
+ //while (--node->numcolbrushd)
+ // Mem_Free(node->colbrushdlist[node->numcolbrushd]);
+ Mem_Free(node);
+}
+
+void Collision_FreeCollisionBSP(colbsp_t *bsp)
+{
+ Collision_FreeCollisionBSPNode(bsp->nodes);
+ Mem_Free(bsp);
+}
+
+void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const colbrushf_t *end, vec3_t mins, vec3_t maxs, float startfrac, float endfrac)
+{
+ int i;
+ colpointf_t *ps, *pe;
+ float tempstart[3], tempend[3];
+ VectorLerp(start->points[0].v, startfrac, end->points[0].v, mins);
+ VectorCopy(mins, maxs);
+ for (i = 0, ps = start->points, pe = end->points;i < start->numpoints;i++, ps++, pe++)
+ {
+ VectorLerp(ps->v, startfrac, pe->v, tempstart);
+ VectorLerp(ps->v, endfrac, pe->v, tempend);
+ mins[0] = min(mins[0], min(tempstart[0], tempend[0]));
+ mins[1] = min(mins[1], min(tempstart[1], tempend[1]));
+ mins[2] = min(mins[2], min(tempstart[2], tempend[2]));
+ maxs[0] = min(maxs[0], min(tempstart[0], tempend[0]));
+ maxs[1] = min(maxs[1], min(tempstart[1], tempend[1]));
+ maxs[2] = min(maxs[2], min(tempstart[2], tempend[2]));
+ }
+}
+
int *elements;
// used to avoid tracing against the same brush more than once
int markframe;
+ // culling box
+ vec3_t mins;
+ vec3_t maxs;
}
colbrushf_t;
colbrushf_t *Collision_AllocBrushFromPermanentPolygonFloat(mempool_t *mempool, int numpoints, float *points, int supercontents);
colbrushf_t *Collision_NewBrushFromPlanes(mempool_t *mempool, int numoriginalplanes, const mplane_t *originalplanes, int supercontents);
void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end);
+void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, int supercontents);
+void Collision_TraceBrushTriangleMeshFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numtriangles, const int *element3i, const float *vertex3f, int supercontents, const vec3_t segmentmins, const vec3_t segmentmaxs);
void Collision_TraceLineBrushFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, const colbrushf_t *thatbrush_start, const colbrushf_t *thatbrush_end);
-void Collision_TraceBrushPolygonFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points);
-void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, const matrix4x4_t *polygonmatrixstart, const matrix4x4_t *polygonmatrixend);
+void Collision_TraceLinePolygonFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numpoints, const float *points, int supercontents);
+void Collision_TraceLineTriangleMeshFloat(trace_t *trace, const vec3_t linestart, const vec3_t lineend, int numtriangles, const int *element3i, const float *vertex3f, int supercontents, const vec3_t segmentmins, const vec3_t segmentmaxs);
+
+void Collision_TraceBrushPolygonTransformFloat(trace_t *trace, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int numpoints, const float *points, const matrix4x4_t *polygonmatrixstart, const matrix4x4_t *polygonmatrixend, int supercontents);
colbrushf_t *Collision_BrushForBox(const matrix4x4_t *matrix, const vec3_t mins, const vec3_t maxs);
+void Collision_BoundingBoxOfBrushTraceSegment(const colbrushf_t *start, const colbrushf_t *end, vec3_t mins, vec3_t maxs, float startfrac, float endfrac);
+
#endif
cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "1"};
+cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "-4"};
static int dlightdivtable[32768];
void R_Q3BSP_DrawFace(entity_render_t *ent, q3mface_t *face)
{
rmeshstate_t m;
- if ((face->texture->renderflags & Q3MTEXTURERENDERFLAGS_NODRAW) || !face->numtriangles)
+ if ((face->texture->renderflags & Q3MTEXTURERENDERFLAGS_NODRAW) || !face->numtriangles || R_CullBox(face->mins, face->maxs))
return;
memset(&m, 0, sizeof(m));
GL_BlendFunc(GL_ONE, GL_ZERO);
{
int i;
q3mleaf_t *leaf;
+ q3mface_t *face;
while (node->isnode)
{
if (R_CullBox(node->mins, node->maxs))
{
for (i = 0;i < leaf->numleaffaces;i++)
{
- if (leaf->firstleafface[i]->markframe != markframe)
+ face = leaf->firstleafface[i];
+ if (face->markframe != markframe)
{
- leaf->firstleafface[i]->markframe = markframe;
- R_Q3BSP_DrawFace(ent, leaf->firstleafface[i]);
+ face->markframe = markframe;
+ R_Q3BSP_DrawFace(ent, face);
}
}
}
model_t *model;
qbyte *pvs;
static int markframe = 0;
+ qglEnable(GL_POLYGON_OFFSET_FILL);
R_Mesh_Matrix(&ent->matrix);
model = ent->model;
if (r_drawcollisionbrushes.integer < 2)
{
+ qglPolygonOffset(1.0f, 0);
if (ent == &cl_entities[0].render && model->brushq3.num_pvsclusters && !r_novis.integer)
{
Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
GL_DepthMask(false);
GL_DepthTest(true);
R_Mesh_State_Texture(&m);
+ qglPolygonOffset(1.0f, r_drawcollisionbrushes_polygonoffset.value);
for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
if (model->brushq3.data_thismodel->firstbrush[i].colbrushf && model->brushq3.data_thismodel->firstbrush[i].colbrushf->numtriangles)
R_DrawCollisionBrush(model->brushq3.data_thismodel->firstbrush[i].colbrushf);
}
+ qglDisable(GL_POLYGON_OFFSET_FILL);
}
/*
}
*/
-/*
void R_Q3BSP_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)
{
+ int i;
+ q3mface_t *face;
+ vec3_t modelorg;
+ model_t *model;
+ qbyte *pvs;
+ static int markframe = 0;
+ R_Mesh_Matrix(&ent->matrix);
+ model = ent->model;
+ if (r_drawcollisionbrushes.integer < 2)
+ {
+ if (ent == &cl_entities[0].render && model->brushq3.num_pvsclusters && !r_novis.integer)
+ {
+ Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
+ pvs = model->brush.GetPVS(model, modelorg);
+ R_Q3BSP_RecursiveWorldNode(ent, model->brushq3.data_nodes, modelorg, pvs, ++markframe);
+ }
+ else
+ for (i = 0, face = model->brushq3.data_thismodel->firstface;i < model->brushq3.data_thismodel->numfaces;i++, face++)
+ R_Q3BSP_DrawFace(ent, face);
+ }
+ if (r_drawcollisionbrushes.integer >= 1)
+ {
+ rmeshstate_t m;
+ memset(&m, 0, sizeof(m));
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ GL_DepthMask(false);
+ GL_DepthTest(true);
+ R_Mesh_State_Texture(&m);
+ for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
+ if (model->brushq3.data_thismodel->firstbrush[i].colbrushf && model->brushq3.data_thismodel->firstbrush[i].colbrushf->numtriangles)
+ R_DrawCollisionBrush(model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+ }
}
-*/
static void gl_surf_start(void)
{
Cvar_RegisterVariable(&r_floatbuildlightmap);
Cvar_RegisterVariable(&r_detailtextures);
Cvar_RegisterVariable(&r_surfaceworldnode);
+ Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);
R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
}
#define VectorNormalizeDouble(v) {double ilength = sqrt(DotProduct(v,v));if (ilength) ilength = 1.0 / ilength;v[0] *= ilength;v[1] *= ilength;v[2] *= ilength;}
#define VectorDistance2(a, b) (((a)[0] - (b)[0]) * ((a)[0] - (b)[0]) + ((a)[1] - (b)[1]) * ((a)[1] - (b)[1]) + ((a)[2] - (b)[2]) * ((a)[2] - (b)[2]))
#define VectorDistance(a, b) (sqrt(VectorDistance2(a,b)))
-#define VectorLength(a) sqrt(DotProduct(a, a))
+#define VectorLength(a) (sqrt(DotProduct(a, a)))
+#define VectorLength2(a) (DotProduct(a, a))
#define VectorScale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale))
#define VectorCompare(a,b) (((a)[0]==(b)[0])&&((a)[1]==(b)[1])&&((a)[2]==(b)[2]))
#define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2])
}\
}
#define VectorRandom(v) do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1)
-#define VectorBlend(b1, b2, blend, c) do{float iblend = 1 - (blend);VectorMAM(iblend, b1, blend, b2, c);}while(0)
#define VectorLerp(v1,lerp,v2,c) ((c)[0] = (v1)[0] + (lerp) * ((v2)[0] - (v1)[0]), (c)[1] = (v1)[1] + (lerp) * ((v2)[1] - (v1)[1]), (c)[2] = (v1)[2] + (lerp) * ((v2)[2] - (v1)[2]))
#define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2])
+#define TriangleNormal(a,b,c,n) ((n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), (n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), (n)[2] = ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0]))
+
// fast PointInfrontOfTriangle
// subtracts v1 from v0 and v2, combined into a crossproduct, combined with a
// dotproduct of the light location relative to the first point of the
cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
-cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
-cvar_t r_curves_subdivide_level = {0, "r_curves_subdivide_level", "2"};
+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", "1"};
void Mod_BrushInit(void)
{
Cvar_RegisterVariable(&r_miplightmaps);
Cvar_RegisterVariable(&r_lightmaprgba);
Cvar_RegisterVariable(&r_nosurftextures);
- Cvar_RegisterVariable(&r_sortsurfaces);
- Cvar_RegisterVariable(&r_curves_subdivide_level);
+ Cvar_RegisterVariable(&mod_q3bsp_curves_subdivide_level);
+ Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
+ Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
memset(mod_q1bsp_novis, 0xff, sizeof(mod_q1bsp_novis));
}
float *originalcolor4f;
float *originaltexcoordtexture2f;
float *originaltexcoordlightmap2f;
+ float *v;
in = (void *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
continue;
}
// convert patch to Q3FACETYPE_MESH
- xlevel = r_curves_subdivide_level.integer;
- ylevel = r_curves_subdivide_level.integer;
+ xlevel = mod_q3bsp_curves_subdivide_level.integer;
+ ylevel = mod_q3bsp_curves_subdivide_level.integer;
finalwidth = ((patchsize[0] - 1) << xlevel) + 1;
finalheight = ((patchsize[1] - 1) << ylevel) + 1;
finalvertices = finalwidth * finalheight;
row1++;
}
}
+ out->numtriangles = Mod_RemoveDegenerateTriangles(out->numtriangles, out->data_element3i, out->data_element3i, out->data_vertex3f);
+ if (developer.integer)
+ {
+ if (out->numtriangles < 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->numvertices, finaltriangles, finaltriangles - out->numtriangles, out->numtriangles);
+ else
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->numvertices, out->numtriangles);
+ }
+ // q3map does not put in collision brushes for curves... ugh
+ out->collisions = true;
break;
case Q3FACETYPE_FLARE:
Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
Mod_BuildTriangleNeighbors(out->data_neighbor3i, out->data_element3i, out->numtriangles);
// for per pixel lighting
Mod_BuildTextureVectorsAndNormals(out->numvertices, out->numtriangles, out->data_vertex3f, out->data_texcoordtexture2f, out->data_element3i, out->data_svector3f, out->data_tvector3f, out->data_normal3f);
+ // calculate a bounding box
+ VectorClear(out->mins);
+ VectorClear(out->maxs);
+ if (out->numvertices)
+ {
+ VectorCopy(out->data_vertex3f, out->mins);
+ VectorCopy(out->data_vertex3f, out->maxs);
+ for (j = 1, v = out->data_vertex3f + 3;j < out->numvertices;j++, v += 3)
+ {
+ out->mins[0] = min(out->mins[0], v[0]);
+ out->maxs[0] = max(out->maxs[0], v[0]);
+ out->mins[1] = min(out->mins[1], v[1]);
+ out->maxs[1] = max(out->maxs[1], v[1]);
+ out->mins[2] = min(out->mins[2], v[2]);
+ out->maxs[2] = max(out->maxs[2], v[2]);
+ }
+ out->mins[0] -= 1.0f;
+ out->mins[1] -= 1.0f;
+ out->mins[2] -= 1.0f;
+ out->maxs[0] += 1.0f;
+ out->maxs[1] += 1.0f;
+ out->maxs[2] += 1.0f;
+ }
}
}
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)
{
int i, startside, endside;
- float dist1, dist2, midfrac, mid[3];
+ float dist1, dist2, midfrac, mid[3], segmentmins[3], segmentmaxs[3];
q3mleaf_t *leaf;
+ q3mface_t *face;
+ colbrushf_t *brush;
+ if (startfrac >= trace->fraction)
+ return;
// note: all line fragments past first impact fraction are ignored
while (node->isnode)
{
}
else
{
+ // line crosses node plane, split the line
+ midfrac = dist1 / (dist1 - dist2);
+ VectorLerp(linestart, midfrac, lineend, mid);
// take the near side first
- if (startfrac < trace->fraction)
- {
- // line crosses node plane, split the line
- midfrac = dist1 / (dist1 - dist2);
- VectorLerp(linestart, midfrac, lineend, mid);
- 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);
- }
+ 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;
}
}
// 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]);
leaf = (q3mleaf_t *)node;
for (i = 0;i < leaf->numleafbrushes;i++)
{
- if (endfrac >= trace->fraction)
+ if (startfrac >= trace->fraction)
return;
- if (leaf->firstleafbrush[i]->colbrushf && leaf->firstleafbrush[i]->colbrushf->markframe != markframe)
+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe)
{
- leaf->firstleafbrush[i]->colbrushf->markframe = markframe;
- Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ brush->markframe = markframe;
+ if (BoxesOverlap(segmentmins, segmentmaxs, brush->mins, brush->maxs))
+ Collision_TraceLineBrushFloat(trace, linestart, lineend, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
+ }
+ }
+ if (mod_q3bsp_curves_collisions.integer)
+ {
+ for (i = 0;i < leaf->numleaffaces;i++)
+ {
+ if (startfrac >= trace->fraction)
+ return;
+ face = leaf->firstleafface[i];
+ if (face->collisions && face->collisionmarkframe != markframe)
+ {
+ face->collisionmarkframe = markframe;
+ if (BoxesOverlap(segmentmins, segmentmaxs, face->mins, face->maxs))
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, face->numtriangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ }
}
}
}
-static void Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace_t *trace, q3mnode_t *node, const colbrushf_t *thisbrush_start, const colbrushf_t *thisbrush_end, int markframe)
+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;
- float dist;
- colpointf_t *ps, *pe;
+ int i, 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)
+ {
+ 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);
+ }
+ else if (sides == 2)
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe, segmentmins, segmentmaxs);
+ else // sides == 1
+ 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++)
{
if (DotProduct(ps->v, node->plane->normal) >= dist || DotProduct(pe->v, node->plane->normal) >= dist)
{
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe);
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[0], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
break;
}
}
+ */
+ /*
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++)
{
if (DotProduct(ps->v, node->plane->normal) <= dist || DotProduct(pe->v, node->plane->normal) <= dist)
{
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe);
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, node->children[1], thisbrush_start, thisbrush_end, markframe, nodesegmentmins, nodesegmentmaxs);
break;
}
}
+ */
/*
sides = BoxOnPlaneSide(boxstartmins, boxstartmaxs, node->plane) | BoxOnPlaneSide(boxendmins, boxendmaxs, node->plane);
if (sides & 1)
leaf = (q3mleaf_t *)node;
for (i = 0;i < leaf->numleafbrushes;i++)
{
- if (leaf->firstleafbrush[i]->colbrushf && leaf->firstleafbrush[i]->colbrushf->markframe != markframe)
+ brush = leaf->firstleafbrush[i]->colbrushf;
+ if (brush && brush->markframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, brush->mins, brush->maxs))
{
- leaf->firstleafbrush[i]->colbrushf->markframe = markframe;
+ brush->markframe = markframe;
Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, leaf->firstleafbrush[i]->colbrushf, leaf->firstleafbrush[i]->colbrushf);
}
}
+ if (mod_q3bsp_curves_collisions.integer)
+ {
+ for (i = 0;i < leaf->numleaffaces;i++)
+ {
+ 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->numtriangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ }
+ }
}
}
static void Mod_Q3BSP_TraceBox(model_t *model, trace_t *trace, const vec3_t boxstartmins, const vec3_t boxstartmaxs, const vec3_t boxendmins, const vec3_t boxendmaxs, int hitsupercontentsmask)
{
int i;
+ float segmentmins[3], segmentmaxs[3];
colbrushf_t *thisbrush_start, *thisbrush_end;
matrix4x4_t startmatrix, endmatrix;
static int markframe = 0;
+ q3mface_t *face;
memset(trace, 0, sizeof(*trace));
trace->fraction = 1;
trace->hitsupercontentsmask = hitsupercontentsmask;
Matrix4x4_CreateIdentity(&startmatrix);
Matrix4x4_CreateIdentity(&endmatrix);
- if (VectorCompare(boxstartmins, boxstartmaxs) && VectorCompare(boxendmins, boxendmaxs))
+ 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))
{
// 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)
+ {
+ 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->numtriangles, 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);
}
else
{
- // box trace, performed as box trace
+ // box trace, performed as brush trace
thisbrush_start = Collision_BrushForBox(&startmatrix, boxstartmins, boxstartmaxs);
thisbrush_end = Collision_BrushForBox(&endmatrix, boxendmins, boxendmaxs);
if (model->brushq3.submodel)
for (i = 0;i < model->brushq3.data_thismodel->numbrushes;i++)
if (model->brushq3.data_thismodel->firstbrush[i].colbrushf)
Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, model->brushq3.data_thismodel->firstbrush[i].colbrushf, model->brushq3.data_thismodel->firstbrush[i].colbrushf);
+ if (mod_q3bsp_curves_collisions.integer)
+ {
+ for (i = 0;i < model->brushq3.data_thismodel->numfaces;i++)
+ {
+ face = model->brushq3.data_thismodel->firstface + i;
+ if (face->collisions)
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, face->numtriangles, face->data_element3i, face->data_vertex3f, face->texture->supercontents, segmentmins, segmentmaxs);
+ }
+ }
}
else
- Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model->brushq3.data_nodes, thisbrush_start, thisbrush_end, ++markframe);
+ Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model->brushq3.data_nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
}
}
float corner[3], yawradius, modelradius;
mod->type = mod_brushq3;
+ mod->numframes = 1;
+ mod->numskins = 1;
header = (q3dheader_t *)buffer;
return i;
}
+int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
+{
+ int i, outtriangles;
+ float d, edgedir[3], temp[3];
+ // a degenerate triangle is one with no width (thickness, surface area)
+ // these are characterized by having all 3 points colinear (along a line)
+ // or having two points identical
+ for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
+ {
+ // calculate first edge
+ VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir);
+ if (VectorLength2(edgedir) < 0.0001f)
+ continue; // degenerate first edge (no length)
+ VectorNormalize(edgedir);
+ // check if third point is on the edge (colinear)
+ d = -DotProduct(vertex3f + inelement3i[2] * 3, edgedir);
+ VectorMA(vertex3f + inelement3i[2] * 3, d, edgedir, temp);
+ if (VectorLength2(temp) < 0.0001f)
+ continue; // third point colinear with first edge
+ // valid triangle (no colinear points, no duplicate points)
+ VectorCopy(inelement3i, outelement3i);
+ outelement3i += 3;
+ outtriangles++;
+ }
+ return outtriangles;
+}
struct q3mtexture_s *texture;
struct q3meffect_s *effect;
rtexture_t *lightmaptexture;
+ int collisions; // performs per triangle collisions on this surface
+ int collisionmarkframe; // don't collide twice in one trace
int type;
int firstvertex;
int numvertices;
int numelements;
int patchsize[2];
int markframe;
+ // bounding box for culling
+ float mins[3];
+ float maxs[3];
float *data_vertex3f;
float *data_texcoordtexture2f;
void Mod_FreeSkinFiles(skinfile_t *skinfile);
int Mod_CountSkinFiles(skinfile_t *skinfile);
+int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f);
+
#endif // __MODEL__
testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
- if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_WORLDONLY, NULL).fraction == 1)
+ sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, testeye, testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
+ if (trace.fraction == 1)
client->visibletime[e] = realtime + 1;
else
{
testorigin[1] = bound(entmins[1], testeye[1], entmaxs[1]);
testorigin[2] = bound(entmins[2], testeye[2], entmaxs[2]);
- if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_WORLDONLY, NULL).fraction == 1)
+ sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, testeye, testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
+ if (trace.fraction == 1)
client->visibletime[e] = realtime + 1;
else if (realtime > client->visibletime[e])
{
MSG_WriteShort (msg,e);
else
MSG_WriteByte (msg,e);
- if (bits & U_MODEL) MSG_WriteByte (msg, ent->v->modelindex);
- if (bits & U_FRAME) MSG_WriteByte (msg, ent->v->frame);
- if (bits & U_COLORMAP) MSG_WriteByte (msg, ent->v->colormap);
- if (bits & U_SKIN) MSG_WriteByte (msg, ent->v->skin);
- if (bits & U_EFFECTS) MSG_WriteByte (msg, ent->v->effects);
- if (bits & U_ORIGIN1) MSG_WriteDPCoord (msg, origin[0]);
+ if (bits & U_MODEL) MSG_WriteByte(msg, ent->v->modelindex);
+ if (bits & U_FRAME) MSG_WriteByte(msg, ent->v->frame);
+ if (bits & U_COLORMAP) MSG_WriteByte(msg, ent->v->colormap);
+ if (bits & U_SKIN) MSG_WriteByte(msg, ent->v->skin);
+ if (bits & U_EFFECTS) MSG_WriteByte(msg, ent->v->effects);
+ if (bits & U_ORIGIN1) MSG_WriteDPCoord(msg, origin[0]);
if (bits & U_ANGLE1) MSG_WriteAngle(msg, angles[0]);
- if (bits & U_ORIGIN2) MSG_WriteDPCoord (msg, origin[1]);
+ if (bits & U_ORIGIN2) MSG_WriteDPCoord(msg, origin[1]);
if (bits & U_ANGLE2) MSG_WriteAngle(msg, angles[1]);
- if (bits & U_ORIGIN3) MSG_WriteDPCoord (msg, origin[2]);
+ if (bits & U_ORIGIN3) MSG_WriteDPCoord(msg, origin[2]);
if (bits & U_ANGLE3) MSG_WriteAngle(msg, angles[2]);
// LordHavoc: new stuff
testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f;
testorigin[1] = (entmins[1] + entmaxs[1]) * 0.5f;
testorigin[2] = (entmins[2] + entmaxs[2]) * 0.5f;
- trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_WORLDONLY, NULL);
+ sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
else
testorigin[0] = lhrandom(entmins[0], entmaxs[0]);
testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
- trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_WORLDONLY, NULL);
+ sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
else
testorigin[0] = lhrandom(lightmins[0], lightmaxs[0]);
testorigin[1] = lhrandom(lightmins[1], lightmaxs[1]);
testorigin[2] = lhrandom(lightmins[2], lightmaxs[2]);
- trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_WORLDONLY, NULL);
+ sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
}
ent->v->angles[1] += trace.fraction * pushangles[1];
SV_LinkEdict (ent, true);
- if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
+ if (trace.fraction < 1 && trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
SV_Impact (ent, trace.ent);
return trace;
}
-n darkplaces: fix a crash when changing level while using qe1 textures (Todd)
-n darkplaces: revert noclip movement to match nq for compatibility with mods that trap movement as input (MauveBib)
-n dpmod: make grapple off-hand (joe hill)
+2 darkplaces: write a readme (Antti)
+0 darkplaces: add graphics options menu and put realtime lighting stuff in it (Antti)
+0 darkplaces: add cl_particles_particleffect_bloodhack cvar to menu (Alex Boveri)
+0 darkplaces: add cl_particles_particleffect_bloodhack cvar to enable converting id1 blood effects to TE_BLOOD style (Alex Boveri)
+0 darkplaces: add slowmo to options menu (Cristian Beltramo)
+0 darkplaces: noclipping out the ceiling of q3dm17 crashes (Static_Fiend)
+0 dpmod: add support for info_player_deathmatch in singleplayer for q3 compatibility (Static_Fiend)
+0 dpmod: add target_position entity for a touch of q3 compatibility on jumppads (Static_Fiend)
+0 darkplaces: add support for multiple -game's (note: this needs an enhanced COM_CheckParm to find the multiple matches) (Static_Fiend)
+0 darkplaces: dedicated server hosting prydon with multiple players exhibited severe networking bugs in tests, including failure to find acked network frames, and a segfault (Supajoe, Uffe, FrikaC, Harb)
0 darkplaces: add chase_pitch cvar to control pitch angle of chase camera, and chase_angle cvar to control yaw angle of chase camera, and add back chase_right cvar (Electro)
0 darkplaces: add a scr_screenshot_jpeg_quality cvar (Electro)
0 darkplaces: shadows are not working with model tag attachments (Electro)
// size when clipping against monsters
vec3_t mins2, maxs2;
- // size when clipping against brush models
- vec3_t hullmins, hullmaxs;
-
// start and end origin of move
vec3_t start, end;
Matrix4x4_Invert_Simple(&imatrix, &matrix);
Matrix4x4_Transform(&imatrix, start, starttransformed);
Matrix4x4_Transform(&imatrix, end, endtransformed);
- VectorAdd(starttransformed, maxs, starttransformedmaxs);
- VectorAdd(endtransformed, maxs, endtransformedmaxs);
- VectorAdd(starttransformed, mins, starttransformedmins);
- VectorAdd(endtransformed, mins, endtransformedmins);
if (model && model->brush.TraceBox)
+ {
+ VectorAdd(starttransformed, maxs, starttransformedmaxs);
+ VectorAdd(endtransformed, maxs, endtransformedmaxs);
+ VectorAdd(starttransformed, mins, starttransformedmins);
+ VectorAdd(endtransformed, mins, endtransformedmins);
model->brush.TraceBox(model, &trace, starttransformedmins, starttransformedmaxs, endtransformedmins, endtransformedmaxs, SUPERCONTENTS_SOLID);
+ }
else
Collision_ClipTrace_Box(&trace, ent->v->mins, ent->v->maxs, starttransformed, mins, maxs, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID);
if (trace.fraction < 1 || trace.startsolid)
+ {
trace.ent = ent;
- VectorLerp(start, trace.fraction, end, trace.endpos);
- VectorCopy(trace.plane.normal, tempnormal);
- Matrix4x4_Transform3x3(&matrix, tempnormal, trace.plane.normal);
- // FIXME: should recalc trace.plane.dist
+ VectorLerp(start, trace.fraction, end, trace.endpos);
+ VectorCopy(trace.plane.normal, tempnormal);
+ Matrix4x4_Transform3x3(&matrix, tempnormal, trace.plane.normal);
+ // FIXME: should recalc trace.plane.dist
+ }
+ else
+ VectorCopy(end, trace.endpos);
return trace;
}
// might interact, so do an exact clip
if (touch->v->solid == SOLID_BSP)
- trace = SV_ClipMoveToEntity (touch, clip->start, clip->hullmins, clip->hullmaxs, clip->end);
+ trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
else if ((int)touch->v->flags & FL_MONSTER)
trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
else
trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict)
{
moveclip_t clip;
- vec3_t bigmins, bigmaxs;
+ vec3_t hullmins, hullmaxs;
areagrid_t *grid;
int i, igrid[3], igridmins[3], igridmaxs[3];
VectorCopy(end, clip.end);
VectorCopy(mins, clip.mins);
VectorCopy(maxs, clip.maxs);
- VectorCopy(mins, clip.hullmins);
- VectorCopy(maxs, clip.hullmaxs);
+ VectorCopy(mins, clip.mins2);
+ VectorCopy(maxs, clip.maxs2);
clip.type = type;
clip.passedict = passedict;
- if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
- sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, clip.hullmins, clip.hullmaxs);
-
// clip to world
- clip.trace = SV_ClipMoveToEntity(sv.edicts, clip.start, clip.hullmins, clip.hullmaxs, clip.end);
+ clip.trace = SV_ClipMoveToEntity(sv.edicts, clip.start, clip.mins, clip.maxs, clip.end);
if (clip.type == MOVE_WORLDONLY)
//if (clip.trace.allsolid)
return clip.trace;
if (clip.type == MOVE_MISSILE)
{
- // LordHavoc: modified this, was = -15, now = clip.mins[i] - 15
- for (i=0 ; i<3 ; i++)
+ // LordHavoc: modified this, was = -15, now -= 15
+ for (i = 0;i < 3;i++)
{
- clip.mins2[i] = clip.mins[i] - 15;
- clip.maxs2[i] = clip.maxs[i] + 15;
+ clip.mins2[i] -= 15;
+ clip.maxs2[i] += 15;
}
}
+
+ // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
+ if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
+ sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, hullmins, hullmaxs);
else
{
- VectorCopy (clip.mins, clip.mins2);
- VectorCopy (clip.maxs, clip.maxs2);
+ VectorCopy(clip.mins, hullmins);
+ VectorCopy(clip.maxs, hullmaxs);
}
- bigmins[0] = min(clip.mins2[0], clip.hullmins[0]);
- bigmaxs[0] = max(clip.maxs2[0], clip.hullmaxs[0]);
- bigmins[1] = min(clip.mins2[1], clip.hullmins[1]);
- bigmaxs[1] = max(clip.maxs2[1], clip.hullmaxs[1]);
- bigmins[2] = min(clip.mins2[2], clip.hullmins[2]);
- bigmaxs[2] = max(clip.maxs2[2], clip.hullmaxs[2]);
-
// create the bounding box of the entire move
- if (!sv_debugmove.integer)
+ for (i = 0;i < 3;i++)
{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if (clip.trace.endpos[i] > clip.start[i])
- {
- clip.boxmins[i] = clip.start[i] + bigmins[i] - 1;
- clip.boxmaxs[i] = clip.trace.endpos[i] + bigmaxs[i] + 1;
- }
- else
- {
- clip.boxmins[i] = clip.trace.endpos[i] + bigmins[i] - 1;
- clip.boxmaxs[i] = clip.start[i] + bigmaxs[i] + 1;
- }
- }
+ clip.boxmins[i] = min(clip.start[i], clip.trace.endpos[i]) + min(hullmins[i], clip.mins2[i]) - 1;
+ clip.boxmaxs[i] = max(clip.start[i], clip.trace.endpos[i]) + max(hullmaxs[i], clip.maxs2[i]) + 1;
}
- else
+
+ // debug override to test against everything
+ if (sv_debugmove.integer)
{
- // debug to test against everything
clip.boxmins[0] = clip.boxmins[1] = clip.boxmins[2] = -999999999;
clip.boxmaxs[0] = clip.boxmaxs[1] = clip.boxmaxs[2] = 999999999;
}