//------------------------------------------------------------------- // bouncing.cpp // // This animation was constructed purely for demonstrating some // graphics principles. First, it illustrates the 'tearing' of // images which can occur when more redrawing is attempted than // there is time for during the vertical blanking interval. We // will need to employ some special techniques to overcome this // 'image-tearing' effect. Second, we can use this application // as a platform upon which to try mechanisms for synchronizing // the timing of sound-effects with actions that are displayed. // // compile using: $ g++ bouncing.cpp int86.cpp -o bouncing // // programmer: ALLAN CRUSE // date begun: 27 SEP 2005 //------------------------------------------------------------------- #include // for perror() #include // for open() #include // for exit() #include // for lseek() #include // for mmap() #include // for inb(), outb(), etc. #include "int86.h" // for init8086(), int86() unsigned char *vram = (unsigned char*)0xA0000000; int vesa_mode = 0x4105, hres = 1024, vres = 768; struct vm86plus_struct vm; void draw_horizontal_segments( int x, int y, int xcent, int ycent, int color ) { // This is a helper-function for the circle-filling function. // It draws four horizontal line-segments which join pairs of // the eight symmetrically placed images of point (x,y) about // a 'center' located at (xcent,ycent), making sure to 'clip' // these segments to stay within the screen-dimension bounds. int xmin = 0, ymin = 0, xmax = hres-1, ymax = vres-1; int xlo, xhi, ylo, yhi, h; xlo = xcent - x, xhi = xcent + x, ylo = ycent - y, yhi = ycent + y; if ( xlo < xmin ) xlo = xmin; if ( xhi > xmax ) xhi = xmax; if (( ylo >= ymin )&&( ylo <= ymax )) for (h = xlo; h <= xhi; h++) vram[ ylo * hres + h ] = color; if (( yhi >= ymin )&&( yhi <= ymax )) for (h = xlo; h <= xhi; h++) vram[ yhi * hres + h ] = color; xlo = xcent - y, xhi = xcent + y, ylo = ycent - x, yhi = ycent + x; if ( xlo < xmin ) xlo = xmin; if ( xhi > xmax ) xhi = xmax; if (( ylo >= ymin )&&( ylo <= ymax )) for (h = xlo; h <= xhi; h++) vram[ ylo * hres + h ] = color; if (( yhi >= ymin )&&( yhi <= ymax )) for (h = xlo; h <= xhi; h++) vram[ yhi * hres + h ] = color; } void fill_circle( int x, int y, int radius, int color ) { // This routine fills a circular region based Michner's Algorithm int xcent = x, ycent = y, decision_var = 3 - 2*radius; for (y = radius, x = 0; x < radius; x++) { if ( x > y ) break; draw_horizontal_segments( x, y, xcent, ycent, color ); if ( decision_var < 0 ) decision_var += 4*x + 6; else { decision_var += 4*(x - y) + 10; --y; } } } void vertical_retrace_sync( void ) { while ( ( inb( 0x3DA )&8 ) == 8 ); while ( ( inb( 0x3DA )&8 ) == 0 ); } int main( int argc, char **argv ) { // memory-map the display-memory into user-space int vd = open( "/dev/vram", O_RDWR ); if ( vd < 0 ) { perror( "/dev/vram" ); exit(1); } int size = lseek( vd, 0, SEEK_END ); int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)vram; if ( mmap( mm, size, prot, flag, vd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode printf( "\e[H\n" ); init8086(); vm.regs.eax = 0x4F02; vm.regs.ebx = vesa_mode; int86( 0x10, vm ); // draw screen border int x = 0, y = 0, color = 15; do { vram[ y * hres + x ] = color; ++x; } while ( x < hres-1 ); do { vram[ y * hres + x ] = color; ++y; } while ( y < vres-1 ); do { vram[ y * hres + x ] = color; --x; } while ( x > 0 ); do { vram[ y * hres + x ] = color; --y; } while ( y > 0 ); getchar(); // show the ball in its initial position int radius = vres/8, black = 0; x = hres/2, y = vres/2, color = 13; fill_circle( x, y, radius, color ); getchar(); // show the 'bouncing ball' animation int dy = 4; for (int t = 0; t < 1000; t++) { fill_circle( x, y, radius, black ); y += dy; if ( y >= vres-2-radius ) { y = vres-2-radius; dy = -dy; } if ( y <= radius+1 ) { y = radius+1; dy = -dy; } fill_circle( x, y, radius, color ); vertical_retrace_sync(); } getchar(); // leave graphics mode vm.regs.eax = 0x0003; int86( 0x10, vm ); printf( "\n" ); }