home *** CD-ROM | disk | FTP | other *** search
/ Graphics Programming Black Book (Special Edition) / BlackBook.bin / disk1 / source / chapterd / ld-4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-18  |  5.3 KB  |  159 lines

  1. /* *** Listing 19.4 ***
  2.  *
  3.  * Draws an ellipse of the specified X and Y axis radii and color,
  4.  * using a fast integer-only & square-root-free approach.
  5.  * VGA or EGA.
  6.  * Compile with Borland C++ 4.02 and link with L19-2.C or L19-3.C.
  7.  * Checked by Jim Mischel 11/30/94.
  8.  */
  9.  
  10. #include <math.h>
  11. #include <dos.h>
  12.  
  13. /* Turbo C accepts outp for outportb, but not outpw for outport */
  14. #ifdef __TURBOC__
  15. #define outpw  outport
  16. #endif
  17.  
  18. #define SCREEN_WIDTH_IN_BYTES 80    /* # of bytes across one scan
  19.                                        line in modes 10h and 12h */
  20. #define SCREEN_SEGMENT        0xA000 /* mode 10h/12h display memory seg */
  21. #define GC_INDEX              0x3CE /* Graphics Controller Index port */
  22. #define SET_RESET_INDEX       0     /* Set/Reset reg index in GC */
  23. #define SET_RESET_ENABLE_INDEX 1    /* Set/Reset Enable reg index in GC */
  24. #define BIT_MASK_INDEX        8     /* Bit Mask reg index in GC */
  25.  
  26. /* Draws a pixel at screen coordinate (X,Y) */
  27. void DrawDot(int X, int Y) {
  28.    unsigned char far *ScreenPtr;
  29.  
  30.    /* Point to the byte the pixel is in */
  31. #ifdef __TURBOC__
  32.    ScreenPtr = MK_FP(SCREEN_SEGMENT, (Y*SCREEN_WIDTH_IN_BYTES) + (X/8));
  33. #else
  34.    FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
  35.    FP_OFF(ScreenPtr) = (Y * SCREEN_WIDTH_IN_BYTES) + (X / 8);
  36. #endif
  37.  
  38.    /* Set the bit mask within the byte for the pixel */
  39.    outp(GC_INDEX + 1, 0x80 >> (X & 0x07));
  40.  
  41.    /* Draw the pixel. ORed to force read/write to load latches.
  42.       Data written doesn't matter, because set/reset is enabled
  43.       for all planes. Note: don't OR with 0; MSC optimizes that
  44.       statement to no operation */
  45.    *ScreenPtr |= 0xFE;
  46. }
  47.  
  48. /* Draws an ellipse of X axis radius A and Y axis radius B in
  49.  * color Color centered at screen coordinate (X,Y). Radii must
  50.  * both be non-zero */
  51. void DrawEllipse(int X, int Y, int A, int B, int Color) {
  52.    int WorkingX, WorkingY;
  53.    long Threshold;
  54.    long ASquared = (long) A * A;
  55.    long BSquared = (long) B * B;
  56.    long XAdjust, YAdjust;
  57.  
  58.    /* Set drawing color via set/reset */
  59.    outpw(GC_INDEX, (0x0F << 8) | SET_RESET_ENABLE_INDEX);
  60.                                  /* enable set/reset for all planes */
  61.    outpw(GC_INDEX, (Color << 8) | SET_RESET_INDEX);
  62.                                  /* set set/reset (drawing) color */
  63.    outp(GC_INDEX, BIT_MASK_INDEX); /* leave the GC Index reg pointing
  64.                                        to the Bit Mask reg */
  65.  
  66.    /* Draw the four symmetric arcs for which X advances faster (that is,
  67.       for which X is the major axis) */
  68.    /* Draw the initial top & bottom points */
  69.    DrawDot(X, Y+B);
  70.    DrawDot(X, Y-B);
  71.  
  72.    /* Draw the four arcs; set draw parameters for initial point (0,B) */
  73.    WorkingX = 0;
  74.    WorkingY = B;
  75.    XAdjust = 0;
  76.    YAdjust = ASquared * 2 * B;
  77.    Threshold = ASquared / 4 - ASquared * B;
  78.  
  79.    for (;;) {
  80.       /* Advance the threshold to the value for the next X point
  81.          to be drawn */
  82.       Threshold += XAdjust + BSquared;
  83.  
  84.       /* If the threshold has passed 0, then the Y coordinate has
  85.          advanced more than halfway to the next pixel and it's time
  86.          to advance the Y coordinate by 1 and set the next threhold
  87.          accordingly */
  88.       if ( Threshold >= 0 ) {
  89.          YAdjust -= ASquared * 2;
  90.          Threshold -= YAdjust;
  91.          WorkingY--;
  92.       }
  93.  
  94.       /* Advance the X coordinate by 1 */
  95.       XAdjust += BSquared * 2;
  96.       WorkingX++;
  97.  
  98.       /* Stop if X is no longer the major axis (the arc has passed the
  99.          45-degree point) */
  100.       if ( XAdjust >= YAdjust )
  101.          break;
  102.  
  103.       /* Draw the 4 symmetries of the current point */
  104.       DrawDot(X+WorkingX, Y-WorkingY);
  105.       DrawDot(X-WorkingX, Y-WorkingY);
  106.       DrawDot(X+WorkingX, Y+WorkingY);
  107.       DrawDot(X-WorkingX, Y+WorkingY);
  108.    }
  109.  
  110.    /* Draw the four symmetric arcs for which Y advances faster (that is,
  111.       for which Y is the major axis) */
  112.    /* Draw the initial left & right points */
  113.    DrawDot(X+A, Y);
  114.    DrawDot(X-A, Y);
  115.  
  116.    /* Draw the four arcs; set draw parameters for initial point (A,0) */
  117.    WorkingX = A;
  118.    WorkingY = 0;
  119.    XAdjust = BSquared * 2 * A;
  120.    YAdjust = 0;
  121.    Threshold = BSquared / 4 - BSquared * A;
  122.  
  123.    for (;;) {
  124.       /* Advance the threshold to the value for the next Y point
  125.          to be drawn */
  126.       Threshold += YAdjust + ASquared;
  127.  
  128.       /* If the threshold has passed 0, then the X coordinate has
  129.          advanced more than halfway to the next pixel and it's time
  130.          to advance the X coordinate by 1 and set the next threhold
  131.          accordingly */
  132.       if ( Threshold >= 0 ) {
  133.          XAdjust -= BSquared * 2;
  134.          Threshold = Threshold - XAdjust;
  135.          WorkingX--;
  136.       }
  137.  
  138.       /* Advance the Y coordinate by 1 */
  139.       YAdjust += ASquared * 2;
  140.       WorkingY++;
  141.  
  142.       /* Stop if Y is no longer the major axis (the arc has passed the
  143.          45-degree point) */
  144.       if ( YAdjust > XAdjust )
  145.          break;
  146.  
  147.       /* Draw the 4 symmetries of the current point */
  148.       DrawDot(X+WorkingX, Y-WorkingY);
  149.       DrawDot(X-WorkingX, Y-WorkingY);
  150.       DrawDot(X+WorkingX, Y+WorkingY);
  151.       DrawDot(X-WorkingX, Y+WorkingY);
  152.    }
  153.  
  154.    /* Reset the Bit Mask register to normal */
  155.    outp(GC_INDEX + 1, 0xFF);
  156.    /* Turn off set/reset enable */
  157.    outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
  158. }
  159.