//------------------------------------------------------------------- // flood.cpp // // This program demonstrates a recursive flood-fill algorithm, // used to color all the points of a region that is defined by // a set of curved borders (each generated as a Bezier curve). // [How should the potential for 'stack overflow' be handled?] // // compile using: $ g++ flood.cpp int86.cpp -o flood // // programmer: ALLAN CRUSE // written on: 10 DEC 2003 // revised on: 11 NOV 2003 -- replace 'svgalib' with 'int86()' //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for close() #include // for tcgetattr(), tcsetattr() #include // for mmap() #include // for signal() #include // for fabs() #include // for memcpy() #include "int86.h" // for init8086(), int86() #define MAXVERT 15 typedef struct { double x, y; } point_t; typedef struct { int numverts; point_t vert[ MAXVERT ]; } polyline_t; typedef struct { point_t east, north, west, south; } compass_t; unsigned char *vram = (unsigned char*)0xA0000000; int vesa_mode = 0x4101, hres = 640, vres = 480; struct vm86plus_struct vm; void setup_compass( int x, int y, int h, int v, compass_t &compass ) { // subdivides a specified rectangle into four quadrants, // then locates the midpoint on each radial axis int wide = h/2, high = v/2; int midx = x + wide, midy = y + high; compass.east.x = midx + wide/2, compass.east.y = midy; compass.west.x = midx - wide/2, compass.west.y = midy; compass.north.x = midx, compass.north.y = midy - high/2; compass.south.x = midx, compass.south.y = midy + high/2; } void setup_random_point( int x, int y, int h, int v, point_t &p ) { // selects a random point within a specified rectangle p.x = x + rand()%h; // p.x satisfies x <= p.x < h p.y = y + rand()%v; // p.y satisfied y <= p.y < v } void setup_boxed_curve( int x, int y, int h, int v, polyline_t &curve ) { compass_t compass; setup_compass( x, y, h, v, compass ); // sets up an array of "control-points" for four bezier cuuves, // each curve being confined within a single rectangle-quadrant curve.numverts = 12; curve.vert[0] = compass.east; setup_random_point( x + h/2, y + 0, h/2, v/2, curve.vert[1] ); setup_random_point( x + h/2, y + 0, h/2, v/2, curve.vert[2] ); curve.vert[3] = compass.north; setup_random_point( x + 0, y + 0, h/2, v/2, curve.vert[4] ); setup_random_point( x + 0, y + 0, h/2, v/2, curve.vert[5] ); curve.vert[6] = compass.west; setup_random_point( x + 0, y + v/2, h/2, v/2, curve.vert[7] ); setup_random_point( x + 0, y + v/2, h/2, v/2, curve.vert[8] ); curve.vert[9] = compass.south; setup_random_point( x + h/2, y + v/2, h/2, v/2, curve.vert[10] ); setup_random_point( x + h/2, y + v/2, h/2, v/2, curve.vert[11] ); curve.vert[12] = compass.east; } int get_pixel( int x, int y, int page ) { unsigned char *dstn = &vram[ (hres*vres) * page ]; if (( x < 0 )||( x >= hres )) return -1; if (( y < 0 )||( y >= vres )) return -1; return dstn[ y*hres + x ]; } void set_pixel( int x, int y, int color, int page ) { unsigned char *dstn = &vram[ (hres*vres) * page ]; if (( x < 0 )||( x >= hres )) return; if (( y < 0 )||( y >= vres )) return; dstn[ y*hres + x ] = color; } void flood_fill( int x, int y, int interior, int newcolor, int page ) { if ( get_pixel( x, y, page ) == interior ) { set_pixel( x, y, newcolor, page ); flood_fill( x-1, y, interior, newcolor, page ); flood_fill( x+1, y, interior, newcolor, page ); flood_fill( x, y-1, interior, newcolor, page ); flood_fill( x, y+1, interior, newcolor, page ); } } void copy_page( int src_page, int dst_page ) { int pagesize = hres * vres; long *srcp = (long*)&vram[ src_page * pagesize ]; long *dstp = (long*)&vram[ dst_page * pagesize ]; pagesize /= 4; for (int i = 0; i < pagesize; i++) dstp[ i ] = srcp[ i ]; } void wipe_page( int page ) { int pagesize = hres * vres; long *dstn = (long*)&vram[ page * pagesize ]; pagesize /= 4; for (int i = 0; i < pagesize; i++) dstn[ i ] = 0; } void draw_line( int x1, int y1, int x2, int y2, int color, int page ) { int deltax = x2 - x1; int deltay = y2 - y1; int xinc = ( deltax < 0 ) ? -1 : 1; int yinc = ( deltay < 0 ) ? -1 : 1; if ( deltax < 0 ) deltax = - deltax; if ( deltay < 0 ) deltay = - deltay; set_pixel( x1, y1, color, page ); if (( deltax == 0 )&&( deltay == 0 )) return; else if ( deltay <= deltax ) { int error_term = - deltax; while ( x1 != x2 ) { error_term += 2*deltay; if ( error_term >= 0 ) { y1 += yinc; error_term -= 2*deltax; } x1 += xinc; set_pixel( x1, y1, color, page ); } } else { int error_term = - deltay; while ( y1 != y2 ) { error_term += 2*deltax; if ( error_term >= 0 ) { x1 += xinc; error_term -= 2*deltay; } y1 += yinc; set_pixel( x1, y1, color, page ); } } } void draw_rectangle( int x, int y, int h, int v, int color, int page ) { unsigned char *dstn = &vram[ (hres*vres) * page ]; int minx = 0, miny = 0, maxx = hres-1, maxy = vres-1; do { set_pixel( x, y, color, page ); ++x; } while ( x < maxx ); do { set_pixel( x, y, color, page ); ++y; } while ( y < maxy ); do { set_pixel( x, y, color, page ); --x; } while ( x > minx ); do { set_pixel( x, y, color, page ); --y; } while ( y > minx ); } int map_system_memory( int base, int size ) { int fd = open( "/dev/vram", O_RDWR ); if ( fd < 0 ) { perror( "/dev/vram" ); return -1; } int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)base; if ( mmap( mm, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); return -1; } close( fd ); } void inbetween( polyline_t &p, polyline_t &q, float t, polyline_t &b ) { if ( p.numverts != q.numverts ) return; b.numverts = p.numverts; for (int i = 0; i <= b.numverts; i++) { b.vert[i].x = t * p.vert[i].x + (1.0 - t) * q.vert[i].x; b.vert[i].y = t * p.vert[i].y + (1.0 - t) * q.vert[i].y; } } void draw_polyline( polyline_t &p, int color, int page ) { for (int i = 0; i < p.numverts; i++) { int x1 = (int)p.vert[i].x; int y1 = (int)p.vert[i].y; int x2 = (int)p.vert[i+1].x; int y2 = (int)p.vert[i+1].y; draw_line( x1, y1, x2, y2, color, page ); } } void middle( point_t &p, point_t &q, point_t &btw ) { btw.x = ( p.x + q.x )/2.0; btw.y = ( p.y + q.y )/2.0; } void recursive_bezier( point_t &p1, point_t &h1, point_t &h2, point_t p2, int color, int page ) { // base case if (( fabs( p1.x - p2.x ) <= 1.0 )&&( fabs( p1.y - p2.y ) <= 1.0 )) { int x1 = (int)p1.x, y1 = (int)p1.y; int x2 = (int)p2.x, y2 = (int)p2.y; draw_line( x1, y1, x2, y2, color, page ); } else { point_t a, b1, b2, c1, c2, d; middle( h1, h2, a ); middle( p1, h1, b1 ); middle( h2, p2, b2 ); middle( b1, a, c1 ); middle( a, b2, c2 ); middle( c1, c2, d ); recursive_bezier( p1, b1, c1, d, color, page ); recursive_bezier( d, c2, b2, p2, color, page ); } } void draw_bezier( polyline_t &bezier, int color, int page ) { recursive_bezier( bezier.vert[0], bezier.vert[1], bezier.vert[2], bezier.vert[3], color, page ); } int main( int argc, char **argv ) { int fd = open( "/dev/vram", O_RDWR ); if ( fd < 0 ) { perror( "/dev/vram" ); return -1; } int size = lseek( fd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; if ( mmap( (void*)vram, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); return -1; } struct termios otty; tcgetattr( 0, &otty ); struct termios tty = otty; tty.c_lflag &= ~( ICANON | ECHO | ISIG ); tty.c_cc[ VMIN ] = 1; tty.c_cc[ VTIME ] = 0; tcsetattr( 0, TCSAFLUSH, &tty ); init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); int white = 15, black = 0, green = 10; int cyan = 3, magenta = 5, yellow = 14; draw_rectangle( 0, 0, hres, vres, white, 0 ); getchar(); compass_t compass; setup_compass( 0, 0, hres, vres, compass ); polyline_t poly; poly.numverts = 4; poly.vert[0] = compass.east; poly.vert[1] = compass.north; poly.vert[2] = compass.west; poly.vert[3] = compass.south; poly.vert[4] = compass.east; draw_polyline( poly, green, 0 ); getchar(); int done = 0, fast = 0, ptsize = sizeof( point_t ); while ( !done ) { polyline_t curve = {0}; setup_boxed_curve( 0, 0, hres, vres, curve ); wipe_page( 0 ); draw_rectangle( 0, 0, hres, vres, white, 0 ); getchar(); polyline_t *polyp = &poly; for (int i = 0; i < 4; i++) { polyp->numverts = 3; memcpy( polyp->vert, &curve.vert[i*3], 4 * ptsize ); draw_bezier( *polyp, yellow, 0 ); if ( !fast ) getchar(); } if ( fast ) getchar(); fast = 1; flood_fill( hres/2, vres/2, black, cyan, 0 ); if ( getchar() == 0x1B ) done = 1; flood_fill( 1, 1, black, magenta, 0 ); if ( getchar() == 0x1B ) done = 1; } vm.regs.eax = 0x0003; int86( 0x10, vm ); tcsetattr( 0, TCSAFLUSH, &otty ); }