home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / USCX / PJ81.ARC / CIRCLE3.C < prev    next >
Text File  |  1989-10-19  |  4KB  |  106 lines

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