Listing 1

/*  Copyright 1990 by Gary R. Olhoeft
 *  This code may be freely copied for personal,
 *  non-commercial use. compile using MicroWay's
 *  NDP C-386 compiler:
 *    cc graphics.c -w -v -rt2 -n2 -n3 -lGREX.LIB
 */
#include <stdio.h>
#include <dos.h>
#include <grex.h>
void plot_pixel();
void graphics();
void spectrum();
void ext_palette();

union REGS reg;    /*  required by inline assembly */
int v_mode, v_color, v_rowy, v_colx, page;
unsigned short ati_extreg;
char ega_palette[17] = (0,1,9,11,3,19,2,18,6,54,38,
                    52,4,36,41,13,0};
int modes[] = {0x0d,0x0e,0x10,0x12,0x13,0x54,
             0x62,0x63,0x65};
void main()
{
  int i,x,y,key;
  unsigned char color;
  for (i=0; i<9; i++)
    {
      graphics(modes[i]); /*  cycle through ATI VGA
                        Wonder graphics modes */
      printf("Mode %d %dx%dx%d\n",v_mode,v_colx+1,
              v_rowy+1,v_color+1);
      /* printing shrinks as pixel count increases */
      spectrum();
      /* draw banded color lines on screen */
      for (x = 0; x<=v_colx>>2; x++)
        {
          for (y = 0; y<=v_rowy; y++)
            {
              color = y % v_color;
              plot_pixel(x+y,y,color);
            }
        }
      /*  pause loop until keypress;
         exit with ^C or Esc */
      if ((key=pauseb())==27) {
         set_video_mode(0x02); exit();
         }
      }
  set_video_mode(0x02); /* restore text mode */
  exit();
}
void graphics(mode)
unsigned char mode;
{
  unsigned char buffer[2];
  switch (mode) /*  note: not all possible modes shown */
    {
      case 0x0d: /*  EGA */
         v_colx = 320;
         v_rowy = 200;
         v_color = 16;
         break;
      case 0x0e: /*  EGA */
         v_colx = 640;
         v_rowy = 200;
         v_color= 16;
         break;
      case 0x10: /*  EGA high resolution */
         v_colx = 640;
         v_rowy = 350;
         v_color = 16;
         break;
      case 0x12: /*  VGA */
         v_colx = 640;
         v_rowy = 480;
         v_color = 16;
         break;
      case 0x13: /*  MCGA */
         v_colx = 320;
         v_rowy = 200;
         v_color = 256;
         break;
      case 0x54: /*  ATI SVGA */
         v_colx = 800;
         v_rowy = 600;
         v_color = 16;
         break;
      case 0x62: /*  ATI SVGA */
         v_colx = 640;
         v_rowy = 480;
         v_color = 256;
         break;
      case 0x63: /*  ATI SVGA */
         v_colx = 800;
         v_rowy = 600;
         v_color = 256;
         break;
      case 0x65: /*  ATI SVGA */
         v_colx = 1024;
         v_rowy = 768;
         v_color = 16;
         break;
      default:
         mode = 0x02; /*  text mode */
         v_colx = 80;
         v_rowy = 25;
         v_color = 1;
         break;
    }
    v_mode = mode;
    v_colx--; /*  set ranges 0 to pixels-1 */
    v_rowy--;
    v_color--;
    
    reg.b.ah = 0;
    reg.b.al = mode;
    int386(0x10,&reg,&reg); /* call BIOS video
                     interrupt to set mode */
    
    blk_mb(buffer, 0x34, 786448, 2);
    ati_extreg = buffer[0]+256*buffer[1];
        /*  find ATI extended_reg address
               (could use peek() instead)*/
    page = 99; /*  force paging first plot cycle */
}

