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

  1. /*
  2.  * Illustrates color paging by color-animating a series of
  3.  * concentric circles to produce the illusion of motion.
  4.  * Runs on the VGA only, because color paging isn't available on
  5.  * the EGA.
  6.  *
  7.  * Compiled with Borland C++ 4.02, with the command line:
  8.  *   bcc l12-1.c
  9.  *
  10.  * Checked by Jim Mischel 11/21/94
  11.  */
  12.  
  13. #include <dos.h>
  14.  
  15. #define USE_BIOS  0  /* set to 1 to use BIOS functions to perform
  16.                         color paging, 0 to program color paging
  17.                         registers directly */
  18.  
  19. /* Handle differences between Turbo C & MSC. Note that Turbo C accepts
  20.    outp as a synonym for outportb, but not outpw for outport */
  21.  
  22. #define SCREEN_WIDTH_IN_BYTES 80    /* # of bytes across one scan
  23.                                        line in mode 12h */
  24. #define SCREEN_SEGMENT        0xA000 /* mode 12h display memory seg */
  25. #define GC_INDEX              0x3CE /* Graphics Controller index */
  26. #define SET_RESET_INDEX       0     /* Set/Reset reg index in GC */
  27. #define SET_RESET_ENABLE_INDEX 1    /* Set/Reset Enable reg index
  28.                                        in GC */
  29. #define BIT_MASK_INDEX        8     /* Bit Mask reg index in GC */
  30. #define INPUT_STATUS_1        0x3DA /* Input Status 1 port */
  31. #define AC_INDEX              0x3C0 /* Attribute Controller index */
  32. #define AC_DATA_W             0x3C0 /* Attribute Controller data
  33.                                        register for writes */
  34. #define AC_DATA_R             0x3C1 /* Attribute Controller data
  35.                                        register for reads */
  36. #define AC_MODE_INDEX         0x30  /* AC Mode reg index, with bit 6
  37.                                        set to avoid blanking screen */
  38. #define AC_COLOR_SELECT_INDEX 0x34  /* Color Select reg index, with
  39.                                        bit 6 set to avoid blanking
  40.                                        screen */
  41.  
  42. void main();
  43. void DrawDot(int X, int Y);
  44. void DrawCircle(int X, int Y, int Radius, int Color);
  45.  
  46. /* Array used to load the DAC. Organized as 256 RGB triplets */
  47. static unsigned char DACSettings[256*3];
  48.  
  49. /* Array used to load the palette RAM to a pass-through state.
  50.    The 17th entry sets the border color to 0 */
  51. static unsigned char PaletteRAMSettings[] = {
  52.    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0};
  53.  
  54. void main() {
  55.    int Radius, Color, Page, Element, i;
  56.    union REGS Regs;
  57.    struct SREGS Sregs;
  58.    unsigned char GreenComponent;
  59.  
  60.    /* Select VGA's hi-res 640x480 graphics mode, mode 12h */
  61.    Regs.x.ax = 0x0012;
  62.    int86(0x10, &Regs, &Regs);
  63.  
  64.    /* Draw concentric circles */
  65.    for ( Radius = 10, Color = 1; Radius < 240; Radius += 2 ) {
  66.       DrawCircle(640/2, 480/2, Radius, Color);
  67.       if (++Color >= 16)
  68.          Color = 1;                 /* skip color 0 */
  69.    }
  70.  
  71.    /* Load the upper 240 DAC locations (15 pages) with one-position
  72.       rotations of a series of increasingly green colors. Because
  73.       page 0 is being displayed, the screen remains unchanged while
  74.       the other 15 color pages are being loaded */
  75.  
  76.    /* First, fill DACSettings with the desired green settings
  77.       (because it's a static array, all locations are initialized to
  78.       zero, so we don't need to initialize the red or green color
  79.       components, which we want to be zero) */
  80.    GreenComponent = 8;
  81.    for ( Page = 1; Page <= 15; Page++ ) {
  82.       GreenComponent = Page * 4;
  83.       for ( Element = 1; Element <= 15; Element++ ) {
  84.          DACSettings[Page*16*3 + Element*3 + 1] = GreenComponent;
  85.          if ( (GreenComponent += 4) >= 64 )
  86.             GreenComponent = 4;
  87.       }
  88.    }
  89.       
  90.    /* Now call the BIOS to load the upper 240 DAC locations */
  91.    Regs.h.ah = 0x10;
  92.    Regs.h.al = 0x12;
  93.    Regs.x.bx = 16;
  94.    Regs.x.cx = 240;
  95.    Regs.x.dx = (unsigned int)(DACSettings + 16*3);
  96.    segread(&Sregs);
  97.    Sregs.es = Sregs.ds;       /* point ES:DX to DACSettings */
  98.    int86x(0x10, &Regs, &Regs, &Sregs);
  99.  
  100.    /* Put the palette RAM in a pass-through state and set the Overscan
  101.       register (border color) to 0. We've saved this for last because
  102.       it changes the colors being displayed */
  103.    Regs.h.ah = 0x10;
  104.    Regs.h.al = 2;
  105.    Regs.x.dx = (unsigned int)PaletteRAMSettings;
  106.    segread(&Sregs);
  107.    Sregs.es = Sregs.ds;       /* point ES:DX to PaletteRAMSettings */
  108.    int86x(0x10, &Regs, &Regs, &Sregs);
  109.  
  110.    /* Enable 16-pages-of-16-colors paging */
  111. #if USE_BIOS
  112.    Regs.h.ah = 0x10;
  113.    Regs.h.al = 0x13;
  114.    Regs.h.bl = 0;
  115.    Regs.h.bh = 1;
  116.    int86(0x10, &Regs, &Regs);
  117. #else
  118.    inp(INPUT_STATUS_1);
  119.    outp(AC_INDEX, AC_MODE_INDEX);
  120.    outp(AC_DATA_W, inp(AC_DATA_R) | 0x80);
  121. #endif /* USE_BIOS */
  122.  
  123.    /* We're read to roll; the upper 15 pages are set up, the
  124.       palette RAM is in a pass-through state, and 16-pages-of-16-
  125.       colors paging is enabled. Now we'll loop through and display
  126.       each of pages 15 through 1 and then back to 15 for one frame
  127.       until a key is pressed */
  128.    for ( Page = 15, i = 0 ; i < 1000; i++ ) {
  129.  
  130. #if USE_BIOS
  131.       /* Select the desired color page */
  132.       Regs.h.ah = 0x10;
  133.       Regs.h.al = 0x13;
  134.       Regs.h.bl = 1;
  135.       Regs.h.bh = Page;
  136.       int86(0x10, &Regs, &Regs);
  137. #else
  138.       /* Wait for the leading edge of the vertical sync pulse; this
  139.          ensures that we change color pages during vertical
  140.          non-display time, and that the page flips are even spaced
  141.          over time */
  142.       while ( (inp(INPUT_STATUS_1) & 0x08) != 0 )
  143.          ;                 /* wait for non-vertical sync time */
  144.       while ( (inp(INPUT_STATUS_1) & 0x08) == 0 )
  145.          ;                 /* wait for vertical sync time */
  146.       inp(INPUT_STATUS_1);
  147.       outp(AC_INDEX, AC_COLOR_SELECT_INDEX);
  148.       outp(AC_DATA_W, Page);
  149. #endif /* USE_BIOS */
  150.  
  151.  
  152.       /* Cycle from page 15 down to page 1, and then back to page 15.
  153.          Avoid page 0 entirely */
  154.       if (--Page == 0)
  155.          Page = 15;
  156.    }
  157.  
  158.    /* Restore text mode and done */
  159.    Regs.x.ax = 0x0003;
  160.    int86(0x10, &Regs, &Regs);
  161. }
  162.  
  163. /* Draws a pixel at screen coordinate (X,Y) */
  164. void DrawDot(int X, int Y) {
  165.    unsigned char far *ScreenPtr;
  166.  
  167.    /* Point to the byte the pixel is in */
  168. #ifdef __TURBOC__
  169.    ScreenPtr = MK_FP(SCREEN_SEGMENT,
  170.       (Y * SCREEN_WIDTH_IN_BYTES) + (X / 8));
  171. #else
  172.    FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
  173.    FP_OFF(ScreenPtr) =(Y * SCREEN_WIDTH_IN_BYTES) + (X / 8);
  174. #endif
  175.  
  176.    /* Set the bit mask within the byte for the pixel */
  177.    outp(GC_INDEX + 1, 0x80 >> (X & 0x07));
  178.  
  179.    /* Draw the pixel. ORed to force read/write to load latches.
  180.       Data written doesn't matter, because set/reset is enabled
  181.       for all planes. Note: don't OR with 0; MSC optimizes that
  182.       statement to no operation */
  183.    *ScreenPtr |= 0xFF;
  184. }
  185.  
  186. /* Draws a circle of radius Radius in color Color centered at
  187.  * screen coordinate (X,Y) */
  188. void DrawCircle(int X, int Y, int Radius, int Color) {
  189.    int MajorAxis, MinorAxis;
  190.    unsigned long RadiusSqMinusMajorAxisSq;
  191.    unsigned long MinorAxisSquaredThreshold;
  192.  
  193.    /* Set drawing color via set/reset */
  194.    outpw(GC_INDEX, (0x0F << 8) | SET_RESET_ENABLE_INDEX);
  195.                                  /* enable set/reset for all planes */
  196.    outpw(GC_INDEX, (Color << 8) | SET_RESET_INDEX);
  197.                                  /* set set/reset (drawing) color */
  198.    outp(GC_INDEX, BIT_MASK_INDEX);
  199.                                  /* leave the GC Index reg pointing to
  200.                                     the Bit Mask reg */
  201.  
  202.    /* Set up to draw the circle by setting the initial point to one
  203.       end of the 1/8th of a circle arc we'll draw */
  204.    MajorAxis = 0;
  205.    MinorAxis = Radius;
  206.    /* Set initial Radius**2 - MajorAxis**2 (MajorAxis is initially 0) */
  207.    RadiusSqMinusMajorAxisSq = Radius * Radius;
  208.    /* Set threshold for minor axis movement at (MinorAxis - 0.5)**2 */
  209.    MinorAxisSquaredThreshold = MinorAxis * MinorAxis - MinorAxis;
  210.  
  211.    /* Draw all points along an arc of 1/8th of the circle, drawing
  212.       all 8 symmetries at the same time */
  213.    do {
  214.       /* Draw all 8 symmetries of current point */
  215.       DrawDot(X+MajorAxis, Y-MinorAxis);
  216.       DrawDot(X-MajorAxis, Y-MinorAxis);
  217.       DrawDot(X+MajorAxis, Y+MinorAxis);
  218.       DrawDot(X-MajorAxis, Y+MinorAxis);
  219.       DrawDot(X+MinorAxis, Y-MajorAxis);
  220.       DrawDot(X-MinorAxis, Y-MajorAxis);
  221.       DrawDot(X+MinorAxis, Y+MajorAxis);
  222.       DrawDot(X-MinorAxis, Y+MajorAxis);
  223.       /* Advance (Radius**2 - MajorAxis**2); if it equals or passes
  224.          the MinorAxis**2 threshold, advance one pixel along the minor
  225.          axis and set the next MinorAxis**2 threshold */
  226.       if ( (RadiusSqMinusMajorAxisSq -=
  227.          MajorAxis + MajorAxis + 1) <= MinorAxisSquaredThreshold ) {
  228.          MinorAxis--;
  229.          MinorAxisSquaredThreshold -= MinorAxis + MinorAxis;
  230.       }
  231.       MajorAxis++;         /* advance one pixel along the major axis */
  232.    } while ( MajorAxis <= MinorAxis );
  233.  
  234.    /* Reset the Bit Mask register to normal */
  235.    outp(GC_INDEX + 1, 0xFF);
  236.  
  237.    /* Turn off set/reset enable */
  238.    outpw(GC_INDEX, (0x00 << 8) | SET_RESET_ENABLE_INDEX);
  239. }
  240.  
  241.