home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / ega / egacolrs.arc / EGACOLRS.C next >
Encoding:
C/C++ Source or Header  |  1989-03-10  |  29.5 KB  |  703 lines

  1. /* EGACOLRS --- by Mark Adler    9 Jan 1988     Pasadena, CA          */
  2. /*     modified by Mark Adler   10 Mar 1989     to work with VGA      */
  3. /* This program may be used and freely copied by anyone except that   */
  4. /*  it may not be sold by itself or as part of any package without    */
  5. /*  the permission of the author.                                     */
  6.  
  7. /* Compile with Turbo C using options -mt -lt (tiny model). */
  8. /* Compilation requires Microsoft MASM or Borland TASM */
  9.  
  10. #pragma inline          /* Tell compiler there is assembly code here */
  11.  
  12. char notice[] = "EGACOLRS - Copyright (c) 1988,1989 Mark Adler";
  13.  
  14. /* Key values returned by keyin() */
  15. #define UP      0x4800
  16. #define DOWN    0x5000
  17. #define RIGHT   0x4d00
  18. #define LEFT    0x4b00
  19. #define HOME    0x4700
  20. #define END     0x4f00
  21. #define PGUP    0x4900
  22. #define PGDN    0x5100
  23. #define SPACE   0x3920
  24.  
  25. /* Default palette for EGA---used to restore palette when done. */
  26. char egapal[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
  27.                  0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x00};
  28.  
  29.  
  30. int trick(int s, char *p)
  31. /**********************************************************************/
  32. /*                                                                    */
  33. /* trick() watches the horizontal and vertical retraces and uses the  */
  34. /*  information to change the color palette of the EGA on the         */
  35. /*  desired scan lines.  This allows displaying all 64 possible       */
  36. /*  colors at a time, albeit in a restricted way.                     */
  37. /*                                                                    */
  38. /*  's' is the address of the status port with the sync information.  */
  39. /*  It should be 0x3ba or 0x3da depending on the display.             */
  40. /*                                                                    */
  41. /*  'p[]' is a sequence of instructions that specify how to change    */
  42. /*  the colors.  Each instruction is three bytes---the first byte is  */
  43. /*  the low byte of the number of the scan line to change the color   */
  44. /*  on, the second byte is the palette color to change (0..15 or 17   */
  45. /*  for overscan), and the third byte is the color to change it to    */
  46. /*  (0..63).  The last three bytes are sent to port 0x3c0 on the      */
  47. /*  line specified by the first byte.  The format of the color byte   */
  48. /*  is from most significant to least significant bit:  00rgbRGB.     */
  49. /*  The letters refer to the colors red, green, and blue, and the     */
  50. /*  upper case letters are "stronger" than the lower case letters.    */
  51. /*  So, 00000100 is a stronger red than 00100000.                     */
  52. /*                                                                    */
  53. /*  After the last palette change, the next byte should be a scan     */
  54. /*  line that does not occur.  On vertical retrace, the 17 bytes      */
  55. /*  that follow are sent to the palette port.  This allows setting    */
  56. /*  part of the palette to black to avoid color flashes while         */
  57. /*  processing keystrokes.                                            */
  58. /*                                                                    */
  59. /*  At each vertical retrace, interrupts are allowed and if a key was */
  60. /*  hit, the process terminates.  Else, it starts over at the top of  */
  61. /*  of the screen.                                                    */
  62. /*                                                                    */
  63. /*  The timing is so tight on 4.77 MHz PC's with 8088's, it is        */
  64. /*  necessary to avoid jumps that reload the queue and to disable the */
  65. /*  DMA refreshes to guarantee that the horizontal retrace will be    */
  66. /*  caught.  Jumps are avoided by repeating the code to check for     */
  67. /*  horizontal retrace instead of allowing it to loop on itself.  The */
  68. /*  DMA is not actually disabled, but instead it is synchronized to   */
  69. /*  the horizontal lines.  Refreshes must be done on the average      */
  70. /*  every 15.625 uS.  A horizontal line is 45.765 uS, so three        */
  71. /*  refreshes per line is more than sufficient.  The DMA refresh is   */
  72. /*  disabled before looking for the horizontal retrace.  After        */
  73. /*  finding the retrace, refreshes are set to a high enough rate to   */
  74. /*  get three in before the next time the refresh is disabled.  On    */
  75. /*  vertical retrace, the refresh time is set back to normal.         */
  76. /*                                                                    */
  77. /**********************************************************************/
  78. {
  79.         /* Get Input Status Register 1 port for retrace info */
  80.   asm mov DX,s
  81.   asm mov DI,DX
  82.   asm cli
  83.      ivwt:
  84.   asm  in AL,DX
  85.   asm  test AL,8                /* Check vertical retrace bit */
  86.   asm  jz ivwt                  /* Wait for vertical retrace */
  87.  
  88.         /* Change palette at specified lines on screen until key hit */
  89.      again:
  90.   asm  cld                      /* String instructions increment */
  91.   asm  mov SI,p                 /* Point to palettes table */
  92.   asm  lodsb                    /* Get first scan number low byte */
  93.   asm  mov AH,AL                /* Save in AH */
  94.   asm  sub BX,BX                /* Initialize count */
  95.   asm  mov DX,DI                /* Get sync port in DX */
  96.  
  97.         /* Wait for end of vertical retrace */
  98.   asm  cli                      /* Kill interrupts until screen end */
  99.       enwt:
  100.   asm   in AL,DX
  101.   asm   test AL,1
  102.   asm   jnz enwt                /* Wait for display enable */
  103.  
  104.         /* Go through loop once for each horizontal line */
  105.       llp:
  106.  
  107.         /* Synchronize refreshes to lines */
  108.   asm   mov AL,54h              /* Turn off refresh until retrace */
  109.   asm   out 43h,AL
  110.  
  111.         /* Wait for end of line---hard to catch on slow machines */
  112.         /*  (there are 25 of these lines:) */
  113.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  114.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  115.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  116.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  117.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  118.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  119.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  120.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  121.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  122.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  123.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  124.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  125.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  126.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  127.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  128.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  129.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  130.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  131.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  132.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  133.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  134.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  135.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  136.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  137.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  138.   /* (If we got this far, machine is fast enough to loop.) */
  139.        hwt:
  140.   asm    in AL,DX
  141.   asm    test AL,1              /* Check display enable bit */
  142.   asm    jz hwt                 /* Wait for horizontal retrace */
  143.        horiz:
  144.  
  145.         /* Set refresh rate to get three in before next turn off */
  146.   asm   mov AL,8                /* Have about 31 clocks of code */
  147.   asm   out 41h,AL              /*  before turn off */
  148.  
  149.         /* Check if need to change color (BX is the next line's #) */
  150.   asm   cmp BL,AH               /* Only need to check low byte */
  151.   asm   jne noout               /* If not, check for vertical retrace */
  152.  
  153.         /* Do palette change */
  154.   asm   mov DL,0C0h             /* Point to palette registers */
  155.   asm   lodsb                   /* Output 2 bytes */
  156.   asm   out DX,AL
  157.   asm   lodsw                   /* Also gets next scan low byte in AH */
  158.   asm   out DX,AL
  159.   asm   mov DX,DI               /* Restore DX */
  160.   asm   inc BX                  /* Increment line count */
  161.   asm   jmp llp                 /* Wait for next line */
  162.  
  163.         /* Wait for line (probably already there) or vertical retrace */
  164.        noout:
  165.        ewt:
  166.   asm    in AL,DX
  167.   asm    and AL,9               /* Pick out blank, horiz bits */
  168.   asm    cmp AL,1               /* See if horizontal retrace */
  169.   asm    je ewt                 /* Wait for NOT horizontal retrace */
  170.   asm   test AL,8               /* See if vertical retrace */
  171.   asm   jnz done                /* If so, then at end of screen */
  172.   asm   inc BX                  /* Increment line count */
  173.   asm   jmp llp                 /* Wait for next line */
  174.       done:
  175.  
  176.         /* Vertical retrace just started---fix palette */
  177.   asm  mov AL,18                /* Restore refresh timing */
  178.   asm  out 41h,AL
  179.   asm  mov DL,0C0h              /* Point to palette registers */
  180.   asm  mov CX,17                /* Output 17 bytes */
  181.       olp:
  182.   asm   lodsb
  183.   asm   out DX,AL
  184.   asm   loop olp
  185.   asm  sti                      /* Allow interrupts at vert retrace */
  186.  
  187.         /* See if key hit */
  188.   asm  push DI                  /* Save port */
  189.   asm  mov AH,1                 /* See if key hit */
  190.   asm  int 16h
  191.   asm  pop DI                   /* Restore port */
  192.   asm  jnz leave                /* If key hit, return to process it */
  193.   asm  jmp again                /* Else, do next screen */
  194.      leave:
  195.   asm mov AX,BX                 /* Else done--return line count */
  196.   return _AX;
  197. }
  198.  
  199.  
  200. int trickfast(int s, char *p)
  201. /**********************************************************************/
  202. /*                                                                    */
  203. /* trickfast() differs from trick() in that it enables the palette on */
  204. /*  every line very near the start to avoid the flashes from enabling */
  205. /*  the palette that occurs on some VGA clones (like mine).  It also  */
  206. /*  checks for the end of horizontal retrace, even when changing the  */
  207. /*  palette to allow for machines that are so fast, they get the      */
  208. /*  palette change done before hsync is over.                         */
  209. /*                                                                    */
  210. /**********************************************************************/
  211. {
  212.         /* Get Input Status Register 1 port for retrace info */
  213.   asm mov DX,s
  214.   asm mov DI,DX
  215.   asm cli
  216.      ivwt:
  217.   asm  in AL,DX
  218.   asm  test AL,8                /* Check vertical retrace bit */
  219.   asm  jz ivwt                  /* Wait for vertical retrace */
  220.  
  221.         /* Change palette at specified lines on screen until key hit */
  222.      again:
  223.   asm  cld                      /* String instructions increment */
  224.   asm  mov SI,p                 /* Point to palettes table */
  225.   asm  lodsb                    /* Get first scan number low byte */
  226.   asm  mov AH,AL                /* Save in AH */
  227.   asm  sub BX,BX                /* Initialize count */
  228.   asm  mov DX,DI                /* Get sync port in DX */
  229.  
  230.         /* Wait for end of vertical retrace */
  231.   asm  cli                      /* Kill interrupts until screen end */
  232.       enwt:
  233.   asm   in AL,DX
  234.   asm   test AL,1
  235.   asm   jnz enwt                /* Wait for display enable */
  236.  
  237.         /* Go through loop once for each horizontal line */
  238.       llp:
  239.  
  240.         /* Synchronize refreshes to lines */
  241.   asm   mov AL,54h              /* Turn off refresh until retrace */
  242.   asm   out 43h,AL
  243.  
  244.         /* Wait for end of line---hard to catch on slow machines */
  245.         /*  (there are 25 of these lines:) */
  246.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  247.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  248.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  249.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  250.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  251.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  252.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  253.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  254.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  255.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  256.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  257.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  258.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  259.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  260.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  261.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  262.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  263.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  264.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  265.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  266.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  267.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  268.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  269.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  270.   asm   in AL,DX ; asm test AL,1 ; asm jnz horiz
  271.   /* (If we got this far, machine is fast enough to loop.) */
  272.        hwt:
  273.   asm    in AL,DX
  274.   asm    test AL,1              /* Check display enable bit */
  275.   asm    jz hwt                 /* Wait for horizontal retrace */
  276.        horiz:
  277.  
  278.         /* Enable palette right after hsync */
  279.   asm   mov DL,0C0h             /* Point to palette registers */
  280.   asm   mov AL,020h
  281.   asm   out DX,AL
  282.  
  283.         /* Set refresh rate to get three in before next turn off */
  284.   asm   mov AL,8                /* Have about 31 clocks of code */
  285.   asm   out 41h,AL              /*  before turn off */
  286.  
  287.         /* Check if need to change color (BX is the next line's #) */
  288.   asm   cmp BL,AH               /* Only need to check low byte */
  289.   asm   jne noout               /* If not, check for vertical retrace */
  290.  
  291.         /* Do palette change */
  292.   asm   mov AL,0                /* Dummy byte to toggle 3C0 flip-flop */
  293.   asm   out DX,AL
  294.   asm   lodsb                   /* Output 2 bytes */
  295.   asm   out DX,AL
  296.   asm   lodsw                   /* Also gets next scan low byte in AH */
  297.   asm   out DX,AL
  298.  
  299.         /* Wait for line (probably already there) or vertical retrace */
  300.        noout:
  301.   asm   mov DX,DI               /* Restore DX */
  302.        ewt:
  303.   asm    in AL,DX
  304.   asm    and AL,9               /* Pick out blank, horiz bits */
  305.   asm    cmp AL,1               /* See if horizontal retrace */
  306.   asm    je ewt                 /* Wait for NOT horizontal retrace */
  307.   asm   test AL,8               /* See if vertical retrace */
  308.   asm   jnz done                /* If so, then at end of screen */
  309.   asm   inc BX                  /* Increment line count */
  310.   asm   jmp llp                 /* Wait for next line */
  311.       done:
  312.  
  313.         /* Vertical retrace just started---fix palette */
  314.   asm  mov AL,18                /* Restore refresh timing */
  315.   asm  out 41h,AL
  316.   asm  mov DL,0C0h              /* Point to palette registers */
  317.   asm  mov CX,17                /* Output 17 bytes */
  318.       olp:
  319.   asm   lodsb
  320.   asm   out DX,AL
  321.   asm   loop olp
  322.   asm  sti                      /* Allow interrupts at vert retrace */
  323.  
  324.         /* See if key hit */
  325.   asm  push DI                  /* Save port */
  326.   asm  mov AH,1                 /* See if key hit */
  327.   asm  int 16h
  328.   asm  pop DI                   /* Restore port */
  329.   asm  jnz leave                /* If key hit, return to process it */
  330.   asm  jmp again                /* Else, do next screen */
  331.      leave:
  332.   asm mov AX,BX                 /* Else done--return line count */
  333.   return _AX;
  334. }
  335.  
  336.  
  337. int keyrdy(void)        /* Return true if key ready */
  338. {
  339.   asm mov AH,1
  340.   asm int 16h
  341.   asm mov AX,0
  342.   asm jz notrdy
  343.   asm  inc AX
  344.      notrdy: ;
  345.   return _AX;
  346. }
  347.  
  348.  
  349. int keyin(void)         /* Wait for and return key code */
  350. {
  351.   asm mov AH,0
  352.   asm int 16h
  353.   return _AX;
  354. }
  355.  
  356.  
  357. int mode(int m)         /* Set video mode, return status port */
  358. {
  359.   asm mov AL,m
  360.   asm mov AH,0
  361.   asm int 10h
  362.   asm mov BL,10h                /* Get port addresses */
  363.   asm mov AH,12h
  364.   asm int 10h
  365.   asm mov AX,03DAh              /* Usually set up like color card */
  366.   asm test BH,BH
  367.   asm jz color
  368.   asm  mov AL,0BAh              /* Set up like mono card */
  369.      color:
  370.   return _AX;
  371. }
  372.  
  373.  
  374. int vga(void)           /* Return true (1) if VGA, false (0) if EGA */
  375. {
  376.   asm mov AX,1A00h      /* Attempt to determine display type */
  377.   asm int 10h
  378.   asm cmp AL,1Ah        /* See if VGA */
  379.   asm mov AX,0          /* (Return zero if not.) */
  380.   asm jne ega
  381.   asm cmp BL,7          /* See if decent monitor hooked up */
  382.   asm jb ega
  383.   asm cmp BL,8
  384.   asm ja ega
  385.   asm inc AX            /* Is VGA with VGA monitor, return 1 */
  386.     ega:
  387.   return _AX;
  388. }
  389.  
  390.  
  391. unsigned int rawspeed(int s)
  392. /* Determine the machine's instruction execution speed relative to the
  393.    vertical interval of the EGA or VGA.  s is the status port address */
  394. {
  395.   asm mov DX,s          /* Get status port */
  396.   asm sub CX,CX         /* Count is in BX:CX */
  397.   asm mov BX,CX
  398.   asm mov SI,1          /* DI:SI is 1 */
  399.   asm mov DI,CX
  400.  
  401.         /* Wait for start of vertical retrace */
  402.   asm cli
  403.      nvwt1:
  404.   asm  in AL,DX
  405.   asm  test AL,8        /* Check vertical retrace bit */
  406.   asm  jnz nvwt1        /* Wait for not vertical retrace */
  407.      vwt1:
  408.   asm  in AL,DX
  409.   asm  test AL,8
  410.   asm  jz vwt1          /* Wait for vertical retrace */
  411.  
  412.         /* Wait for start of next vertical retrace, counting */
  413.      nvwt2:
  414.   asm  add CX,SI        /* Increment count */
  415.   asm  adc BX,DI
  416.   asm  in AL,DX
  417.   asm  test AL,8
  418.   asm  jnz nvwt2        /* Wait for not vertical retrace */
  419.      vwt2:
  420.   asm  add CX,SI        /* Increment count */
  421.   asm  adc BX,DI
  422.   asm  in AL,DX
  423.   asm  test AL,8
  424.   asm  jz vwt2          /* Wait for vertical retrace */
  425.   asm sti
  426.  
  427.         /* Return count */
  428.   asm mov AX,-1
  429.   asm test BX,BX
  430.   asm jnz maxcount
  431.   asm  mov AX,CX
  432.     maxcount:
  433.   return _AX;
  434. }
  435.  
  436.  
  437. void palette(char *p)   /* Set palette to 17 byte table */
  438. {
  439.   asm mov AX,DS         /* Point ES:DX to 17 byte table. */
  440.   asm mov ES,AX
  441.   asm mov DX,p
  442.   asm mov AX,1002h      /* Set all palette registers and overscan. */
  443.   asm int 10h
  444. }
  445.  
  446.  
  447. void cpos(int r, int c) /* Set cursor position */
  448. {
  449.   asm mov DH,r          /* (origin 0) */
  450.   asm mov DL,c          /* (origin 0) */
  451.   asm mov BH,0          /* Select page 0 */
  452.   asm mov AH,2
  453.   asm int 10h
  454. }
  455.  
  456.  
  457. void wrchr(int r, int c, int b, int a)  /* Write char with attribute */
  458. /*          row    col    char   attr   */
  459. {
  460.         /* Do it direct to avoid BIOS delay */
  461.         /* Get regen segment based on mono or color */
  462.   asm xor AX,AX                 /* Point to BIOS data */
  463.   asm mov ES,AX
  464.   asm mov AL,ES:[0410h]         /* Get low byte of equipment */
  465.   asm and AL,30h                /* Check for mono */
  466.   asm cmp AL,30h
  467.   asm mov AX,0B000h             /* Segment for mono */
  468.   asm je mono
  469.   asm  mov AH,0B8h              /* Segment for color */
  470.      mono:
  471.   asm mov ES,AX
  472.  
  473.         /* Compute offset of character/attribute in segment */
  474.   asm mov AL,80
  475.   asm mul byte ptr r            /* Multiply row times cols/row */
  476.   asm add AX,c                  /* Add column */
  477.   asm shl AX,1                  /* Double for 2 bytes/position */
  478.   asm mov DI,AX
  479.  
  480.         /* Put character and attribute there */
  481.   asm mov AL,b                  /* Character */
  482.   asm mov AH,a                  /* Attribute */
  483.   asm stosw                     /* Store it */
  484. }
  485.  
  486.  
  487. void wrstr(int n, int m, char *s, int a)
  488. /**********************************************************************/
  489. /*                                                                    */
  490. /* Write a string of characters to the screen with an attribute.  It  */
  491. /*  is assumed that the string will not go past the end of the line.  */
  492. /*                                                                    */
  493. /**********************************************************************/
  494. {
  495.   while (*s)
  496.     wrchr(n, m++, *s++, a);
  497. }
  498.  
  499.  
  500. void wrblk(int i, int j, int k, int b)
  501. /**********************************************************************/
  502. /*                                                                    */
  503. /* Write a block of characters on the screen consisting of pure fore- */
  504. /*  ground color, and setting the color attribute of the characters   */
  505. /*  to select the proper color in the palette for that area of the    */
  506. /*  screen.  (b = 0x80 to blink.)                                     */
  507. /*                                                                    */
  508. /**********************************************************************/
  509. {
  510.   register int n, m;
  511.   int c;
  512.   static char s[] = "\333\333\333\333\333";     /* All foreground */
  513.  
  514.   n = (i & 2 ? 14 : 1) + 3 * j;         /* Row number of upper left */
  515.   m = (i & 1 ? 41 : 10) + 7 * k;        /* Column number of same */
  516.   c = (i & 1 ? 12 : 8) + k + b;         /* Color for this block */
  517.   wrstr(n, m, s, c);            /* Do first row of six */
  518.   wrstr(n+1, m, s, c);          /* Do second row of six */
  519. }
  520.  
  521.  
  522. int padr(int i, int j, int k)
  523. /**********************************************************************/
  524. /*                                                                    */
  525. /* Return the offset in the palettes table for the color byte of the  */
  526. /*  (i,j,k) block.  The index 'i' selects which 4x4 group the block   */
  527. /*  is in, 'j' is which row in the 4x4 group selected by 'i', and 'k' */
  528. /*  is which block in the row selected by 'i' and 'j'.                */
  529. /*                                                                    */
  530. /**********************************************************************/
  531. {
  532.   return 2 + 3 * ((((i & 2) << 1) + j) * 9 + ((i & 1) << 2) + k);
  533. }
  534.  
  535.  
  536. void colors(char *p, int a, int b, int c)
  537. /**********************************************************************/
  538. /*                                                                    */
  539. /* Set the colors in the palettes table to the desired permutation    */
  540. /*  of the color axes.  a is the first axis---it spans the four large */
  541. /*  4x4 blocks.  b is the second axis---it is the vertical axis for   */
  542. /*  each 4x4 block.  c is the last axis---it is the horizontal axis   */
  543. /*  for each 4x4 block.  a, b, and c should be some permutation of    */
  544. /*  0, 1, and 2.  The value 2 picks red for that axis, 1 picks green, */
  545. /*  and 0 picks blue.                                                 */
  546. /*                                                                    */
  547. /**********************************************************************/
  548. {
  549.   register int j, k;
  550.   int i;
  551.  
  552.   for (i = 0; i < 4; i++)
  553.     for (j = 0; j < 4; j++)
  554.       for (k = 0; k < 4; k++)
  555.         p[padr(i, j, k)] = (((i >> 1) & 1) << a) | ((i & 1) << (a+3)) |
  556.                            (((j >> 1) & 1) << b) | ((j & 1) << (b+3)) |
  557.                            (((k >> 1) & 1) << c) | ((k & 1) << (c+3));
  558. }
  559.  
  560.  
  561. void main(void)
  562. /**********************************************************************/
  563. /*                                                                    */
  564. /* EGACOLRS - displays all 64 colors the EGA can produce at once on   */
  565. /*  the screen.  The EGA makes 64 colors by mixing four intensities   */
  566. /*  each of red, green, and blue (4*4*4 = 64).  The colors are shown  */
  567. /*  in four 4x4 blocks, corresponding to an imaginary 4x4x4 three-    */
  568. /*  dimensional array.  So, each edge of this 4x4x4 cube corresponds  */
  569. /*  to one of the three colors, red, green, or blue.  There are six   */
  570. /*  possible ways to assign three colors to three axes.  Hitting the  */
  571. /*  space bar steps through all six ways, rearranging the colors on   */
  572. /*  the screen each time.  At any time, one of the blocks is selected */
  573. /*  and this is indicated by the block blinking (unless it is the     */
  574. /*  black block, in which case you just can't tell it's blinking).    */
  575. /*  The color value of that block (the byte you would put in the EGA  */
  576. /*  palette for that color) is displayed in the lower right corner    */
  577. /*  of the screen, next to the bright white block.  (It is left as an */
  578. /*  exercise to the reader why that block does not move when the      */
  579. /*  axes are permuted.  What other blocks don't move?)  Different     */
  580. /*  blocks are selected with the cursor keys.  Also, the Home and End */
  581. /*  keys go to the far left and far right on the current row, and the */
  582. /*  PgUp and PgDn keys go to top and bottom of the current column.    */
  583. /*  Any of Esc, 'q', or 'Q' exits the program.                        */
  584. /*                                                                    */
  585. /*  The EGA can only display 16 of the 64 possible colors at any one  */
  586. /*  time.  (Well, in the supported modes anyway, and not counting the */
  587. /*  overscan color, but let's not get picky.)  Which 16, is selected  */
  588. /*  by a software redefinable table called the "palette".  This       */
  589. /*  program tricks the EGA into displaying all 64 possible colors by  */
  590. /*  taking the phrase "at any one time" above quite literally.  The   */
  591. /*  key point is that it takes quite a while (from the point of view  */
  592. /*  of the computer) to put up one frame on your monitor's screen     */
  593. /*  (about 1/60th of a second).  During that time, that software      */
  594. /*  definable palette is changed by this software several times.      */
  595. /*  In that way, different parts of the screen have different         */
  596. /*  palettes.  Specifically, eight sections of the screen have eight  */
  597. /*  different palettes, and in each of those sections is eight        */
  598. /*  colored boxes.  Only the last eight of the 16 colors in the       */
  599. /*  palette need to be changed to set the colors of those eight       */
  600. /*  boxes, and in fact that is what is done.                          */
  601. /*                                                                    */
  602. /**********************************************************************/
  603. {
  604.   int i, j, k;          /* Current color */
  605.   int a, b, c;          /* Current axis selection */
  606.   int f, s;
  607.   unsigned int r;
  608.   char *p, pal[8*9*3 + 1 + 2*8 + 1];
  609.  
  610.   /* Set mode, get info on video adapter */
  611.   s = mode(3);                  /* Select 80x25 color, set port */
  612.   r = vga() ? 16 : 14;          /* Set scan lines per row */
  613.  
  614.   /* Set up palettes table */
  615.   /* Format of table: low byte of the scan line number preceding the
  616.                       scan line to change the palette on, followed by
  617.                       two bytes to send to the palette address and data
  618.                       port.  The two bytes are a color number and a
  619.                       color value.  Every eight such groups are followed
  620.                       by a ninth: a scan line number followed by a 0x20
  621.                       to turn the palette back on (and a dummy byte). */
  622.   p = pal;                      /* Change palette at eight scan */
  623.   for (i = 0; i < 8; i++)       /*  lines (every three char lines) */
  624.   {
  625.     for (j = 8, k = 3 * r * i + (i > 4) * r + 1; j < 16; j++, k++)
  626.     {
  627.       *p++ = k;                 /* Low byte of scan line */
  628.       *p++ = j;                 /* Color number */
  629.       p++;                      /* Color---filled in by colors() */
  630.     }
  631.     *p++ = k;                   /* Scan line to turn palette on on */
  632.     *p++ = 0x20;  *p++ = 0;     /* Turn-on command and dummy byte */
  633.   }
  634.   *p++ = 25 * r + 1;            /* Non-existent line */
  635.   for (j = 8; j < 16; j++)      /* Kill colors at vertical retrace */
  636.   {
  637.     *p++ = j;
  638.     *p++ = 0;                   /* Black */
  639.   }
  640.   *p = 0x20;
  641.  
  642.   /* Get speed to decide between trick() and trickfast() */
  643.   r = rawspeed(s);
  644.  
  645.   /* Set up initial axes, fill in palette table */
  646.   a = 2;  b = 1;  c = 0;        /* Initial choice of color axes */
  647.   colors(pal, a, b, c);         /* Set colors */
  648.  
  649.  
  650.   /* Put colors on screen */
  651.   for (i = 0; i < 4; i++)
  652.     for (j = 0; j < 4; j++)
  653.       for (k = 0; k < 4; k++)
  654.         wrblk(i, j, k, 0);      /* Write 64 colored blocks */
  655.   cpos(24, 80);                 /* Hide cursor (one char after end) */
  656.  
  657.  
  658.   /* Display colors, process keystrokes */
  659.   i = j = k = 0;                /* Initial selected block */
  660.   do {                          /* Process keystrokes */
  661.         /* Blink selected block and show its color value in hex */
  662.     wrblk(i, j, k, 0x80);       /* Blink the selected block */
  663.     f = pal[padr(i, j, k)];     /* Get color of selected block */
  664.     wrstr(24, 69, "color 0x", 0x0f);    /* Show color in hex */
  665.     wrchr(24, 77, "0123456789ABCDEF"[f >> 4], 0x0f);
  666.     wrchr(24, 78, "0123456789ABCDEF"[f & 0x0f], 0x0f);
  667.  
  668.         /* Change palettes on the fly, waiting for keystroke */
  669.     if (r < 3000)
  670.       trick(s, pal);
  671.     else
  672.       trickfast(s, pal);
  673.  
  674.         /* Get the key hit and process it */
  675.     wrblk(i, j, k, 0);          /* Unblink last selected block */
  676.     switch (f = keyin())        /* Get key, see what it is */
  677.     {
  678.     case RIGHT:  if (k < 3)  k++;  else  { i ^= 1;  k = 0; }  break;
  679.     case LEFT:   if (k > 0)  k--;  else  { i ^= 1;  k = 3; }  break;
  680.     case DOWN:   if (j < 3)  j++;  else  { i ^= 2;  j = 0; }  break;
  681.     case UP:     if (j > 0)  j--;  else  { i ^= 2;  j = 3; }  break;
  682.     case HOME:   i &= 2;  k = 0;  break;
  683.     case END:    i |= 1;  k = 3;  break;
  684.     case PGUP:   i &= 1;  j = 0;  break;
  685.     case PGDN:   i |= 2;  j = 3;  break;
  686.     case SPACE:                         /* Toggle color axes */
  687.       if ((b - a + 3) % 3 == 2)         /* Step through all */
  688.       { f = a;  a = b;  b = f;          /*  permutations of 3 things */
  689.         f = i;  i = j;  j = f; }        /* Keep same selected color. */
  690.       else
  691.       { f = b;  b = c;  c = f;
  692.         f = j;  j = k;  k = f; }
  693.       colors(pal, a, b, c);             /* Change color palettes */
  694.     }
  695.  
  696.         /* If Esc, 'q', or 'Q' hit, then exit */
  697.   } while ((f & 0x7f) != 27 && (f & 0x5f) != 'Q');
  698.  
  699.   /* Done---restore default palette and exit */
  700.   palette(egapal);
  701.   cpos(24, 0);                  /* Put prompt on next line */
  702. }
  703.