home *** CD-ROM | disk | FTP | other *** search
- /* *** Listing 18.3 ***
- *
- * Draws a circle of the specified radius and color, using a fast
- * integer-only & square-root-free approach, and generating the
- * arc for one octant into a buffer, then drawing all 8 symmetries
- * from that buffer. Uses assembly language for inner loops of octant
- * generation & drawing.
- * Will work on VGA or EGA, but will draw what appears to be an
- * ellipse in non-square-pixel modes.
- * Compiled with Borland C++ 4.02. Link with L18-2.C and L18-4.ASM.
- * Checked by Jim Mischel 11/30/94.
- */
- #define ISVGA 0 /* set to 1 to use VGA write mode 3*/
- /* keep synchronized with Listing 4 */
- #include <dos.h>
-
- /* Handle differences between Turbo C & MSC. Note that Turbo C accepts
- outp as a synonym for outportb, but not outpw for outport */
- #ifdef __TURBOC__
- #define outpw outport
- #endif
-
- #define SCREEN_WIDTH_IN_BYTES 80 /* # of bytes across one scan
- line in mode 12h */
- #define SCREEN_SEGMENT 0xA000 /* mode 12h display memory seg */
- #define GC_INDEX 0x3CE /* Graphics Controller port */
- #define SET_RESET_INDEX 0 /* Set/Reset reg index in GC */
- #define SET_RESET_ENABLE_INDEX 1 /* Set/Reset Enable reg index in GC */
- #define GC_MODE_INDEX 5 /* Graphics Mode reg index in GC */
- #define COLOR_DONT_CARE 7 /* Color Don't Care reg index in GC */
- #define BIT_MASK_INDEX 8 /* Bit Mask reg index in GC */
-
- unsigned char PixList[SCREEN_WIDTH_IN_BYTES*8/2];
- /* maximum major axis length is
- 1/2 screen width, because we're
- assuming no clipping is needed */
- /* Draws a circle of radius Radius in color Color centered at
- * screen coordinate (X,Y) */
- void DrawCircle(int X, int Y, int Radius, int Color) {
- int MajorAxis, MinorAxis;
- unsigned long RadiusSqMinusMajorAxisSq, MinorAxisSquaredThreshold;
- unsigned char *PixListPtr, OriginalGCMode;
-
- /* Set drawing color via set/reset */
- outpw(GC_INDEX, (0x0F << 8) | SET_RESET_ENABLE_INDEX);
- /* enable set/reset for all planes */
- outpw(GC_INDEX, (Color << 8) | SET_RESET_INDEX);
- /* set set/reset (drawing) color */
- #if ISVGA
- /* Remember original read/write mode & select
- read mode 1/write mode 3, with Color Don't Care
- set to ignore all planes and therefore always return 0xFF */
- outp(GC_INDEX, GC_MODE_INDEX);
- OriginalGCMode = inp(GC_INDEX + 1);
- outp(GC_INDEX+1, OriginalGCMode | 0x0B);
- outpw(GC_INDEX, (0x00 << 8) | COLOR_DONT_CARE);
- outpw(GC_INDEX, (0xFF << 8) | BIT_MASK_INDEX);
- #else
- outp(GC_INDEX, BIT_MASK_INDEX); /* leave the GC Index reg pointing
- to the Bit Mask reg */
- #endif
-
- /* Set up to draw the circle by setting the initial point to one
- end of the 1/8th of a circle arc we'll draw */
- MajorAxis = 0;
- MinorAxis = Radius;
- /* Set initial Radius**2 - MajorAxis**2 (MajorAxis is initially 0) */
- RadiusSqMinusMajorAxisSq = (unsigned long) Radius * Radius;
- /* Set threshold for minor axis movement at (MinorAxis - 0.5)**2 */
- MinorAxisSquaredThreshold = (unsigned long) MinorAxis * MinorAxis -
- MinorAxis;
-
- /* Calculate all points along an arc of 1/8th of the circle.
- Results are placed in PixList */
- MajorAxis = GenerateOctant(PixList, MajorAxis, MinorAxis,
- RadiusSqMinusMajorAxisSq, MinorAxisSquaredThreshold);
-
- /* Now draw each of the 8 symmetries of the octant in turn */
- /* Draw the octants for which Y is the major axis */
- DrawVOctant(X-Radius,Y,MajorAxis,-SCREEN_WIDTH_IN_BYTES,1,PixList);
- DrawVOctant(X-Radius,Y,MajorAxis,SCREEN_WIDTH_IN_BYTES,1,PixList);
- DrawVOctant(X+Radius,Y,MajorAxis,-SCREEN_WIDTH_IN_BYTES,0,PixList);
- DrawVOctant(X+Radius,Y,MajorAxis,SCREEN_WIDTH_IN_BYTES,0,PixList);
-
- /* Draw the octants for which X is the major axis */
- DrawHOctant(X,Y-Radius,MajorAxis,SCREEN_WIDTH_IN_BYTES,0,PixList);
- DrawHOctant(X,Y-Radius,MajorAxis,SCREEN_WIDTH_IN_BYTES,1,PixList);
- DrawHOctant(X,Y+Radius,MajorAxis,-SCREEN_WIDTH_IN_BYTES,0, PixList);
- DrawHOctant(X,Y+Radius,MajorAxis,-SCREEN_WIDTH_IN_BYTES,1, PixList);
-
- #if ISVGA
- /* Restore original write mode */
- outpw(GC_INDEX, (OriginalGCMode << 8) | GC_MODE_INDEX);
- /* Restore normal Color Don't Care setting */
- outpw(GC_INDEX, (0x0F << 8) | COLOR_DONT_CARE);
- #else
- /* Reset the Bit Mask register to normal */
- outp(GC_INDEX + 1, 0xFF);
- #endif
- /* Turn off set/reset enable */
- outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
- }
-