index ea18cf4..cf7569d 100644 (file)
--- a/curves.c
+++ b/curves.c
@@ -136,18 +136,18 @@ void Q3PatchTesselateFloat(int numcomponents, int outputstride, float *outputver
#endif
}

-static int Q3PatchTesselation(float largestsquared2xcurvearea, float tolerance)
+static int Q3PatchTesselation(float largestsquared3xcurvearea, float tolerance)
{
float f;
// f is actually a squared 2x curve area... so the formula had to be adjusted to give roughly the same subdivisions
-       f = pow(largestsquared2xcurvearea / 64.0, 0.25) / tolerance;
+       f = pow(largestsquared3xcurvearea / 64.0f, 0.25f) / tolerance;
//if(f < 0.25) // VERY flat patches
if(f < 0.0001) // TOTALLY flat patches
return 0;
else if(f < 2)
return 1;
else
-               return (int) floor(log(f) / log(2)) + 1;
+               return (int) floor(log(f) / log(2.0f)) + 1;
// this is always at least 2
// maps [0.25..0.5[ to -1 (actually, 1 is returned)
// maps [0.5..1[ to 0 (actually, 1 is returned)
@@ -156,7 +156,7 @@ static int Q3PatchTesselation(float largestsquared2xcurvearea, float tolerance)
// maps [4..8[ to 4
}

