/* =============== 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; }
/* ================== PutPointsOnCurve ================== */ static void PutPointsOnCurve(drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int width, int height) { int i, j; drawVert_t prev, next; for (i = 0 ; i < width ; i++) { for (j = 1 ; j < height ; j += 2) { LerpDrawVert(&ctrl[j][i], &ctrl[j + 1][i], &prev); LerpDrawVert(&ctrl[j][i], &ctrl[j - 1][i], &next); LerpDrawVert(&prev, &next, &ctrl[j][i]); } } for (j = 0 ; j < height ; j++) { for (i = 1 ; i < width ; i += 2) { LerpDrawVert(&ctrl[j][i], &ctrl[j][i + 1], &prev); LerpDrawVert(&ctrl[j][i], &ctrl[j][i - 1], &next); LerpDrawVert(&prev, &next, &ctrl[j][i]); } } }
/* * 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; }
static void PutPointsOnCurve( idWorldVertex ctrl[ MAX_GRID_SIZE ][ MAX_GRID_SIZE ], int width, int height ) { for ( int i = 0; i < width; i++ ) { for ( int j = 1; j < height; j += 2 ) { idWorldVertex prev = LerpDrawVert( ctrl[ j ][ i ], ctrl[ j + 1 ][ i ] ); idWorldVertex next = LerpDrawVert( ctrl[ j ][ i ], ctrl[ j - 1 ][ i ] ); ctrl[ j ][ i ] = LerpDrawVert( prev, next ); } } for ( int j = 0; j < height; j++ ) { for ( int i = 1; i < width; i += 2 ) { idWorldVertex prev = LerpDrawVert( ctrl[ j ][ i ], ctrl[ j ][ i + 1 ] ); idWorldVertex next= LerpDrawVert( ctrl[ j ][ i ], ctrl[ j ][ i - 1 ] ); ctrl[ j ][ i ] = LerpDrawVert( prev, next ); } } }
/* ================= 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); }
mesh_t *SubdivideMesh2( mesh_t in, int iterations ) { int i, j, k; bspDrawVert_t prev, next, mid; mesh_t out; /* ydnar: static for os x */ MAC_STATIC bspDrawVert_t expand[ MAX_EXPANDED_AXIS ][ MAX_EXPANDED_AXIS ]; /* initial setup */ out.width = in.width; out.height = in.height; for( i = 0; i < in.width; i++ ) { for( j = 0; j < in.height; j++ ) expand[ j ][ i ] = in.verts[ j * in.width + i ]; } /* keep chopping */ for( iterations; iterations > 0; iterations-- ) { /* horizontal subdivisions */ for( j = 0; j + 2 < out.width; j += 4 ) { /* check size limit */ if( out.width + 2 >= MAX_EXPANDED_AXIS ) break; /* insert two columns and replace the peak */ out.width += 2; for( i = 0; i < out.height; i++ ) { LerpDrawVert( &expand[ i ][ j ], &expand[ i ][ j + 1 ], &prev ); LerpDrawVert( &expand[ i ][ j + 1 ], &expand[ i ][ j + 2 ], &next ); LerpDrawVert( &prev, &next, &mid ); for ( k = out.width - 1 ; k > j + 3; k-- ) expand [ i ][ k ] = expand[ i ][ k - 2 ]; expand[ i ][ j + 1 ] = prev; expand[ i ][ j + 2 ] = mid; expand[ i ][ j + 3 ] = next; } } /* vertical subdivisions */ for ( j = 0; j + 2 < out.height; j += 4 ) { /* check size limit */ if( out.height + 2 >= MAX_EXPANDED_AXIS ) break; /* insert two columns and replace the peak */ out.height += 2; for( i = 0; i < out.width; i++ ) { LerpDrawVert( &expand[ j ][ i ], &expand[ j + 1 ][ i ], &prev ); LerpDrawVert( &expand[ j + 1 ][ i ], &expand[ j + 2 ][ i ], &next ); LerpDrawVert( &prev, &next, &mid ); for( k = out.height - 1; k > j + 3; k-- ) expand[ k ][ i ] = expand[ k - 2 ][ i ]; expand[ j + 1 ][ i ] = prev; expand[ j + 2 ][ i ] = mid; expand[ j + 3 ][ i ] = next; } } } /* collapse the verts */ out.verts = &expand[ 0 ][ 0 ]; for( i = 1; i < out.height; i++ ) memmove( &out.verts[ i * out.width ], expand[ i ], out.width * sizeof( bspDrawVert_t ) ); /* return to sender */ return CopyMesh( &out ); }
/* ================= SubdivideMesh ================= */ mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ) { int i, j, k, l; bspDrawVert_t prev, next, mid; vec3_t prevxyz, nextxyz, midxyz; vec3_t delta; float len; mesh_t out; /* ydnar: static for os x */ MAC_STATIC bspDrawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS]; out.width = in.width; out.height = in.height; for ( i = 0 ; i < in.width ; i++ ) { for ( j = 0 ; j < in.height ; j++ ) { expand[j][i] = in.verts[j*in.width+i]; } } // horizontal subdivisions for ( j = 0 ; j + 2 < out.width ; j += 2 ) { // check subdivided midpoints against control points for ( i = 0 ; i < out.height ; i++ ) { for ( l = 0 ; l < 3 ; l++ ) { prevxyz[l] = expand[i][j+1].xyz[l] - expand[i][j].xyz[l]; nextxyz[l] = expand[i][j+2].xyz[l] - expand[i][j+1].xyz[l]; midxyz[l] = (expand[i][j].xyz[l] + expand[i][j+1].xyz[l] * 2 + expand[i][j+2].xyz[l] ) * 0.25; } // if the span length is too long, force a subdivision if ( VectorLength( prevxyz ) > minLength || VectorLength( nextxyz ) > minLength ) { break; } // see if this midpoint is off far enough to subdivide VectorSubtract( expand[i][j+1].xyz, midxyz, delta ); len = VectorLength( delta ); if ( len > maxError ) { break; } } if ( out.width + 2 >= MAX_EXPANDED_AXIS ) { break; // can't subdivide any more } if ( i == out.height ) { continue; // didn't need subdivision } // insert two columns and replace the peak out.width += 2; for ( i = 0 ; i < out.height ; i++ ) { LerpDrawVert( &expand[i][j], &expand[i][j+1], &prev ); LerpDrawVert( &expand[i][j+1], &expand[i][j+2], &next ); LerpDrawVert( &prev, &next, &mid ); for ( k = out.width - 1 ; k > j + 3 ; k-- ) { expand[i][k] = expand[i][k-2]; } expand[i][j + 1] = prev; expand[i][j + 2] = mid; expand[i][j + 3] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } // vertical subdivisions for ( j = 0 ; j + 2 < out.height ; j += 2 ) { // check subdivided midpoints against control points for ( i = 0 ; i < out.width ; i++ ) { for ( l = 0 ; l < 3 ; l++ ) { prevxyz[l] = expand[j+1][i].xyz[l] - expand[j][i].xyz[l]; nextxyz[l] = expand[j+2][i].xyz[l] - expand[j+1][i].xyz[l]; midxyz[l] = (expand[j][i].xyz[l] + expand[j+1][i].xyz[l] * 2 + expand[j+2][i].xyz[l] ) * 0.25; } // if the span length is too long, force a subdivision if ( VectorLength( prevxyz ) > minLength || VectorLength( nextxyz ) > minLength ) { break; } // see if this midpoint is off far enough to subdivide VectorSubtract( expand[j+1][i].xyz, midxyz, delta ); len = VectorLength( delta ); if ( len > maxError ) { break; } } if ( out.height + 2 >= MAX_EXPANDED_AXIS ) { break; // can't subdivide any more } if ( i == out.width ) { continue; // didn't need subdivision } // insert two columns and replace the peak out.height += 2; for ( i = 0 ; i < out.width ; i++ ) { LerpDrawVert( &expand[j][i], &expand[j+1][i], &prev ); LerpDrawVert( &expand[j+1][i], &expand[j+2][i], &next ); LerpDrawVert( &prev, &next, &mid ); for ( k = out.height - 1 ; k > j + 3 ; k-- ) { expand[k][i] = expand[k-2][i]; } expand[j+1][i] = prev; expand[j+2][i] = mid; expand[j+3][i] = next; } // back up and recheck this set again, it may need more subdivision j -= 2; } // collapse the verts out.verts = &expand[0][0]; for ( i = 1 ; i < out.height ; i++ ) { memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(bspDrawVert_t) ); } return CopyMesh(&out); }
/* * 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); }
/* ================= 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; drawVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; float errorTable[2][MAX_GRID_SIZE]; srfGridMesh_t *grid; drawVert_t *vert; vec3_t tmpVec; 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 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.25; } // 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 = VectorLength( midxyz ); if ( len > maxLen ) { maxLen = len; } } // if all the points are on the lines, remove the entire columns if ( maxLen < 0.1 ) { 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.0/maxLen; continue; // can't subdivide any more } if ( maxLen <= r_subdivisions->value ) { errorTable[dir][j+1] = 1.0/maxLen; continue; // didn't need subdivision } errorTable[dir][j+2] = 1.0/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 ); // copy the results out to a grid grid = (struct srfGridMesh_s *) R_Hunk_Alloc( (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ), qtrue ); grid->widthLodError = (float *) R_Hunk_Alloc( width * 4, qfalse ); memcpy( grid->widthLodError, errorTable[0], width * 4 ); grid->heightLodError = (float *) R_Hunk_Alloc( height * 4, qfalse ); memcpy( grid->heightLodError, errorTable[1], height * 4 ); grid->width = width; grid->height = height; grid->surfaceType = SF_GRID; ClearBounds( grid->meshBounds[0], grid->meshBounds[1] ); for ( i = 0 ; i < width ; i++ ) { for ( j = 0 ; j < height ; j++ ) { vert = &grid->verts[j*width+i]; *vert = ctrl[j][i]; AddPointToBounds( vert->xyz, grid->meshBounds[0], grid->meshBounds[1] ); } } // compute local origin and bounds VectorAdd( grid->meshBounds[0], grid->meshBounds[1], grid->localOrigin ); VectorScale( grid->localOrigin, 0.5f, grid->localOrigin ); VectorSubtract( grid->meshBounds[0], grid->localOrigin, tmpVec ); grid->meshRadius = VectorLength( tmpVec ); VectorCopy( grid->localOrigin, grid->lodOrigin ); grid->lodRadius = grid->meshRadius; return grid; }
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_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; }