home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
progjorn
/
pj_7_5.arc
/
EVGALINE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-03
|
5KB
|
153 lines
/*
* 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 <conio.h>
#include <dos.h>
/*------------------------ 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);
}