//---------------------------------------------------------------- // polyfill.cpp // // Adaptation of Bresenham's Line Algorithm to Polygon Fill. // // compile using: $ g++ polyfill.cpp int86.cpp -o polyfill // // programmer: ALLAN CRUSE // written on: 30 OCT 1997 // revised on: 04 OCT 2005 -- ported from MS-DOS to Linux //---------------------------------------------------------------- #include // for getchar() #include // for open() #include // for exit() #include // for lseek() #include // for mmap() #include // for tcgetattr(), tcsetattr() #include "int86.h" // for init8086(), int86() #define NIL 0 #define MAXVERT 10 typedef struct { int h, v; } Point; typedef struct { int numverts; Point vert[ 1+MAXVERT ]; } Polygon; typedef struct Node { int x; Node *next; } Node; typedef Node *NodePtr; unsigned char *vram = (unsigned char*)0xA0000000; const int vesa_mode = 0x4101, hres = 640, vres = 480; struct vm86plus_struct vm; const int maxnode = vres * MAXVERT; Node pool[ maxnode ]; int used = 0; NodePtr bucket[ vres ]; int segment[ vres ][2]; int between( int y1, int y2, int y3 ) { return ( ((y1 < y2)&&(y2 < y3)) || ((y1 > y2)&&(y2 > y3)) ); } void init_buckets( void ) { for (int i = 0; i < vres; i++) bucket[ i ] = NIL; } NodePtr newnode( void ) { if ( used < maxnode ) return &pool[ used++ ]; else return NIL; } void insert_pixel( int x, int y ) { int xmin = 0, ymin = 0, xmax = hres-1, ymax = vres-1; if (( y < ymin )||( y > ymax )) return; if ( x < xmin ) x = xmin; if ( x > xmax ) x = xmax; NodePtr p = newnode(); if ( p == NIL ) exit( 1 ); p->x = x; p->next = bucket[ y ]; bucket[ y ] = p; NodePtr q = p->next; while ( q != NIL ) { if ( p->x > q->x ) { int tmp = p->x; p->x = q->x; q->x = tmp; } p = p->next; q = q->next; } } void insert_line( Point pt0, Point pt1 ) { int xinc = ( pt0.h > pt1.h ) ? -1 : 1; int yinc = ( pt0.v > pt1.v ) ? -1 : 1; int dy = ( pt1.v - pt0.v )*yinc; int dx = ( pt1.h - pt0.h )*xinc; int x = pt0.h; int y = pt0.v; int d = 2*dx-dy; insert_pixel( x, y ); while ( y != pt1.v ) { if ( d >= 0 ) do { x += xinc; d -= 2*dy; } while ( d >= 0 ); d += 2*dx; y += yinc; insert_pixel( x, y ); } } void draw_segment( int y, int x0, int x1, int color ) { unsigned char *dstn = vram + y*hres; for ( int x = x0; x < x1; x++) dstn[ x ] = color; } void save_segment( int y, int x_lo, int x_hi ) { int xmin = 0, ymin = 0, xmax = hres-1, ymax = vres-1; if (( y < ymin )||( y > ymax )) return; if ( x_lo < xmin ) x_lo = xmin; if ( x_hi > xmax ) x_hi = xmax; if ( x_lo > x_hi ) return; segment[ y ][ 0 ] = x_lo; segment[ y ][ 1 ] = x_hi; } void draw_segments( int ymin, int ymax, int color ) { if ( ymin < 0 ) ymin = 0; if ( ymax > vres-1 ) ymin = vres-1; for (int y = ymin; y <= ymax; y++) draw_segment( y, segment[y][0], segment[y][1], color ); } void octant_points( int x_center, int y_center, int x, int y ) { save_segment( y_center + y, x_center - x, x_center + x ); save_segment( y_center - y, x_center - x, x_center + x ); save_segment( y_center + x, x_center - y, x_center + y ); save_segment( y_center - x, x_center - y, x_center + y ); } void fill_circle( int x_center, int y_center, int radius, int color ) { int x = 0, y = radius, d = 3 - 2*radius; while ( x <= y ) { octant_points( x_center, y_center, x, y ); if ( d < 0 ) { d += 6 + x * 4; ++x; } else { d += 10 + (x - y)*4; --y; ++x; } } draw_segments( y_center - radius, y_center + radius, color ); } void create_new_polygon( Polygon &poly ) { for (int i = 1; i < MAXVERT; i++) { poly.vert[i].h = (unsigned)rand() % hres; //random( HRES ); poly.vert[i].v = (unsigned)rand() % vres; //random( VRES ); } poly.numverts = 3; for (int i = 0; i < 2; i++) poly.vert[i] = poly.vert[ i + poly.numverts ]; } void do_scan_conversion( Polygon &poly ) { used = 0; init_buckets(); for (int i = 0; i < poly.numverts; i++) if ( poly.vert[i].v != poly.vert[i+1].v ) insert_line( poly.vert[i], poly.vert[i+1] ); for (int i = 0; i < poly.numverts; i++) { int y0 = poly.vert[i].v; int y1 = poly.vert[i+1].v; int y2 = poly.vert[i+2].v; int x1 = poly.vert[i+1].h; if ( between( y0, y1, y2 ) ) insert_pixel( x1, y1 ); } } void do_polygon_fill( int color ) { for (int y = 0; y < vres; y++) if ( bucket[ y ] != NIL ) { NodePtr p = bucket[y]; NodePtr q = p->next; while (( p != NIL )&&( q != NIL )) { draw_segment( y, p->x, q->x, color ); p = q->next; if ( p != NIL ) q = p->next; else q = p; } } } int main( void ) { // memory-map the frame-buffer to user-space int fd = open( "/dev/vram", O_RDWR ); if ( fd < 0 ) { perror( "/dev/vram" ); exit(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" ); exit(1); } // enable non-canonical terminal input struct termios tty; tcgetattr( 0, &tty ); struct termios otty = tty; tty.c_lflag &= ~( ECHO | ICANON | ISIG ); tty.c_cc[ VMIN ] = 1; tty.c_cc[ VTIME ] = 0; tcsetattr( 0, TCSAFLUSH, &tty ); // enter graphics mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); // draw the initial circle as background int color = 3; int radius = 200, x_center = hres/2, y_center = vres/2; fill_circle( x_center, y_center, radius, color ); getchar(); // show random color-filled polygons Polygon poly; do { create_new_polygon( poly ); do_scan_conversion( poly ); do_polygon_fill( ++color ); } while ( ( getchar() ) != '\e' ); // leave graphics mode vm.regs.eax = 0x4F02; vm.regs.ebx = 0x0003; int86( 0x10, vm ); tcsetattr( 0, TCSAFLUSH, &otty ); }