/*  plot pixel of color at (x,y) display units */
void plot_pixel(x,y, color)
int x,y;
unsigned char color;
{
#define peek(addr, val) asm("     push    es"); \
       asm("     mov   ax, 034h"); asm("     mov  \
       es, ax"); ebx = addr;  asm(ebx, "    mov   \
       cl, byte ptr  es:[ebx]", cl); val = cl; asm\
       ("     pop    es")
#define poke(addr, val)  asm("      push   es"); \
       cl = val; asm("      mov    ax, 034h"); \
       asm("     mov    es, ax");  ebx = addr;  \
       asm(ebx, cl,  "     mov   byte ptr es:[ebx], \
       cl"); asm("      pop   es")
/*  required by inline assembly */
reg$eax unsigned short ax;
reg$eax unsigned char al;
reg$ah unsigned char ah;
reg$ecx unsigned short cx;
reg$ch unsigned char ch;
reg$ecx unsigned char cl;
reg$edx unsigned short dx;
reg$edx unsigned char dl, val;
reg$ebx unsigned ebx, addr;
int i,vcol,yvx;
if ((y < 0) || (y > v_rowy) || (x < 0) ||
   (x > v_colx)) return;
     /* clip physical display boundaries */
y = v_rowy-y; /* put (0,0) at lower left corner of plotter */
vcol = v_colx+1;
yvx = y*vcol + x;
switch (v_mode)
  {
    case 0x65: /* ATI 1024x768x16 */
      ch = (char)(y >> 6);
      if (ch!=page) /* only change page if different */
        {
          dx = ati_extreg; /* location of ATI card external register */
          asm("     cli     ");         /*  disable interrupts */
          asm("     mov     al,0b2h");  /*  page select */
       asm(dx,"      out     dx,al");    /*  ATI extended register */
          asm("     inc     dl");
          asm("     in      al,dx");
          asm("     mov     ah,al");
          asm("     and     ah,0e1h");  /*  page mask */
       asm(ch,"      or      ah, ch");   /*  ch = memory page desired */
          asm("     mov     al,0b2h");  /*  page select */
          asm("     dec     dl");
          asm("     out     dx,ax");
          asm("     sti     ");         /*  enable interrupts */
          page = ch;
        }
      addr = 655360 + ((y << 9) % 65536) + (x >> 1);
      peek(addr, val); /* read existing color of pixel pair */
      if (x % 2) val = color | (val & 0xF0); /* change addressed pixel */
      else val = (color << 4) | (val & 0x0F);
      poke(addr, val); /* write pixel pair */
      break;
    case 0x13: /*  MCGA 320x200x256 */
      addr = 655360 + yvx;
      poke(addr, color); /* write direct to real video memory */
      break;
    case 0x62: /* ATI 640x480x256 */
    case 0x63: /* ATI 800x600x256 */
      ch = (unsigned char)(yvx >> 15);
      if (ch!=page)
        {
          dx = ati_extreg; /* location of ATI card external register */
          asm("     cli     ");         /*  disable interrupts */
          asm("     mov     al,0b2h");  /*  page select */
       asm(dx,"      out     dx,al");    /*  ATI extended register */
          asm("     inc     dl");
          asm("     in      al,dx");
          asm("     mov     ah,al");
          asm("     and     ah,0e1h");  /*  page mask */
       asm(ch,"      or      ah,ch");    /*  ch = memory page desired */
          asm("     mov     al,0b2h");  /*  page select */
          asm("     dec     dl");
          asm("     out     dx,ax");
          asm("     sti     ");         /*  enable interrupts */
          page = ch;
        }
      addr = 655360 + (yvx % 65536);
      poke(addr, color); /* write direct to real video memory */
      break;
    default:
    /  * 0x10 EGA 640x350x16, 0x12 VGA 640x480x16, 0x54 ATI 800x600x16 */
        asm("     push   es");        /*  save segment register */
        asm("     mov    ax, 034h");  /*  use Phar Lap LDT to */
        asm("     mov    es, ax");    /*  access real memory */
        dx = 0x3ce;                   /*  EGA graphics register */
        ebx= 655360 + (yvx >> 3);     /*  memory position of pixel */
    asm(ebx,"      mov    cl, byte ptr es:[ebx]"); */  load EGA registers */
        ax = color << 8;
    asm(dx, ax, "      out    dx, ax"); /*  set color */
           ax = 0x0F01;
    asm(dx, ax,"       out    dx, ax"); /*  enable */
           ax = 0x0003; /* 0x00 = replace, 0x10 OR, 0x18 XOR, 0x08 AND */
    asm(dx, ax,"       out    dx, ax"); /*  pixel write mode */
           ax = ((0x80 >> (x%8)) << 8 ) + 8;
    asm(dx, ax,"       out    dx, ax"); /*  bit mask (8 pixels/byte) */
       asm(ebx,"     mov    byte ptr es:[ebx], 255"); /* write EGA regs */
           asm("         pop    es");     /*  restore segment register */
       }
}

void spectrum() /*  create color spectrum palette */
{
    int i;
    if (v_mode == 0x65) /* 1024x768x16 mode only */
      {
        ext_palette( 0,  0,  0,  0); /* black */
        ext_palette( 1, 63,  0,  0); /* red */
        ext_palette( 2, 63, 21,  0);
        ext_palette( 3, 63, 42,  0);
        ext_palette( 4, 63, 63,  0); /* yellow */
        ext_palette( 5, 42, 63,  0);
        ext_palette( 6, 21, 63,  0);
        ext_palette( 7,  0, 63,  0); /* green */
        ext_palette( 8,  0, 63, 21);
        ext_palette( 9,  0, 63, 42);
        ext_palette(10,  0, 63, 63); /* cyan */
        ext_palette(11,  0, 42, 63);
        ext_palette(12,  0, 21, 63);
        ext_palette(13,  0,  0,  63); /* blue */
        ext_palette(14, 21,  0,  63);
        ext_palette(15, 42,  0,  63); /* magenta */
      }
    else
      {
        if (v_color == 255) /* all 256 color modes */
          {
            vga_palette(0,0,0,0);
            for (i=1; i<=64; i++) { vga_palette(i,63,i-1,0); }
            for (i=65; i<=128; i++) { vga_palette(i,128-i,63,0); }
            for (i=129; i<=192; i++) { vga_palette(i,0,63,i-129); }
            for (i=193; i<=255; i++) { vga_palette(i,0,255-i,63); }
          }
        else
          { /*  16 color EGA modes except 1024x768 */
            set_palette(ega_palette);
          }
      }
}
void ext_palette(i,r,g,b) /* write to external palette registers */
unsigned char i,r,g,b;
{
#define outp(p,v) dx = p; al = v; asm(dx,al,"     out     dx,al")
    reg$eax unsigned char al,v;
    reg$edx unsigned short dx,p;
    outp(0x3C8, i);
    outp(0x3C9, r);
    outp(0x3C9, g);
    outp(0x3C9, b);
    outp(0x3C8, i<<4);
    outp(0x3C9, r);
    outp(0x3C9, g);
    outp(0x3C9, b);
}