home *** CD-ROM | disk | FTP | other *** search
- /*
- * Illustrates color paging by color-animating a series of
- * concentric circles to produce the illusion of motion.
- * Runs on the VGA only, because color paging isn't available on
- * the EGA.
- *
- * Compiled with Borland C++ 4.02, with the command line:
- * bcc l12-1.c
- *
- * Checked by Jim Mischel 11/21/94
- */
-
- #include <dos.h>
-
- #define USE_BIOS 0 /* set to 1 to use BIOS functions to perform
- color paging, 0 to program color paging
- registers directly */
-
- /* Handle differences between Turbo C & MSC. Note that Turbo C accepts
- outp as a synonym for outportb, but not outpw for outport */
-
- #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 index */
- #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 BIT_MASK_INDEX 8 /* Bit Mask reg index in GC */
- #define INPUT_STATUS_1 0x3DA /* Input Status 1 port */
- #define AC_INDEX 0x3C0 /* Attribute Controller index */
- #define AC_DATA_W 0x3C0 /* Attribute Controller data
- register for writes */
- #define AC_DATA_R 0x3C1 /* Attribute Controller data
- register for reads */
- #define AC_MODE_INDEX 0x30 /* AC Mode reg index, with bit 6
- set to avoid blanking screen */
- #define AC_COLOR_SELECT_INDEX 0x34 /* Color Select reg index, with
- bit 6 set to avoid blanking
- screen */
-
- void main();
- void DrawDot(int X, int Y);
- void DrawCircle(int X, int Y, int Radius, int Color);
-
- /* Array used to load the DAC. Organized as 256 RGB triplets */
- static unsigned char DACSettings[256*3];
-
- /* Array used to load the palette RAM to a pass-through state.
- The 17th entry sets the border color to 0 */
- static unsigned char PaletteRAMSettings[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
-
- void main() {
- int Radius, Color, Page, Element, i;
- union REGS Regs;
- struct SREGS Sregs;
- unsigned char GreenComponent;
-
- /* Select VGA's hi-res 640x480 graphics mode, mode 12h */
- Regs.x.ax = 0x0012;
- int86(0x10, &Regs, &Regs);
-
- /* Draw concentric circles */
- for ( Radius = 10, Color = 1; Radius < 240; Radius += 2 ) {
- DrawCircle(640/2, 480/2, Radius, Color);
- if (++Color >= 16)
- Color = 1; /* skip color 0 */
- }
-
- /* Load the upper 240 DAC locations (15 pages) with one-position
- rotations of a series of increasingly green colors. Because
- page 0 is being displayed, the screen remains unchanged while
- the other 15 color pages are being loaded */
-
- /* First, fill DACSettings with the desired green settings
- (because it's a static array, all locations are initialized to
- zero, so we don't need to initialize the red or green color
- components, which we want to be zero) */
- GreenComponent = 8;
- for ( Page = 1; Page <= 15; Page++ ) {
- GreenComponent = Page * 4;
- for ( Element = 1; Element <= 15; Element++ ) {
- DACSettings[Page*16*3 + Element*3 + 1] = GreenComponent;
- if ( (GreenComponent += 4) >= 64 )
- GreenComponent = 4;
- }
- }
-
- /* Now call the BIOS to load the upper 240 DAC locations */
- Regs.h.ah = 0x10;
- Regs.h.al = 0x12;
- Regs.x.bx = 16;
- Regs.x.cx = 240;
- Regs.x.dx = (unsigned int)(DACSettings + 16*3);
- segread(&Sregs);
- Sregs.es = Sregs.ds; /* point ES:DX to DACSettings */
- int86x(0x10, &Regs, &Regs, &Sregs);
-
- /* Put the palette RAM in a pass-through state and set the Overscan
- register (border color) to 0. We've saved this for last because
- it changes the colors being displayed */
- Regs.h.ah = 0x10;
- Regs.h.al = 2;
- Regs.x.dx = (unsigned int)PaletteRAMSettings;
- segread(&Sregs);
- Sregs.es = Sregs.ds; /* point ES:DX to PaletteRAMSettings */
- int86x(0x10, &Regs, &Regs, &Sregs);
-
- /* Enable 16-pages-of-16-colors paging */
- #if USE_BIOS
- Regs.h.ah = 0x10;
- Regs.h.al = 0x13;
- Regs.h.bl = 0;
- Regs.h.bh = 1;
- int86(0x10, &Regs, &Regs);
- #else
- inp(INPUT_STATUS_1);
- outp(AC_INDEX, AC_MODE_INDEX);
- outp(AC_DATA_W, inp(AC_DATA_R) | 0x80);
- #endif /* USE_BIOS */
-
- /* We're read to roll; the upper 15 pages are set up, the
- palette RAM is in a pass-through state, and 16-pages-of-16-
- colors paging is enabled. Now we'll loop through and display
- each of pages 15 through 1 and then back to 15 for one frame
- until a key is pressed */
- for ( Page = 15, i = 0 ; i < 1000; i++ ) {
-
- #if USE_BIOS
- /* Select the desired color page */
- Regs.h.ah = 0x10;
- Regs.h.al = 0x13;
- Regs.h.bl = 1;
- Regs.h.bh = Page;
- int86(0x10, &Regs, &Regs);
- #else
- /* Wait for the leading edge of the vertical sync pulse; this
- ensures that we change color pages during vertical
- non-display time, and that the page flips are even spaced
- over time */
- while ( (inp(INPUT_STATUS_1) & 0x08) != 0 )
- ; /* wait for non-vertical sync time */
- while ( (inp(INPUT_STATUS_1) & 0x08) == 0 )
- ; /* wait for vertical sync time */
- inp(INPUT_STATUS_1);
- outp(AC_INDEX, AC_COLOR_SELECT_INDEX);
- outp(AC_DATA_W, Page);
- #endif /* USE_BIOS */
-
-
- /* Cycle from page 15 down to page 1, and then back to page 15.
- Avoid page 0 entirely */
- if (--Page == 0)
- Page = 15;
- }
-
- /* Restore text mode and done */
- Regs.x.ax = 0x0003;
- int86(0x10, &Regs, &Regs);
- }
-
- /* Draws a pixel at screen coordinate (X,Y) */
- void DrawDot(int X, int Y) {
- unsigned char far *ScreenPtr;
-
- /* Point to the byte the pixel is in */
- #ifdef __TURBOC__
- ScreenPtr = MK_FP(SCREEN_SEGMENT,
- (Y * SCREEN_WIDTH_IN_BYTES) + (X / 8));
- #else
- FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
- FP_OFF(ScreenPtr) =(Y * SCREEN_WIDTH_IN_BYTES) + (X / 8);
- #endif
-
- /* Set the bit mask within the byte for the pixel */
- outp(GC_INDEX + 1, 0x80 >> (X & 0x07));
-
- /* Draw the pixel. ORed to force read/write to load latches.
- Data written doesn't matter, because set/reset is enabled
- for all planes. Note: don't OR with 0; MSC optimizes that
- statement to no operation */
- *ScreenPtr |= 0xFF;
- }
-
- /* 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;
- unsigned long MinorAxisSquaredThreshold;
-
- /* 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 */
- outp(GC_INDEX, BIT_MASK_INDEX);
- /* leave the GC Index reg pointing to
- the Bit Mask reg */
-
- /* 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 = Radius * Radius;
- /* Set threshold for minor axis movement at (MinorAxis - 0.5)**2 */
- MinorAxisSquaredThreshold = MinorAxis * MinorAxis - MinorAxis;
-
- /* Draw all points along an arc of 1/8th of the circle, drawing
- all 8 symmetries at the same time */
- do {
- /* Draw all 8 symmetries of current point */
- DrawDot(X+MajorAxis, Y-MinorAxis);
- DrawDot(X-MajorAxis, Y-MinorAxis);
- DrawDot(X+MajorAxis, Y+MinorAxis);
- DrawDot(X-MajorAxis, Y+MinorAxis);
- DrawDot(X+MinorAxis, Y-MajorAxis);
- DrawDot(X-MinorAxis, Y-MajorAxis);
- DrawDot(X+MinorAxis, Y+MajorAxis);
- DrawDot(X-MinorAxis, Y+MajorAxis);
- /* Advance (Radius**2 - MajorAxis**2); if it equals or passes
- the MinorAxis**2 threshold, advance one pixel along the minor
- axis and set the next MinorAxis**2 threshold */
- if ( (RadiusSqMinusMajorAxisSq -=
- MajorAxis + MajorAxis + 1) <= MinorAxisSquaredThreshold ) {
- MinorAxis--;
- MinorAxisSquaredThreshold -= MinorAxis + MinorAxis;
- }
- MajorAxis++; /* advance one pixel along the major axis */
- } while ( MajorAxis <= MinorAxis );
-
- /* Reset the Bit Mask register to normal */
- outp(GC_INDEX + 1, 0xFF);
-
- /* Turn off set/reset enable */
- outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
- }
-
-