//------------------------------------------------------------------- // ellipse.cpp // // This is our initial prototype for a graphics animation that // will demonstrate the 'reflective property' for the ellipse. // // compile using: $ g++ ellipse.cpp int86.cpp -o ellipse // // programmer: ALLAN CRUSE // date begun: 04 NOV 2005 // completion: 07 NOV 2005 //------------------------------------------------------------------- #include // for fprintf(), perror() #include // for open() #include // for exit() #include // for lseek() #include // for mmap() #include // for inb() #include // for sin(), cos(), acos() #include "int86.h" // for init8086(), int86() #define PI 3.1459 #define TWO_PI (2.0 * PI) unsigned char *vram = (unsigned char*)0xA0000000; struct vm86plus_struct vm; int vesa_mode = 0x4105, hres = 1024, vres = 768; struct ellipse { double a, b, c; } ellipse; struct vector { double x, y; }; int xcent = hres/2, ycent = vres/2; void draw_pixel( int x, int y, int color ) { // transform the pixel to screen coordinates x = (xcent + x); y = (ycent - y); // clip if outside the screen window if (( x < 0 )||( x >= hres )) return; if (( y < 0 )||( y >= vres )) return; // draw the pixel on the screen vram[ y * hres + x ] = color; } void emit_pixel( double angle, double radius, struct ellipse e, int color ) { // point P on the circle of the given radius about focus1 double px = radius * cos( angle ) - e.c; double py = radius * sin( angle ); // distances from (px,py) to focus1 and to focus2 double from1 = sqrt( (px+e.c)*(px+e.c) + py*py ); double from2 = sqrt( (px-e.c)*(px-e.c) + py*py ); // now we can determine if P is inside or outside the ellipse if ( from1 + from2 + 1.0 < 2.0 * e.a ) { draw_pixel( (int)px, (int)py, color ); return; } // ok, we now know P is outside the ellipse /// draw_pixel( (int)px, (int)py, color+2 ); //------------------------------------------ // so we want to draw the reflected pixel Q //------------------------------------------ // point A is on circle about focus1 at angle alpha and distance 2a double major = 2.0 * e.a; double ax = major * cos( angle ) - e.c; double ay = major * sin( angle ); // ray1 is vector from A to focus1 struct vector ray1; ray1.x = -e.c - ax; ray1.y = - ay; // ray2 is vector from A to focus2 struct vector ray2; ray2.x = e.c - ax; ray2.y = - ay; // compute angle theta between ray1 and ray2 double ray1len = sqrt( ray1.x*ray1.x + ray1.y*ray1.y ); double ray2len = sqrt( ray2.x*ray2.x + ray2.y*ray2.y ); double dotprod = ray1.x*ray2.x + ray1.y*ray2.y; double theta = acos( dotprod / (ray1len * ray2len) ); // compute angle omega = alpha + 2*theta; double omega = angle + 2.0 * theta; // compute radius2 = 2a - radius; double radius2 = major - radius; double qx = radius2 * cos( omega ) + e.c; double qy = radius2 * sin( omega ); // see if Q is outside the ellipse from1 = sqrt( (qx+e.c)*(qx+e.c) + qy*qy ); from2 = sqrt( (qx-e.c)*(qx-e.c) + qy*qy ); if ( from1 + from2 + 1.0 < major ) draw_pixel( (int)qx, (int)qy, color ); } 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; if ( mmap( (void*)vram, size, prot, flag, vd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode 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(); // draw the ellipse double semimajor = hres / 4.0, semiminor = vres / 4.0; double angle_inc = TWO_PI / (4.0 * 360.0); for (double angle = 0.0; angle < TWO_PI; angle += angle_inc) { double x = semimajor * cos( angle ); double y = semiminor * sin( angle ); draw_pixel( (int)x, (int)y, color ); } getchar(); // draw the two foci double semifocus = sqrt( semimajor*semimajor - semiminor*semiminor ); double c = semifocus, o = 0.0; draw_pixel( (int)(-c), (int)(o), color ); draw_pixel( (int)( c), (int)(o), color ); getchar(); // draw circle around focus ellipse.a = semimajor; ellipse.b = semiminor; ellipse.c = semifocus; int black = 0, green = 10; double radius_max = (2.0 * semimajor); double radius_inc = radius_max / 100.0; int count = 0; int done = 0; double ang_inc = TWO_PI / 25.0; double angle = 0.0; while ( !done ) { double percent = (double)(rand() / 100); angle += ang_inc; double radius = 0.0; while ( radius < radius_max ) { radius += 4.0; emit_pixel( angle, radius, ellipse, green ); // wait for next vertical blanking interval while ( (inb( 0x3DA )&8) == 8 ); while ( (inb( 0x3DA )&8) == 0 ); } ++count; if ( count >= 10 ) done = 1; } count = 0; done = 0; while ( !done ) { double radius = 0.0; while ( radius < radius_max ) { radius += radius_inc; // show the wave for (double alpha = -PI; alpha < PI; alpha += angle_inc) emit_pixel( alpha, radius, ellipse, green ); // wait for next verticle blanking interval while ( (inb( 0x3DA )&8) == 8 ); while ( (inb( 0x3DA )&8) == 0 ); // hide the wave for (double alpha = -PI; alpha < PI; alpha += angle_inc) emit_pixel( alpha, radius, ellipse, black ); } ++count; if ( count >= 10 ) done = 1; } // leave graphics mode vm.regs.eax = 0x0003; int86( 0x10, vm ); fprintf( stdout, "\n" ); }