/* =============== 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; MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; float lodRadius; vec3_t lodOrigin; oldheight = 0; width = grid->width; height = grid->height + 1; 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++) { LerpDrawVert(&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 normals MakeMeshNormals(width, height, ctrl); 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); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); return grid; }
/* * R_GridInsertRow */ srfGridMesh_t * R_GridInsertRow(srfGridMesh_t *grid, int row, int column, Vec3 point, float loderror) { int i, j; int width, height, oldheight; Drawvert ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; float lodRadius; Vec3 lodOrigin; oldheight = 0; width = grid->width; height = grid->height + 1; 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++){ LerpDrawVert(&grid->verts[(i-1) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j]); if(j == column) copyv3(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 normals */ MakeMeshNormals(width, height, ctrl); copyv3(grid->lodOrigin, lodOrigin); lodRadius = grid->lodRadius; /* free the old grid */ R_FreeSurfaceGridMesh(grid); /* create a new grid */ grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable); grid->lodRadius = lodRadius; copyv3(lodOrigin, grid->lodOrigin); return grid; }
bool R_GridInsertRow( class idSurfaceGrid* grid, int row, int column, const idVec3& point, float loderror ) { int oldheight = 0; int width = grid->width; int height = grid->height + 1; if ( height > MAX_GRID_SIZE ) { return false; } idWorldVertex ctrl[ MAX_GRID_SIZE ][ MAX_GRID_SIZE ]; float errorTable[ 2 ][ MAX_GRID_SIZE ]; for ( int i = 0; i < height; i++ ) { if ( i == row ) { //insert new row for ( int j = 0; j < grid->width; j++ ) { ctrl[ i ][ j ] = LerpDrawVert( grid->vertexes[ ( i - 1 ) * grid->width + j ], grid->vertexes[ i * grid->width + j ] ); if ( j == column ) { ctrl[ i ][ j ].xyz = point; } } errorTable[ 1 ][ i ] = loderror; continue; } errorTable[ 1 ][ i ] = grid->heightLodError[ oldheight ]; for ( int j = 0; j < grid->width; j++ ) { ctrl[ i ][ j ] = grid->vertexes[ oldheight * grid->width + j ]; } oldheight++; } for ( int 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 normals MakeMeshNormals( width, height, ctrl ); // free the old grid R_FreeSurfaceGridMeshAndVertexes( grid ); // create a new grid R_CreateSurfaceGridMesh( grid, width, height, ctrl, errorTable ); return true; }
/* ================= R_SubdividePatchToGrid ================= */ srfGridMesh_t *R_SubdividePatchToGrid(int width, int height, drawVert_t points[MAX_PATCH_SIZE * MAX_PATCH_SIZE]) { int i, j, k, l; drawVert_t prev, next, mid; float len, maxLen; int dir; int t; MAC_STATIC drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; 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 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, midxyz); len = VectorLengthSquared(midxyz); // 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++) { LerpDrawVert(&ctrl[i][j], &ctrl[i][j + 1], &prev); LerpDrawVert(&ctrl[i][j + 1], &ctrl[i][j + 2], &next); LerpDrawVert(&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--; } // 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); } // calculate normals MakeMeshNormals(width, height, ctrl); return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable); }
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; }
/* * R_SubdividePatchToGrid */ srfGridMesh_t * R_SubdividePatchToGrid(int width, int height, Drawvert points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]) { int i, j, k, l; drawVert_t_cleared(prev); drawVert_t_cleared(next); drawVert_t_cleared(mid); float len, maxLen; int dir; int t; Drawvert ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; 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 midxyz; Vec3 midxyz2; Vec3 dir; Vec3 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 */ subv3(midxyz, ctrl[i][j].xyz, midxyz); subv3(ctrl[i][j+2].xyz, ctrl[i][j].xyz, dir); normv3(dir); d = dotv3(midxyz, dir); scalev3(dir, d, projected); subv3(midxyz, projected, midxyz2); len = lensqrv3(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++){ LerpDrawVert(&ctrl[i][j], &ctrl[i][j+1], &prev); LerpDrawVert(&ctrl[i][j+1], &ctrl[i][j+2], &next); LerpDrawVert(&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 normals */ MakeMeshNormals(width, height, ctrl); return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable); }
void R_SubdividePatchToGrid( idSurfaceGrid* surf, int width, int height, idWorldVertex points[ MAX_PATCH_SIZE * MAX_PATCH_SIZE ] ) { idWorldVertex ctrl[ MAX_GRID_SIZE ][ MAX_GRID_SIZE ]; for ( int i = 0; i < width; i++ ) { for ( int j = 0; j < height; j++ ) { ctrl[ j ][ i ] = points[ j * width + i ]; } } float errorTable[ 2 ][ MAX_GRID_SIZE ]; for ( int dir = 0; dir < 2; dir++ ) { for ( int j = 0; j < MAX_GRID_SIZE; j++ ) { errorTable[ dir ][ j ] = 0; } // horizontal subdivisions for ( int 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. float maxLen = 0; for ( int i = 0; i < height; i++ ) { // calculate the point on the curve idVec3 midxyz = ( ctrl[ i ][ j ].xyz + ctrl[ i ][ j + 1 ].xyz * 2 + ctrl[ i ][ j + 2 ].xyz ) * 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 midxyz = midxyz - ctrl[ i ][ j ].xyz; idVec3 dir = ctrl[ i ][ j + 2 ].xyz - ctrl[ i ][ j ].xyz; dir.Normalize(); float d = midxyz * dir; idVec3 projected = dir * d; idVec3 midxyz2 = midxyz - projected; float len = midxyz2.LengthSqr(); // 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 ( int i = 0; i < height; i++ ) { idWorldVertex prev = LerpDrawVert( ctrl[ i ][ j ], ctrl[ i ][ j + 1 ] ); idWorldVertex next = LerpDrawVert( ctrl[ i ][ j + 1 ], ctrl[ i ][ j + 2 ] ); idWorldVertex mid = LerpDrawVert( prev, next ); for ( int 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 ); int 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 ( int i = 1; i < width - 1; i++ ) { if ( errorTable[ 0 ][ i ] != 999 ) { continue; } for ( int j = i + 1; j < width; j++ ) { for ( int k = 0; k < height; k++ ) { ctrl[ k ][ j - 1 ] = ctrl[ k ][ j ]; } errorTable[ 0 ][ j - 1 ] = errorTable[ 0 ][ j ]; } width--; } for ( int i = 1; i < height - 1; i++ ) { if ( errorTable[ 1 ][ i ] != 999 ) { continue; } for ( int j = i + 1; j < height; j++ ) { for ( int 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 ); int t = width; width = height; height = t; InvertCtrl( width, height, ctrl ); } #endif // calculate normals MakeMeshNormals( width, height, ctrl ); R_CreateSurfaceGridMesh( surf, width, height, ctrl, errorTable ); }
/* =============== 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; }
/* =============== R_GridInsertColumn =============== */ srfGridMesh_t *R_GridInsertColumn(srfGridMesh_t *grid, int column, int row, vec3_t point, float loderror) { int i, j; int width, height, oldwidth; 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[(MAX_GRID_SIZE - 1) * (MAX_GRID_SIZE - 1) * 2]; oldwidth = 0; width = grid->width + 1; if (width > MAX_GRID_SIZE) { return NULL; } height = grid->height; for (i = 0; i < width; i++) { if (i == column) { //insert new column for (j = 0; j < grid->height; j++) { LerpDrawVert(&grid->verts[j * grid->width + i - 1], &grid->verts[j * grid->width + i], &ctrl[j][i]); if (j == row) { VectorCopy(point, ctrl[j][i].xyz); } } errorTable[0][i] = loderror; continue; } errorTable[0][i] = grid->widthLodError[oldwidth]; for (j = 0; j < grid->height; j++) { ctrl[j][i] = grid->verts[j * grid->width + oldwidth]; } oldwidth++; } for (j = 0; j < grid->height; j++) { errorTable[1][j] = grid->heightLodError[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); 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; }