//------------------------------------------------------------------- // animate1.cpp // // This program shows how to synchronize vram updates with the // CRT's Vertical Retrace signal, so that drawing occurs while // the screen is blanked, thus allowing for smooth animations. // It's an initial prototype for implementing the "pong" game. // (But it has a subtle visual flaw for you find -- and fix!) // // compile using: $ g++ animate1.cpp int86.cpp -o animate1 // // programmer: ALLAN CRUSE // date begun: 21 AUG 2003 // completion: 17 SEP 2003 // revised on: 10 SEP 2005 -- replaced svgalib with 'int86()' //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for close() #include // for mman() #include // for iopl(), inb() #include "int86.h" // for init8086(), int86() #define INPUT_STATUS_1 0x3DA #define VRAM_BASE 0xA0000000 #define VRAM_SIZE (1 << 20) typedef unsigned char PEL; PEL *fb = (PEL*)VRAM_BASE; int vesa_mode = 0x4101, hres = 640, vres = 480; struct vm86plus_struct vm; char devname[] = "/dev/vram"; void vertical_retrace_sync( void ) { // wait for current retrace to finish while ( ( inb( INPUT_STATUS_1 ) & 8 ) == 8 ); // then wait till next retrace begins while ( ( inb( INPUT_STATUS_1 ) & 8 ) == 0 ); } 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 { fb[ y*hres + x ] = color; ++x; } while ( x < maxx ); do { fb[ y*hres + x ] = color; ++y; } while ( y < maxy ); do { fb[ y*hres + x ] = color; --x; } while ( x > minx ); do { fb[ y*hres + x ] = color; --y; } while ( y > miny ); } void fill_rectangle( int x, int y, int h, int v, int color ) { int minx = x, miny = y, maxx = x+h-1, maxy = y+v-1; for (y = miny; y <= maxy; y++) for (x = minx; x < maxx; x++) fb[ y*hres + x ] = color; } void fill_oval( int x, int y, int h, int v, int color ) { int midh = (h+1)/2, midv = (v+1)/2; for (int r = 0; r < v; r++) for (int k = 0; k < h; k++) { int dh = k - midh; int dv = r - midv; int rr = midh * midv; dh *= midv; dv *= midh; if ( dh*dh + dv*dv < rr*rr ) fb[ (y+r)*hres + (x+k) ] = color; } } int main( int argc, char **argv ) { int speed = 2; // set the default speed // allow the user to specify an alternative speed if ( argc > 1 ) { int arg = atoi( argv[1] ); if (( arg > 0 )&( arg < 10 )) speed = arg; } // memory-map the SVGA display memory int size = VRAM_SIZE; int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)VRAM_BASE; int fd = open( devname, O_RDWR ); if ( fd < 0 ) { perror( devname ); exit(1); } if ( mmap( mm, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode init8086(); // initialize ram and IO vm.regs.eax = 0x4F02; // VESA Set Display Mode vm.regs.ebx = vesa_mode; // 640-by-480, 256-color int86( 0x10, vm ); // invoke BIOS service // draw screen border int black = 0, white = 15, blue = 9, green = 10, yellow = 14; int x = 0, y = 0, wide = hres, high = vres; draw_rectangle( x, y, wide, high, white ); getchar(); // draw game wall x += 40, y += 30, wide -= 80, high -= 60; fill_rectangle( x, y, wide, high, blue ); x += 20, y += 20, wide -= 40, high -= 40; fill_rectangle( x, y, wide, high, black ); getchar(); // draw game ball int xpos = 100, ypos = 200, diam = 20; fill_oval( xpos, ypos, diam, diam, yellow ); getchar(); // draw game paddle fill_rectangle( 80, 454, 100, 8, green ); getchar(); // animate the game ball int minx = x, maxx = x+wide-diam, dx = 1; int miny = y, maxy = y+high-diam, dy = -1; int incs, xold, yold; int hits = 5; do { xold = xpos; yold = ypos; for (int incs = 0; incs < speed; incs++) { xpos += dx; ypos += dy; if (( xpos <= minx )||( xpos >= maxx )) dx = -dx; if (( ypos <= miny )||( ypos >= maxy )) dy = -dy; if ( ypos >= maxy ) --hits; } vertical_retrace_sync(); fill_oval( xold, yold, diam, diam, black ); fill_oval( xpos, ypos, diam, diam, yellow ); } while ( hits > 0 ); // leave graphics mode vm.regs.eax = 0x0003; // VGA Set Display Mode int86( 0x10, vm ); // invoke BIOS service printf( "\n" ); }