static void PutPointsOnCurve(srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int width, int height) { int i, j; srfVert_t prev, next; for (i = 0; i < width; i++) { for (j = 1; j < height; j += 2) { LerpSurfaceVert(&ctrl[j][i], &ctrl[j + 1][i], &prev); LerpSurfaceVert(&ctrl[j][i], &ctrl[j - 1][i], &next); LerpSurfaceVert(&prev, &next, &ctrl[j][i]); } } for (j = 0; j < height; j++) { for (i = 1; i < width; i += 2) { LerpSurfaceVert(&ctrl[j][i], &ctrl[j][i + 1], &prev); LerpSurfaceVert(&ctrl[j][i], &ctrl[j][i - 1], &next); LerpSurfaceVert(&prev, &next, &ctrl[j][i]); } } }
srfGridMesh_t *R_GridInsertRow(srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror) { int i, j; int width = grid->width, height = grid->height + 1, oldheight = 0; static srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; float lodRadius; vec3_t lodOrigin; int numTriangles; static srfTriangle_t triangles[SHADER_MAX_TRIANGLES]; if (height > MAX_GRID_SIZE) { return NULL; } for (i = 0; i < height; i++) { if (i == row) { //insert new row for (j = 0; j < grid->width; j++) { LerpSurfaceVert(&grid->verts[(i - 1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j]); if (j == column) { VectorCopy(point, ctrl[i][j].xyz); } } errorTable[1][i] = loderror; continue; } errorTable[1][i] = grid->heightLodError[oldheight]; for (j = 0; j < grid->width; j++) { ctrl[i][j] = grid->verts[oldheight * grid->width + j]; } oldheight++; } for (j = 0; j < grid->width; j++) { errorTable[0][j] = grid->widthLodError[j]; } // put all the aproximating points on the curve //PutPointsOnCurve( ctrl, width, height ); // calculate triangles numTriangles = MakeMeshTriangles(width, height, ctrl, triangles); // calculate normals MakeMeshNormals(width, height, ctrl); MakeMeshTangentVectors(width, height, ctrl, numTriangles, triangles); // calculate tangent spaces //MakeTangentSpaces(width, height, ctrl, numTriangles, triangles); VectorCopy(grid->lodOrigin, lodOrigin); lodRadius = grid->lodRadius; // free the old grid R_FreeSurfaceGridMesh(grid); // create a new grid grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); return grid; }
srfGridMesh_t *R_SubdividePatchToGrid(int width, int height, srfVert_t points[MAX_PATCH_SIZE * MAX_PATCH_SIZE]) { int i, j, k, l; srfVert_t prev, next, mid; float len, maxLen; int dir; int t; static srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; int numTriangles; static srfTriangle_t triangles[SHADER_MAX_TRIANGLES]; for (i = 0; i < width; i++) { for (j = 0; j < height; j++) { ctrl[j][i] = points[j * width + i]; } } for (dir = 0; dir < 2; dir++) { for (j = 0; j < MAX_GRID_SIZE; j++) { errorTable[dir][j] = 0; } // horizontal subdivisions for (j = 0; j + 2 < width; j += 2) { // check subdivided midpoints against control points // FIXME: also check midpoints of adjacent patches against the control points // this would basically stitch all patches in the same LOD group together. maxLen = 0; for (i = 0; i < height; i++) { vec3_t midxyz; vec3_t midxyz2; vec3_t dir; vec3_t projected; float d; // calculate the point on the curve for (l = 0; l < 3; l++) { midxyz[l] = (ctrl[i][j].xyz[l] + ctrl[i][j + 1].xyz[l] * 2 + ctrl[i][j + 2].xyz[l]) * 0.25f; } // see how far off the line it is // using dist-from-line will not account for internal // texture warping, but it gives a lot less polygons than // dist-from-midpoint VectorSubtract(midxyz, ctrl[i][j].xyz, midxyz); VectorSubtract(ctrl[i][j + 2].xyz, ctrl[i][j].xyz, dir); VectorNormalize(dir); d = DotProduct(midxyz, dir); VectorScale(dir, d, projected); VectorSubtract(midxyz, projected, midxyz2); len = VectorLengthSquared(midxyz2); // we will do the sqrt later if (len > maxLen) { maxLen = len; } } maxLen = sqrt(maxLen); // if all the points are on the lines, remove the entire columns if (maxLen < 0.1f) { errorTable[dir][j + 1] = 999; continue; } // see if we want to insert subdivided columns if (width + 2 > MAX_GRID_SIZE) { errorTable[dir][j + 1] = 1.0f / maxLen; continue; // can't subdivide any more } if (maxLen <= r_subdivisions->value) { errorTable[dir][j + 1] = 1.0f / maxLen; continue; // didn't need subdivision } errorTable[dir][j + 2] = 1.0f / maxLen; // insert two columns and replace the peak width += 2; for (i = 0; i < height; i++) { LerpSurfaceVert(&ctrl[i][j], &ctrl[i][j + 1], &prev); LerpSurfaceVert(&ctrl[i][j + 1], &ctrl[i][j + 2], &next); LerpSurfaceVert(&prev, &next, &mid); for (k = width - 1; k > j + 3; k--) { ctrl[i][k] = ctrl[i][k - 2]; } ctrl[i][j + 1] = prev; ctrl[i][j + 2] = mid; ctrl[i][j + 3] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } Transpose(width, height, ctrl); t = width; width = height; height = t; } // put all the aproximating points on the curve PutPointsOnCurve(ctrl, width, height); // cull out any rows or columns that are colinear for (i = 1; i < width - 1; i++) { if (errorTable[0][i] != 999) { continue; } for (j = i + 1; j < width; j++) { for (k = 0; k < height; k++) { ctrl[k][j - 1] = ctrl[k][j]; } errorTable[0][j - 1] = errorTable[0][j]; } width--; } for (i = 1; i < height - 1; i++) { if (errorTable[1][i] != 999) { continue; } for (j = i + 1; j < height; j++) { for (k = 0; k < width; k++) { ctrl[j - 1][k] = ctrl[j][k]; } errorTable[1][j - 1] = errorTable[1][j]; } height--; } #if 1 // flip for longest tristrips as an optimization // the results should be visually identical with or // without this step if (height > width) { Transpose(width, height, ctrl); InvertErrorTable(errorTable, width, height); t = width; width = height; height = t; InvertCtrl(width, height, ctrl); } #endif // calculate triangles numTriangles = MakeMeshTriangles(width, height, ctrl, triangles); // calculate normals MakeMeshNormals(width, height, ctrl); MakeMeshTangentVectors(width, height, ctrl, numTriangles, triangles); // calculate tangent spaces //MakeTangentSpaces(width, height, ctrl, numTriangles, triangles); return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numTriangles, triangles); }
/* =============== R_GridInsertRow =============== */ srfGridMesh_t *R_GridInsertRow( srfGridMesh_t *grid, int row, int column, vec3_t point, float loderror ) { int i, j; int width, height, oldheight; float errorTable[ 2 ][ MAX_GRID_SIZE ]; float lodRadius; vec3_t lodOrigin; int numTriangles; oldheight = 0; width = grid->width; height = grid->height + 1; if ( height > MAX_GRID_SIZE ) { return nullptr; } for ( i = 0; i < height; i++ ) { if ( i == row ) { //insert new row for ( j = 0; j < grid->width; j++ ) { LerpSurfaceVert( &grid->verts[( i - 1 ) * grid->width + j ], &grid->verts[ i * grid->width + j ], &gridctrl[ i ][ j ] ); if ( j == column ) { VectorCopy( point, gridctrl[ i ][ j ].xyz ); } } errorTable[ 1 ][ i ] = loderror; continue; } errorTable[ 1 ][ i ] = grid->heightLodError[ oldheight ]; for ( j = 0; j < grid->width; j++ ) { gridctrl[ i ][ j ] = grid->verts[ oldheight * grid->width + j ]; } oldheight++; } for ( j = 0; j < grid->width; j++ ) { errorTable[ 0 ][ j ] = grid->widthLodError[ j ]; } // calculate triangles numTriangles = MakeMeshTriangles( width, height, gridctrl, gridtriangles ); // calculate normals MakeMeshNormals( width, height, gridctrl ); VectorCopy( grid->lodOrigin, lodOrigin ); lodRadius = grid->lodRadius; // free the old grid R_FreeSurfaceGridMesh( grid ); // create a new grid grid = R_CreateSurfaceGridMesh( width, height, gridctrl, errorTable, numTriangles, gridtriangles ); grid->lodRadius = lodRadius; VectorCopy( lodOrigin, grid->lodOrigin ); return grid; }