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

  1. /* *** Listing 19.1 ***
  2.  *
  3.  * Draws an ellipse of the specified X and Y axis radii and color,
  4.  * using floating-point calculations.
  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.    double ASquared = (double) A * A;
  54.    double BSquared = (double) B * B;
  55.    double Temp;
  56.  
  57.    /* Set drawing color via set/reset */
  58.    outpw(GC_INDEX, (0x0F << 8) | SET_RESET_ENABLE_INDEX);
  59.                                  /* enable set/reset for all planes */
  60.    outpw(GC_INDEX, (Color << 8) | SET_RESET_INDEX);
  61.                                  /* set set/reset (drawing) color */
  62.    outp(GC_INDEX, BIT_MASK_INDEX); /* leave the GC Index reg pointing
  63.                                        to the Bit Mask reg */
  64.  
  65.    /* Draw the four symmetric arcs for which X advances faster (that is,
  66.       for which X is the major axis) */
  67.    /* Draw the initial top & bottom points */
  68.    DrawDot(X, Y+B);
  69.    DrawDot(X, Y-B);
  70.  
  71.    /* Draw the four arcs */
  72.    for (WorkingX = 0; ; ) {
  73.       /* Advance one pixel along the X axis */
  74.       WorkingX++;
  75.  
  76.       /* Calculate the corresponding point along the Y axis. Guard
  77.          against floating-point roundoff making the intermediate term
  78.          less than 0 */
  79.       Temp = BSquared - (BSquared *
  80.          (double)WorkingX * (double)WorkingX / ASquared);
  81.       if ( Temp >= 0 ) {
  82.          WorkingY = sqrt(Temp) + 0.5;
  83.       } else {
  84.          WorkingY = 0;
  85.       }
  86.  
  87.       /* Stop if X is no longer the major axis (the arc has passed the
  88.          45-degree point) */
  89.       if (((double)WorkingY/BSquared) <= ((double)WorkingX/ASquared))
  90.          break;
  91.  
  92.       /* Draw the 4 symmetries of the current point */
  93.       DrawDot(X+WorkingX, Y-WorkingY);
  94.       DrawDot(X-WorkingX, Y-WorkingY);
  95.       DrawDot(X+WorkingX, Y+WorkingY);
  96.       DrawDot(X-WorkingX, Y+WorkingY);
  97.    }
  98.  
  99.    /* Draw the four symmetric arcs for which Y advances faster (that is,
  100.       for which Y is the major axis) */
  101.    /* Draw the initial left & right points */
  102.    DrawDot(X+A, Y);
  103.    DrawDot(X-A, Y);
  104.  
  105.    /* Draw the four arcs */
  106.    for (WorkingY = 0; ; ) {
  107.       /* Advance one pixel along the Y axis */
  108.       WorkingY++;
  109.  
  110.       /* Calculate the corresponding point along the X axis. Guard
  111.          against floating-point roundoff making the intermediate term
  112.          less than 0 */
  113.       Temp = ASquared - (ASquared *
  114.          (double)WorkingY * (double)WorkingY / BSquared);
  115.       if ( Temp >= 0 ) {
  116.          WorkingX = sqrt(Temp) + 0.5;
  117.       } else {
  118.          WorkingX = 0;           /* floating-point roundoff */
  119.       }
  120.  
  121.       /* Stop if Y is no longer the major axis (the arc has passed the
  122.          45-degree point) */
  123.       if (((double)WorkingX/ASquared) < ((double)WorkingY/BSquared))
  124.          break;
  125.  
  126.       /* Draw the 4 symmetries of the current point */
  127.       DrawDot(X+WorkingX, Y-WorkingY);
  128.       DrawDot(X-WorkingX, Y-WorkingY);
  129.       DrawDot(X+WorkingX, Y+WorkingY);
  130.       DrawDot(X-WorkingX, Y+WorkingY);
  131.    }
  132.  
  133.    /* Reset the Bit Mask register to normal */
  134.    outp(GC_INDEX + 1, 0xFF);
  135.  
  136.    /* Turn off set/reset enable */
  137.    outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
  138. }
  139.  
  140.