/* ======================================================================================================================================= RemoveColinearPoints ======================================================================================================================================= */ void RemoveColinearPoints(winding_t *w) { int i, j, k; vec3_t v1, v2; int nump = 0; vec3_t p[MAX_POINTS_ON_WINDING]; for (i = 0; i < w->numpoints; i++) { j = (i + 1)%w->numpoints; k = (i + w->numpoints - 1)%w->numpoints; VectorSubtract(w->p[j], w->p[i], v1); VectorSubtract(w->p[i], w->p[k], v2); vec3_norm2(v1, v1); vec3_norm2(v2, v2); if (DotProduct(v1, v2) < 0.999f) { VectorCopy(w->p[i], p[nump]); nump++; } } if (nump == w->numpoints) { return; } c_removed += w->numpoints - nump; w->numpoints = nump; Com_Memcpy(w->p, p, nump * sizeof(p[0])); }
static box_t get_box(const vec3_t *p0, const vec3_t *p1, const vec3_t *n, float r, const plane_t *plane) { mat4_t rot; box_t box; if (p1 == NULL) { box = bbox_from_extents(*p0, r, r, r); box = box_swap_axis(box, 2, 0, 1); return box; } if (r == 0) { box = bbox_grow(bbox_from_points(*p0, *p1), 0.5, 0.5, 0.5); // Apply the plane rotation. rot = plane->mat; rot.vecs[3] = vec4(0, 0, 0, 1); mat4_imul(&box.mat, rot); return box; } // Create a box for a line: int i; const vec3_t AXES[] = {vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1)}; box.mat = mat4_identity; box.p = vec3_mix(*p0, *p1, 0.5); box.d = vec3_sub(*p1, box.p); for (i = 0; i < 3; i++) { box.w = vec3_cross(box.d, AXES[i]); if (vec3_norm2(box.w) > 0) break; } if (i == 3) return box; box.w = vec3_mul(vec3_normalized(box.w), r); box.h = vec3_mul(vec3_normalized(vec3_cross(box.d, box.w)), r); return box; }
/* ======================================================================================================================================= BaseWindingForPlane ======================================================================================================================================= */ winding_t *BaseWindingForPlane(vec3_t normal, vec_t dist) { int i, x = -1; vec_t max = -MAX_MAP_BOUNDS, v; vec3_t org, vright, vup; winding_t *w; // find the major axis for (i = 0; i < 3; i++) { v = Q_fabs(normal[i]); if (v > max) { x = i; max = v; } } if (x == -1) { Com_Error(ERR_DROP, "BaseWindingForPlane: no axis found"); } VectorCopy(vec3_origin, vup); switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } v = DotProduct(vup, normal); VectorMA(vup, -v, normal, vup); vec3_norm2(vup, vup); VectorScale(normal, dist, org); vec3_cross(vup, normal, vright); VectorScale(vup, MAX_MAP_BOUNDS, vup); VectorScale(vright, MAX_MAP_BOUNDS, vright); // project a really big axis aligned box onto the plane w = AllocWinding(4); VectorSubtract(org, vright, w->p[0]); VectorAdd(w->p[0], vup, w->p[0]); VectorAdd(org, vright, w->p[1]); VectorAdd(w->p[1], vup, w->p[1]); VectorAdd(org, vright, w->p[2]); VectorSubtract(w->p[2], vup, w->p[2]); VectorSubtract(org, vright, w->p[3]); VectorSubtract(w->p[3], vup, w->p[3]); w->numpoints = 4; return w; }
/* ======================================================================================================================================= WindingPlane ======================================================================================================================================= */ void WindingPlane(winding_t *w, vec3_t normal, vec_t *dist) { vec3_t v1, v2; VectorSubtract(w->p[1], w->p[0], v1); VectorSubtract(w->p[2], w->p[0], v2); vec3_cross(v2, v1, normal); vec3_norm2(normal, normal); *dist = DotProduct(w->p[0], normal); }
/* ======================================================================================================================================= AddWindingToConvexHull Both w and *hull are on the same plane. ======================================================================================================================================= */ void AddWindingToConvexHull(winding_t *w, winding_t **hull, vec3_t normal) { int i, j, k; float *p, *copy; vec3_t dir; float d; int numHullPoints, numNew; vec3_t hullPoints[MAX_HULL_POINTS]; vec3_t newHullPoints[MAX_HULL_POINTS]; vec3_t hullDirs[MAX_HULL_POINTS]; qboolean hullSide[MAX_HULL_POINTS]; qboolean outside; if (!*hull) { *hull = CopyWinding(w); return; } numHullPoints = (*hull)->numpoints; Com_Memcpy(hullPoints, (*hull)->p, numHullPoints * sizeof(vec3_t)); for (i = 0; i < w->numpoints; i++) { p = w->p[i]; // calculate hull side vectors for (j = 0; j < numHullPoints; j++) { k = (j + 1) % numHullPoints; VectorSubtract(hullPoints[k], hullPoints[j], dir); vec3_norm2(dir, dir); vec3_cross(normal, dir, hullDirs[j]); } outside = qfalse; for (j = 0; j < numHullPoints; j++) { VectorSubtract(p, hullPoints[j], dir); d = DotProduct(dir, hullDirs[j]); if (d >= ON_EPSILON) { outside = qtrue; } if (d >= -ON_EPSILON) { hullSide[j] = qtrue; } else { hullSide[j] = qfalse; } } // if the point is effectively inside, do nothing if (!outside) { continue; } // find the back side to front side transition for (j = 0; j < numHullPoints; j++) { if (!hullSide[j % numHullPoints] && hullSide[(j + 1) % numHullPoints]) { break; } } if (j == numHullPoints) { continue; } // insert the point here VectorCopy(p, newHullPoints[0]); numNew = 1; // copy over all points that aren't double fronts j = (j + 1)%numHullPoints; for (k = 0; k < numHullPoints; k++) { if (hullSide[(j + k) % numHullPoints] && hullSide[(j + k + 1) % numHullPoints]) { continue; } copy = hullPoints[(j + k + 1) % numHullPoints]; VectorCopy(copy, newHullPoints[numNew]); numNew++; } numHullPoints = numNew; Com_Memcpy(hullPoints, newHullPoints, numHullPoints * sizeof(vec3_t)); } FreeWinding(*hull); w = AllocWinding(numHullPoints); w->numpoints = numHullPoints; *hull = w; Com_Memcpy(w->p, hullPoints, numHullPoints * sizeof(vec3_t)); }
/* ======================================================================================================================================= CheckWinding ======================================================================================================================================= */ void CheckWinding(winding_t *w) { int i, j; vec_t *p1, *p2; vec_t d, edgedist; vec3_t dir, edgenormal, facenormal; vec_t area; vec_t facedist; if (w->numpoints < 3) { Com_Error(ERR_DROP, "CheckWinding: %i points", w->numpoints); } area = WindingArea(w); if (area < 1) { Com_Error(ERR_DROP, "CheckWinding: %f area", (double)area); } WindingPlane(w, facenormal, &facedist); for (i = 0; i < w->numpoints; i++) { p1 = w->p[i]; for (j = 0; j < 3; j++) { if (p1[j] > MAX_MAP_BOUNDS || p1[j] < -MAX_MAP_BOUNDS) { Com_Error(ERR_DROP, "CheckWinding: MAX_MAP_BOUNDS: %f", (double)p1[j]); } } j = i + 1 == w->numpoints ? 0 : i + 1; // check the point is on the face plane d = DotProduct(p1, facenormal) - facedist; if (d < -ON_EPSILON || d > ON_EPSILON) { Com_Error(ERR_DROP, "CheckWinding: point off plane"); } // check the edge isn't degenerate p2 = w->p[j]; VectorSubtract(p2, p1, dir); if (vec3_length(dir) < ON_EPSILON) { Com_Error(ERR_DROP, "CheckWinding: degenerate edge"); } vec3_cross(facenormal, dir, edgenormal); vec3_norm2(edgenormal, edgenormal); edgedist = DotProduct(p1, edgenormal); edgedist += ON_EPSILON; // all other points must be on front side for (j = 0; j < w->numpoints; j++) { if (j == i) { continue; } d = DotProduct(w->p[j], edgenormal); if (d > edgedist) { Com_Error(ERR_DROP, "CheckWinding: non-convex"); } } } }