//------------------------------------------------------------------- // bezier.cpp // // This program uses the deCasteljau recursive algorithm to // draw a bezier curve. // // compile using: $ g++ bezier.cpp int86.cpp -o bezier // // programmer: Kai Long // written on: 21 October 2003 // revised on: 8 November 2005 by Allan Cruse for Linux 2.6.12 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for lseek(), read(), sleep() #include // for mmap() #include // for gettimeofday() #include // for tcgetattr(), tcsetattr() #include // for inb() #include // for fabs() #include "int86.h" // for init8086(), int86() unsigned char *vram = (unsigned char*)0xA0000000; int hres = 640, vres = 480, display_mode = 0x4101; struct vm86plus_struct vm; #define MAXVERT 10 // maximum number of control points typedef struct { double h, v; } Point; typedef struct { int numcpts; Point cpts[ 1+MAXVERT ]; } BezierCurve; #define ESCAPE_KEY 0x1B #define random(range) (int)(range*((float)rand()/RAND_MAX)) void draw_rectangle( int x, int y, int h, int v, int color ) { int minx = x, miny = y, maxx = x+h-1, maxy = y+v-1; do { vram[ y*hres + x ] = color; ++x; } while ( x < maxx ); do { vram[ y*hres + x ] = color; ++y; } while ( y < maxy ); do { vram[ y*hres + x ] = color; --x; } while ( x > minx ); do { vram[ y*hres + x ] = color; --y; } while ( y > miny ); } void draw_pixel( int x, int y, int color ) { if (( x < 0 )||( x >= hres )) return; if (( y < 0 )||( y >= vres )) return; vram[ y*hres + x ] = color; } void draw_line( int x1, int y1, int x2, int y2, int color ) { 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; if (( deltax == 0 )&&( deltay == 0 )) { draw_pixel( x1, y1, color ); return; } if ( deltay <= deltax ) // odd octant { int errorterm = - deltax; do { draw_pixel( x1, y1, color ); errorterm += 2*deltay; if ( errorterm >= 0 ) { y1 += yinc; errorterm -= 2*deltax; } x1 += xinc; } while ( x1 != x2 ); } else { int errorterm = - deltay; do { draw_pixel( x1, y1, color ); errorterm += 2*deltax; if ( errorterm >= 0 ) { x1 += xinc; errorterm -= 2*deltay; } y1 += yinc; } while ( y1 != y2 ); } } // to caculate the middle point of two points void middle(Point &p0, Point &p1, Point &p01) { p01.h = (p0.h+p1.h)/2; p01.v = (p0.v+p1.v)/2; } // recursive function to implement deCasteljau algorithm void recursive_bezier(Point &p1, Point &h1, Point &h2, Point &p2, int color) { if(fabs(p1.h - p2.h) <=1 && fabs(p1.v - p2.v) <=1) { draw_line((int)p1.h, (int)p1.v, (int)p2.h, (int)p2.v, color); } else { Point 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); recursive_bezier(d, c2, b2, p2, color); } } // function to draw Bezier curve void draw_bezier(BezierCurve &bezier, int color) { recursive_bezier(bezier.cpts[0], bezier.cpts[1], bezier.cpts[2], bezier.cpts[3], color); } void create_new_bezier(BezierCurve &bezier) { bezier.numcpts = 4; //cpts > 3 ? cpts : 4; for(int i = 0; i < bezier.numcpts; i++) { bezier.cpts[i].h = random(hres); bezier.cpts[i].v = random(vres); } } void vsync( void ) { // wait for current retrace to finish while ( ( inb( 0x3DA ) & 8 ) != 8 ); // then wait till next retrace begins while ( ( inb( 0x3DA ) & 8 ) == 8 ); } int main( int argc, char **argv ) { // memory-map VRAM to this application's address-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; void *mm = mmap( (void*)vram, size, prot, flag, fd, 0 ); if ( mm == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = display_mode; int86( 0x10, vm ); // draw screen border int white = 15, magenta = 5; draw_rectangle( 0, 0, hres, vres, white ); getchar(); // save a copy of the current terminal's default settings struct termios orig_termios; if ( tcgetattr( STDIN_FILENO, &orig_termios ) < 0 ) { perror( "tcgetattr" ); exit(1); } struct termios work_termios = orig_termios; work_termios.c_lflag &= ~ISIG; work_termios.c_lflag &= ~ECHO; work_termios.c_lflag &= ~ICANON; work_termios.c_cc[ VMIN ] = 0; work_termios.c_cc[ VTIME ] = 0; tcsetattr( STDIN_FILENO, TCSAFLUSH, &work_termios ); int done=0; // set the seed for rand int generation struct timeval t; gettimeofday(&t,NULL); srand(t.tv_sec); BezierCurve bezier; // use deCasteljau algorithm to draw Bezier curves int color = 3; do { int inch = 0; read(STDIN_FILENO, &inch, sizeof(inch)); if(inch == ESCAPE_KEY) done=1; create_new_bezier(bezier); draw_bezier(bezier, color++); vsync(); sleep(1); draw_bezier(bezier, 0); } while(!done); // leave graphics mode vm.regs.eax = 0x0003; int86( 0x10, vm ); tcsetattr( STDIN_FILENO, TCSAFLUSH, &orig_termios ); }