Category : Files from Magazines
Archive   : PJ-VGA.ZIP
Filename : EVGALINE.C

 
Output of file : EVGALINE.C contained in archive : PJ-VGA.ZIP
/*
* *** 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 /* 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);
}


  3 Responses to “Category : Files from Magazines
Archive   : PJ-VGA.ZIP
Filename : EVGALINE.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/