int main( int argc, char* args[] ) { if ( SDL_Init( SDL_INIT_VIDEO ) == -1 ) return 1; SDL_Surface *screen = SDL_SetVideoMode( WIDTH, HEIGHT, 32, SDL_SWSURFACE ); if ( !screen ) return 1; // Initialize the grid from the BMP file. SDL_Surface *temp = SDL_LoadBMP( "test.bmp" ); temp = SDL_ConvertSurface( temp, screen->format, SDL_SWSURFACE ); SDL_LockSurface( temp ); for( int y=0;y<HEIGHT;y++ ) { for ( int x=0;x<WIDTH;x++ ) { Uint8 r,g,b; Uint32 *src = ( (Uint32 *)( (Uint8 *)temp->pixels + y*temp->pitch ) ) + x; SDL_GetRGB( *src, temp->format, &r, &g, &b ); // Points inside get marked with a dx/dy of zero. // Points outside get marked with an infinitely large distance. if ( g < 128 ) { Put( grid1, x, y, inside ); Put( grid2, x, y, empty ); } else { Put( grid2, x, y, inside ); Put( grid1, x, y, empty ); } } } SDL_UnlockSurface( temp ); // Generate the SDF. GenerateSDF( grid1 ); GenerateSDF( grid2 ); // Render out the results. SDL_LockSurface( screen ); for( int y=0;y<HEIGHT;y++ ) { for ( int x=0;x<WIDTH;x++ ) { // Calculate the actual distance from the dx/dy int dist1 = (int)( sqrt( (double)Get( grid1, x, y ).DistSq() ) ); int dist2 = (int)( sqrt( (double)Get( grid2, x, y ).DistSq() ) ); int dist = dist1 - dist2; // Clamp and scale it, just for display purposes. int c = dist*3 + 128; if ( c < 0 ) c = 0; if ( c > 255 ) c = 255; Uint32 *dest = ( (Uint32 *)( (Uint8 *)screen->pixels + y*screen->pitch ) ) + x; *dest = SDL_MapRGB( screen->format, c, c, c ); } } SDL_UnlockSurface( screen ); SDL_Flip( screen ); // Wait for a keypress SDL_Event event; while( true ) { if ( SDL_PollEvent( &event ) ) switch( event.type ) { case SDL_QUIT: case SDL_KEYDOWN: return true; } } return 0; }
bool BitmapToSDF(Pixel *SourceBitmap, BMSize SourceWidth, BMSize SourceHeight, Pixel *DestBitmap, BMSize DestWidth, BMSize DestHeight, BMSize InsertX, BMSize InsertY, BMSize InsertWidth, BMSize InsertHeight) { // Check parameters if(SourceBitmap == nullptr || SourceWidth == 0 || SourceHeight == 0 || DestBitmap == nullptr || SourceBitmap == DestBitmap || DestWidth == 0 || DestHeight == 0 || (InsertX + InsertWidth) > DestWidth || (InsertY + InsertHeight) > DestHeight || InsertWidth == 0 || InsertHeight == 0) return false; // Sizes const BMSize SDFWidth = SourceWidth + SDFPaddingSize; const BMSize SDFHeight = SourceHeight + SDFPaddingSize; // Create two 1-bit per point grids from the Source bitmap, the grids being inverses of each other SDFPoint *Grid1 = new SDFPoint[SDFWidth*SDFHeight](); SDFPoint *Grid2 = new SDFPoint[SDFWidth*SDFHeight](); for(BMSize i = 0; i < SDFWidth*SDFHeight; ++i) // Fill grids with blank { Grid1[i] = SDFInside; Grid2[i] = SDFOutside; } for(BMSize y = 0; y < SourceHeight; ++y) // Write data from source { for(BMSize x = 0; x < SourceWidth; ++x) { if(SourceBitmap[(y*SourceWidth) + x] < 128) { Grid1[(((SDFPaddingSize / 2) + y)*SDFWidth) + ((SDFPaddingSize / 2) + x)] = SDFInside; Grid2[(((SDFPaddingSize / 2) + y)*SDFWidth) + ((SDFPaddingSize / 2) + x)] = SDFOutside; } else { Grid1[(((SDFPaddingSize / 2) + y)*SDFWidth) + ((SDFPaddingSize / 2) + x)] = SDFOutside; Grid2[(((SDFPaddingSize / 2) + y)*SDFWidth) + ((SDFPaddingSize / 2) + x)] = SDFInside; } } } // Compute SDF grids GenerateSDF(Grid1, SDFWidth, SDFHeight); GenerateSDF(Grid2, SDFWidth, SDFHeight); // Copy SDF to destination bitmap if(SDFWidth == InsertWidth && SDFHeight == InsertHeight && false) // The generation size and output size are the same, so there is no need to convert { // Copy the final values directly to the destination bitmap for(BMSize y = 0; y < SDFHeight; ++y) { for(BMSize x = 0; x < SDFWidth; ++x) { // Calculate the actual distance from the dx/dy int dist1 = (int)(sqrt((double)SDFGetPoint(Grid1, x, y, SDFWidth, SDFHeight).DistSq())); int dist2 = (int)(sqrt((double)SDFGetPoint(Grid2, x, y, SDFWidth, SDFHeight).DistSq())); int dist = dist1 - dist2; // Clamp int c = dist * 3 + 128; if(c < 0) c = 0; if(c > 255) c = 255; // Write to bitmap DestBitmap[((InsertY + y)*SDFWidth) + (InsertX + x)] = c; } } } else // Need to scale the output { // Copy the final values to a temporary buffer first Pixel *SDF = new Pixel[SDFWidth*SDFHeight](); for(BMSize y = 0; y < SDFHeight; ++y) { for(BMSize x = 0; x < SDFWidth; ++x) { // Calculate the actual distance from the dx/dy int dist1 = (int)(sqrt((double)SDFGetPoint(Grid1, x, y, SDFWidth, SDFHeight).DistSq())); int dist2 = (int)(sqrt((double)SDFGetPoint(Grid2, x, y, SDFWidth, SDFHeight).DistSq())); int dist = dist1 - dist2; // Clamp int c = dist * 3 + 128; if(c < 0) c = 0; if(c > 255) c = 255; // Write to bitmap SDF[(y*SDFWidth) + x] = c; } } // Scale bitmap to final size and copy it to the destination buffer CopyBitmap(SDF, SDFWidth, SDFHeight, DestBitmap, DestWidth, DestHeight, InsertX, InsertY, InsertWidth, InsertHeight); delete[] SDF; } // Done delete[] Grid1; delete[] Grid2; return true; }