home *** CD-ROM | disk | FTP | other *** search
- /* EGACOLRS --- by Mark Adler 9 Jan 1988 Pasadena, CA */
- /* modified by Mark Adler 10 Mar 1989 to work with VGA */
- /* This program may be used and freely copied by anyone except that */
- /* it may not be sold by itself or as part of any package without */
- /* the permission of the author. */
-
- /* Compile with Turbo C using options -mt -lt (tiny model). */
- /* Compilation requires Microsoft MASM or Borland TASM */
-
- #pragma inline /* Tell compiler there is assembly code here */
-
- char notice[] = "EGACOLRS - Copyright (c) 1988,1989 Mark Adler";
-
- /* Key values returned by keyin() */
- #define UP 0x4800
- #define DOWN 0x5000
- #define RIGHT 0x4d00
- #define LEFT 0x4b00
- #define HOME 0x4700
- #define END 0x4f00
- #define PGUP 0x4900
- #define PGDN 0x5100
- #define SPACE 0x3920
-
- /* Default palette for EGA---used to restore palette when done. */
- char egapal[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
- 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x00};
-
-
- int trick(int s, char *p)
- /**********************************************************************/
- /* */
- /* trick() watches the horizontal and vertical retraces and uses the */
- /* information to change the color palette of the EGA on the */
- /* desired scan lines. This allows displaying all 64 possible */
- /* colors at a time, albeit in a restricted way. */
- /* */
- /* 's' is the address of the status port with the sync information. */
- /* It should be 0x3ba or 0x3da depending on the display. */
- /* */
- /* 'p[]' is a sequence of instructions that specify how to change */
- /* the colors. Each instruction is three bytes---the first byte is */
- /* the low byte of the number of the scan line to change the color */
- /* on, the second byte is the palette color to change (0..15 or 17 */
- /* for overscan), and the third byte is the color to change it to */
- /* (0..63). The last three bytes are sent to port 0x3c0 on the */
- /* line specified by the first byte. The format of the color byte */
- /* is from most significant to least significant bit: 00rgbRGB. */
- /* The letters refer to the colors red, green, and blue, and the */
- /* upper case letters are "stronger" than the lower case letters. */
- /* So, 00000100 is a stronger red than 00100000. */
- /* */
- /* After the last palette change, the next byte should be a scan */
- /* line that does not occur. On vertical retrace, the 17 bytes */
- /* that follow are sent to the palette port. This allows setting */
- /* part of the palette to black to avoid color flashes while */
- /* processing keystrokes. */
- /* */
- /* At each vertical retrace, interrupts are allowed and if a key was */
- /* hit, the process terminates. Else, it starts over at the top of */
- /* of the screen. */
- /* */
- /* The timing is so tight on 4.77 MHz PC's with 8088's, it is */
- /* necessary to avoid jumps that reload the queue and to disable the */
- /* DMA refreshes to guarantee that the horizontal retrace will be */
- /* caught. Jumps are avoided by repeating the code to check for */
- /* horizontal retrace instead of allowing it to loop on itself. The */
- /* DMA is not actually disabled, but instead it is synchronized to */
- /* the horizontal lines. Refreshes must be done on the average */
- /* every 15.625 uS. A horizontal line is 45.765 uS, so three */
- /* refreshes per line is more than sufficient. The DMA refresh is */
- /* disabled before looking for the horizontal retrace. After */
- /* finding the retrace, refreshes are set to a high enough rate to */
- /* get three in before the next time the refresh is disabled. On */
- /* vertical retrace, the refresh time is set back to normal. */
- /* */
- /**********************************************************************/
- {
- /* Get Input Status Register 1 port for retrace info */
- asm mov DX,s
- asm mov DI,DX
- asm cli
- ivwt:
- asm in AL,DX
- asm test AL,8 /* Check vertical retrace bit */
- asm jz ivwt /* Wait for vertical retrace */
-
- /* Change palette at specified lines on screen until key hit */
- again:
- asm cld /* String instructions increment */
- asm mov SI,p /* Point to palettes table */
- asm lodsb /* Get first scan number low byte */
- asm mov AH,AL /* Save in AH */
- asm sub BX,BX /* Initialize count */
- asm mov DX,DI /* Get sync port in DX */
-
- /* Wait for end of vertical retrace */
- asm cli /* Kill interrupts until screen end */
- enwt:
- asm in AL,DX
- asm test AL,1
- asm jnz enwt /* Wait for display enable */
-
- /* Go through loop once for each horizontal line */
- llp:
-
- /* Synchronize refreshes to lines */
- asm mov AL,54h /* Turn off refresh until retrace */
- asm out 43h,AL
-
- /* Wait for end of line---hard to catch on slow machines */
- /* (there are 25 of these lines:) */
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- /* (If we got this far, machine is fast enough to loop.) */
- hwt:
- asm in AL,DX
- asm test AL,1 /* Check display enable bit */
- asm jz hwt /* Wait for horizontal retrace */
- horiz:
-
- /* Set refresh rate to get three in before next turn off */
- asm mov AL,8 /* Have about 31 clocks of code */
- asm out 41h,AL /* before turn off */
-
- /* Check if need to change color (BX is the next line's #) */
- asm cmp BL,AH /* Only need to check low byte */
- asm jne noout /* If not, check for vertical retrace */
-
- /* Do palette change */
- asm mov DL,0C0h /* Point to palette registers */
- asm lodsb /* Output 2 bytes */
- asm out DX,AL
- asm lodsw /* Also gets next scan low byte in AH */
- asm out DX,AL
- asm mov DX,DI /* Restore DX */
- asm inc BX /* Increment line count */
- asm jmp llp /* Wait for next line */
-
- /* Wait for line (probably already there) or vertical retrace */
- noout:
- ewt:
- asm in AL,DX
- asm and AL,9 /* Pick out blank, horiz bits */
- asm cmp AL,1 /* See if horizontal retrace */
- asm je ewt /* Wait for NOT horizontal retrace */
- asm test AL,8 /* See if vertical retrace */
- asm jnz done /* If so, then at end of screen */
- asm inc BX /* Increment line count */
- asm jmp llp /* Wait for next line */
- done:
-
- /* Vertical retrace just started---fix palette */
- asm mov AL,18 /* Restore refresh timing */
- asm out 41h,AL
- asm mov DL,0C0h /* Point to palette registers */
- asm mov CX,17 /* Output 17 bytes */
- olp:
- asm lodsb
- asm out DX,AL
- asm loop olp
- asm sti /* Allow interrupts at vert retrace */
-
- /* See if key hit */
- asm push DI /* Save port */
- asm mov AH,1 /* See if key hit */
- asm int 16h
- asm pop DI /* Restore port */
- asm jnz leave /* If key hit, return to process it */
- asm jmp again /* Else, do next screen */
- leave:
- asm mov AX,BX /* Else done--return line count */
- return _AX;
- }
-
-
- int trickfast(int s, char *p)
- /**********************************************************************/
- /* */
- /* trickfast() differs from trick() in that it enables the palette on */
- /* every line very near the start to avoid the flashes from enabling */
- /* the palette that occurs on some VGA clones (like mine). It also */
- /* checks for the end of horizontal retrace, even when changing the */
- /* palette to allow for machines that are so fast, they get the */
- /* palette change done before hsync is over. */
- /* */
- /**********************************************************************/
- {
- /* Get Input Status Register 1 port for retrace info */
- asm mov DX,s
- asm mov DI,DX
- asm cli
- ivwt:
- asm in AL,DX
- asm test AL,8 /* Check vertical retrace bit */
- asm jz ivwt /* Wait for vertical retrace */
-
- /* Change palette at specified lines on screen until key hit */
- again:
- asm cld /* String instructions increment */
- asm mov SI,p /* Point to palettes table */
- asm lodsb /* Get first scan number low byte */
- asm mov AH,AL /* Save in AH */
- asm sub BX,BX /* Initialize count */
- asm mov DX,DI /* Get sync port in DX */
-
- /* Wait for end of vertical retrace */
- asm cli /* Kill interrupts until screen end */
- enwt:
- asm in AL,DX
- asm test AL,1
- asm jnz enwt /* Wait for display enable */
-
- /* Go through loop once for each horizontal line */
- llp:
-
- /* Synchronize refreshes to lines */
- asm mov AL,54h /* Turn off refresh until retrace */
- asm out 43h,AL
-
- /* Wait for end of line---hard to catch on slow machines */
- /* (there are 25 of these lines:) */
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- asm in AL,DX ; asm test AL,1 ; asm jnz horiz
- /* (If we got this far, machine is fast enough to loop.) */
- hwt:
- asm in AL,DX
- asm test AL,1 /* Check display enable bit */
- asm jz hwt /* Wait for horizontal retrace */
- horiz:
-
- /* Enable palette right after hsync */
- asm mov DL,0C0h /* Point to palette registers */
- asm mov AL,020h
- asm out DX,AL
-
- /* Set refresh rate to get three in before next turn off */
- asm mov AL,8 /* Have about 31 clocks of code */
- asm out 41h,AL /* before turn off */
-
- /* Check if need to change color (BX is the next line's #) */
- asm cmp BL,AH /* Only need to check low byte */
- asm jne noout /* If not, check for vertical retrace */
-
- /* Do palette change */
- asm mov AL,0 /* Dummy byte to toggle 3C0 flip-flop */
- asm out DX,AL
- asm lodsb /* Output 2 bytes */
- asm out DX,AL
- asm lodsw /* Also gets next scan low byte in AH */
- asm out DX,AL
-
- /* Wait for line (probably already there) or vertical retrace */
- noout:
- asm mov DX,DI /* Restore DX */
- ewt:
- asm in AL,DX
- asm and AL,9 /* Pick out blank, horiz bits */
- asm cmp AL,1 /* See if horizontal retrace */
- asm je ewt /* Wait for NOT horizontal retrace */
- asm test AL,8 /* See if vertical retrace */
- asm jnz done /* If so, then at end of screen */
- asm inc BX /* Increment line count */
- asm jmp llp /* Wait for next line */
- done:
-
- /* Vertical retrace just started---fix palette */
- asm mov AL,18 /* Restore refresh timing */
- asm out 41h,AL
- asm mov DL,0C0h /* Point to palette registers */
- asm mov CX,17 /* Output 17 bytes */
- olp:
- asm lodsb
- asm out DX,AL
- asm loop olp
- asm sti /* Allow interrupts at vert retrace */
-
- /* See if key hit */
- asm push DI /* Save port */
- asm mov AH,1 /* See if key hit */
- asm int 16h
- asm pop DI /* Restore port */
- asm jnz leave /* If key hit, return to process it */
- asm jmp again /* Else, do next screen */
- leave:
- asm mov AX,BX /* Else done--return line count */
- return _AX;
- }
-
-
- int keyrdy(void) /* Return true if key ready */
- {
- asm mov AH,1
- asm int 16h
- asm mov AX,0
- asm jz notrdy
- asm inc AX
- notrdy: ;
- return _AX;
- }
-
-
- int keyin(void) /* Wait for and return key code */
- {
- asm mov AH,0
- asm int 16h
- return _AX;
- }
-
-
- int mode(int m) /* Set video mode, return status port */
- {
- asm mov AL,m
- asm mov AH,0
- asm int 10h
- asm mov BL,10h /* Get port addresses */
- asm mov AH,12h
- asm int 10h
- asm mov AX,03DAh /* Usually set up like color card */
- asm test BH,BH
- asm jz color
- asm mov AL,0BAh /* Set up like mono card */
- color:
- return _AX;
- }
-
-
- int vga(void) /* Return true (1) if VGA, false (0) if EGA */
- {
- asm mov AX,1A00h /* Attempt to determine display type */
- asm int 10h
- asm cmp AL,1Ah /* See if VGA */
- asm mov AX,0 /* (Return zero if not.) */
- asm jne ega
- asm cmp BL,7 /* See if decent monitor hooked up */
- asm jb ega
- asm cmp BL,8
- asm ja ega
- asm inc AX /* Is VGA with VGA monitor, return 1 */
- ega:
- return _AX;
- }
-
-
- unsigned int rawspeed(int s)
- /* Determine the machine's instruction execution speed relative to the
- vertical interval of the EGA or VGA. s is the status port address */
- {
- asm mov DX,s /* Get status port */
- asm sub CX,CX /* Count is in BX:CX */
- asm mov BX,CX
- asm mov SI,1 /* DI:SI is 1 */
- asm mov DI,CX
-
- /* Wait for start of vertical retrace */
- asm cli
- nvwt1:
- asm in AL,DX
- asm test AL,8 /* Check vertical retrace bit */
- asm jnz nvwt1 /* Wait for not vertical retrace */
- vwt1:
- asm in AL,DX
- asm test AL,8
- asm jz vwt1 /* Wait for vertical retrace */
-
- /* Wait for start of next vertical retrace, counting */
- nvwt2:
- asm add CX,SI /* Increment count */
- asm adc BX,DI
- asm in AL,DX
- asm test AL,8
- asm jnz nvwt2 /* Wait for not vertical retrace */
- vwt2:
- asm add CX,SI /* Increment count */
- asm adc BX,DI
- asm in AL,DX
- asm test AL,8
- asm jz vwt2 /* Wait for vertical retrace */
- asm sti
-
- /* Return count */
- asm mov AX,-1
- asm test BX,BX
- asm jnz maxcount
- asm mov AX,CX
- maxcount:
- return _AX;
- }
-
-
- void palette(char *p) /* Set palette to 17 byte table */
- {
- asm mov AX,DS /* Point ES:DX to 17 byte table. */
- asm mov ES,AX
- asm mov DX,p
- asm mov AX,1002h /* Set all palette registers and overscan. */
- asm int 10h
- }
-
-
- void cpos(int r, int c) /* Set cursor position */
- {
- asm mov DH,r /* (origin 0) */
- asm mov DL,c /* (origin 0) */
- asm mov BH,0 /* Select page 0 */
- asm mov AH,2
- asm int 10h
- }
-
-
- void wrchr(int r, int c, int b, int a) /* Write char with attribute */
- /* row col char attr */
- {
- /* Do it direct to avoid BIOS delay */
- /* Get regen segment based on mono or color */
- asm xor AX,AX /* Point to BIOS data */
- asm mov ES,AX
- asm mov AL,ES:[0410h] /* Get low byte of equipment */
- asm and AL,30h /* Check for mono */
- asm cmp AL,30h
- asm mov AX,0B000h /* Segment for mono */
- asm je mono
- asm mov AH,0B8h /* Segment for color */
- mono:
- asm mov ES,AX
-
- /* Compute offset of character/attribute in segment */
- asm mov AL,80
- asm mul byte ptr r /* Multiply row times cols/row */
- asm add AX,c /* Add column */
- asm shl AX,1 /* Double for 2 bytes/position */
- asm mov DI,AX
-
- /* Put character and attribute there */
- asm mov AL,b /* Character */
- asm mov AH,a /* Attribute */
- asm stosw /* Store it */
- }
-
-
- void wrstr(int n, int m, char *s, int a)
- /**********************************************************************/
- /* */
- /* Write a string of characters to the screen with an attribute. It */
- /* is assumed that the string will not go past the end of the line. */
- /* */
- /**********************************************************************/
- {
- while (*s)
- wrchr(n, m++, *s++, a);
- }
-
-
- void wrblk(int i, int j, int k, int b)
- /**********************************************************************/
- /* */
- /* Write a block of characters on the screen consisting of pure fore- */
- /* ground color, and setting the color attribute of the characters */
- /* to select the proper color in the palette for that area of the */
- /* screen. (b = 0x80 to blink.) */
- /* */
- /**********************************************************************/
- {
- register int n, m;
- int c;
- static char s[] = "\333\333\333\333\333"; /* All foreground */
-
- n = (i & 2 ? 14 : 1) + 3 * j; /* Row number of upper left */
- m = (i & 1 ? 41 : 10) + 7 * k; /* Column number of same */
- c = (i & 1 ? 12 : 8) + k + b; /* Color for this block */
- wrstr(n, m, s, c); /* Do first row of six */
- wrstr(n+1, m, s, c); /* Do second row of six */
- }
-
-
- int padr(int i, int j, int k)
- /**********************************************************************/
- /* */
- /* Return the offset in the palettes table for the color byte of the */
- /* (i,j,k) block. The index 'i' selects which 4x4 group the block */
- /* is in, 'j' is which row in the 4x4 group selected by 'i', and 'k' */
- /* is which block in the row selected by 'i' and 'j'. */
- /* */
- /**********************************************************************/
- {
- return 2 + 3 * ((((i & 2) << 1) + j) * 9 + ((i & 1) << 2) + k);
- }
-
-
- void colors(char *p, int a, int b, int c)
- /**********************************************************************/
- /* */
- /* Set the colors in the palettes table to the desired permutation */
- /* of the color axes. a is the first axis---it spans the four large */
- /* 4x4 blocks. b is the second axis---it is the vertical axis for */
- /* each 4x4 block. c is the last axis---it is the horizontal axis */
- /* for each 4x4 block. a, b, and c should be some permutation of */
- /* 0, 1, and 2. The value 2 picks red for that axis, 1 picks green, */
- /* and 0 picks blue. */
- /* */
- /**********************************************************************/
- {
- register int j, k;
- int i;
-
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++)
- for (k = 0; k < 4; k++)
- p[padr(i, j, k)] = (((i >> 1) & 1) << a) | ((i & 1) << (a+3)) |
- (((j >> 1) & 1) << b) | ((j & 1) << (b+3)) |
- (((k >> 1) & 1) << c) | ((k & 1) << (c+3));
- }
-
-
- void main(void)
- /**********************************************************************/
- /* */
- /* EGACOLRS - displays all 64 colors the EGA can produce at once on */
- /* the screen. The EGA makes 64 colors by mixing four intensities */
- /* each of red, green, and blue (4*4*4 = 64). The colors are shown */
- /* in four 4x4 blocks, corresponding to an imaginary 4x4x4 three- */
- /* dimensional array. So, each edge of this 4x4x4 cube corresponds */
- /* to one of the three colors, red, green, or blue. There are six */
- /* possible ways to assign three colors to three axes. Hitting the */
- /* space bar steps through all six ways, rearranging the colors on */
- /* the screen each time. At any time, one of the blocks is selected */
- /* and this is indicated by the block blinking (unless it is the */
- /* black block, in which case you just can't tell it's blinking). */
- /* The color value of that block (the byte you would put in the EGA */
- /* palette for that color) is displayed in the lower right corner */
- /* of the screen, next to the bright white block. (It is left as an */
- /* exercise to the reader why that block does not move when the */
- /* axes are permuted. What other blocks don't move?) Different */
- /* blocks are selected with the cursor keys. Also, the Home and End */
- /* keys go to the far left and far right on the current row, and the */
- /* PgUp and PgDn keys go to top and bottom of the current column. */
- /* Any of Esc, 'q', or 'Q' exits the program. */
- /* */
- /* The EGA can only display 16 of the 64 possible colors at any one */
- /* time. (Well, in the supported modes anyway, and not counting the */
- /* overscan color, but let's not get picky.) Which 16, is selected */
- /* by a software redefinable table called the "palette". This */
- /* program tricks the EGA into displaying all 64 possible colors by */
- /* taking the phrase "at any one time" above quite literally. The */
- /* key point is that it takes quite a while (from the point of view */
- /* of the computer) to put up one frame on your monitor's screen */
- /* (about 1/60th of a second). During that time, that software */
- /* definable palette is changed by this software several times. */
- /* In that way, different parts of the screen have different */
- /* palettes. Specifically, eight sections of the screen have eight */
- /* different palettes, and in each of those sections is eight */
- /* colored boxes. Only the last eight of the 16 colors in the */
- /* palette need to be changed to set the colors of those eight */
- /* boxes, and in fact that is what is done. */
- /* */
- /**********************************************************************/
- {
- int i, j, k; /* Current color */
- int a, b, c; /* Current axis selection */
- int f, s;
- unsigned int r;
- char *p, pal[8*9*3 + 1 + 2*8 + 1];
-
- /* Set mode, get info on video adapter */
- s = mode(3); /* Select 80x25 color, set port */
- r = vga() ? 16 : 14; /* Set scan lines per row */
-
- /* Set up palettes table */
- /* Format of table: low byte of the scan line number preceding the
- scan line to change the palette on, followed by
- two bytes to send to the palette address and data
- port. The two bytes are a color number and a
- color value. Every eight such groups are followed
- by a ninth: a scan line number followed by a 0x20
- to turn the palette back on (and a dummy byte). */
- p = pal; /* Change palette at eight scan */
- for (i = 0; i < 8; i++) /* lines (every three char lines) */
- {
- for (j = 8, k = 3 * r * i + (i > 4) * r + 1; j < 16; j++, k++)
- {
- *p++ = k; /* Low byte of scan line */
- *p++ = j; /* Color number */
- p++; /* Color---filled in by colors() */
- }
- *p++ = k; /* Scan line to turn palette on on */
- *p++ = 0x20; *p++ = 0; /* Turn-on command and dummy byte */
- }
- *p++ = 25 * r + 1; /* Non-existent line */
- for (j = 8; j < 16; j++) /* Kill colors at vertical retrace */
- {
- *p++ = j;
- *p++ = 0; /* Black */
- }
- *p = 0x20;
-
- /* Get speed to decide between trick() and trickfast() */
- r = rawspeed(s);
-
- /* Set up initial axes, fill in palette table */
- a = 2; b = 1; c = 0; /* Initial choice of color axes */
- colors(pal, a, b, c); /* Set colors */
-
-
- /* Put colors on screen */
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++)
- for (k = 0; k < 4; k++)
- wrblk(i, j, k, 0); /* Write 64 colored blocks */
- cpos(24, 80); /* Hide cursor (one char after end) */
-
-
- /* Display colors, process keystrokes */
- i = j = k = 0; /* Initial selected block */
- do { /* Process keystrokes */
- /* Blink selected block and show its color value in hex */
- wrblk(i, j, k, 0x80); /* Blink the selected block */
- f = pal[padr(i, j, k)]; /* Get color of selected block */
- wrstr(24, 69, "color 0x", 0x0f); /* Show color in hex */
- wrchr(24, 77, "0123456789ABCDEF"[f >> 4], 0x0f);
- wrchr(24, 78, "0123456789ABCDEF"[f & 0x0f], 0x0f);
-
- /* Change palettes on the fly, waiting for keystroke */
- if (r < 3000)
- trick(s, pal);
- else
- trickfast(s, pal);
-
- /* Get the key hit and process it */
- wrblk(i, j, k, 0); /* Unblink last selected block */
- switch (f = keyin()) /* Get key, see what it is */
- {
- case RIGHT: if (k < 3) k++; else { i ^= 1; k = 0; } break;
- case LEFT: if (k > 0) k--; else { i ^= 1; k = 3; } break;
- case DOWN: if (j < 3) j++; else { i ^= 2; j = 0; } break;
- case UP: if (j > 0) j--; else { i ^= 2; j = 3; } break;
- case HOME: i &= 2; k = 0; break;
- case END: i |= 1; k = 3; break;
- case PGUP: i &= 1; j = 0; break;
- case PGDN: i |= 2; j = 3; break;
- case SPACE: /* Toggle color axes */
- if ((b - a + 3) % 3 == 2) /* Step through all */
- { f = a; a = b; b = f; /* permutations of 3 things */
- f = i; i = j; j = f; } /* Keep same selected color. */
- else
- { f = b; b = c; c = f;
- f = j; j = k; k = f; }
- colors(pal, a, b, c); /* Change color palettes */
- }
-
- /* If Esc, 'q', or 'Q' hit, then exit */
- } while ((f & 0x7f) != 27 && (f & 0x5f) != 'Q');
-
- /* Done---restore default palette and exit */
- palette(egapal);
- cpos(24, 0); /* Put prompt on next line */
- }