+ patch = in + ((y * patchwidth) + x) * components;
+ squared3xcurvearea = Squared3xCurveArea(&patch[0], &patch[patchwidth*components], &patch[2*patchwidth*components], components);
+ if (largestsquared3xcurvearea < squared3xcurvearea)
+ largestsquared3xcurvearea = squared3xcurvearea;
+ }
+ }
+ return Q3PatchTesselation(largestsquared3xcurvearea, tolerance);
+}
+
+// Find an equal vertex in array. Check only vertices with odd X and Y
+static int FindEqualOddVertexInArray(int numcomponents, float *vertex, float *vertices, int width, int height)
+{
+ int x, y, j;
+ for (y=0; y<height; y+=2)
+ {
+ for (x=0; x<width; x+=2)
+ {
+ qbool found = true;
+ for (j=0; j<numcomponents; j++)
+ if (fabs(*(vertex+j) - *(vertices+j)) > 0.05)
+ // div0: this is notably smaller than the smallest radiant grid
+ // but large enough so we don't need to get scared of roundoff
+ // errors
+ {
+ found = false;
+ break;
+ }
+ if(found)
+ return y*width+x;
+ vertices += numcomponents*2;
+ }
+ vertices += numcomponents*(width-1);
+ }
+ return -1;
+}
+
+#define SIDE_INVALID -1
+#define SIDE_X 0
+#define SIDE_Y 1
+
+static int GetSide(int p1, int p2, int width, int height, int *pointdist)
+{
+ int x1 = p1 % width, y1 = p1 / width;
+ int x2 = p2 % width, y2 = p2 / width;
+ if (p1 < 0 || p2 < 0)
+ return SIDE_INVALID;
+ if (x1 == x2)
+ {
+ if (y1 != y2)
+ {
+ *pointdist = abs(y2 - y1);
+ return SIDE_Y;
+ }
+ else
+ return SIDE_INVALID;
+ }
+ else if (y1 == y2)
+ {
+ *pointdist = abs(x2 - x1);
+ return SIDE_X;
+ }
+ else
+ return SIDE_INVALID;
+}
+
+// Increase tesselation of one of two touching patches to make a seamless connection between them
+// Returns 0 in case if patches were not modified, otherwise 1
+int Q3PatchAdjustTesselation(int numcomponents, patchinfo_t *patch1, float *patchvertices1, patchinfo_t *patch2, float *patchvertices2)
+{
+ // what we are doing here is:
+ // we take for each corner of one patch
+ // and check if the other patch contains that corner
+ // once we have a pair of such matches
+
+ struct {int id1,id2;} commonverts[8];
+ int i, j, k, side1, side2, *tess1, *tess2;
+ int dist1 = 0, dist2 = 0;
+ qbool modified = false;
+
+ // Potential paired vertices (corners of the first patch)
+ commonverts[0].id1 = 0;
+ commonverts[1].id1 = patch1->xsize-1;
+ commonverts[2].id1 = patch1->xsize*(patch1->ysize-1);
+ commonverts[3].id1 = patch1->xsize*patch1->ysize-1;
+ for (i=0;i<4;++i)
+ commonverts[i].id2 = FindEqualOddVertexInArray(numcomponents, patchvertices1+numcomponents*commonverts[i].id1, patchvertices2, patch2->xsize, patch2->ysize);
+
+ // Corners of the second patch
+ commonverts[4].id2 = 0;
+ commonverts[5].id2 = patch2->xsize-1;
+ commonverts[6].id2 = patch2->xsize*(patch2->ysize-1);
+ commonverts[7].id2 = patch2->xsize*patch2->ysize-1;
+ for (i=4;i<8;++i)
+ commonverts[i].id1 = FindEqualOddVertexInArray(numcomponents, patchvertices2+numcomponents*commonverts[i].id2, patchvertices1, patch1->xsize, patch1->ysize);
+
+ for (i=0;i<8;++i)
+ for (j=i+1;j<8;++j)
+ {
+ side1 = GetSide(commonverts[i].id1,commonverts[j].id1,patch1->xsize,patch1->ysize,&dist1);
+ side2 = GetSide(commonverts[i].id2,commonverts[j].id2,patch2->xsize,patch2->ysize,&dist2);
+
+ if (side1 == SIDE_INVALID || side2 == SIDE_INVALID)
+ continue;
+
+ if(dist1 != dist2)
+ {
+ // no patch welding if the resolutions mismatch
+ continue;
+ }
+
+ // Update every lod level
+ for (k=0;k<PATCH_LODS_NUM;++k)