-float Squared2xCurveArea(const float *a, const float *control, const float *b, int components)
+static float Squared3xCurveArea(const float *a, const float *control, const float *b, int components)
{
#if 0
// mimicing the old behaviour with the new code...
@@ -178,6 +178,13 @@ float Squared2xCurveArea(const float *a, const float *control, const float *b, i
// but as this is hard to calculate, let's calculate an upper bound of it:
// the area of the triangle a->control->b->a.
//
+       // one can prove that the area of a quadratic spline = 2/3 * the area of
+       // the triangle of its control points!
+       // to do it, first prove it for the spline through (0,0), (1,1), (2,0)
+       // (which is a parabola) and then note that moving the control point
+       // left/right is just shearing and keeps the area of both the spline and
+       // the triangle invariant.
+       //
// why are we going for the spline area anyway?
// we know that:
//
@@ -186,6 +193,8 @@ float Squared2xCurveArea(const float *a, const float *control, const float *b, i
//
//   also, on circle-like or parabola-like curves, you easily get that the
//   double amount of line approximation segments reduces the error to its quarter
+       //   (also, easy to prove for splines by doing it for one specific one, and using
+       //   affine transforms to get all other splines)
//
// so...
//
@@ -214,7 +223,8 @@ float Squared2xCurveArea(const float *a, const float *control, const float *b, i
bb += xb * xb;
}
// area is 0.5 * sqrt(aa*bb - ab*ab)
-       // 2x area is sqrt(aa*bb - ab*ab)
+       // 2x TRIANGLE area is sqrt(aa*bb - ab*ab)
+       // 3x CURVE area is sqrt(aa*bb - ab*ab)
return aa * bb - ab * ab;
#endif
}
@@ -224,19 +234,19 @@ int Q3PatchTesselationOnX(int patchwidth, int patchheight, int components, const
{
int x, y;
const float *patch;
-       float squared2xcurvearea, largestsquared2xcurvearea;
-       largestsquared2xcurvearea = 0;
+       float squared3xcurvearea, largestsquared3xcurvearea;
+       largestsquared3xcurvearea = 0;
for (y = 0;y < patchheight;y++)
{
for (x = 0;x < patchwidth-1;x += 2)
{
patch = in + ((y * patchwidth) + x) * components;
-                       squared2xcurvearea = Squared2xCurveArea(&patch, &patch[components], &patch[2*components], components);
-                       if (largestsquared2xcurvearea < squared2xcurvearea)
-                               largestsquared2xcurvearea = squared2xcurvearea;
+                       squared3xcurvearea = Squared3xCurveArea(&patch, &patch[components], &patch[2*components], components);
+                       if (largestsquared3xcurvearea < squared3xcurvearea)
+                               largestsquared3xcurvearea = squared3xcurvearea;
}
}
-       return Q3PatchTesselation(largestsquared2xcurvearea, tolerance);
+       return Q3PatchTesselation(largestsquared3xcurvearea, tolerance);
}

// returns how much tesselation of each segment is needed to remain under tolerance
@@ -244,19 +254,19 @@ int Q3PatchTesselationOnY(int patchwidth, int patchheight, int components, const
{
int x, y;
const float *patch;
-       float squared2xcurvearea, largestsquared2xcurvearea;
-       largestsquared2xcurvearea = 0;
+       float squared3xcurvearea, largestsquared3xcurvearea;
+       largestsquared3xcurvearea = 0;
for (y = 0;y < patchheight-1;y += 2)
{
for (x = 0;x < patchwidth;x++)
{
patch = in + ((y * patchwidth) + x) * components;
-                       squared2xcurvearea = Squared2xCurveArea(&patch, &patch[patchwidth*components], &patch[2*patchwidth*components], components);
-                       if (largestsquared2xcurvearea < squared2xcurvearea)
-                               largestsquared2xcurvearea = squared2xcurvearea;
+                       squared3xcurvearea = Squared3xCurveArea(&patch, &patch[patchwidth*components], &patch[2*patchwidth*components], components);
+                       if (largestsquared3xcurvearea < squared3xcurvearea)
+                               largestsquared3xcurvearea = squared3xcurvearea;
}
}
-       return Q3PatchTesselation(largestsquared2xcurvearea, tolerance);
+       return Q3PatchTesselation(largestsquared3xcurvearea, tolerance);
}

// Find an equal vertex in array. Check only vertices with odd X and Y
@@ -326,7 +336,7 @@ int Q3PatchAdjustTesselation(int numcomponents, patchinfo_t *patch1, float *patc

struct {int id1,id2;} commonverts;
int i, j, k, side1, side2, *tess1, *tess2;
-       int dist1, dist2;
+       int dist1 = 0, dist2 = 0;
qboolean modified = false;

// Potential paired vertices (corners of the first patch)
@@ -392,18 +402,38 @@ void Q3PatchTriangleElements(int *elements, int width, int height, int firstvert
int x, y, row0, row1;
for (y = 0;y < height - 1;y++)
{
-               row0 = firstvertex + (y + 0) * width;
-               row1 = firstvertex + (y + 1) * width;
-               for (x = 0;x < width - 1;x++)
+               if(y % 2)
+               {
+                       // swap the triangle order in odd rows as optimization for collision stride
+                       row0 = firstvertex + (y + 0) * width + width - 2;
+                       row1 = firstvertex + (y + 1) * width + width - 2;
+                       for (x = 0;x < width - 1;x++)
+                       {
+                               *elements++ = row1;
+                               *elements++ = row1 + 1;
+                               *elements++ = row0 + 1;
+                               *elements++ = row0;
+                               *elements++ = row1;
+                               *elements++ = row0 + 1;
+                               row0--;
+                               row1--;
+                       }
+               }
+               else
{
-                       *elements++ = row0;
-                       *elements++ = row1;
-                       *elements++ = row0 + 1;
-                       *elements++ = row1;
-                       *elements++ = row1 + 1;
-                       *elements++ = row0 + 1;
-                       row0++;
-                       row1++;
+                       row0 = firstvertex + (y + 0) * width;
+                       row1 = firstvertex + (y + 1) * width;
+                       for (x = 0;x < width - 1;x++)
+                       {
+                               *elements++ = row0;
+                               *elements++ = row1;
+                               *elements++ = row0 + 1;
+                               *elements++ = row1;
+                               *elements++ = row1 + 1;
+                               *elements++ = row0 + 1;
+                               row0++;
+                               row1++;
+                       }
}
}
}