home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / PJGRAPH.ZIP / CHAP12.1 < prev    next >
Encoding:
Text File  |  1989-09-26  |  6.5 KB  |  191 lines

  1. /* Turbo C implementation of Bresenham's line-drawing algorithm
  2.  * for the EGA and VGA. Works in modes 0xE, 0xF, 0x10, and 0x12.
  3.  *
  4.  * Compiled with Turbo C 2.0.
  5.  *
  6.  * By Michael Abrash.  2/4/89.
  7.  */
  8. #include <dos.h>     /* contains MK_FP macro */
  9.  
  10. #define EVGA_SCREEN_WIDTH_IN_BYTES     80
  11.                                        /* memory offset from start of
  12.                                           one row to start of next */
  13. #define EVGA_SCREEN_SEGMENT            0xA000
  14.                                        /* display-memory segment */
  15. #define GC_INDEX                       0x3CE
  16.                                        /* Graphics Controller
  17.                                           Index register port */
  18. #define GC_DATA                        0x3CF
  19.                                        /* Graphics Controller
  20.                                           Data register port */
  21. #define SET_RESET_INDEX                0  /* indexes of needed */
  22. #define ENABLE_SET_RESET_INDEX         1  /* Graphics Controller */
  23. #define BIT_MASK_INDEX                 8  /* registers */
  24.  
  25. /*
  26.  * Draws a dot at (X0,Y0) in whatever color the EGA/VGA hardware is
  27.  * set up for. Leaves the bit mask set to whatever value the
  28.  * dot required.
  29.  */
  30. void EVGADot(X0, Y0)
  31. unsigned int X0;     /* coordinates at which to draw dot, with */
  32. unsigned int Y0;     /* (0,0) at the upper left of the screen */
  33. {
  34.    unsigned char far *PixelBytePtr;
  35.    unsigned char PixelMask;
  36.  
  37.    /* Calculate the offset in the screen segment of the byte in
  38.       which the pixel lies */
  39.    PixelBytePtr = MK_FP(EVGA_SCREEN_SEGMENT,
  40.       ( Y0 * EVGA_SCREEN_WIDTH_IN_BYTES ) + ( X0 / 8 ));
  41.  
  42.    /* Generate a mask with a 1 bit in the pixel's position within the
  43.       screen byte */
  44.    PixelMask = 0x80 >> ( X0 & 0x07 );
  45.  
  46.    /* Set up the Graphics Controller's Bit Mask register to allow
  47.       only the bit corresponding to the pixel being drawn to
  48.       be modified */
  49.    outportb(GC_INDEX, BIT_MASK_INDEX);
  50.    outportb(GC_DATA, PixelMask);
  51.  
  52.    /* Draw the pixel. Because of the operation of the set/reset
  53.       feature of the EGA/VGA, the value written doesn't matter.
  54.       The screen byte is ORed in order to perform a read to latch the
  55.       display memory, then perform a write in order to modify it. 
  56. */
  57.    *PixelBytePtr |= 0xFF;
  58. }
  59.  
  60. /*
  61.  * Draws a line in octant 0 or 3 ( |DeltaX| >= DeltaY ).
  62.  * |DeltaX|+1 points are drawn.
  63.  */
  64. void Octant0(X0, Y0, DeltaX, DeltaY, XDirection)
  65. unsigned int X0, Y0;          /* coordinates of start of the line */
  66. unsigned int DeltaX, DeltaY;  /* length of the line */
  67. int XDirection;               /* 1 if line is drawn left to right,
  68.                                  -1 if drawn right to left */
  69. {
  70.    int DeltaYx2;
  71.    int DeltaYx2MinusDeltaXx2;
  72.    int ErrorTerm;
  73.  
  74.    /* Set up initial error term and values used inside drawing loop */
  75.    DeltaYx2 = DeltaY * 2;
  76.    DeltaYx2MinusDeltaXx2 = DeltaYx2 - (int) ( DeltaX * 2 );
  77.    ErrorTerm = DeltaYx2 - (int) DeltaX;
  78.  
  79.    /* Draw the line */
  80.    EVGADot(X0, Y0);              /* draw the first pixel */
  81.    while ( DeltaX-- ) {
  82.       /* See if it's time to advance the Y coordinate */
  83.       if ( ErrorTerm >= 0 ) {
  84.          /* Advance the Y coordinate & adjust the error term
  85.             back down */
  86.          Y0++;
  87.          ErrorTerm += DeltaYx2MinusDeltaXx2;
  88.       } else {
  89.          /* Add to the error term */
  90.          ErrorTerm += DeltaYx2;
  91.       }
  92.       X0 += XDirection;          /* advance the X coordinate */
  93.       EVGADot(X0, Y0);           /* draw a pixel */
  94.    }
  95. }
  96.  
  97. /*
  98.  * Draws a line in octant 1 or 2 ( |DeltaX| < DeltaY ).
  99.  * |DeltaY|+1 points are drawn.
  100.  */
  101. void Octant1(X0, Y0, DeltaX, DeltaY, XDirection)
  102. unsigned int X0, Y0;          /* coordinates of start of the line */
  103. unsigned int DeltaX, DeltaY;  /* length of the line */
  104. int XDirection;               /* 1 if line is drawn left to right,
  105.                                  -1 if drawn right to left */
  106. {
  107.    int DeltaXx2;
  108.    int DeltaXx2MinusDeltaYx2;
  109.    int ErrorTerm;
  110.  
  111.    /* Set up initial error term and values used inside drawing loop */
  112.    DeltaXx2 = DeltaX * 2;
  113.    DeltaXx2MinusDeltaYx2 = DeltaXx2 - (int) ( DeltaY * 2 );
  114.    ErrorTerm = DeltaXx2 - (int) DeltaY;
  115.  
  116.    EVGADot(X0, Y0);           /* draw the first pixel */
  117.    while ( DeltaY-- ) {
  118.       /* See if it's time to advance the X coordinate */
  119.       if ( ErrorTerm >= 0 ) {
  120.          /* Advance the X coordinate & adjust the error term
  121.             back down */
  122.          X0 += XDirection;
  123.          ErrorTerm += DeltaXx2MinusDeltaYx2;
  124.       } else {
  125.          /* Add to the error term */
  126.          ErrorTerm += DeltaXx2;
  127.       }
  128.       Y0++;                   /* advance the Y coordinate */
  129.       EVGADot(X0, Y0);        /* draw a pixel */
  130.    }
  131. }
  132.  
  133. /*
  134.  * Draws a line on the EGA or VGA.
  135.  */
  136. void EVGALine(X0, Y0, X1, Y1, Color)
  137. int X0, Y0;    /* coordinates of one end of the line */
  138. int X1, Y1;    /* coordinates of the other end of the line */
  139. char Color;    /* color to draw line in */
  140. {
  141.    int DeltaX, DeltaY;
  142.    int Temp;
  143.  
  144.    /* Set the drawing color */
  145.  
  146.    /* Put the drawing color in the Set/Reset register */
  147.    outportb(GC_INDEX, SET_RESET_INDEX);
  148.    outportb(GC_DATA, Color);
  149.    /* Cause all planes to be forced to the Set/Reset color */
  150.    outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
  151.    outportb(GC_DATA, 0xF);
  152.  
  153.    /* Save half the line-drawing cases by swapping Y0 with Y1
  154.       and X0 with X1 if Y0 is greater than Y1. As a result, DeltaY
  155.       is always > 0, and only the octant 0-3 cases need to be
  156.       handled. */
  157.    if ( Y0 > Y1 ) {
  158.       Temp = Y0;
  159.       Y0 = Y1;
  160.       Y1 = Temp;
  161.       Temp = X0;
  162.       X0 = X1;
  163.       X1 = Temp;
  164.    }
  165.  
  166.    /* Handle as four separate cases, for the four octants in which
  167.       Y1 is greater than Y0 */
  168.    DeltaX = X1 - X0;    /* calculate the length of the line
  169.                            in each coordinate */
  170.    DeltaY = Y1 - Y0;
  171.    if ( DeltaX > 0 ) {
  172.       if ( DeltaX > DeltaY ) {
  173.          Octant0(X0, Y0, DeltaX, DeltaY, 1);
  174.       } else {
  175.          Octant1(X0, Y0, DeltaX, DeltaY, 1);
  176.       }
  177.    } else {
  178.       DeltaX = -DeltaX;             /* absolute value of DeltaX */
  179.       if ( DeltaX > DeltaY ) {
  180.          Octant0(X0, Y0, DeltaX, DeltaY, -1);
  181.       } else {
  182.          Octant1(X0, Y0, DeltaX, DeltaY, -1);
  183.       }
  184.    }
  185.  
  186.    /* Return the state of the EGA/VGA to normal */
  187.    outportb(GC_INDEX, ENABLE_SET_RESET_INDEX);
  188.    outportb(GC_DATA, 0);
  189.    outportb(GC_INDEX, BIT_MASK_INDEX);
  190.    outportb(GC_DATA, 0xFF);
  191. }