/* ================= 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); }
/* ================= 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; }
/* * 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 ); }