home *** CD-ROM | disk | FTP | other *** search
- /*
- * *** Listing 1 ***
- *
- * Turbo C implementation of Bresenham's line drawing algorithm
- * for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12.
- *
- * Compiled with Turbo C 2.0.
- *
- * By Michael Abrash. 2/4/89.
- */
- #include <dos.h> /* contains MK_FP macro */
-
- #define EVGA_SCREEN_WIDTH_IN_BYTES 80
- /* memory offset from start of
- one row to start of next */
- #define EVGA_SCREEN_SEGMENT 0xA000
- /* display memory segment */
- #define GC_INDEX 0x3CE
- /* Graphics Controller
- Index register port */
- #define GC_DATA 0x3CF
- /* Graphics Controller
- Data register port */
- #define SET_RESET_INDEX 0 /* indexes of needed */
- #define ENABLE_SET_RESET_INDEX 1 /* Graphics Controller */
- #define BIT_MASK_INDEX 8 /* registers */
-
- /*
- * Draws a dot at (X0,Y0) in whatever color the EGA/VGA hardware is
- * set up for. Leaves the bit mask set to whatever value the
- * dot required.
- */
- void EVGADot(X0, Y0)
- unsigned int X0; /* coordinates at which to draw dot, with */
- unsigned int Y0; /* (0,0) at the upper left of the screen */
- {
- unsigned char far *PixelBytePtr;
- unsigned char PixelMask;
-
- /* Calculate the offset in the screen segment of the byte in
- which the pixel lies */
- PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT,
- ( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 ));
-
- /* Generate a mask with a 1 bit in the pixel's position within the
- screen byte */
- PixelMask = 0x80 >> ( X0 & 0x07 );
-
- /* Set up the Graphics Controller's Bit Mask register to allow
- only the bit corresponding to the pixel being drawn to
- be modified */
- outportb(GC_INDEX, BIT_MASK_INDEX);
- outportb(GC_DATA, PixelMask);
-
- /* Draw the pixel. Because of the operation of the set/reset
- feature of the EGA/VGA, the value written doesn't matter.
- The screen byte is ORed in order to perform a read to latch the
- display memory, then perform a write in order to modify it. */
- *PixelBytePtr |= 0xFF;
- }
-
- /*
- * Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
- * |DeltaX|+1 points are drawn.
- */
- void Octant0(X0, Y0, DeltaX, DeltaY, XDirection)
- unsigned int X0, Y0; /* coordinates of start of the line */
- unsigned int DeltaX, DeltaY; /* length of the line */
- int XDirection; /* 1 if line is drawn left to right,
- -1 if drawn right to left */
- {
- int DeltaYx2;
- int DeltaYx2MinusDeltaXx2;
- int ErrorTerm;
-
- /* Set up initial error term and values used inside drawing loop */
- DeltaYx2 = DeltaY * 2;
- DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
- ErrorTerm = DeltaYx2 - (int) DeltaX;
-
- /* Draw the line */
- EVGADot(X0, Y0); /* draw the first pixel */
- while ( DeltaX-- ) {
- /* See if it's time to advance the Y coordinate */
- if ( ErrorTerm >= 0 ) {
- /* Advance the Y coordinate & adjust the error term
- back down */
- Y0++;
- ErrorTerm += DeltaYx2MinusDeltaXx2;
- } else {
- /* Add to the error term */
- ErrorTerm += DeltaYx2;
- }
- X0 += XDirection; /* advance the X coordinate */
- EVGADot(X0, Y0); /* draw a pixel */
- }
- }
-
- /*
- * Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
- * |DeltaY|+1 points are drawn.
- */
- void Octant1(X0, Y0, DeltaX, DeltaY, XDirection)
- unsigned int X0, Y0; /* coordinates of start of the line */
- unsigned int DeltaX, DeltaY; /* length of the line */
- int XDirection; /* 1 if line is drawn left to right,
- -1 if drawn right to left */
- {
- int DeltaXx2;
- int DeltaXx2MinusDeltaYx2;
- int ErrorTerm;
-
- /* Set up initial error term and values used inside drawing loop */
- DeltaXx2 = DeltaX * 2;
- DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
- ErrorTerm = DeltaXx2 - (int) DeltaY;
-
- EVGADot(X0, Y0); /* draw the first pixel */
- while ( DeltaY-- ) {
- /* See if it's time to advance the X coordinate */
- if ( ErrorTerm >= 0 ) {
- /* Advance the X coordinate & adjust the error term
- back down */
- X0 += XDirection;
- ErrorTerm += DeltaXx2MinusDeltaYx2;
- } else {
- /* Add to the error term */
- ErrorTerm += DeltaXx2;
- }
- Y0++; /* advance the Y coordinate */
- EVGADot(X0, Y0); /* draw a pixel */
- }
- }
-
- /*
- * Draws a line on the EGA or VGA.
- */
- void EVGALine(X0, Y0, X1, Y1, Color)
- int X0, Y0; /* coordinates of one end of the line */
- int X1, Y1; /* coordinates of the other end of the line */
- char Color; /* color to draw line in */
- {
- int DeltaX, DeltaY;
- int Temp;
-
- /* Set the drawing color */
-
- /* Put the drawing color in the Set/Reset register */
- outportb(GC_INDEX, SET_RESET_INDEX);
- outportb(GC_DATA, Color);
- /* Cause all planes to be forced to the Set/Reset color */
- outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
- outportb(GC_DATA, 0xF);
-
- /* Save half the line-drawing cases by swapping Y0 with Y1
- and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
- is always > 0, and only the octant 0-3 cases need to be
- handled. */
- if ( Y0 > Y1 ) {
- Temp = Y0;
- Y0 = Y1;
- Y1 = Temp;
- Temp = X0;
- X0 = X1;
- X1 = Temp;
- }
-
- /* Handle as four separate cases, for the four octants in which
- Y1 is greater than Y0 */
- DeltaX = X1 - X0; /* calculate the length of the line
- in each coordinate */
- DeltaY = Y1 - Y0;
- if ( DeltaX > 0 ) {
- if ( DeltaX > DeltaY ) {
- Octant0(X0, Y0, DeltaX, DeltaY, 1);
- } else {
- Octant1(X0, Y0, DeltaX, DeltaY, 1);
- }
- } else {
- DeltaX = -DeltaX; /* absolute value of DeltaX */
- if ( DeltaX > DeltaY ) {
- Octant0(X0, Y0, DeltaX, DeltaY, -1);
- } else {
- Octant1(X0, Y0, DeltaX, DeltaY, -1);
- }
- }
-
- /* Return the state of the EGA/VGA to normal */
- outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
- outportb(GC_DATA, 0);
- outportb(GC_INDEX, BIT_MASK_INDEX);
- outportb(GC_DATA, 0xFF);
- }