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

  1. /* *** Listing 17.3 ***
  2.  *
  3.  * Draws a circle of the specified radius and color, using a fast
  4.  * integer-only & square-root-free approach.
  5.  * Will work on VGA, or EGA in 16-color mode.
  6.  * Compile with Borland C++ 4.02 and link with L17-2.C in small model.
  7.  * Checked by Jim Mischel 11/30/94
  8.  */
  9.  
  10. #include <dos.h>
  11. #include <math.h>
  12.  
  13. /* Handle differences between Turbo C & MSC. Note that Turbo C accepts
  14.    outp as a synonym for outportb, but not outpw for outport */
  15. #ifdef __TURBOC__
  16. #define outpw  outport
  17. #endif
  18.  
  19. #define SCREEN_WIDTH_IN_BYTES 80        /* # of bytes across one scan
  20.                                              line in mode 12h */
  21. #define SCREEN_SEGMENT        0xA000     /* mode 12h display memory seg */
  22. #define GC_INDEX              0x3CE     /* Graphics Controller port */
  23. #define SET_RESET_INDEX       0         /* Set/Reset reg index in GC */
  24. #define SET_RESET_ENABLE_INDEX 1        /* Set/Reset enable reg index
  25.                                              in GC */
  26. #define BIT_MASK_INDEX        8         /* Bit Mask reg index in GC */
  27.  
  28. /* Draws a pixel at screen coordinate (X,Y) */
  29. void DrawDot(int X, int Y) {
  30.    unsigned char far *ScreenPtr;
  31.  
  32.    /* Point to the byte the pixel is in */
  33. #ifdef __TURBOC__
  34.    ScreenPtr = MK_FP(SCREEN_SEGMENT,
  35.       (Y * SCREEN_WIDTH_IN_BYTES) + (X / 8));
  36. #else
  37.    FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
  38.    FP_OFF(ScreenPtr) =(Y * SCREEN_WIDTH_IN_BYTES) + (X / 8);
  39. #endif
  40.  
  41.    /* Set the bit mask within the byte for the pixel */
  42.    outp(GC_INDEX + 1, 0x80 >> (X & 0x07));
  43.  
  44.    /* Draw the pixel. ORed to force read/write to load latches.
  45.       Data written doesn't matter, because set/reset is enabled
  46.       for all planes. Note: don't OR with 0; MSC optimizes that
  47.       statement to no operation */
  48.    *ScreenPtr |= 0xFE;
  49. }
  50.  
  51. /* Draws a circle of radius Radius in color Color centered at
  52.  * screen coordinate (X,Y) */
  53. void DrawCircle(int X, int Y, int Radius, int Color) {
  54.    int MajorAxis, MinorAxis;
  55.    unsigned long RadiusSqMinusMajorAxisSq;
  56.    unsigned long MinorAxisSquaredThreshold;
  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);
  64.                                  /* leave the GC pointing to Bit Mask
  65.                                     reg */
  66.  
  67.    /* Set up to draw the circle by setting the initial point to one
  68.       end of the 1/8th of a circle arc we'll draw */
  69.    MajorAxis = 0;
  70.    MinorAxis = Radius;
  71.    /* Set initial Radius**2 - MajorAxis**2 (MajorAxis is initially 0 */
  72.    RadiusSqMinusMajorAxisSq = (unsigned long) Radius * Radius;
  73.    /* Set threshold for minor axis movement at (MinorAxis - 0.5)**2 */
  74.    MinorAxisSquaredThreshold =
  75.         (unsigned long) MinorAxis * MinorAxis - MinorAxis;
  76.  
  77.    /* Draw all points along an arc of 1/8th of the circle, drawing
  78.       all 8 symmetries at the same time */
  79.    do {
  80.       /* Draw all 8 symmetries of current point */
  81.       DrawDot(X+MajorAxis, Y-MinorAxis);
  82.       DrawDot(X-MajorAxis, Y-MinorAxis);
  83.       DrawDot(X+MajorAxis, Y+MinorAxis);
  84.       DrawDot(X-MajorAxis, Y+MinorAxis);
  85.       DrawDot(X+MinorAxis, Y-MajorAxis);
  86.       DrawDot(X-MinorAxis, Y-MajorAxis);
  87.       DrawDot(X+MinorAxis, Y+MajorAxis);
  88.       DrawDot(X-MinorAxis, Y+MajorAxis);
  89.       MajorAxis++;            /* advance one pixel along major axis */
  90.       if ( (RadiusSqMinusMajorAxisSq -=
  91.          MajorAxis + MajorAxis - 1) <= MinorAxisSquaredThreshold ) {
  92.          MinorAxis--;
  93.          MinorAxisSquaredThreshold -= MinorAxis + MinorAxis;
  94.       }
  95.    } while ( MajorAxis <= MinorAxis );
  96.  
  97.    /* Reset the Bit Mask register to normal */
  98.    outp(GC_INDEX + 1, 0xFF);
  99.  
  100.    /* Turn off set/reset enable */
  101.    outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
  102. }
  103.  
  104.