/* graph16.h - Routinen zur EGA bzw. VGA Graphicprogrammierung */

#include <stdlib.h>                             /* min,max */
#include <dos.h>                                /* int86,REGS */
#include <conio.h>                              /* outpw */

#define TEXT80x25       0x03
#define GRAPH640x350    0x10
#define GRAPH640x480    0x12
#define GRAPH800x600    0x29
#define GRAPH1024x768   0x37

void setvideo(int mode) {
  union REGS regs;
  regs.x.ax=mode;                               /* Setmode: AH=0 */
  int86(0x10,&regs,&regs);                      /* Video-Bios */
  switch (mode) {
    case GRAPH640x350:
      xpoints=640;
      ypoints=350;
      break;
    case GRAPH640x480:
      xpoints=640;
      ypoints=480;
      break;
    case GRAPH800x600:
      xpoints=800;
      ypoints=600;
      break;
    case GRAPH1024x768:
      xpoints=1024;
      ypoints=768;
      break; } }

/* Funktion:            Planes  Wr.Mask BitMask Rotate  Daten   */
/* Set Pixel            0f      2       1Bit    ----    Color   */
/* set Line             4 mal 1 0       alle B. keine   Bits    */
/* inv Pixel            0f      0       alle B. XOR     Bitmask */

void setpixel(int x,int y,char c) {
  char far *vptr,dummy;
  long address=(long)y*xpoints+x;               /* Zeilenadresse im EGA-RAM */
  outpw(0x3c4,0x0f02);                          /* alle Planes */
  outpw(0x3ce,0x0205);                          /* Write-Modus 2 */
  outpw(0x3ce,(0x8000 >> (address & 7))+0x08);  /* Bit-Mask */
  vptr=(char far *)(0xa0000000+(address>>3));
  dummy=*vptr;                                  /* im EGA-Latch einlesen */
  *vptr=c; }                                    /* Bits schreiben */

void setline(int y,char *buffer) {
  char *bufptr,pixels,far *vptr;
  int plane,byte,bit;
  outpw(0x3ce,0x0003);                          /* EGA-Latch normal Modus */
  outpw(0x3ce,0x0005);                          /* Write-Modus 0 */
  outpw(0x3ce,0xff08);                          /* Bit-Mask normal */
  for (plane=0; plane<4; plane++) {             /* fr jede Plane */
    outpw(0x3c4,(0x100<<plane)+0x02);           /*  ausw„hlen (1,2,4,8) */
    bufptr=buffer;
    vptr=(char far *)(0xa0000000+(long)y*xpoints/8); /* Zeilenadr im EGA-RAM */
    for (byte=0; byte<xpoints/8; byte++) {      /* fr jedes Byte */
      for (bit=0; bit<8; bit++)                 /*  bilden */
	pixels=(pixels<<1) | (((*bufptr++) >> plane)  & 1);
      *vptr++=pixels; } } }                     /*  setzen */

void invpixel(int x,int y) {
  char far *vptr,dummy;
  long address=(long)y*xpoints+x;               /* Zeilenadresse im EGA-RAM */
  outpw(0x3c4,0x0f02);                          /* alle Planes */
  outpw(0x3ce,0x1803);                          /* EGA-Latch xor Modus */
  outpw(0x3ce,0x0005);                          /* Write-Modus 0 */
  outpw(0x3ce,0xff08);                          /* Bit-Mask */
  vptr=(char far *)(0xa0000000+(address>>3));
  dummy=*vptr;                                  /* im EGA-Latch einlesen */
  *vptr=(128 >> (address & 7)); }               /* Bits schreiben */

void invcursor(int x,int y) {
  int i;
  for (i=1; i<=4; i++) {                        /* Kreuzarme 4 lang */
    invpixel(max(x-i,0),y);                     /* oben */
    invpixel(x,min(y+i,(ypoints-1)));           /* rechts */
    invpixel(min(x+i,(xpoints-1)),y);           /* unten */
    invpixel(x,max(y-i,0)); } }                 /* links */

void invbox(int x1,int y1,int x2,int y2) {
  int i;
  if (x1 == x2) {                               /* senkrechte Linie */
    for (i=y1; i<=y2; i++)
      invpixel(i,x1);
    return; }
  if (y1 == y2) {                               /* waagrechte Linie */
    for (i=x1; i<=x2; i++)
      invpixel(i,y1);
    return; }
  for (i=x1; i<x2; i++)                         /* 4 Linien zeichnen, */
    invpixel(i,y1);                             /* Ecken nur ein mal inv! */
  for (i=y1; i<y2; i++)
    invpixel(x2,i);
  for (i=x2; i>x1; i--)
    invpixel(i,y2);
  for (i=y2; i>y1; i--)
    invpixel(x1,i); }

