diff --git a/libs/mathlib.h b/libs/mathlib.h index aafe568..bf94f20 100644 --- a/libs/mathlib.h +++ b/libs/mathlib.h @@ -335,6 +335,9 @@ typedef vec_accu_t vec3_accu_t[3]; #define VectorCopyAccu(a, b) ((b)[0] = (a)[0], (b)[1] = (a)[1], (b)[2] = (a)[2]) #define VectorScaleAccu(a, b, c) ((c)[0] = (b) * (a)[0], (c)[1] = (b) * (a)[1], (c)[2] = (b) * (a)[2]) #define CrossProductAccu(a, b, c) ((c)[0] = (a)[1] * (b)[2] - (a)[2] * (b)[1], (c)[1] = (a)[2] * (b)[0] - (a)[0] * (b)[2], (c)[2] = (a)[0] * (b)[1] - (a)[1] * (b)[0]) +#define Q_rintAccu(in) ((vec_accu_t) floor(in + 0.5)) + +vec_accu_t VectorLengthAccu(vec3_accu_t v); #ifdef __cplusplus } diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c index 33945cd..a710fb3 100644 --- a/libs/mathlib/mathlib.c +++ b/libs/mathlib/mathlib.c @@ -63,6 +63,11 @@ vec_t VectorLength(vec3_t v) return length; } +vec_accu_t VectorLengthAccu(vec3_accu_t v) +{ + return (vec_accu_t) sqrt((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2])); +} + qboolean VectorCompare (vec3_t v1, vec3_t v2) { int i; diff --git a/tools/quake3/common/polylib.c b/tools/quake3/common/polylib.c index 79eb3fb..2ff3278 100644 --- a/tools/quake3/common/polylib.c +++ b/tools/quake3/common/polylib.c @@ -459,6 +459,28 @@ winding_t *CopyWinding (winding_t *w) return c; } +/* +================== +CopyWindingAccuToNormal +================== +*/ +winding_t *CopyWindingAccuToNormal(winding_accu_t *w) +{ + int i; + winding_t *c; + + c = AllocWinding(w->numpoints); + c->numpoints = w->numpoints; + for (i = 0; i < c->numpoints; i++) + { + // TODO: Add VectorCopyAccuToNormal() to mathlib.h. + c->p[i][0] = (vec_t) w->p[i][0]; + c->p[i][1] = (vec_t) w->p[i][1]; + c->p[i][2] = (vec_t) w->p[i][2]; + } + return c; +} + /* ================== ReverseWinding diff --git a/tools/quake3/common/polylib.h b/tools/quake3/common/polylib.h index 558c8a2..54795f7 100644 --- a/tools/quake3/common/polylib.h +++ b/tools/quake3/common/polylib.h @@ -70,3 +70,5 @@ typedef struct winding_accu_t *BaseWindingForPlaneAccu(vec3_t normal, vec_t dist); void ChopWindingInPlaceAccu(winding_accu_t **w, vec3_t normal, vec_t dist, vec_t epsilon); +winding_t *CopyWindingAccuToNormal(winding_accu_t *w); +void FreeWindingAccu(winding_accu_t *w); diff --git a/tools/quake3/q3map2/brush.c b/tools/quake3/q3map2/brush.c index abe3145..f19a30d 100644 --- a/tools/quake3/q3map2/brush.c +++ b/tools/quake3/q3map2/brush.c @@ -277,6 +277,34 @@ void SnapWeldVector( vec3_t a, vec3_t b, vec3_t out ) } } +void SnapWeldVectorAccu(vec3_accu_t a, vec3_accu_t b, vec3_accu_t out) +{ + // I have very serious concerns about this function. + // This is a first pass where I just copy the original SnapWeldVector() + // and make sure it works with the higher resolution data types. + // TODO: Examine this function with a fine-toothed comb. + + int i; + vec_accu_t ai, bi, outi; + + if (a == NULL || b == NULL || out == NULL) return; + + for (i = 0; i < 3; i++) + { + ai = Q_rintAccu(a[i]); + bi = Q_rintAccu(a[i]); // Note, it's using a[i]. This is from legacy code. + + if (ai == a[i]) out[i] = a[i]; + else if (bi == b[i]) out[i] = b[i]; + + else if (fabs(ai - a[i]) < fabs(bi < b[i])) out[i] = a[i]; + else out[i] = b[i]; + + outi = Q_rintAccu(out[i]); + if (fabs(outi - out[i]) <= SNAP_EPSILON) out[i] = outi; + } +} + /* @@ -338,11 +366,44 @@ qboolean FixWinding( winding_t *w ) return valid; } +qboolean FixWindingAccu(winding_accu_t *w) +{ + // Serious doubts about this function. Will check it out later. + // This is just a copy from the original for high res data types. + // TODO: Examine this function with a fine-toothed comb. + qboolean valid = qtrue; + int i, j, k; + vec3_accu_t vec; + vec_accu_t dist; + if (!w) return qfalse; + for (i = 0; i < w->numpoints; i++) + { + if (w->numpoints == 3) return valid; + j = (i + 1) % w->numpoints; + VectorSubtractAccu(w->p[i], w->p[j], vec); + dist = VectorLengthAccu(vec); + if (dist < DEGENERATE_EPSILON) + { + valid = qfalse; + SnapWeldVectorAccu(w->p[i], w->p[j], vec); + VectorCopyAccu(vec, w->p[i]); + for (k = i + 2; k < w->numpoints; k++) { + VectorCopyAccu(w->p[k], w->p[k - 1]); + } + w->numpoints--; + } + } + + if (w->numpoints < 3) valid = qfalse; + return valid; +} + +#define EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES 1 /* CreateBrushWindings() @@ -353,7 +414,11 @@ returns false if the brush doesn't enclose a valid volume qboolean CreateBrushWindings( brush_t *brush ) { int i, j; +#ifdef EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES + winding_accu_t *w; +#else winding_t *w; +#endif side_t *side; plane_t *plane; @@ -366,7 +431,11 @@ qboolean CreateBrushWindings( brush_t *brush ) plane = &mapplanes[ side->planenum ]; /* make huge winding */ +#ifdef EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES + w = BaseWindingForPlaneAccu(plane->normal, plane->dist); +#else w = BaseWindingForPlane( plane->normal, plane->dist ); +#endif /* walk the list of brush sides */ for( j = 0; j < brush->numsides && w != NULL; j++ ) @@ -378,14 +447,27 @@ qboolean CreateBrushWindings( brush_t *brush ) if( brush->sides[ j ].bevel ) continue; plane = &mapplanes[ brush->sides[ j ].planenum ^ 1 ]; +#ifdef EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES + ChopWindingInPlaceAccu(&w, plane->normal, plane->dist, 0); +#else ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); // CLIP_EPSILON ); +#endif /* ydnar: fix broken windings that would generate trifans */ +#ifdef EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES + FixWindingAccu(w); +#else FixWinding( w ); +#endif } /* set side winding */ +#ifdef EXPERIMENTAL_HIGH_PRECISION_MATH_Q3MAP2_FIXES + side->winding = CopyWindingAccuToNormal(w); + FreeWindingAccu(w); +#else side->winding = w; +#endif } /* find brush bounds */