/* * C implementation of Bresenham's line drawing algorithm * for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12. * * Compiled with Microsoft C 5.1 and Turbo C 2.0. * * By John Navas. Thursday June 8, 1989. */ #include #include /*------------------------ SUPPORT FOR TURBO C --------------------------*/ #ifdef __TURBOC__ #undef outp #define outp(port, val) (((int(*)(int, unsigned char))outportb)(port, val)) #endif /*-----------------------------------------------------------------------*/ #define EVGA_SCREEN_WIDTH_IN_BYTES 80 /* memory offset from start of one row to start of next */ #define EVGA_SCREEN_ADDRESS 0xA0000000 /* display memory address */ #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 */ char far *Display = (char far *)EVGA_SCREEN_ADDRESS; /* macro to swap two items of any type */ #define swap(typ, a, b) { typ x = *(a); *(a) = *(b); *(b) = x; } /* * 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 Cnt, Err = 0; unsigned Mask; DeltaX = X1 - X0; if (DeltaX < 0) { DeltaX = -DeltaX; swap(int, &X0, &X1); /* ensure drawing from left to right */ swap(int, &Y0, &Y1); } DeltaY = Y1 - Y0; if (DeltaY < 0) DeltaY = -DeltaY; FP_OFF(Display) = /* starting video address and bit mask */ (unsigned)X0 / 8 + (unsigned)Y0 * EVGA_SCREEN_WIDTH_IN_BYTES; Mask = 0x80 > ((unsigned)X0 & 7); /* Put the drawing Color in the Set/Reset register */ outp(GC_INDEX, SET_RESET_INDEX); outp(GC_DATA, Color); /* Cause all planes to be forced to the Set/Reset color */ outp(GC_INDEX, ENABLE_SET_RESET_INDEX); outp(GC_DATA, 0xF); /* Set up GC index register to point to the bit mask register */ outp(GC_INDEX, BIT_MASK_INDEX); if (DeltaX >= DeltaY) { /* more horizontal */ unsigned Acc = 0; /* accumulator for byte */ if (Y1 >= Y0) /* down slope */ for (Cnt = X1 - X0; Cnt; --Cnt) { Acc |= Mask; Mask >= 1; if (!Mask) { Mask = 0x80; *Display |= outp(GC_DATA, Acc); /* quick video write */ Acc = 0; ++Display; } Err += DeltaY; if (Err >= DeltaX) { Err -= DeltaX; if (Acc) { *Display |= outp(GC_DATA, Acc); Acc = 0; } Display += EVGA_SCREEN_WIDTH_IN_BYTES; } } else /* up slope */ for (Cnt = X1 - X0; Cnt; --Cnt) { Acc |= Mask; Mask >= 1; if (!Mask) { Mask = 0x80; *Display |= outp(GC_DATA, Acc); Acc = 0; ++Display; } Err += DeltaY; if (Err >= DeltaX) { Err -= DeltaX; if (Acc) { *Display |= outp(GC_DATA, Acc); Acc = 0; } Display -= EVGA_SCREEN_WIDTH_IN_BYTES; } } Mask |= Acc; /* setup mask for last video write */ } else /* more vertical */ if (Y1 >= Y0) /* down slope */ for (Cnt = Y1 - Y0; Cnt; --Cnt) { *Display |= outp(GC_DATA, Mask); Display += EVGA_SCREEN_WIDTH_IN_BYTES; Err += DeltaX; if (Err >= DeltaY) { Err -= DeltaY; Mask >= 1; if (!Mask) { Mask = 0x80; ++Display; } } } else /* up slope */ for (Cnt = Y0 - Y1; Cnt; --Cnt) { *Display |= outp(GC_DATA, Mask); Display -= EVGA_SCREEN_WIDTH_IN_BYTES; Err += DeltaX; if (Err >= DeltaY) { Err -= DeltaY; Mask >= 1; if (!Mask) { Mask = 0x80; ++Display; } } } *Display |= outp(GC_DATA, Mask); /* last video write for all 4 cases */ /* Return the state of the EGA/VGA to normal */ outp(GC_INDEX, ENABLE_SET_RESET_INDEX); outp(GC_DATA, 0); outp(GC_INDEX, BIT_MASK_INDEX); outp(GC_DATA, 0xFF); }