//---------------------------------------------------------------- // polyfill.cpp // // Adaptation of Bresenham's Line Algorithm to Polygon Fill // // NOTE: Compile for MS-DOS with Borland's TURBO-C++ // // programmer: ALLAN CRUSE // written on: 30 OCT 1997 //---------------------------------------------------------------- #include #include #include #define HRES 640 #define VRES 480 #define NIL 0 typedef struct { int h, v; } Point; const MAXVERT = 10; typedef struct { int numverts; Point vert[ 1+MAXVERT ]; } Polygon; typedef struct Node { int x; Node *next; } Node; typedef Node *NodePtr; int segment[ VRES ][2]; const MAXNODE = VRES*MAXVERT; Node pool[ MAXNODE ]; int used = 0; NodePtr bucket[ VRES ]; int between( int y1, int y2, int y3 ) { return ( ((y1 < y2)&&(y2 < y3)) || ((y1 > y2)&&(y2 > y3)) ); } void set_display_mode( int mode ) { union REGS r; r.h.ah = 0x00; r.h.al = mode; int86( 0x10, &r, &r ); } 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 ) { if (( y < 0 )||( y > VRES-1 )) return; if ( x < 0 ) x = 0; if ( x > HRES-1 ) x = HRES-1; 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 save_segment( int y, int x_lo, int x_hi ) { if (( y < 0 )||( y > 479 )) return; if ( x_lo < 0 ) x_lo = 0; if ( x_hi > 639 ) x_hi = 639; if ( x_lo > x_hi ) return; segment[ y ][ 0 ] = x_lo; segment[ y ][ 1 ] = x_hi; } void draw_segment( int y, int x0, int x1 ) { char far *vram = (char far *)MK_FP( 0xA000, y*80 ); int j0 = x0 / 8; // starting byte's offset int j1 = x1 / 8; // ending byte's offset int s0 = x0 % 8; // shift-factor for left endpoint int s1 = x1 % 8; // shift-factor for right endpoint for (int j = j0; j <= j1; j++) { char mask0 = ( j == j0 ) ? ( 0xFF >> s0 ) : 0xFF; char mask1 = ( j == j1 ) ? ~( 0x7F >> s1 ) : 0xFF; outportb( 0x3CE, 8 ); // select bitmask register outportb( 0x3CF, mask0 & mask1 ); // output mask vram[ j ] = vram[ j ]; } } void draw_segments( int ymin, int ymax, int color ) { outport( 0x3CE, 0x0005 ); // setup GC for Write Mode 0 outport( 0x3CE, 0x0003 ); // data-rotate/function-select outport( 0x3CE, 0x0F01 ); // enable set/reset register outportb( 0x3CE, 0 ); // select set/reset register outportb( 0x3CF, color & 0x0F ); // use color-value as fill if ( ymin < 0 ) ymin = 0; if ( ymax > 479 ) ymin = 479; for (int y = ymin; y <= ymax; y++) draw_segment( y, segment[y][0], segment[y][1] ); } 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; octant_points( x_center, y_center, x, y ); while ( x < y ) { if ( d < 0 ) { d += 6 + x*4; ++x; } else { d += 10 + (x - y)*4; --y; ++x; } octant_points( x_center, y_center, x, y ); } 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 = random( HRES ); poly.vert[i].v = random( VRES ); } poly.numverts = 3; for (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 (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 ) { outportb( 0x3CE, 0 ); outportb( 0x3CF, color & 0x0F ); 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 ); p = q->next; if ( p != NIL ) q = p->next; else q = p; } } } void main( void ) { set_display_mode( 0x12 ); int color = 3; int radius = 200, x_center = 320, y_center = 240; fill_circle( x_center, y_center, radius, color ); getch(); randomize(); Polygon poly; do { create_new_polygon( poly ); do_scan_conversion( poly ); do_polygon_fill( ++color ); } while ( getch() != 0x1B ); set_display_mode( 0x03 ); }