# Pixel-Graphik für CLISP
# Bruno Haible 30.6.1997

#include "lispbibl.c"
#include "arilev0.c" # wegen dreisatz


/*

Graphics primitives in CLISP
============================

In CLISP 1994-01-07 or newer,
* DOS version,
* Linux version, installed setuid root,
there are some pixel graphics primitives in the SYSTEM package.
They operate on a VGA card.

Similar pixel graphics primitives can be used in the
* Unix version running under X11
by use of the small XTERM package available on
ma2s2.mathematik.uni-karlsruhe.de.

This is the description of the PC/VGA graphics primitives:

(SYSTEM::GRAPH-INIT [width [height [colors]]])
initializes the graphics system. The width, height parameters are hints for
the size of the desired graphics screen (positive integers). The colors
parameter is a hint for the number of colors. The actual width, height
is implementation dependent, currently up to 640x480 on VGA cards and up to
1024x768 on ET4000 SVGA cards.
Returns an alist ((color-value color-keyword) ...) which lists the available
colours and their numerical equivalents.

(SYSTEM::GRAPH-SHOW)
switches the graphics hardware so that the graphics screen is visible. The
text screen is activated on any text output.

(SYSTEM::GRAPH-CLEAR [color])
fills the entire graphics screen with a single color.

(SYSTEM::GRAPH-DIMS)
returns two values: the actual width and the actual height of the graphics
screen (in pixels).

If (SYSTEM::GRAPH-DIMS) returns the values w and h, then valid screen
coordinates are pairs (x,y) with 0 <= x < w and 0 <= y < h. x=0 denotes the
left edge, y=0 the top edge.

(SYSTEM::GRAPH-DOT x y)
returns the colour of the pixel (x,y).
(SYSTEM::GRAPH-DOT x y color)
sets the colour of the pixel (x,y) to color.

(SYSTEM::GRAPH-BOX x1 y1 x2 y2 color)
draws a box (= filled rectangle) in colour color, the vertices being the pixels
        (x1,y1)   (x2,y1)
        (x1,y2)   (x2,y2)

(SYSTEM::GRAPH-LINE x1 y1 x2 y2 color)
Draws a line in colour color from pixel (x1,y1) to pixel (x2,y2).

(SYSTEM::GRAPH-TEXT x y dir string color)
Paints the text contained in string, starting at (x,y), in colour color,
and returns as values the end coordinates (x,y). dir is the direction:
0 goes to the right, 90 vertically up, 180 to the left, 270 vertically down.

This specification is subject to change.

*/


#ifdef GRAPHICS


# Low-Level-Funktionen der Pixel-Grafik:
# gr_init(width,height,colors);  erzeugt einen Grafik-Bildschirm mit
#                                (andeutungsweise) gegebener Größe.
# gr_show();                     zeigt den Grafik-Bildschirm an.
# gr_colors()                    liefert einen Array von benannten Farben.
# gr_clear(color);               löscht den gesamten Grafik-Bildschirm.
# gr_xdim                        Breite des Grafik-Bildschirms in Pixeln.
# gr_ydim                        Höhe des Grafik-Bildschirms in Pixeln.
# gr_get(x,y)                    liefert die Farbe des Punktes (x,y)
# gr_dot(color,x,y);             zeichnet einen Punkt (x,y)
# gr_box(color,x1,y1,x2,y2);     zeichnet ein Rechteck [x1,x2] x [y1,y2]
# gr_line(color,x1,y1,x2,y2);    zeichnet eine Linie von (x1,y1) bis (x2,y2)
# gr_text(color,&x,&y,dir,charptr,count);  zeichnet einen String ab (x,y)

struct named_color
{
    int color;
    char* name;
};


# Hilfsfunktionen fürs Clipping:

# dot_clipping(&clip,&args)   modifiziert die Argumente passend für gr_dot
# box_clipping(&clip,&args)   modifiziert die Argumente passend für gr_box
# line_clipping(&clip,&args)  modifiziert die Argumente passend für gr_line
# Rückgabewert ist jeweils 0, wenn überhaupt nichts zu zeichnen ist, sonst 1.

struct clip
{
    sintL x1, x2;  # Bereich x1 <= x <= x2 (x1,x2 >= 0)
    sintL y1, y2;  # Bereich y1 <= y <= y2 (y1,y2 >= 0)
    # Bei x1 > x2 oder y1 > y2 ist der Bereich leer.
};

struct dot_args
{
    sintL x, y;    # Pixel (x,y)
};

struct box_args
{
    sintL xa, ya, xb, yb; # alle Pixel im Rechteck mit Ecken (xa,ya) und (xb,yb)
};

struct line_args
{
    sintL xa, ya, xb, yb; # Linie von (xa,ya) bis (xb,yb)
};

local int dot_clipping (const struct clip * clip, const struct dot_args * args);
local int dot_clipping(clip,args)
    var const struct clip * clip;
    var const struct dot_args * args;
{
    return    (clip->x1 <= args->x) && (args->x <= clip->x2)
           && (clip->y1 <= args->y) && (args->y <= clip->y2);
}

local int box_clipping (const struct clip * clip, struct box_args * args);
local int box_clipping(clip,args)
    var const struct clip * clip;
    var struct box_args * args;
{
    sintL xa, ya, xb, yb;
    # Clipping in x-Richtung:
    if (args->xa <= args->xb)
      { xa = args->xa; xb = args->xb; }
      else
      { xa = args->xb; xb = args->xa; }
    if (xa < clip->x1)
      xa = clip->x1;
    if (xb > clip->x2)
      xb = clip->x2;
    if (xa > xb)
      return 0;
    args->xa = xa; args->xb = xb;
    # Clipping in y-Richtung:
    if (args->ya <= args->yb)
      { ya = args->ya; yb = args->yb; }
      else
      { ya = args->yb; yb = args->ya; }
    if (ya < clip->y1)
      ya = clip->y1;
    if (yb > clip->y2)
      yb = clip->y2;
    if (ya > yb)
      return 0;
    args->ya = ya; args->yb = yb;
    # Fertig.
    return 1;
}

# Liefert zu a,b>=0, c>0 (alle <2^31):  round(a * b / c) = floor(2*a*b+c,2*c)
local sintL dreisatz (uintL a, uintL b, uintL c);
local sintL dreisatz(a,b,c)
    var uintL a;
    var uintL b;
    var uintL c;
{
    uintL hi, lo;
    mulu32(a,2*b, hi=,lo=); # 2^32*hi + lo = 2*a*b
    if ((lo += c) < c) { hi += 1; } # 2^32*hi + lo = 2*a*b + c
    if (hi < c) # avoid overflow
      { uintL q;
        divu_6432_3232(hi,lo,2*c, q=,);
        if ((sintL)q >= 0)
          return q;
      }
    return (1UL<<31)-1;
}

local int line_clipping (const struct clip * clip, struct line_args * args);
local int line_clipping(clip,args)
    var const struct clip * clip;
    var struct line_args * args;
{
    sintL xa, ya, xb, yb;
    sintL x1 = clip->x1;
    sintL x2 = clip->x2;
    sintL y1 = clip->y1;
    sintL y2 = clip->y2;
    # Check whether x1 <= x2 and y1 <= y2.
    if ((x1 > x2) || (y1 > y2))
      return 0;
    # Ensure xa <= xb.
    if (args->xa <= args->xb)
      { xa = args->xa; ya = args->ya; xb = args->xb; yb = args->yb; }
      else
      { xa = args->xb; ya = args->yb; xb = args->xa; yb = args->ya; }
    # Line entirely outside the window, in the same sector?
    if (   (xa > x2) # implies xb > x2 too
        || (xb < x1) # implies xa < x1 too
        || (ya < y1 && yb < y1)
        || (ya > y2 && yb > y2)
       )
      return 0;
    # Line entirely inside the window?
    if (xa >= x1 && xb <= x2 && ya >= y1 && ya <= y2 && yb >= y1 && yb <= y2)
      goto ok;
    # Special case horizontal line
    if (ya == yb)
      { if (xa < x1) xa = x1;
        if (xb > x2) xb = x2;
        goto ok;
      }
    # Special case vertical line
    if (xa == xb)
      { if (ya < y1) ya = y1;
        elif (ya > y2) ya = y2;
        if (yb < y1) yb = y1;
        elif (yb > y2) yb = y2;
        goto ok;
      }
    # Move left starting point into the clip rectangle.
    if (xa < x1 || ya < y1 || ya > y2)
      { # try to intersect line with left border
        sintL y;
        if (ya < yb)
          { if ((xa < x1)
                && ((y = ya + dreisatz(x1-xa, yb-ya, xb-xa)) >= y1)
               )
              { if (y > y2)
                  return 0;
                xa = x1; ya = y;
              }
            elif (ya < y1)
              { xa = xa + dreisatz(y1-ya, xb-xa, yb-ya); ya = y1; }
          }
          else # ya > yb
          { if ((xa < x1)
                && ((y = ya - dreisatz(x1-xa, ya-yb, xb-xa)) <= y2)
               )
              { if (y < y1)
                  return 0;
                xa = x1; ya = y;
              }
            elif (ya > y2)
              { xa = xa + dreisatz(ya-y2, xb-xa, ya-yb); ya = y2; }
          }
      }
    # Move right starting point into the clip rectangle.
    if (xb > x2 || yb < y1 || yb > y2)
      { # try to intersect line with right border
        sintL y;
        if (ya < yb)
          { if ((xb > x2)
                && ((y = yb - dreisatz(xb-x2, yb-ya, xb-xa)) <= y2)
               )
              { if (y < y1)
                  return 0;
                xb = x2; yb = y;
              }
            elif (yb > y2)
              { xb = xb - dreisatz(yb-y2, xb-xa, yb-ya); yb = y2; }
          }
          else # ya > yb
          { if ((xb > x2)
                && ((y = yb + dreisatz(xb-x2, ya-yb, xb-xa)) >= y1)
               )
              { if (y > y2)
                  return 0;
                xb = x2; yb = y;
              }
            elif (yb < y1)
              { xb = xb - dreisatz(y1-yb, xb-xa, ya-yb); yb = y1; }
          }
      }
    ok:
    args->xa = xa; args->ya = ya; args->xb = xb; args->yb = yb;
    return 1;
}


#ifdef GRAPHICS_SWITCH

# Ein Text-Bildschirm und ein Grafik-Bildschirm können sichtbar sein, jedoch
# nicht gleichzeitig.
# switch_text_mode(); wechselt auf den Text-Bildschirm.
# switch_graphics_mode(); wechselt auf den Grafik-Bildschirm.
extern void switch_text_mode (void);
extern void switch_graphics_mode (void);


#ifdef EMUNIX_PORTABEL


#include <graph.h>
extern unsigned char *_g_mem;

#ifdef EMUNIX_NEW_9a
/* see emx/src/lib/graph1.c, emx/src/lib/graph2.h, emx/src/lib/ega.h */
#include <stdlib.h>
#include <graph.h>
#include <dos.h>
#include <memory.h>
#include <sys/hw.h>
#define INCL_DOSMEMMGR
#define INCL_DOSPROCESS
#define INCL_VIO
#include <os2emx.h>
#include <os2thunk.h>
extern int _g_locklevel;
#define GLOCK  \
  if (_osmode == OS2_MODE && _g_locklevel == 0) \
    { unsigned char not_locked; VioScrLock (LOCKIO_WAIT, &not_locked, 0); }
#define GUNLOCK  \
  if (_osmode == OS2_MODE && _g_locklevel == 0) \
    { VioScrUnLock (0); }
#endif

# The following modes are provided by the graph.a library:
# G_MODE_OFF (text)
# G_MODE_VGA_L (320x200x256)
#ifdef EMUNIX_NEW_9a
# G_MODE_EGA_C (640x200x16)
# G_MODE_EGA_E (640x350x16)
# G_MODE_VGA_H (640x480x16)
#endif

#define GRAPH_SIZE_L  (320*200)
#ifdef EMUNIX_NEW_9a
#define GRAPH_SIZE_C  (640*200/2)
#define GRAPH_SIZE_E  (640*350/2)
#define GRAPH_SIZE_H  (640*480/2)
#define GRAPH_SIZE_MAX  GRAPH_SIZE_H
#else
#define GRAPH_SIZE_MAX  GRAPH_SIZE_L
#endif

int cur_mode = G_MODE_OFF;   /* current video mode       */
int flip_mode = G_MODE_OFF;  /* flipped video mode       */
unsigned char * graph_buf;   /* saves graphics data during flip */
static struct clip cur_clip; /* current whole-screen clipping */

static int initialized = 0;

static int initialize (void)
{
    if ((graph_buf = (unsigned char *) malloc(GRAPH_SIZE_MAX)) == NULL)
        { errno = ENOMEM; return -1; }
    initialized = 1;
    return 0;
}

void switch_text_mode (void)
{
    if (cur_mode == G_MODE_OFF)
        return;
    /* cur_mode != G_MODE_OFF, so flip_mode == G_MODE_OFF,
       and initialize() has already been called. */
#ifdef EMUNIX_NEW_9a
    if (cur_mode != GRAPH_SIZE_L)
      { /* save 4 bitplanes separately */
        int plane;
        int plane_size = g_xsize * g_ysize / 8;
        char* bufptr = graph_buf;
        GLOCK;
        _outp16 (0x3ce, 0x0304); /* bit plane 3 */
        memcpy(bufptr,_g_mem,plane_size); bufptr += plane_size;
        _outp8 (0x3cf, 0x02); /* bit plane 2 */
        memcpy(bufptr,_g_mem,plane_size); bufptr += plane_size;
        _outp8 (0x3cf, 0x01); /* bit plane 1 */
        memcpy(bufptr,_g_mem,plane_size); bufptr += plane_size;
        _outp8 (0x3cf, 0x00); /* bit plane 0 */
        memcpy(bufptr,_g_mem,plane_size);
        GUNLOCK;
      }
    else
#endif
      memcpy(graph_buf,_g_mem,GRAPH_SIZE_L);
    flip_mode = cur_mode;
    g_mode(G_MODE_OFF); cur_mode = G_MODE_OFF;
}

void switch_graphics_mode (void)
{
    if (flip_mode == G_MODE_OFF)
        return;
    /* flip_mode != G_MODE_OFF, so cur_mode == G_MODE_OFF,
       and initialize() has already been called. */
    g_mode(flip_mode); cur_mode = flip_mode;
    cur_clip.x1 = 0; cur_clip.x2 = g_xsize-1;
    cur_clip.y1 = 0; cur_clip.y2 = g_ysize-1;
#ifdef EMUNIX_NEW_9a
    if (cur_mode != GRAPH_SIZE_L)
      { /* restore 4 bitplanes separately */
        int plane;
        int plane_size = g_xsize * g_ysize / 8;
        char* bufptr = graph_buf;
        GLOCK;
        _outp16 (0x3c4, 0x0802); /* bit plane 3 */
        memcpy(_g_mem,bufptr,plane_size); bufptr += plane_size;
        _outp8 (0x3c5, 0x04); /* bit plane 2 */
        memcpy(_g_mem,bufptr,plane_size); bufptr += plane_size;
        _outp8 (0x3c5, 0x02); /* bit plane 1 */
        memcpy(_g_mem,bufptr,plane_size); bufptr += plane_size;
        _outp8 (0x3c5, 0x01); /* bit plane 0 */
        memcpy(_g_mem,bufptr,plane_size);
        GUNLOCK;
      }
    else
#endif
      memcpy(_g_mem,graph_buf,GRAPH_SIZE_L);
    flip_mode = G_MODE_OFF;
}

int gr_init (sintL width, sintL height, sintL colors)
{
    int mode;
    if (!initialized)
        if (initialize())
            { OS_error(); }
    #ifdef EMUNIX_NEW_9a
    if (colors <= 16)
      { # choose a 16-color mode if possible
        if (height > 350)
          { mode = G_MODE_VGA_H; }
        elif (height > 200)
          { mode = G_MODE_EGA_E; }
        elif (width > 320)
          { mode = G_MODE_EGA_C; }
        else
          { mode = G_MODE_VGA_L; }
      }
      else
    #endif
      { # choose a 256-color mode
        mode = G_MODE_VGA_L;
      }
    if (!g_mode(mode))
        return -1;
    flip_mode = G_MODE_OFF; cur_mode = mode;
    cur_clip.x1 = 0; cur_clip.x2 = g_xsize-1;
    cur_clip.y1 = 0; cur_clip.y2 = g_ysize-1;
    return 0;
}

void gr_show (void)
{
    if (cur_mode == G_MODE_OFF)
      { switch_graphics_mode();
        if (cur_mode == G_MODE_OFF)
          { fehler(error,
                   DEUTSCH ? "Grafik nicht initialisiert." :
                   ENGLISH ? "graphics not initialized" :
                   FRANCAIS ? "Système graphique non initialisé." :
                   ""
                  );
      }   }
}

static struct named_color EGA_colors []
  = { { G_BLACK,                 "BLACK"         },
      { G_BLUE,                  "BLUE"          },
      { G_GREEN,                 "GREEN"         },
      { G_CYAN,                  "CYAN"          },
      { G_RED,                   "RED"           },
      { G_MAGENTA,               "MAGENTA"       },
      { G_BROWN,                 "BROWN"         },
      { G_WHITE,                 "LIGHT-GRAY"    },
      { G_INTENSITY | G_BLACK,   "DARK-GRAY"     },
      { G_INTENSITY | G_BLUE,    "LIGHT-BLUE"    },
      { G_INTENSITY | G_GREEN,   "LIGHT-GREEN"   },
      { G_INTENSITY | G_CYAN,    "LIGHT-CYAN"    },
      { G_INTENSITY | G_RED,     "LIGHT-RED"     },
      { G_INTENSITY | G_MAGENTA, "LIGHT-MAGENTA" },
      { G_INTENSITY | G_YELLOW,  "YELLOW"        },
      { G_INTENSITY | G_WHITE,   "WHITE"         },
      { 0,                       NULL            }
    };

struct named_color * gr_colors (void)
{
    return &!EGA_colors;
}

#define gr_xdim  g_xsize
#define gr_ydim  g_ysize

int gr_get (sintL x, sintL y)
{
    int color;
    gr_show();
    color = g_get(x,y);
    if (color < 0)
        color = G_BLACK;
    return color;
}

void gr_dot (sintL color, sintL x, sintL y)
{
    gr_show();
    if (color >= 0 && color < g_colors)
        g_set(x,y,color);
}

void gr_box (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    gr_show();
    if (color >= 0 && color < g_colors)
        g_box(x1,y1,x2,y2,color,G_FILL);
}

void gr_clear (sintL color)
{
    gr_show();
    if (color >= 0 && color < g_colors)
        g_clear(color);
}

void gr_line (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    # Clipping selber durchführen; dem EMX-Clipping trauen wir nicht.
    struct clip clip;
    struct line_args args;
    gr_show();
    args.xa = x1; args.ya = y1; args.xb = x2; args.yb = y2;
    if (color >= 0 && color < g_colors)
      if (line_clipping(&cur_clip,&args))
        g_line(args.xa,args.ya,args.xb,args.yb,color);
}


#else # (EMUNIX && !EMUNIX_PORTABEL) || UNIX_LINUX


#ifdef UNIX

# Um Zugriff auf I/O-Ports und den Bildschirmspeicher zu haben, muß das
# Programm mit "setuid root"-Privileg installiert werden.

global uid_t root_uid; # wird von SPVW initialisiert

#define BEGIN_ROOT_PRIV  \
  set_break_sem_1(); \
  setreuid(user_uid,root_uid);

#define END_ROOT_PRIV  \
  setreuid(root_uid,user_uid); \
  clr_break_sem_1();

#endif

#ifdef EMUNIX

# INT 10 documentation:
#   INT 10,01 - Set cursor type
#   INT 10,03 - Read Cursor Position and Size
#   INT 10,0F - Get current video state
#   INT 10,12 - Video subsystem configuration (EGA/VGA)
#   INT 10,1A - Video Display Combination (VGA)
#
# INT 10,01 - Set Cursor Type
#     AH = 01
#     CH = cursor starting scan line (cursor top) (low order 5 bits)
#     CL = cursor ending scan line (cursor bottom) (low order 5 bits)
#     returns nothing
#     - cursor scan lines are zero based
#     - the following is a list of the cursor scan lines associated with
#       most common adapters;  screen sizes over 40 lines may differ
#       depending on adapters.
#               Line     Starting     Ending      Character
#       Video   Count    Scan Line    Scan Line   Point Size
#       CGA      25         06           07           08
#       MDA      25         0B           0C           0E
#       EGA      25         06           07           0E
#       EGA      43       04/06          07           08
#       VGA      25         0D           0E           10
#       VGA      40         08           09           0A
#       VGA      50         06           07           08
#     - use CX = 2000h to disable cursor
#
# INT 10,03 - Read Cursor Position and Size
#     AH = 03
#     BH = video page
#     on return:
#     CH = cursor starting scan line (low order 5 bits)
#     CL = cursor ending scan line (low order 5 bits)
#     DH = row
#     DL = column
#
# INT 10,0F - Get Video State
#     AH = 0F
#     on return:
#     AH = number of screen columns
#     AL = mode currently set (see ~VIDEO MODES~)
#     BH = current display page
#     - video modes greater than 13h on EGA, MCGA and VGA indicate
#       ~INT 10,0~ was called with the high bit of the mode (AL) set
#       to 1, meaning the display does not need cleared
#     - function returns byte value at 40:49;  On EGA, MCGA and
#       VGA bit 7 of register AL is determined by bit 7 of BIOS Data
#       Area byte 40:87.   This bit is usually set by INT 10,0
#       with bit 7 of the requested mode (in AL) set to 1
#
# INT 10,12 - Video Subsystem Configuration (EGA/VGA)
#     AH = 12h
#     BL = 10  return video configuration information
#     on return:
#     BH = 0 if color mode in effect
#        = 1 if mono mode in effect
#     BL = 0 if 64k EGA memory
#        = 1 if 128k EGA memory
#        = 2 if 192k EGA memory
#        = 3 if 256k EGA memory
#     CH = feature bits
#     CL = switch settings
#
# INT 10,1A - Video Display Combination (VGA)
#     AH = 1A
#     AL = 00 get video display combination
#        = 01 set video display combination
#          BL = active display  (see table below)
#          BH = inactive display
#     on return:
#     AL = 1A, if a valid function was requested in AH
#     BL = active display  (AL=00, see table below)
#     BH = inactive display  (AL=00)
#     Valid display codes:
#       FF  Unrecognized video system
#       00  No display
#       01  MDA with monochrome display
#       02  CGA with color display
#       03  Reserved
#       04  EGA with color display
#       05  EGA with monochrome display
#       06  Professional graphics controller
#       07  VGA with analog monochrome display
#       08  VGA with analog color display
#       09  Reserved
#       0A  MCGA with digital color display
#       0B  MCGA with analog monochrome display
#       0C  MCGA with analog color display
#     - returns value at byte 40:8A indicating display combination status
#     - used to detect video display capabilities

# Perform an INT 10
  static void intvideo (union REGS * in_regs, union REGS * out_regs);
  static void intvideo(in_regs,out_regs)
    var register union REGS * in_regs;
    var register union REGS * out_regs;
    { __asm__ __volatile__ ( "movl 0(%%esi),%%eax ; "
                             "movl 4(%%esi),%%ebx ; "
                             "movl 8(%%esi),%%ecx ; "
                             "movl 12(%%esi),%%edx ; "
                             "pushl %%edi ; "
                             ".byte 0xcd ; .byte 0x10 ; "
                             "popl %%edi ; "
                             "movl %%eax,0(%%edi) ; "
                             "movl %%ebx,4(%%edi) ; "
                             "movl %%ecx,8(%%edi) ; "
                             "movl %%edx,12(%%edi)"
                             :                                                         # OUT
                             : "S" /* %esi */ (in_regs), "D" /* %edi */ (out_regs)     # IN
                             : "ax","bx","cx","si","di" /* %eax,%ebx,%ecx,%esi,%edi */ # CLOBBER
                           );
    }

# Some variables used for saving the text data during flip
static unsigned long text_phys_mem; /* physical address of text video RAM */
static unsigned long text_size;     /* size of text data */
static unsigned short * text_mem;   /* address of text video RAM */
static unsigned short * text_buf;   /* buffer for text data */
static unsigned short text_cursor_shape; /* text cursor shape */
static int text_saved = 0; /* flag: does text_buf contain the text data? */

# Enquire text mode settings
static void get_text_info (void);
static void get_text_info()
  { var unsigned char video_mode;
    var unsigned int video_cols;
    var unsigned int video_rows;
    var int vga_present;
    var union REGS in;
    var union REGS out;
    in.regB.ah = 0x0F; intvideo(&in,&out); # INT 10,0F : get current video state
    video_mode = out.regB.al & 0x7f; video_cols = out.regB.ah; video_rows = 25;
    { var int scrsize[2];
      _scrsize(&!scrsize);
      if (scrsize[0] > 0) { video_cols = scrsize[0]; }
      if (scrsize[1] > 0) { video_rows = scrsize[1]; }
    }
    # check for VGA
    vga_present = 0;
    #if 0 # EMX doesn't allow this BIOS call
    in.regB.ah = 0x12; in.regB.bl = 0x10; intvideo(&in,&out); # INT 10,12: check for EGA/VGA
    if (!(out.regB.bl == 0x10))
    #endif
      { in.regB.ah = 0x1A; in.regB.al = 0x00; intvideo(&in,&out); # INT 10,1A: check for VGA
        if (!(out.regB.al == 0x1A))
          { vga_present = 1; } # check for SVGA??
      }
    text_size = video_rows * video_cols;
    if (video_mode == 7) # monochrome?
      { text_phys_mem = 0xB0000;
        # if (vga_present)
        #   { 0xB0000..0xB7FFF } # EGA/VGA in Mono mode
        #   else
        #   { 0xB0000..0xB1FFF } # MDA
      }
      else # color
      { text_phys_mem = 0xB8000;
        # if (vga_present)
        #   { 0xB8000..0xBFFFF } # EGA/VGA in Color mode
        #   else
        #   { 0xB8000..0xB9FFF } # CGA
      }
  }

static void memsetw (unsigned short * s, unsigned short c, int count);
static inline void memsetw(s,c,count)
  var unsigned short * s;
  var unsigned short c;
  var int count;
  { __asm__ __volatile__ ("cld ; rep ; stosw"
                          :
                          : "a" /* %ax */ (c), /* %edi */ "D" (s), /* %ecx */ "c" (count)
                          : /* %ecx */ "cx", /* %edi */ "di"
                         );
  }

# Equivalent to Linux ioctl KD_GRAPHICS: save text data.
static void kd_graphics (void);
static void kd_graphics()
  { if (text_saved) return;
    # save text data
    memcpy(text_buf,text_mem,2*text_size);
    # hide cursor
    { var union REGS in;
      var union REGS out;
      in.regB.ah = 0x03; in.regB.bh = 0x00; intvideo(&in,&out); # INT 10,03 : read cursor shape
      text_cursor_shape = out.regW.cx;
      in.regB.ah = 0x01; in.regW.cx = 0x2000; intvideo(&in,&out); # INT 10,01 : set cursor type
    }
    text_saved = 1;
    # clear text screen
    memsetw(text_mem,0x0020,text_size);
  }

# Equivalent to Linux ioctl KD_TEXT: restore text data.
static void kd_text (void);
static void kd_text()
  { if (!text_saved) return;
    # restore text data
    memcpy(text_mem,text_buf,2*text_size);
    # show cursor
    { var union REGS in;
      var union REGS out;
      in.regB.ah = 0x01; in.regW.cx = text_cursor_shape; intvideo(&in,&out); # INT 10,01 : set cursor type
    }
    text_saved = 0;
  }

#endif


# =========================== vgalib/vga.h =================================== #

/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
/*                                                                 */
/* This library is free software; you can redistribute it and/or   */
/* modify it without any restrictions. This library is distributed */
/* in the hope that it will be useful, but without any warranty.   */

#define TEXT         0
#define G320x200x16  1
#define G640x200x16  2
#define G640x350x16  3
#define G640x480x16  4
#define G320x200x256 5
#define G320x240x256 6
#define G320x400x256 7
#define G360x480x256 8
#define G640x480x2   9

#define G640x480x256  10
#define G800x600x256  11
#define G1024x768x256 12

extern int vga_setmode (int mode);
extern int vga_hasmode (int mode);

extern void vga_clear (void);

extern int vga_getxdim (void);
extern int vga_getydim (void);
extern int vga_getcolors (void);

extern void vga_screenoff (void);
extern void vga_screenon (void);

extern void switch_text_mode (void);
extern void switch_graphics_mode (void);

extern void vga_setcolor (int color);
extern void vga_drawpixel (int x, int y);
extern void vga_drawhline (int x1, int x2, int y);
extern void vga_drawbox (int x1, int y1, int x2, int y2);
extern void vga_drawline (int x1, int y1, int x2, int y2);
#if 0
extern void vga_drawscanline (int line, unsigned char* colors);
extern void vga_drawscansegment (unsigned char* colors, int x, int y, int length);
#endif


# =========================== vgalib/vga.c =================================== #

/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
/*                                                                 */
/* This library is free software; you can redistribute it and/or   */
/* modify it without any restrictions. This library is distributed */
/* in the hope that it will be useful, but without any warranty.   */

#ifdef UNIX
  #include <sys/kd.h>
#endif
#ifdef EMUNIX
  #include <sys/hw.h>  /* declares _portaccess(), _memaccess() */
  /* Ensure that the arguments to _memaccess() are page-aligned */
  #define memaccess(first,last,flag)  \
    _memaccess((first) & ~0xfff, (last) | 0xfff, flag)
#endif

#define uchar unsigned char

#define GRAPH_BASE 0xA0000
#define GRAPH_SIZE 0x10000
#define FONT_BASE  0xA0000
#define FONT_SIZE  0x2000
#define NULL_SIZE  0x1000

#define MAX_REGS 100

/* VGA index register ports */
#define CRT_IC  0x3D4   /* CRT Controller Index - color emulation */
#define CRT_IM  0x3B4   /* CRT Controller Index - mono emulation */
#define ATT_IW  0x3C0   /* Attribute Controller Index & Data Write Register */
#define GRA_I   0x3CE   /* Graphics Controller Index */
#define SEQ_I   0x3C4   /* Sequencer Index */
#define PEL_IW  0x3C8   /* PEL Write Index */
#define PEL_IR  0x3C7   /* PEL Read Index */

/* VGA data register ports */
#define CRT_DC  0x3D5   /* CRT Controller Data Register - color emulation */
#define CRT_DM  0x3B5   /* CRT Controller Data Register - mono emulation */
#define ATT_R   0x3C1   /* Attribute Controller Data Read Register */
#define GRA_D   0x3CF   /* Graphics Controller Data Register */
#define SEQ_D   0x3C5   /* Sequencer Data Register */
#define MIS_R   0x3CC   /* Misc Output Read Register */
#define MIS_W   0x3C2   /* Misc Output Write Register */
#define IS1_RC  0x3DA   /* Input Status Register 1 - color emulation */
#define IS1_RM  0x3BA   /* Input Status Register 1 - mono emulation */
#define PEL_D   0x3C9   /* PEL Data Register */

/* VGA indexes max counts */
#define CRT_C   24      /* 24 CRT Controller Registers */
#define ATT_C   21      /* 21 Attribute Controller Registers */
#define GRA_C   9       /* 9  Graphics Controller Registers */
#define SEQ_C   5       /* 5  Sequencer Registers */
#define MIS_C   1       /* 1  Misc Output Register */

/* VGA registers saving indexes */
#define CRT     0               /* CRT Controller Registers start */
#define ATT     CRT+CRT_C       /* Attribute Controller Registers start */
#define GRA     ATT+ATT_C       /* Graphics Controller Registers start */
#define SEQ     GRA+GRA_C       /* Sequencer Registers */
#define MIS     SEQ+SEQ_C       /* General Registers */
#define EXT     MIS+MIS_C       /* SVGA Extended Registers */

#define SEG_SELECT 0x3CD

#define ABS(a) (((a)<0) ? -(a) : (a))

/* variables used to shift between monchrome and color emulation */
static int CRT_I;               /* current CRT index register address */
static int CRT_D;               /* current CRT data register address */
static int IS1_R;               /* current input status register address */
static int color_text;          /* true if color text emulation */


/* graphics mode information */
struct info {
    int xdim;
    int ydim;
    int colors;
    int xbytes;
};


/* BIOS mode 0Dh - 320x200x16 */
static uchar g320x200x16_regs[60] = {
  0x2D,0x27,0x28,0x90,0x2B,0x80,0xBF,0x1F,0x00,0xC0,0x00,0x00,
  0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x14,0x00,0x96,0xB9,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x0F,0x00,0x20,0x00,0x00,0x05,0x0F,0xFF,
  0x03,0x09,0x0F,0x00,0x06,
  0x63
};
static struct info g320x200x16_info = { 320, 200, 16, 40 };


/* BIOS mode 0Eh - 640x200x16 */
static uchar g640x200x16_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0xC0,0x00,0x00,
  0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x0F,0x00,0x20,0x00,0x00,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0x63
};
static struct info g640x200x16_info = { 640, 200, 16, 80 };


/* BIOS mode 10h - 640x350x16 */
static uchar g640x350x16_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0x83,0x85,0x5D,0x28,0x0F,0x63,0xBA,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x0F,0x00,0x20,0x00,0x00,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0xA3
};
static struct info g640x350x16_info = { 640, 350, 16, 80 };


/* BIOS mode 12h - 640x480x16 */
static uchar g640x480x16_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0xEA,0x8C,0xDF,0x28,0x00,0xE7,0x04,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x0F,0x00,0x20,0x00,0x00,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0xE3
};
static struct info g640x480x16_info = { 640, 480, 16, 80 };


/* BIOS mode 13h - 320x200x256 */
static uchar g320x200x256_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x41,0x00,0x00,
  0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x40,0x96,0xB9,0xA3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x0E,
  0x63
};
static struct info g320x200x256_info = { 320, 200, 256, 320 };


/* non-BIOS mode - 320x240x256 */
static uchar g320x240x256_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0x0D,0x3E,0x00,0x41,0x00,0x00,
  0x00,0x00,0x00,0x00,0xEA,0xAC,0xDF,0x28,0x00,0xE7,0x06,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0xE3
};
static struct info g320x240x256_info = { 320, 240, 256, 80 };


/* non-BIOS mode - 320x400x256 */
static uchar g320x400x256_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0x63
};
static struct info g320x400x256_info = { 320, 400, 256, 80 };


/* non-BIOS mode - 360x480x256 */
static uchar g360x480x256_regs[60] = {
  0x6B,0x59,0x5A,0x8E,0x5E,0x8A,0x0D,0x3E,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0xEA,0xAC,0xDF,0x2D,0x00,0xE7,0x06,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x41,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0xE7
};
static struct info g360x480x256_info = { 360, 480, 256, 90 };


/* monochrome mode based on BIOS mode 12h - 640x480x2 */
static uchar g640x480x2_regs[60] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0xEA,0x8C,0xDF,0x28,0x00,0xE7,0x04,0xE3,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x0F,0x00,0x20,0x00,0x00,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x06,
  0xE3
};
static struct info g640x480x2_info = { 640, 480, 2, 80 };


/* ET4000 BIOS mode 2Eh - 640x480x256 */
static uchar g640x480x256_regs[70] = {
  0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0xEA,0x8C,0xDF,0x50,0x60,0xE7,0x04,0xAB,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x0E,
  0xE3,
  0x70,0x00,0x08,0x00,0x43,0x1F,0xBC,0x00,0x00,0x00
};
static struct info g640x480x256_info = { 640, 480, 256, 640 };


/* ET4000 BIOS mode 30h - 800x600x256 */
static uchar g800x600x256_regs[70] = {
  0x7A,0x63,0x64,0x1D,0x68,0x9A,0x78,0xF0,0x00,0x60,0x00,0x00,
  0x00,0x00,0x00,0x00,0x5C,0x8E,0x57,0x64,0x60,0x5B,0x75,0xAB,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x0E,
  0xEF,
  0x70,0x00,0x08,0x00,0x43,0x1F,0xBC,0x00,0x00,0x00
};
static struct info g800x600x256_info = { 800, 600, 256, 800 };


/* ET4000 BIOS mode 38h - 1024x768x256 */
static uchar g1024x768x256_regs[70] = {
  0x99,0x7F,0x7F,0x1D,0x83,0x17,0x2F,0xF5,0x00,0x60,0x00,0x00,
  0x00,0x00,0x00,0x00,0x08,0x80,0xFF,0x80,0x60,0xFF,0x30,0xAB,
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
  0x0C,0x0D,0x0E,0x0F,0x01,0x00,0x0F,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF,
  0x03,0x01,0x0F,0x00,0x0E,
  0x27,
  0x70,0x00,0x0A,0x80,0x43,0x1F,0xBC,0x00,0x00,0x00
};
static struct info g1024x768x256_info = { 1024, 768, 256, 1024 };


/* default palette values */
static uchar default_red[256]
             = { 0, 0, 0, 0,42,42,42,42,21,21,21,21,63,63,63,63,
                 0, 5, 8,11,14,17,20,24,28,32,36,40,45,50,56,63,
                 0,16,31,47,63,63,63,63,63,63,63,63,63,47,31,16,
                 0, 0, 0, 0, 0, 0, 0, 0,31,39,47,55,63,63,63,63,
                63,63,63,63,63,55,47,39,31,31,31,31,31,31,31,31,
                45,49,54,58,63,63,63,63,63,63,63,63,63,58,54,49,
                45,45,45,45,45,45,45,45, 0, 7,14,21,28,28,28,28,
                28,28,28,28,28,21,14, 7, 0, 0, 0, 0, 0, 0, 0, 0,
                14,17,21,24,28,28,28,28,28,28,28,28,28,24,21,17,
                14,14,14,14,14,14,14,14,20,22,24,26,28,28,28,28,
                28,28,28,28,28,26,24,22,20,20,20,20,20,20,20,20,
                 0, 4, 8,12,16,16,16,16,16,16,16,16,16,12, 8, 4,
                 0, 0, 0, 0, 0, 0, 0, 0, 8,10,12,14,16,16,16,16,
                16,16,16,16,16,14,12,10, 8, 8, 8, 8, 8, 8, 8, 8,
                11,12,13,15,16,16,16,16,16,16,16,16,16,15,13,12,
                11,11,11,11,11,11,11,11, 0, 0, 0, 0, 0, 0, 0, 0};
static uchar default_green[256]
             = { 0, 0,42,42, 0, 0,21,42,21,21,63,63,21,21,63,63,
                 0, 5, 8,11,14,17,20,24,28,32,36,40,45,50,56,63,
                 0, 0, 0, 0, 0, 0, 0, 0, 0,16,31,47,63,63,63,63,
                63,63,63,63,63,47,31,16,31,31,31,31,31,31,31,31,
                31,39,47,55,63,63,63,63,63,63,63,63,63,55,47,39,
                45,45,45,45,45,45,45,45,45,49,54,58,63,63,63,63,
                63,63,63,63,63,58,54,49, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 7,14,21,29,28,28,28,28,28,28,28,28,21,14, 7,
                14,14,14,14,14,14,14,14,14,17,21,24,28,28,28,28,
                28,28,28,28,28,24,21,17,20,20,20,20,20,20,20,20,
                20,22,24,26,28,28,28,28,28,28,28,28,28,26,24,22,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8,12,16,16,16,16,
                16,16,16,16,16,12, 8, 4, 8, 8, 8, 8, 8, 8, 8, 8,
                 8,10,12,14,16,16,16,16,16,16,16,16,16,14,12,10,
                11,11,11,11,11,11,11,11,11,12,13,15,16,16,16,16,
                16,16,16,16,16,15,13,12, 0, 0, 0, 0, 0, 0, 0, 0};
static uchar default_blue[256]
             = { 0,42, 0,42, 0,42, 0,42,21,63,21,63,21,63,21,63,
                 0, 5, 8,11,14,17,20,24,28,32,36,40,45,50,56,63,
                63,63,63,63,63,47,31,16, 0, 0, 0, 0, 0, 0, 0, 0,
                 0,16,31,47,63,63,63,63,63,63,63,63,63,55,47,39,
                31,31,31,31,31,31,31,31,31,39,47,55,63,63,63,63,
                63,63,63,63,63,58,54,49,45,45,45,45,45,45,45,45,
                45,49,54,58,63,63,63,63,28,28,28,28,28,21,14, 7,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,14,21,28,28,28,28,
                28,28,28,28,28,24,21,17,14,14,14,14,14,14,14,14,
                14,17,21,24,28,28,28,28,28,28,28,28,28,26,24,22,
                20,20,20,20,20,20,20,20,20,22,24,26,28,28,28,28,
                16,16,16,16,16,12, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 4, 8,12,16,16,16,16,16,16,16,16,16,14,12,10,
                 8, 8, 8, 8, 8, 8, 8, 8, 8,10,12,14,16,16,16,16,
                16,16,16,16,16,15,13,12,11,11,11,11,11,11,11,11,
                11,12,13,15,16,16,16,16, 0, 0, 0, 0, 0, 0, 0, 0};


/* used to decompose color value into bits (for fast scanline drawing) */
union bits {
    struct {
        uchar bit3;
        uchar bit2;
        uchar bit1;
        uchar bit0;
    } b;
    unsigned int i;
};

/* color decompositions */
static union bits color16[16] = {{0,0,0,0},
                                 {0,0,0,1},
                                 {0,0,1,0},
                                 {0,0,1,1},
                                 {0,1,0,0},
                                 {0,1,0,1},
                                 {0,1,1,0},
                                 {0,1,1,1},
                                 {1,0,0,0},
                                 {1,0,0,1},
                                 {1,0,1,0},
                                 {1,0,1,1},
                                 {1,1,0,0},
                                 {1,1,0,1},
                                 {1,1,1,0},
                                 {1,1,1,1}};


static uchar text_regs[MAX_REGS];   /* VGA registers for saved text mode */

/* saved text mode palette values */
static uchar text_red[256];
static uchar text_green[256];
static uchar text_blue[256];

/* saved graphics mode palette values */
static uchar graph_red[256];
static uchar graph_green[256];
static uchar graph_blue[256];

static int         cur_mode  = TEXT;     /* current video mode       */
static int         flip_mode = TEXT;     /* flipped video mode       */
static struct info cur_info;             /* current video parameters */
static int         cur_color;            /* current color            */
static struct clip cur_clip;             /* current whole-screen clipping */

static int initialized = 0;   /* flag: initialize() called ?  */
static int et4000      = 0;   /* flag: ET4000 or standard VGA */

#ifdef UNIX
static int   tty0_fd;    /* /dev/tty0 file descriptor                 */
#endif
static uchar* graph_mem; /* dummy buffer for mmapping graphics memory */
static uchar* graph_buf; /* saves graphics data during flip           */

static uchar font_buf1[FONT_SIZE];  /* saved font data - plane 2 */
static uchar font_buf2[FONT_SIZE];  /* saved font data - plane 3 */
static uchar null_buf[NULL_SIZE];   /* used to speed up clear */


static inline void port_out (uchar value, unsigned short port)
{
        __asm__ volatile ("outb %0,%1"
                          :
                          : "a" ((uchar) value), "d" ((unsigned short) port));
}

static inline uchar port_in (unsigned short port)
{
        uchar _v;
        __asm__ volatile ("inb %1,%0"
                          : "=a" (_v)
                          : "d" ((unsigned short) port));
        return _v;
}


# There is a big problem:
#   Text output may not occur while the VGA hardware is in graphics mode.
#
# We distinguish
# a. text output from CLISP itself,
# b. text output from the OS, for example when the user types something,
# c. text output from other programs.
#
# a. Solved: We switch to text mode every time we are about to output
#    something to stdout. (See stream.d.)
# b. Solved: DOS/EMX doesn't output anything (local echo is not done until
#    the next read() call), Linux consoles are protected by KD_GRAPHICS.
# c. Partially solved: On exit, CLISP switches to text mode (see spvw.d).
#    Signals SIGTSTP, SIGTTIN, SIGTTOU are ignored, and signal SIGSTOP is
#    de facto disabled, using termios ioctl's.
#    But when other programs are called by CLISP (using SHELL, EXECUTE or
#    MAKE-PIPE-OUTPUT-STREAM), it is up to the user to ensure they don't do
#    any output!

#ifdef UNIX

static char suspend_char = 0; # the suspend character (normally Ctrl-Z)

static void set_graphmode_signals (void)
{
    begin_system_call();
    SIGNAL(SIGTSTP,SIG_IGN);
    SIGNAL(SIGTTIN,SIG_IGN);
    SIGNAL(SIGTTOU,SIG_IGN);
    { struct termios the_termio;
      if ( tcgetattr(stdin_handle,&the_termio) ==0)
        { if (!suspend_char && the_termio.c_cc[VSUSP])
            suspend_char = the_termio.c_cc[VSUSP];
          the_termio.c_cc[VSUSP] = 0; # disable suspend character
          TCSETATTR(stdin_handle,TCSAFLUSH,&the_termio);
    }   }
    end_system_call();
}

static void set_textmode_signals (void)
{
    begin_system_call();
    SIGNAL(SIGTSTP,SIG_DFL);
    SIGNAL(SIGTTIN,SIG_DFL);
    SIGNAL(SIGTTOU,SIG_DFL);
    if (suspend_char)
      { struct termios the_termio;
        if ( tcgetattr(stdin_handle,&the_termio) ==0)
          { # Be careful not to enable Ctrl-Z when we are in raw mode!
            if ((the_termio.c_lflag & ICANON) && !the_termio.c_cc[VSUSP])
              { the_termio.c_cc[VSUSP] = suspend_char; # re-enable suspend character
                TCSETATTR(stdin_handle,TCSAFLUSH,&the_termio);
      }   }   }
    end_system_call();
}

#endif

#ifdef EMUNIX

# EMX doesn't have these signals.

static inline void set_graphmode_signals (void) {}
static inline void set_textmode_signals (void) {}

#endif


# When poking around in the VGA hardware, we need to disable the most critical
# interrupts. Well, we can't disable the scheduler, but we can block nearly
# all the signals and disable SIGSTOP.
# The macros disable_interrupts() and enable_interrupts() must be called in
# pairs, in the same block.

#ifdef UNIX
  #define disable_interrupts()  \
    { sigset_t old_sigmask, sigblock_mask;                 \
      sigfillset(&sigblock_mask);                          \
      sigprocmask(SIG_BLOCK,&sigblock_mask,&old_sigmask);  \
      { struct termios the_termio;                         \
        if ( tcgetattr(stdin_handle,&the_termio) ==0)      \
          { the_termio.c_lflag &= ~ISIG;                   \
            TCSETATTR(stdin_handle,TCSAFLUSH,&the_termio); \
      }   }
  #define enable_interrupts()  \
      { struct termios the_termio;                         \
        if ( tcgetattr(stdin_handle,&the_termio) ==0)      \
          { the_termio.c_lflag |= ISIG;                    \
            TCSETATTR(stdin_handle,TCSAFLUSH,&the_termio); \
      }   }                                                \
      sigprocmask(SIG_SETMASK,&old_sigmask,NULL);          \
    }
#endif
#ifdef EMUNIX
  # EMX doesn't have these signals.
  #define disable_interrupts()
  #define enable_interrupts()
#endif


# The next six functions should only be called with interrupts disabled.


# Get I/O port permissions.
static int get_perm()
{
    static int done = 0;

    if (!done)
        {

          #ifdef UNIX
          {
            int err = 0;

            BEGIN_ROOT_PRIV;

            /* get I/O permissions for VGA registers */
            if (ioperm(CRT_IC, 1, 1)
             || ioperm(CRT_IM, 1, 1)
             || ioperm(ATT_IW, 1, 1)
             || ioperm(GRA_I,  1, 1)
             || ioperm(SEQ_I,  1, 1)
             || ioperm(PEL_IW, 1, 1)
             || ioperm(PEL_IR, 1, 1)
             || ioperm(CRT_DC, 1, 1)
             || ioperm(CRT_DM, 1, 1)
             || ioperm(ATT_R,  1, 1)
             || ioperm(GRA_D,  1, 1)
             || ioperm(SEQ_D,  1, 1)
             || ioperm(MIS_R,  1, 1)
             || ioperm(MIS_W,  1, 1)
             || ioperm(IS1_RC, 1, 1)
             || ioperm(IS1_RM, 1, 1)
             || ioperm(PEL_D,  1, 1)

            /* ET4000 registers */
             || ioperm(0x3bf,  1, 1)
             || ioperm(0x3cc,  1, 1)
             || ioperm(0x3d8,  1, 1)
             || ioperm(0x3b8,  1, 1)
             || ioperm(0x3c3,  1, 1)
             || ioperm(0x3cd,  1, 1)
               )
                err = 1;

            END_ROOT_PRIV;

            if (err)
                return -1; /* can't get I/O permissions */
          }
          #endif

          #ifdef EMUNIX

            if (_portaccess(0x3B4,0x3DA))
                { errno = EPERM; return -1; } /* can't get I/O permissions */

          #endif

            /* color or monochrome text emulation? */
            color_text = port_in(MIS_R) & 0x01;

            /* chose registers for color/monochrome emulation */
            if (color_text) {
                CRT_I = CRT_IC;
                CRT_D = CRT_DC;
                IS1_R = IS1_RC;
            } else {
                CRT_I = CRT_IM;
                CRT_D = CRT_DM;
                IS1_R = IS1_RM;
            }

            done = 1;
        }

    return 0;
}


# Returns 1 if an ET4000 card is present, else 0.

static int et4000_test (void)
{
    static int result = -1;
    uchar newv, oldv, val;
    int base;

    /* test already done? */
    if (result >= 0)
        return result;

    /* test for Tseng clues */
    oldv = port_in(0x3cd);
    port_out(0x55, 0x3cd);
    newv = port_in(0x3cd);
    port_out(oldv, 0x3cd);

    /* return false if not Tseng */
    if (newv != 0x55)
        return result = 0;

    /* test for ET4000 clues */
    if (port_in(0x3cc) & 1)
        base = 0x3d4;
    else
        base = 0x3b4;
    port_out(0x33, base);
    oldv = port_in(base+1);
    newv = oldv ^ 0xf;
    port_out(newv, base+1);
    val = port_in(base+1);
    port_out(oldv, base+1);

    /* return true if ET4000 */
    return result = (val == newv);
}


static void et4000_save_regs (uchar regs[])
{
    int i;

    /* save extended CRT registers */
    for (i = 0; i < 6; i++) {
         port_out(0x32+i, CRT_I);
         regs[EXT+i] = port_in(CRT_D);
    }

    /* save extended sequencer register */
    port_out(7, SEQ_I);
    regs[EXT+6] = port_in(SEQ_D);

    /* save some other ET4000 specific registers */
    regs[EXT+7] = port_in(0x3c3);
    regs[EXT+8] = port_in(0x3cd);

    /* save extended attribute register */
    port_in(IS1_R);    /* reset flip flop */
    port_out(0x16, ATT_IW);
    regs[EXT+9] = port_in(ATT_R);
}


static void et4000_set_regs (uchar regs[])
{
    int i;

    /* write some ET4000 specific registers */
    port_out(regs[EXT+7], 0x3c3);
    port_out(regs[EXT+8], 0x3cd);

    /* write extended sequencer register */
    port_out(7, SEQ_I);
    port_out(regs[EXT+6], SEQ_D);

    /* write extended CRT registers */
    for (i = 0; i < 6; i++) {
         port_out(0x32+i, CRT_I);
         port_out(regs[EXT+i], CRT_D);
    }

    /* write extended attribute register */
    port_in(IS1_R);    /* reset flip flop */
    port_out(0x16, ATT_IW);
    port_out(regs[EXT+9], ATT_IW);
}


static void save_regs (uchar regs[])
{
    int i;

    /* save VGA registers */
    for (i = 0; i < CRT_C; i++) {
         port_out(i, CRT_I);
         regs[CRT+i] = port_in(CRT_D);
    }
    for (i = 0; i < ATT_C; i++) {
         port_in(IS1_R);
         port_out(i, ATT_IW);
         regs[ATT+i] = port_in(ATT_R);
    }
    for (i = 0; i < GRA_C; i++) {
         port_out(i, GRA_I);
         regs[GRA+i] = port_in(GRA_D);
    }
    for (i = 0; i < SEQ_C; i++) {
         port_out(i, SEQ_I);
         regs[SEQ+i] = port_in(SEQ_D);
    }
    regs[MIS] = port_in(MIS_R);

    if (et4000)
        et4000_save_regs(regs);
}


static void set_regs (uchar regs[], int mode)
{
    int i;

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    /* update misc output register */
    port_out(regs[MIS], MIS_W);

    /* synchronous reset on */
    port_out(0x00,SEQ_I);
    port_out(0x01,SEQ_D);

    /* write sequencer registers */
    for (i = 1; i < SEQ_C; i++) {
        port_out(i, SEQ_I);
        port_out(regs[SEQ+i], SEQ_D);
    }

    /* synchronous reset off */
    port_out(0x00, SEQ_I);
    port_out(0x03, SEQ_D);

    /* deprotect CRT registers 0-7 */
    port_out(0x11, CRT_I);
    port_out(port_in(CRT_D)&0x7F, CRT_D);

    /* write CRT registers */
    for (i = 0; i < CRT_C; i++) {
        port_out(i, CRT_I);
        port_out(regs[CRT+i], CRT_D);
    }

    /* write graphics controller registers */
    for (i = 0; i < GRA_C; i++) {
        port_out(i, GRA_I);
        port_out(regs[GRA+i], GRA_D);
    }

    /* write attribute controller registers */
    for (i = 0; i < ATT_C; i++) {
        port_in(IS1_R);   /* reset flip-flop */
        port_out(i, ATT_IW);
        port_out(regs[ATT+i],ATT_IW);
    }

    if (et4000)
        if (mode == G640x480x256 || mode == G800x600x256 || mode == G1024x768x256)
            et4000_set_regs(regs);
}


static void vga_setpalette (int index, int red, int green, int blue)
{
    int i;

    /* select palette register */
    port_out(index, PEL_IW);

    /* write RGB components */
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    port_out(red, PEL_D);
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    port_out(green, PEL_D);
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    port_out(blue, PEL_D);
}


static void vga_getpalette (int index, int *red, int *green, int *blue)
{
    int i;

    /* select palette register */
    port_out(index, PEL_IR);

    /* read RGB components */
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    *red = (int) port_in(PEL_D);
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    *green = (int) port_in(PEL_D);
    for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
    *blue = (int) port_in(PEL_D);
}

#if 0

static void vga_setpalvec (int start, int num, int *pal)
{
    int i, j;

    /* select palette register */
    port_out(start, PEL_IW);

    for(j = 0; j < num; j++) {
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        port_out(*(pal++), PEL_D);
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        port_out(*(pal++), PEL_D);
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        port_out(*(pal++), PEL_D);
    }
}


static void vga_getpalvec (int start, int num, int *pal)
{
    int i, j;

    /* select palette register */
    port_out(start, PEL_IR);

    for(j = 0; j < num; j++) {
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        *(pal++) = (int) port_in(PEL_D);
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        *(pal++) = (int) port_in(PEL_D);
        for(i = 0; i < 10; i++) ;   /* delay (minimum 240ns) */
        *(pal++) = (int) port_in(PEL_D);
    }
}

#endif

void vga_setcolor (int color)
{
    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
            /* update set/reset register */
            port_out(0x00, GRA_I );
            port_out(color, GRA_D );
            break;
        case G640x480x2:
            if (color != 0)
                color = 15;
            /* update set/reset register */
            port_out(0x00, GRA_I );
            port_out(color, GRA_D );
            break;
        case G320x200x256:
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            cur_color = color;
            break;
    }
}


void vga_screenoff()
{
    /* turn off screen for faster VGA memory access */
    port_out(0x01, SEQ_I);
    port_out(port_in(SEQ_D)|0x20, SEQ_D);
}


void vga_screenon()
{
    /* turn screen back on */
    port_out(0x01, SEQ_I);
    port_out(port_in(SEQ_D)&0xDF, SEQ_D);
}


void vga_clear()
{
    int i, j;

    vga_screenoff();

    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
        case G640x480x2:
            vga_setcolor(0);

            /* write to all bits */
            port_out(0x08, GRA_I );
            port_out(0xFF, GRA_D );

            /* write dummy values to clear video memory */
            for(i = 0; i < 16; i++)
                memcpy(graph_mem + i*NULL_SIZE, null_buf, NULL_SIZE);

            break;
        case G320x200x256:
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
            /* write to all planes */
            port_out(0x02, SEQ_I );
            port_out(0x0F, SEQ_D );

            /* clear video memory */
            for(i = 0; i < 16; i++)
                memcpy(graph_mem + i*NULL_SIZE, null_buf, NULL_SIZE);

            break;
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            for(i = 0; i < 16; i++) {
                /* select segment */
                port_out(i, SEG_SELECT);

                /* clear video memory */
                for(j = 0; j < 16; j++)
                    memcpy(graph_mem + j*NULL_SIZE, null_buf, NULL_SIZE);
            }
            break;
    }

    vga_setcolor(15);

    vga_screenon();
}


/* set cur_mode to TEXT */
static void set_textmode (void)
{
    int i;

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    if (et4000 && cur_mode == G1024x768x256)
        set_regs(g640x480x256_regs, G640x480x256);

    cur_mode = TEXT;

    /* restore font data - first select a 16 color graphics mode */
    set_regs(g640x480x16_regs, G640x480x16);

    /* disable Set/Reset Register */
    port_out(0x01, GRA_I );
    port_out(0x00, GRA_D );

    /* restore font data in plane 2 - necessary for all VGA's */
    port_out(0x02, SEQ_I );
    port_out(0x04, SEQ_D );
    memcpy(graph_mem, font_buf1, FONT_SIZE);

    /* restore font data in plane 3 - necessary for Trident VGA's */
    port_out(0x02, SEQ_I );
    port_out(0x08, SEQ_D );
    memcpy(graph_mem, font_buf2, FONT_SIZE);

    /* change register adresses if monochrome text mode */
    if (!color_text) {
        CRT_I = CRT_IM;
        CRT_D = CRT_DM;
        IS1_R = IS1_RM;
        port_out(port_in(MIS_R)&0xFE, MIS_W);
    }

    /* restore saved palette */
    for(i = 0; i < 256; i++)
        vga_setpalette(i, text_red[i], text_green[i], text_blue[i]);

    /* restore text mode VGA registers */
    set_regs(text_regs, TEXT);

    /* enable video */
    port_in(IS1_R);
    port_out(0x20, ATT_IW);

    #ifdef UNIX
    /* enable text output - restores the screen contents */
    ioctl(tty0_fd, KDSETMODE, KD_TEXT);
    #endif
    #ifdef EMUNIX
    kd_text();
    #endif

    /* restore text mode termio */
    set_textmode_signals();
}


/* set cur_mode to mode != TEXT, maybe clearing the screen */
static void set_graphmode (int mode, int clear)
{
    int i;

    #ifdef UNIX
    /* disable text output */
    ioctl(tty0_fd, KDSETMODE, KD_GRAPHICS);
    #endif
    #ifdef EMUNIX
    kd_graphics();
    #endif

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    if (et4000 && cur_mode == G1024x768x256)
        set_regs(g640x480x256_regs, G640x480x256);

    cur_mode = mode;

    /* shift to color emulation */
    CRT_I = CRT_IC;
    CRT_D = CRT_DC;
    IS1_R = IS1_RC;
    port_out(port_in(MIS_R)|0x01, MIS_W);

    switch (mode) {
        case G320x200x16:
            set_regs(g320x200x16_regs, G320x200x16);
            cur_info = g320x200x16_info;
            break;
        case G640x200x16:
            set_regs(g640x200x16_regs, G640x200x16);
            cur_info = g640x200x16_info;
            break;
        case G640x350x16:
            set_regs(g640x350x16_regs, G640x350x16);
            cur_info = g640x350x16_info;
            break;
        case G640x480x16:
            set_regs(g640x480x16_regs, G640x480x16);
            cur_info = g640x480x16_info;
            break;
        case G320x200x256:
            set_regs(g320x200x256_regs, G320x200x256);
            cur_info = g320x200x256_info;
            break;
        case G320x240x256:
            set_regs(g320x240x256_regs, G320x240x256);
            cur_info = g320x240x256_info;
            break;
        case G320x400x256:
            set_regs(g320x400x256_regs, G320x400x256);
            cur_info = g320x400x256_info;
            break;
        case G360x480x256:
            set_regs(g360x480x256_regs, G360x480x256);
            cur_info = g360x480x256_info;
            break;
        case G640x480x2:
            set_regs(g640x480x2_regs, G640x480x2);
            cur_info = g640x480x2_info;
            break;
        case G640x480x256:
            set_regs(g640x480x256_regs, G640x480x256);
            cur_info = g640x480x256_info;
            break;
        case G800x600x256:
            set_regs(g800x600x256_regs, G800x600x256);
            cur_info = g800x600x256_info;
            break;
        case G1024x768x256:
            set_regs(g1024x768x256_regs, G1024x768x256);
            cur_info = g1024x768x256_info;
            break;
    }
    cur_clip.x1 = 0; cur_clip.x2 = cur_info.xdim-1;
    cur_clip.y1 = 0; cur_clip.y2 = cur_info.ydim-1;

    if (clear) {
        /* set default palette */
        for(i = 0; i < 256; i++)
            vga_setpalette(i, default_red[i],default_green[i],default_blue[i]);

        /* clear screen (sets current color to 15) */
        vga_clear();
    }

    /* enable video */
    port_in(IS1_R);
    port_out(0x20, ATT_IW);

    /* set graphics mode termio */
    set_graphmode_signals();
}


/* Global initialization. */
/* Only called once, by the first call to vga_hasmode() or vga_setmode(). */

static int initialize (void)
{
    int result;
    int i, j;

    disable_interrupts();

    if (get_perm())
        { asciz_out("VGAlib: can't get I/O permissions" NLstring);
          result = -1; goto done;
        }

    et4000 = et4000_test();

    if (et4000) {
        /* get access to extended registers */
        port_out(3, 0x3bf);
        if (port_in( 0x3cc ) & 1)
            port_out(0xa0, 0x3d8);
        else
            port_out(0xa0, 0x3b8);
    }

    #ifdef EMUNIX

    /* enquire text mode parameters */
    get_text_info();

    /* allocate memory for saved text data */
    if ((text_buf = (unsigned short *) malloc(2*text_size)) == NULL)
        { asciz_out("VGAlib: not enough memory" NLstring);
          errno = ENOMEM; return -1;
        }

    #endif

    /* allocate memory for saved graphics data */
    if ((graph_buf = (unsigned char *) malloc(4*GRAPH_SIZE)) == NULL)
        { asciz_out("VGAlib: not enough memory" NLstring);
          errno = ENOMEM; return -1;
        }

    #ifdef UNIX

    {   int mem_fd;
        uchar* mem_area;

        BEGIN_ROOT_PRIV;

        /* open /dev/tty0 - current virtual console */
        if ((tty0_fd = open("/dev/console", O_RDONLY) ) < 0)
            if ((tty0_fd = open("/dev/tty0", O_RDONLY) ) < 0)
                { END_ROOT_PRIV;
                  free(graph_buf);
                  asciz_out("VGAlib: can't open /dev/console" NLstring);
                  result = -1; goto done;
                }

        /* open /dev/mem */
        if ((mem_fd = open("/dev/mem", O_RDWR) ) < 0)
            { END_ROOT_PRIV;
              close(tty0_fd); free(graph_buf);
              asciz_out("VGAlib: can't open /dev/mem" NLstring);
              result = -1; goto done;
            }

        END_ROOT_PRIV;

        /* mmap graphics memory */
        if ((mem_area = (uchar*) malloc(GRAPH_SIZE + getpagesize()-1)) == NULL)
            { close(tty0_fd); close(mem_fd); free(graph_buf);
              asciz_out("VGAlib: not enough memory" NLstring);
              errno = ENOMEM; result = -1; goto done;
            }
        graph_mem = mem_area + ((-(unsigned long)mem_area) & (getpagesize()-1));
        graph_mem = (uchar *) mmap((CADDR_T)graph_mem, GRAPH_SIZE,
                                   PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED,
                                   mem_fd, GRAPH_BASE);
        if (graph_mem == (uchar *)(-1))
            { close(tty0_fd); close(mem_fd); free(mem_area); free(graph_buf);
              asciz_out("VGAlib: couldn't mmap graphics memory" NLstring);
              result = -1; goto done;
            }
    }

    #endif

    #ifdef EMUNIX

    text_mem = memaccess (text_phys_mem, text_phys_mem+2*text_size-1, 1);
    if (text_mem == NULL)
        { asciz_out("VGAlib: couldn't get access to text memory" NLstring);
          errno = EINVAL; result = -1; goto done;
        }

    graph_mem = memaccess (GRAPH_BASE, GRAPH_BASE+GRAPH_SIZE-1, 1);
    if (graph_mem == NULL)
        { asciz_out("VGAlib: couldn't get access to graphics memory" NLstring);
          errno = EINVAL; result = -1; goto done;
        }

    #endif

    /* Here's the point of no return. */

    #ifdef UNIX
    /* disable text output to console */
    ioctl(tty0_fd, KDSETMODE, KD_GRAPHICS);
    #endif

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    save_regs(text_regs);

    /* save text mode palette - first select palette index 0 */
    port_out(0, PEL_IR);

    /* read RGB components - index is autoincremented */
    for(i = 0; i < 256; i++) {
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        text_red[i] = port_in(PEL_D);
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        text_green[i] = port_in(PEL_D);
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        text_blue[i] = port_in(PEL_D);
    }

    /* shift to color emulation */
    CRT_I = CRT_IC;
    CRT_D = CRT_DC;
    IS1_R = IS1_RC;
    port_out(port_in(MIS_R)|0x01, MIS_W);

    /* save font data - first select a 16 color graphics mode */
    set_regs(g640x480x16_regs, G640x480x16);

    /* save font data in plane 2 */
    port_out(0x04, GRA_I);
    port_out(0x02, GRA_D);
    memcpy(font_buf1, graph_mem, FONT_SIZE);

    /* save font data in plane 3 */
    port_out(0x04, GRA_I);
    port_out(0x03, GRA_D);
    memcpy(font_buf2, graph_mem, FONT_SIZE);

    /* enable video */
    port_in(IS1_R);
    port_out(0x20, ATT_IW);

    /* initialize buffer used when clearing in 256 color modes */
    for(i = 0; i < NULL_SIZE; i++)
        null_buf[i] = 0;

    /* we have modified the VGA registers -- back to text mode for now */
    set_textmode();

    initialized = 1;

    result = 0;

    done:
    enable_interrupts();

    return result;
}


int vga_hasmode (int mode)
{
    switch (mode) {
        case TEXT:
            return 1;
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
        case G640x480x2:
        case G320x200x256:
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
            if (!initialized)
                if (initialize())
                    return 0;
            return 1;
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            if (!initialized)
                if (initialize())
                    return 0;
            return et4000;
        default:
            return 0;
    }
}

int vga_setmode (int mode)
{
    if (!initialized)
        if (initialize())
            return -1;

    disable_interrupts();

    if (mode == TEXT)
        set_textmode();
    else
        set_graphmode(mode,1);

    enable_interrupts();

    return 0;
}


# We do `lazy switching' between text mode and graphics mode.
# This switching doesn't lose screen's contents. It is therefore also called
# `flipping'.
# flip_mode is the mode of the "screen behind the scenes".
# At least one of cur_mode and flip_mode is TEXT.

void switch_text_mode (void)
{
    int i, j;

    if (cur_mode == TEXT)
        return;

    /* cur_mode != TEXT, so flip_mode == TEXT,
       and initialize() has already been called. */

    disable_interrupts();

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    /* save all four planes - first select a 16 color graphics mode */
    set_regs(g640x480x16_regs, G640x480x16);

    for(i = 0; i < 4; i++) {
        /* save plane i */
        port_out(0x04, GRA_I);
        port_out(   i, GRA_D);
        memcpy(graph_buf + i*GRAPH_SIZE, graph_mem, GRAPH_SIZE);
    }

    /* save graphics mode palette - first select palette index 0 */
    port_out(0, PEL_IR);

    /* read RGB components - index is autoincremented */
    for(i = 0; i < 256; i++) {
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        graph_red[i] = port_in(PEL_D);
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        graph_green[i] = port_in(PEL_D);
        for(j = 0; j < 10; j++) ;   /* delay (minimum 240ns) */
        graph_blue[i] = port_in(PEL_D);
    }

    flip_mode = cur_mode;

    set_textmode();

    enable_interrupts();
}

void switch_graphics_mode (void)
{
    int i;

    if (flip_mode == TEXT)
        return;

    /* flip_mode != TEXT, so cur_mode == TEXT,
       and initialize() has already been called. */

    disable_interrupts();

    #ifdef UNIX
    /* disable text output */
    ioctl(tty0_fd, KDSETMODE, KD_GRAPHICS);
    #endif
    #ifdef EMUNIX
    kd_graphics();
    #endif

    /* disable video */
    port_in(IS1_R);
    port_out(0x00, ATT_IW);

    /* restore all four planes - first select a 16 color graphics mode */
    set_regs(g640x480x16_regs, G640x480x16);

    /* disable Set/Reset Register */
    port_out(0x01, GRA_I );
    port_out(0x00, GRA_D );

    for(i = 0; i < 4; i++) {
        /* restore plane i */
        port_out(0x02, SEQ_I );
        port_out(1<<i, SEQ_D );
        memcpy(graph_mem, graph_buf + i*GRAPH_SIZE, GRAPH_SIZE);
    }

    /* restore saved palette */
    for(i = 0; i < 256; i++)
        vga_setpalette(i, graph_red[i], graph_green[i], graph_blue[i]);

    set_graphmode(flip_mode,0);

    flip_mode = TEXT;

    enable_interrupts();
}


void vga_drawpixel (int x, int y)
{
    unsigned long offset;

    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
        case G640x480x2:
            /* select bit */
            port_out(8, GRA_I);
            port_out(0x80 >> (x & 7), GRA_D);

            /* read into latch and write dummy back */
            offset = y*cur_info.xbytes + (x>>3);
            graph_mem[offset] = graph_mem[offset];
            break;
        case G320x200x256:
            /* write color to pixel */
            graph_mem[y*320 + x] = cur_color;
            break;
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
            /* select plane */
            port_out(0x02, SEQ_I);
            port_out(1 << (x & 3), SEQ_D);

            /* write color to pixel */
            graph_mem[y*cur_info.xbytes + (x>>2)] = cur_color;
            break;
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            offset = y*cur_info.xbytes+x;

            /* select segment */
            port_out(offset >> 16, SEG_SELECT);

            /* write color to pixel */
            graph_mem[offset & 0xFFFF] = cur_color;
            break;
    }
}


/* Get pixel's color. */
int vga_getpixel (int x, int y)
{
    unsigned long offset;

    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
        case G640x480x2:
            # Not yet tested!!
            { int i;
              int color = 0;
              uchar mask = 0x80 >> (x & 7);
              offset = y*cur_info.xbytes + (x>>3);
              for(i = 0; i < 4; i++) {
                  /* select plane i */
                  port_out(0x04, GRA_I);
                  port_out(   i, GRA_D);
                  if (graph_mem[offset] & mask)
                      color |= (1<<i);
              }
              return color;
            }
        case G320x200x256:
            /* get pixel color */
            return graph_mem[y*320 + x];
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
            /* select plane */
            port_out(0x02, SEQ_I);
            port_out(1 << (x & 3), SEQ_D);

            /* get pixel color */
            return graph_mem[y*cur_info.xbytes + (x>>2)];
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            offset = y*cur_info.xbytes+x;

            /* select segment */
            port_out(offset >> 16, SEG_SELECT);

            /* get pixel color */
            return graph_mem[offset & 0xFFFF];
        default:
            return -1;
    }
}

#if 0

/* display plane buffers (for fast scanline drawing) */
static uchar plane0[256];
static uchar plane1[256];
static uchar plane2[256];
static uchar plane3[256];

void vga_drawscansegment (uchar* colors, int x, int y, int length)
{
    /* both length and x must divide with 8 */

    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
            {
                int i, j, k, first, last;
                union bits bytes;
                uchar* address;

                k = 0;
                for(i = 0; i < length; i += 8) {
                    bytes.i = 0;
                    first = i;
                    last  = i+8;
                    for(j = first; j < last; j++)
                       bytes.i = (bytes.i<<1) | color16[colors[j]].i;
                    plane0[k]   = bytes.b.bit0;
                    plane1[k]   = bytes.b.bit1;
                    plane2[k]   = bytes.b.bit2;
                    plane3[k++] = bytes.b.bit3;
                }

                address = graph_mem + (y*cur_info.xdim+x)/8;

                /* disable Set/Reset Register */
                port_out(0x01, GRA_I );
                port_out(0x00, GRA_D );

                /* write to all bits */
                port_out(0x08, GRA_I );
                port_out(0xFF, GRA_D );

                /* select map mask register */
                port_out(0x02, SEQ_I );

                /* write plane 0 */
                port_out(0x01, SEQ_D );
                memcpy(address, plane0, length/8);

                /* write plane 1 */
                port_out(0x02, SEQ_D );
                memcpy(address, plane1, length/8);

                /* write plane 2 */
                port_out(0x04, SEQ_D );
                memcpy(address, plane2, length/8);

                /* write plane 3 */
                port_out(0x08, SEQ_D );
                memcpy(address, plane3, length/8);

                /* restore map mask register */
                port_out(0x0F, SEQ_D );

                /* enable Set/Reset Register */
                port_out(0x01, GRA_I );
                port_out(0x0F, GRA_D );
            }
            break;
        case G640x480x2:
            {
                /* disable Set/Reset Register */
                port_out(0x01, GRA_I );
                port_out(0x00, GRA_D );

                /* write to all bits */
                port_out(0x08, GRA_I );
                port_out(0xFF, GRA_D );

                /* write to all planes */
                port_out(0x02, SEQ_I );
                port_out(0x0F, SEQ_D );

                memcpy(graph_mem + (y*cur_info.xdim+x)/8, colors, length);

                /* restore map mask register */
                port_out(0x0F, SEQ_D );

                /* enable Set/Reset Register */
                port_out(0x01, GRA_I );
                port_out(0x0F, GRA_D );
            }
            break;
        case G320x200x256:
            /* linear addressing - easy and fast */
            memcpy(graph_mem + y*cur_info.xdim+x, colors, length);
            break;
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
            {
                int first, last, offset, pixel, plane;

                /* select map mask register */
                port_out(0x02, SEQ_I);

                for(plane = 0; plane < 4; plane++) {
                    /* select plane */
                    port_out(1 << plane, SEQ_D);

                    pixel = plane;
                    first = (y*cur_info.xdim+x)/4;
                    last  = (y*cur_info.xdim+x+length)/4;
                    for(offset = first; offset < last; offset++) {
                        graph_mem[offset] = colors[pixel];
                        pixel += 4;
                    }
                }
            }
            break;
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
            {
                unsigned long offset;
                int segment, free;

                offset  = y*cur_info.xbytes+x;
                segment = offset >> 16;
                free    = ((segment+1)<<16)-offset;

                if (free < length) {
                    port_out(segment, SEG_SELECT);
                    memcpy(graph_mem + (offset & 0xFFFF), colors, free);
                    port_out(segment+1, SEG_SELECT);
                    memcpy(graph_mem, colors+free, length-free);
                } else {
                    port_out(segment, SEG_SELECT);
                    memcpy(graph_mem + (offset & 0xFFFF), colors, length);
                }

            }
            break;
    }
}


void vga_drawscanline (int line, uchar* colors)
{
    if (cur_mode == G640x480x2)
        vga_drawscansegment(colors, 0, line, cur_info.xbytes); # xbytes = xdim/8
    else
        vga_drawscansegment(colors, 0, line, cur_info.xdim);
}


void vga_drawbox (int x1, int y1, int x2, int y2)
{
    /* we may assume 0 <= x1 <= x2 and 0 <= y1 <= y2 */
    int x1_8 = round_up((unsigned int) x1, 8);
    int x2_8 = round_down((unsigned int) (x2+1), 8);
    if (x1_8 < x2_8)
      { unsigned int scansegment_length = x2_8 - x1_8;
        if (cur_mode == G640x480x2) scansegment_length = scansegment_length/8;
       {uchar colors[scansegment_length];
        { int i;
          int color = cur_color;
          if (cur_mode == G640x480x2) color = (color==0 ? 0x00 : 0xFF);
          for (i=0; i<scansegment_length; i++)
              colors[i] = color;
        }
        { int x, y;
          for (y = y1; y <= y2; y++) {
              for (x = x1; x < x1_8; x++)
                  vga_drawpixel(x, y);
              vga_drawscansegment(colors,x1_8,y,scansegment_length);
              for (x = x2_8; x <= x2; x++)
                  vga_drawpixel(x, y);
        } }
      }}
      else
      { int x, y;
        for (y = y1; y <= y2; y++)
            for (x = x1; x <= x2; x++)
                vga_drawpixel(x, y);
      }
}

# Leider gehen damit die 16-Farben-Modi nicht.
# Test:
# (progn
#   (graph-init 320 200 16) bzw.
#   (graph-init 640 200 16) bzw.
#   (graph-init 640 350 16) bzw.
#   (graph-init 640 480 16)
#   (graph-clear)
#   (graph-clear 10)
#   (graph-box 17 100 54 130 14)
#   (sleep 2)
# )

#endif

void vga_drawhline (int x1, int x2, int y)
{
    /* we may assume 0 <= x1 <= x2 */

    switch (cur_mode) {
        case G320x200x16:
        case G640x200x16:
        case G640x350x16:
        case G640x480x16:
        case G640x480x2:
          { volatile uchar* p1 = &graph_mem[y*cur_info.xbytes + (x1>>3)];
            volatile uchar* p2 = &graph_mem[y*cur_info.xbytes + (x2>>3)];
            volatile uchar* p;

            x1 &= 7;
            x2 &= 7;
            if (p1 == p2)
              { /* select bits */
                port_out(8, GRA_I);
                port_out((0x100 >> x1) - (0x80 >> x2), GRA_D);
                /* read into latch and write dummy back */
                *p2 = *p2;
              }
              else # p1 < p2
              { p = p1;
                /* select bits 7-x1..0 */
                port_out(8, GRA_I);
                port_out((0x100 >> x1) - 1, GRA_D);
                /* read into latch and write dummy back */
                *p = *p;
                if (++p < p2)
                  { /* select bits 7..0 */
                    port_out(8, GRA_I);
                    port_out(0x100 - 1, GRA_D);
                    do { /* read into latch and write dummy back */
                         *p = *p;
                       }
                       while (++p < p2);
                  }
                /* select bits 7..7-x2 */
                port_out(8, GRA_I);
                port_out(0x100 - (0x80 >> x2), GRA_D);
                /* read into latch and write dummy back */
                *p = *p;
              }
          }
          break;
        case G320x200x256:
          { volatile uchar* p1 = &graph_mem[y*320 + x1];
            volatile uchar* p2 = &graph_mem[y*320 + x2];
            volatile uchar* p;

            /* write color to pixels */
            for (p=p1; p<=p2; p++)
                *p = cur_color;
          }
          break;
        case G320x240x256:
        case G320x400x256:
        case G360x480x256:
          { volatile uchar* p1 = &graph_mem[y*cur_info.xbytes + (x1>>2)];
            volatile uchar* p2 = &graph_mem[y*cur_info.xbytes + (x2>>2)];
            volatile uchar* p;
            int i;

            x1 &= 3;
            x2 &= 3;
            if (p1 == p2)
                for (i = x1; i <= x2; i++) {
                    /* select plane */
                    port_out(0x02, SEQ_I);
                    port_out(1 << i, SEQ_D);

                    /* write color to pixel */
                    *p2 = cur_color;
                }
              else # p1 < p2
                for (i = 0; i < 4; i++) {
                    /* select plane */
                    port_out(0x02, SEQ_I);
                    port_out(1 << i, SEQ_D);

                    /* write color to pixels */
                    p = p1;
                    if (i >= x1)
                        *p = cur_color;
                    while (++p < p2)
                        *p = cur_color;
                    if (i <= x2)
                        *p = cur_color;
                }
          }
          break;
        case G640x480x256:
        case G800x600x256:
        case G1024x768x256:
          { unsigned long offset1 = y*cur_info.xbytes + x1;
            unsigned long offset2 = y*cur_info.xbytes + x2;
            volatile uchar* p;
            volatile uchar* p2;

            if ((offset1 >> 16) == (offset2 >> 16))
              { /* select segment */
                port_out(offset1 >> 16, SEG_SELECT);
                /* write color to pixels */
                offset1 &= 0xFFFF; offset2 &= 0xFFFF;
                for (p = &graph_mem[offset1], p2 = &graph_mem[offset2]; p<=p2; p++)
                    *p = cur_color;
              }
              else
              { /* select segment */
                port_out(offset1 >> 16, SEG_SELECT);
                /* write color to pixels */
                offset1 &= 0xFFFF;
                for (p = &graph_mem[offset1], p2 = &graph_mem[0x10000]; p<p2; p++)
                    *p = cur_color;
                /* select segment */
                port_out(offset2 >> 16, SEG_SELECT);
                /* write color to pixels */
                offset2 &= 0xFFFF;
                for (p = &graph_mem[0], p2 = &graph_mem[offset2]; p<=p2; p++)
                    *p = cur_color;
              }
          }
          break;
    }
}


void vga_drawbox (int x1, int y1, int x2, int y2)
{
    /* we may assume 0 <= x1 <= x2 and 0 <= y1 <= y2 */
    int y;
    for (y = y1; y <= y2; y++)
        vga_drawhline(x1,x2,y);
}


void vga_drawline (int x1, int y1, int x2, int y2)
{
    int dx = x2 - x1;
    int dy = y2 - y1;
    int ax = ABS(dx) << 1;
    int ay = ABS(dy) << 1;
    int sx = (dx >= 0) ? 1 : -1;
    int sy = (dy >= 0) ? 1 : -1;

    int x  = x1;
    int y  = y1;

    if (ax > ay) {
        int d = ay - (ax >> 1);
        while (x != x2) {
            vga_drawpixel(x, y);

            if (d > 0 || (d == 0 && sx == 1)) {
                y += sy;
                d -= ax;
            }
            x += sx;
            d += ay;
        }
    } else {
        int d = ax - (ay >> 1);
        while (y != y2) {
            vga_drawpixel(x, y);

            if (d > 0 || (d == 0 && sy == 1)) {
                x += sx;
                d -= ay;
            }
            y += sy;
            d += ax;
        }
    }
    vga_drawpixel(x, y);
}


int vga_getxdim (void)
{
    return cur_info.xdim;
}


int vga_getydim (void)
{
    return cur_info.ydim;
}


int vga_getcolors (void)
{
    return cur_info.colors;
}


# ============================================================================ #


int gr_init (sintL width, sintL height, sintL colors)
{
    int mode = TEXT;

    if (vga_hasmode(G320x200x16))
      { mode = G320x200x16; }
    if (colors <= 16)
      { # choose a 16-color mode if possible
        if (width > 320)
          { if (vga_hasmode(G640x200x16))
              { mode = G640x200x16; }
            if (height > 200 && vga_hasmode(G640x350x16))
              { mode = G640x350x16; }
            if (height > 350 && vga_hasmode(G640x480x16))
              { mode = G640x480x16; }
          }
          else
          { if (height > 200 && vga_hasmode(G320x240x256))
              { mode = G320x240x256; }
            if (height > 240 && vga_hasmode(G320x400x256))
              { mode = G320x400x256; }
            if (height > 400 && vga_hasmode(G360x480x256))
              { mode = G360x480x256; }
            if (width > 360 && vga_hasmode(G640x480x16))
              { mode = G640x480x16; }
      }   }
      else
      { # choose a 256-color mode
        if (vga_hasmode(G320x200x256))
          { mode = G320x200x256; }
        if (height > 200 && vga_hasmode(G320x240x256))
          { mode = G320x240x256; }
        if (height > 240 && vga_hasmode(G320x400x256))
          { mode = G320x400x256; }
        if ((width > 320 || height > 400) && vga_hasmode(G360x480x256))
          { mode = G360x480x256; }
        if (width > 360 && vga_hasmode(G640x480x256))
          { mode = G640x480x256; }
      }
    if ((width > 640 || height > 480) && vga_hasmode(G800x600x256))
      { mode = G800x600x256; }
    if ((width > 800 || height > 600) && vga_hasmode(G1024x768x256))
      { mode = G1024x768x256; }

    if (mode == TEXT)
      return -1;

    flip_mode = TEXT;
    if (vga_setmode(mode) < 0)
      { OS_error(); }

    return 0;
}

void gr_show (void)
{
    if (cur_mode == TEXT)
      { switch_graphics_mode();
        if (cur_mode == TEXT)
          { fehler(error,
                   DEUTSCH ? "Grafik nicht initialisiert." :
                   ENGLISH ? "graphics not initialized" :
                   FRANCAIS ? "Système graphique non initialisé." :
                   ""
                  );
      }   }
}

static struct named_color mono_colors []
  = { {  0, "BLACK" },
      { 15, "WHITE" },
      { 0,  NULL    }
    };
static struct named_color EGA_colors []
  = { {  0, "BLACK"         },
      {  1, "BLUE"          },
      {  2, "GREEN"         },
      {  3, "CYAN"          },
      {  4, "RED"           },
      {  5, "MAGENTA"       },
      {  6, "BROWN"         },
      {  7, "LIGHT-GRAY"    },
      {  8, "DARK-GRAY"     },
      {  9, "LIGHT-BLUE"    },
      { 10, "LIGHT-GREEN"   },
      { 11, "LIGHT-CYAN"    },
      { 12, "LIGHT-RED"     },
      { 13, "LIGHT-MAGENTA" },
      { 14, "YELLOW"        },
      { 15, "WHITE"         },
      { 0,  NULL            }
    };
static struct named_color VGA_colors []
  = { {  0, "BLACK"         },
      {  1, "DARK-BLUE"     },
      {  2, "DARK-GREEN"    },
      {  3, "DARK-CYAN"     },
      {  4, "DARK-RED"      },
      {  5, "DARK-MAGENTA"  },
      {  9, "BLUE"          },
      { 10, "GREEN"         },
      { 11, "CYAN"          },
      { 12, "RED"           },
      { 13, "MAGENTA"       },
      { 14, "YELLOW"        },
      { 15, "WHITE"         },
      { 43, "BROWN"         }, # or 66
      { 26, "DARK-GRAY"     },
      { 29, "LIGHT-GRAY"    },
      { 0,  NULL            }
    };

struct named_color * gr_colors (void)
{
    switch (cur_info.colors)
      { case 2: return &!mono_colors;
        case 16: return &!EGA_colors;
        case 256: return &!VGA_colors;
        default: NOTREACHED
      }
}

#define gr_xdim  cur_info.xdim
#define gr_ydim  cur_info.ydim

int gr_get (sintL x, sintL y)
{
    struct dot_args args;
    gr_show();
    args.x = x; args.y = y;
    if (dot_clipping(&cur_clip,&args))
      return vga_getpixel(args.x,args.y);
      else
      return 0;
}

void gr_dot (sintL color, sintL x, sintL y)
{
    struct dot_args args;
    gr_show();
    args.x = x; args.y = y;
    if (color >= 0 && color < cur_info.colors)
      if (dot_clipping(&cur_clip,&args))
        { if (!(color == cur_color)) vga_setcolor(color);
          vga_drawpixel(args.x,args.y);
        }
}

void gr_box (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    struct box_args args;
    gr_show();
    args.xa = x1; args.ya = y1; args.xb = x2; args.yb = y2;
    if (color >= 0 && color < cur_info.colors)
      if (box_clipping(&cur_clip,&args))
        { if (!(color == cur_color)) vga_setcolor(color);
          vga_drawbox(args.xa,args.ya,args.xb,args.yb);
        }
}

void gr_clear (sintL color)
{
    gr_show();
    if (color >= 0 && color < cur_info.colors)
      { if (color==0)
          { vga_clear(); }
          else
          { if (!(color == cur_color)) vga_setcolor(color);
            vga_drawbox(cur_clip.x1,cur_clip.y1,cur_clip.x2,cur_clip.y2);
      }   }
}

void gr_line (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    struct line_args args;
    gr_show();
    args.xa = x1; args.ya = y1; args.xb = x2; args.yb = y2;
    if (color >= 0 && color < cur_info.colors)
      if (line_clipping(&cur_clip,&args))
        { if (!(color == cur_color)) vga_setcolor(color);
          vga_drawline(args.xa,args.ya,args.xb,args.yb);
        }
}

#endif # EMUNIX_PORTABEL

# Painting a text string.

typedef uint8 fontchar_8_16 [16];
static fontchar_8_16 font [256] = {
#ifdef ISOLATIN_CHS
/* This was produced using the command
 * hexdump -e '"/" "* %03.3_ax *" "/  {" 15/1 "0x%02X," 1/1 "0x%02X" "},\n"' /usr/lib/kbd/consolefonts/latin | sed -e 's/0 / /g'
 */
/* 00 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 01 */  {0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00},
/* 02 */  {0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00},
/* 03 */  {0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00},
/* 04 */  {0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00},
/* 05 */  {0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 06 */  {0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 07 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 08 */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
/* 09 */  {0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00},
/* 0a */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF},
/* 0b */  {0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
/* 0c */  {0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00},
/* 0d */  {0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00},
/* 0e */  {0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00},
/* 0f */  {0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00},
/* 10 */  {0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00},
/* 11 */  {0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
/* 12 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00},
/* 13 */  {0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00},
/* 14 */  {0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00},
/* 15 */  {0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00},
/* 16 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00},
/* 17 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00},
/* 18 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* 19 */  {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00},
/* 1a */  {0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1b */  {0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1c */  {0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1d */  {0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1e */  {0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00},
/* 1f */  {0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00},
/* 20 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 21 */  {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 22 */  {0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 23 */  {0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00},
/* 24 */  {0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00},
/* 25 */  {0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00},
/* 26 */  {0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 27 */  {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 28 */  {0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
/* 29 */  {0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00},
/* 2a */  {0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2b */  {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2c */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00},
/* 2d */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2e */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 2f */  {0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00},
/* 30 */  {0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 31 */  {0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
/* 32 */  {0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 33 */  {0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 34 */  {0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
/* 35 */  {0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 36 */  {0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 37 */  {0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
/* 38 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 39 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
/* 3a */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
/* 3b */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00},
/* 3c */  {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00},
/* 3d */  {0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 3e */  {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},
/* 3f */  {0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 40 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00},
/* 41 */  {0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 42 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00},
/* 43 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00},
/* 44 */  {0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
/* 45 */  {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
/* 46 */  {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 47 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00},
/* 48 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 49 */  {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 4a */  {0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
/* 4b */  {0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 4c */  {0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
/* 4d */  {0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 4e */  {0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 4f */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 50 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 51 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00},
/* 52 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 53 */  {0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 54 */  {0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 55 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 56 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00},
/* 57 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00},
/* 58 */  {0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 59 */  {0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 5a */  {0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 5b */  {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},
/* 5c */  {0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
/* 5d */  {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},
/* 5e */  {0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 5f */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},
/* 60 */  {0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 61 */  {0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 62 */  {0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00},
/* 63 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 64 */  {0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 65 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 66 */  {0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 67 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00},
/* 68 */  {0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 69 */  {0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 6a */  {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00},
/* 6b */  {0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 6c */  {0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 6d */  {0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00},
/* 6e */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00},
/* 6f */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 70 */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00},
/* 71 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00},
/* 72 */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 73 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 74 */  {0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00},
/* 75 */  {0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 76 */  {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00},
/* 77 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00},
/* 78 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00},
/* 79 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00},
/* 7a */  {0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 7b */  {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00},
/* 7c */  {0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* 7d */  {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00},
/* 7e */  {0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 7f */  {0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00},
/* 80 */  {0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 81 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 82 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 83 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 84 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 85 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 86 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 87 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 88 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 89 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 8a */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 8b */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 8c */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 8d */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 8e */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 8f */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* 90 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00},
/* 91 */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 92 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 93 */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6F,0x60,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 94 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 95 */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 96 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x60,0x6F,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 97 */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6F,0x60,0x6F,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 98 */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x0C,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 99 */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0xEC,0x0C,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 9a */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 9b */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0xEF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 9c */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x0C,0xEC,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 9d */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0xEC,0x0C,0xEC,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 9e */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xEF,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* 9f */  {0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0xEF,0x00,0xEF,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C},
/* a0 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xFE,0x00,0x00,0x00,0x00},
/* a1 */  {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00},
/* a2 */  {0x00,0x00,0x00,0x00,0x10,0x7C,0xD6,0xD0,0xD0,0xD0,0xD6,0x7C,0x10,0x00,0x00,0x00},
/* a3 */  {0x00,0x00,0x38,0x6C,0x60,0x60,0xF0,0x60,0x60,0x66,0xF6,0x6C,0x00,0x00,0x00,0x00},
/* a4 */  {0x00,0x00,0x00,0x00,0xC6,0x7C,0x6C,0x6C,0x7C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00},
/* a5 */  {0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* a6 */  {0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* a7 */  {0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00},
/* a8 */  {0x00,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* a9 */  {0x00,0x00,0x7E,0xC3,0x99,0xA5,0xA1,0xA5,0x99,0xC3,0x7E,0x00,0x00,0x00,0x00,0x00},
/* aa */  {0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* ab */  {0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00},
/* ac */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00},
/* ad */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* ae */  {0x00,0x00,0x7E,0xC3,0xB9,0xA5,0xB9,0xA5,0xA5,0xC3,0x7E,0x00,0x00,0x00,0x00,0x00},
/* af */  {0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b0 */  {0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b1 */  {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x7E,0x00,0x00,0x00,0x00},
/* b2 */  {0x38,0x6C,0x18,0x30,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b3 */  {0x38,0x6C,0x18,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b4 */  {0x00,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b5 */  {0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xF6,0xC0,0xC0,0xC0,0x00},
/* b6 */  {0x00,0x00,0x7F,0xF6,0xF6,0x76,0x36,0x36,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x00},
/* b7 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* b8 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x6C,0x38,0x00},
/* b9 */  {0x30,0x70,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* ba */  {0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* bb */  {0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00},
/* bc */  {0x00,0x60,0xE0,0x66,0x6C,0x18,0x36,0x6E,0xDE,0x36,0x7E,0x06,0x06,0x00,0x00,0x00},
/* bd */  {0x00,0x60,0xE0,0x66,0x6C,0x18,0x30,0x60,0xDC,0x36,0x0C,0x18,0x3E,0x00,0x00,0x00},
/* be */  {0x00,0xE0,0x30,0x66,0x3C,0xF8,0x36,0x6E,0xDE,0x36,0x7E,0x06,0x06,0x00,0x00,0x00},
/* bf */  {0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x30,0x60,0xC6,0xC6,0x7C,0x00,0x00},
/* c0 */  {0x60,0x30,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c1 */  {0x0C,0x18,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c2 */  {0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c3 */  {0x76,0xDC,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c4 */  {0x00,0x6C,0x6C,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c5 */  {0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* c6 */  {0x00,0x00,0x3E,0x78,0xD8,0xD8,0xFC,0xD8,0xD8,0xD8,0xD8,0xDE,0x00,0x00,0x00,0x00},
/* c7 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x66,0x3C,0x00},
/* c8 */  {0x60,0x30,0x18,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00},
/* c9 */  {0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00},
/* ca */  {0x10,0x38,0x6C,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00},
/* cb */  {0x00,0x6C,0x6C,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00},
/* cc */  {0x60,0x30,0x18,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* cd */  {0x06,0x0C,0x18,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* ce */  {0x18,0x3C,0x66,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* cf */  {0x00,0x66,0x66,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* d0 */  {0x00,0x00,0xF8,0x6C,0x66,0x66,0xF6,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
/* d1 */  {0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* d2 */  {0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* d3 */  {0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* d4 */  {0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* d5 */  {0x00,0x76,0xDC,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* d6 */  {0x00,0x6C,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* d7 */  {0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
/* d8 */  {0x00,0x00,0x7E,0xC6,0xCE,0xCE,0xDE,0xF6,0xE6,0xE6,0xC6,0xFC,0x00,0x00,0x00,0x00},
/* d9 */  {0x60,0x30,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* da */  {0x0C,0x18,0x30,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* db */  {0x10,0x38,0x6C,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* dc */  {0x00,0x6C,0x6C,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* dd */  {0x06,0x0C,0x18,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* de */  {0x00,0x00,0xF0,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x60,0xF0,0x00,0x00,0x00,0x00},
/* df */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xCC,0xC6,0xC6,0xC6,0xD6,0xDC,0x80,0x00,0x00,0x00},
/* e0 */  {0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e1 */  {0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e2 */  {0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e3 */  {0x00,0x00,0x76,0xDC,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e4 */  {0x00,0x00,0x6C,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e5 */  {0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* e6 */  {0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0x1B,0x7F,0xD8,0xDB,0x7E,0x00,0x00,0x00,0x00},
/* e7 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x18,0x6C,0x38,0x00},
/* e8 */  {0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* e9 */  {0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* ea */  {0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* eb */  {0x00,0x00,0x6C,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* ec */  {0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* ed */  {0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* ee */  {0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* ef */  {0x00,0x00,0x6C,0x6C,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* f0 */  {0x00,0x78,0x30,0x78,0x0C,0x7E,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f1 */  {0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00},
/* f2 */  {0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f3 */  {0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f4 */  {0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f5 */  {0x00,0x00,0x76,0xDC,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f6 */  {0x00,0x00,0x6C,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* f7 */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
/* f8 */  {0x00,0x00,0x00,0x00,0x00,0x7E,0xCE,0xDE,0xFE,0xF6,0xE6,0xFC,0x00,0x00,0x00,0x00},
/* f9 */  {0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* fa */  {0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* fb */  {0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* fc */  {0x00,0x00,0xCC,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* fd */  {0x00,0x0C,0x18,0x30,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00},
/* fe */  {0x00,0x00,0xF0,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,0x00},
/* ff */  {0x00,0x00,0x6C,0x6C,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00},
#endif
#ifdef IBMPC_CHS
/* This was produced using the command
 * hexdump -e '"/" "* %03.3_ax *" "/  {" 15/1 "0x%02X," 1/1 "0x%02X" "},\n"' /usr/lib/kbd/consolefonts/default | sed -e 's/0 / /g'
 */
/* 00 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 01 */  {0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00},
/* 02 */  {0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00},
/* 03 */  {0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00},
/* 04 */  {0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00},
/* 05 */  {0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 06 */  {0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 07 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 08 */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
/* 09 */  {0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00},
/* 0a */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF},
/* 0b */  {0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
/* 0c */  {0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00},
/* 0d */  {0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00},
/* 0e */  {0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00},
/* 0f */  {0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00},
/* 10 */  {0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00},
/* 11 */  {0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
/* 12 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00},
/* 13 */  {0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00},
/* 14 */  {0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00},
/* 15 */  {0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00},
/* 16 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00},
/* 17 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00},
/* 18 */  {0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* 19 */  {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00},
/* 1a */  {0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1b */  {0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1c */  {0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1d */  {0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00},
/* 1e */  {0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00},
/* 1f */  {0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00},
/* 20 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 21 */  {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 22 */  {0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 23 */  {0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00},
/* 24 */  {0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00},
/* 25 */  {0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00},
/* 26 */  {0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 27 */  {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 28 */  {0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
/* 29 */  {0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00},
/* 2a */  {0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2b */  {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2c */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00},
/* 2d */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 2e */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 2f */  {0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00},
/* 30 */  {0x00,0x00,0x7C,0xC6,0xC6,0xCE,0xDE,0xF6,0xE6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 31 */  {0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
/* 32 */  {0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 33 */  {0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 34 */  {0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
/* 35 */  {0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 36 */  {0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 37 */  {0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
/* 38 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 39 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
/* 3a */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
/* 3b */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00},
/* 3c */  {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00},
/* 3d */  {0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 3e */  {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},
/* 3f */  {0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
/* 40 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00},
/* 41 */  {0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 42 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00},
/* 43 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00},
/* 44 */  {0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
/* 45 */  {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
/* 46 */  {0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 47 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00},
/* 48 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 49 */  {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 4a */  {0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
/* 4b */  {0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 4c */  {0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
/* 4d */  {0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 4e */  {0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 4f */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 50 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 51 */  {0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00},
/* 52 */  {0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 53 */  {0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 54 */  {0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 55 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 56 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00},
/* 57 */  {0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00},
/* 58 */  {0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 59 */  {0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 5a */  {0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 5b */  {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},
/* 5c */  {0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
/* 5d */  {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},
/* 5e */  {0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 5f */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},
/* 60 */  {0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 61 */  {0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 62 */  {0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00},
/* 63 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 64 */  {0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 65 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 66 */  {0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 67 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00},
/* 68 */  {0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 69 */  {0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 6a */  {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00},
/* 6b */  {0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00},
/* 6c */  {0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 6d */  {0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00},
/* 6e */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00},
/* 6f */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 70 */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00},
/* 71 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00},
/* 72 */  {0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
/* 73 */  {0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 74 */  {0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00},
/* 75 */  {0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 76 */  {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00},
/* 77 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00},
/* 78 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00},
/* 79 */  {0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00},
/* 7a */  {0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* 7b */  {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00},
/* 7c */  {0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* 7d */  {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00},
/* 7e */  {0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* 7f */  {0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00},
/* 80 */  {0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00},
/* 81 */  {0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 82 */  {0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 83 */  {0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 84 */  {0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 85 */  {0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 86 */  {0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 87 */  {0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00},
/* 88 */  {0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 89 */  {0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 8a */  {0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 8b */  {0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 8c */  {0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 8d */  {0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* 8e */  {0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 8f */  {0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* 90 */  {0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00},
/* 91 */  {0x00,0x00,0x00,0x00,0x6C,0xFE,0xB2,0x32,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00},
/* 92 */  {0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00},
/* 93 */  {0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 94 */  {0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 95 */  {0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 96 */  {0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 97 */  {0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* 98 */  {0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00},
/* 99 */  {0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 9a */  {0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* 9b */  {0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00},
/* 9c */  {0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00},
/* 9d */  {0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* 9e */  {0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00},
/* 9f */  {0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00},
/* a0 */  {0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* a1 */  {0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
/* a2 */  {0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* a3 */  {0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
/* a4 */  {0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00},
/* a5 */  {0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* a6 */  {0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* a7 */  {0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* a8 */  {0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
/* a9 */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00},
/* aa */  {0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00},
/* ab */  {0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00},
/* ac */  {0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00},
/* ad */  {0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00},
/* ae */  {0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00},
/* af */  {0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00},
/* b0 */  {0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44},
/* b1 */  {0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA},
/* b2 */  {0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77},
/* b3 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* b4 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* b5 */  {0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* b6 */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* b7 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* b8 */  {0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* b9 */  {0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* ba */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* bb */  {0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* bc */  {0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* bd */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* be */  {0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* bf */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* c0 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* c1 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* c2 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* c3 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* c4 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* c5 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* c6 */  {0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* c7 */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* c8 */  {0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* c9 */  {0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* ca */  {0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* cb */  {0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* cc */  {0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* cd */  {0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* ce */  {0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* cf */  {0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* d0 */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* d1 */  {0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* d2 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* d3 */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* d4 */  {0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* d5 */  {0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* d6 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* d7 */  {0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36},
/* d8 */  {0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* d9 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* da */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* db */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
/* dc */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
/* dd */  {0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0},
/* de */  {0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F},
/* df */  {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* e0 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00},
/* e1 */  {0x00,0x00,0x78,0xCC,0xCC,0xCC,0xD8,0xCC,0xC6,0xC6,0xC6,0xCC,0x00,0x00,0x00,0x00},
/* e2 */  {0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00},
/* e3 */  {0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00},
/* e4 */  {0x00,0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00},
/* e5 */  {0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00},
/* e6 */  {0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00,0x00,0x00},
/* e7 */  {0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
/* e8 */  {0x00,0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00},
/* e9 */  {0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00},
/* ea */  {0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00},
/* eb */  {0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00},
/* ec */  {0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00},
/* ed */  {0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00},
/* ee */  {0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00},
/* ef */  {0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
/* f0 */  {0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00},
/* f1 */  {0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00},
/* f2 */  {0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00},
/* f3 */  {0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00},
/* f4 */  {0x00,0x00,0x0E,0x1B,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18},
/* f5 */  {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00},
/* f6 */  {0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
/* f7 */  {0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00},
/* f8 */  {0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* f9 */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* fa */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* fb */  {0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00},
/* fc */  {0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* fd */  {0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
/* fe */  {0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00},
/* ff */  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
#endif
};

void gr_text (sintL color, sintL* x, sintL* y, sintL dir, uintB* charptr, uintL count)
{
    var sintL dx, dy, x1, y1;
    switch (dir)
      { case 0: dx = 1; dy = 0; break;
        case 90: dx = 0; dy = -1; break;
        case 180: dx = -1; dy = 0; break;
        case 270: dx = 0; dy = 1; break;
        default: return;
      }
    x1 = *x; y1 = *y;
    dotimesL(count,count,
      { var uintB c = *charptr++;
        var fontchar_8_16* f = &font[c];
        var uintL i;
        var uintL j;
        var sintL x2;
        var sintL y2;
        for (i = 0; i < 8; i++, x1 += dx, y1 += dy)
          for (j = 0, x2 = x1, y2 = y1; j < 16; j++, x2 -= dy, y2 += dx)
            if ((*f)[j] & bit(7-i))
              gr_dot(color,x2,y2);
      });
    *x = x1; *y = y1;
}

#endif # GRAPHICS_SWITCH

#ifdef GRAPHICS_X

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

static Display* display = NULL;  # X server connection
static int screen;               # the default screen number
#define COLOR_WHITE  WhitePixel(display,screen)
#define COLOR_BLACK  BlackPixel(display,screen)
static Window window;            # window ID
static int x_xdim;               # width of window
static int x_ydim;               # height of window
static GC draw_gc;               # graphics context for drawing
static sintL draw_color;         # current drawing color

int x_fatal_error_handler (Display* display)
{
    fehler(error,
           "X I/O error"
          );
}

int x_init (sintL width, sintL height, sintL colors)
{
    # Open X display:
    if (display==NULL)
      { display = XOpenDisplay(NULL);
        if (display==NULL)
          { return -1; }
      }
    # Get its default screen number:
    screen = DefaultScreen(display);
    # Set the error handler:
    XSetIOErrorHandler(&x_fatal_error_handler);

    # Open the window:
    {   XFontStruct* fontstruct;   # font descriptor
        XSizeHints*  sizehints;    # size hints for window manager
        XWMHints*    wmhints;      # hints for window manager

        # Load default font:
        fontstruct = XLoadQueryFont(display,"fixed");
        if (fontstruct==NULL)
          { return -1; }

        # Select colors:
        {
            #define NUMCOLORS  16
            static char* colorname [NUMCOLORS] =
              { "WHITE",  "BLACK",    "PINK",    "RED",
                "ORANGE", "YELLOW",   "GREEN",   "TURQUOISE",
                "BLUE",   "LAVENDER", "MAGENTA", "PURPLE",
                "GOLD",   "BROWN",    "CYAN",    "LIGHT GRAY"
              };
            Xcolor xcolor [NUMCOLORS];  # the colors
            Xcolor unused_color;
            int numcolors = (colors <= 2 ? 2 : NUMCOLORS);
            int i;
            for (i = 0; i < numcolors; i++)
                XAllocNamedColor (display, DefaultColormap(display,screen),
                                           colorname[i],
                                           &xcolor[i],   # color on screen
                                           &unused_color # exact color: unused
                                 );
        }

        # Size hints for the Window Manager:
        sizehints = XAllocSizeHints();
        if (sizehints==NULL)
          return -1;
        sizehints->flags = PSize | PPosition;
        # size: width, height
        sizehints->width = width; sizehints->height = height;
        # position: centered
        sizehints->x = DisplayWidth(display,screen) - sizehints->width;
        if (sizehints->x < 0) { sizehints->x = 0; }
        sizehints->x >>= 1;
        sizehints->y = DisplayHeight(display,screen) - sizehints->height;
        if (sizehints->y < 0) { sizehints->y = 0; }
        sizehints->y >>= 1;

        # Get a window.
        # Background will be COLOR_WHITE, Foreground will be COLOR_BLACK.
        window = XCreateSimpleWindow (display, RootWindow(display,screen),
                                      sizehints->x, sizehints->y,
                                      sizehints->width, sizehints->height,
                                      1, # border width
                                      COLOR_BLACK, # border color
                                      COLOR_WHITE  # background color
                                     );

        # Attach a label to the window.
        # XSetStandardProperties oder XSetWMProperties ??
        XSetStandardProperties(display,window,
                               "CLISP graphics", # window label
                               "CLISP graphics", # icon label
                               None,
                               NULL, 0, # argv and argc
                               sizehints # size hints
                              );

        # window manager hints
        wmhints = XAllocWMHints();
        if (wmhints==NULL)
          { return -1; }
        wmhints->flags = InputHint | StateHint;
        wmhints->input = FALSE; wmhints->state = NormalState;
        XSetWMHints(display,window, wmhints);

        # Set up colors.
        {   var XSetWindowAttributes xswa;
            xswa.colormap = DefaultColormap(display,screen);
            XChangeWindowAttributes (display,window, CWColormap, &xswa);
        }

        # Set up graphics context.
        {   var XGCValues gcv;
            gcv.font = fontstruct->fid;
            gcv.background = COLOR_WHITE;
            gcv.foreground = draw_color = COLOR_BLACK;
            gcv.plane_mask = AllPlanes;
            draw_gc = XCreateGC (display,window,
                                 GCPlaneMask | GCFont | GCForeground | GCBackground,
                                 &gcv
                                );
        }

        # Specify the events we are interested in.
        XSelectInput (display,window, StructureNotifyMask | ExposureMask);

        # Finally, make the window visible.
        XMapWindow (display,window);

        # Don't laugh, but we have to wait until the window really gets visible.
        loop # a small event-dispatch loop
          { var XEvent event;
            XWindowEvent (display,window, StructureNotifyMask, &event);
            if (event.type == MapNotify)
              break;
          }

        # Clear the window.
        XClearWindow(display,window);

    }
    return 0;
}

# NB: XCloseDisplay(display); ist nicht nötig. Das erledigt der Window-Manager
# von selbst, wenn unser Programm beendet wird.
# XFreeGC(display,draw_gc);
# XUnloadFont(display,fontstruct->fid);
# XCloseDisplay(display);

void x_show (void)
{ # Do nothing, even if the window is iconified.
}

void x_dot (sintL color, sintL x, sintL y)
{
    if (!(color==draw_color))
      { XSetForeground(display,draw_gc,color); draw_color = color; }
    XDrawPoint(display,window, draw_gc, x,y);
}

void x_box (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    if (!(color==draw_color))
      { XSetForeground(display,draw_gc,color); draw_color = color; }
    if (x1 > x2) swap(sintL,x1,x2);
    if (y1 > y2) swap(sintL,y1,y2);
    XDrawRectangle(display,window, draw_gc, x1,y1, x2-x1,y2-y1);
}

void x_clear (sintL color)
{
    if (color == COLOR_WHITE)
      { XClearWindow(display,window); }
      else
      ??
}

void x_line (sintL color, sintL x1, sintL y1, sintL x2, sintL y2)
{
    if (!(color==draw_color))
      { XSetForeground(display,draw_gc,color); draw_color = color; }
    XDrawLine(display,window, draw_gc, x1,y1, x2,y2);
}

Fehlen:
# x_colors()                    liefert einen Array von benannten Farben.
# x_clear(color);               löscht den gesamten Grafik-Bildschirm.
# x_get(x,y)                    liefert die Farbe des Punktes (x,y)

x_text() { XDrawString (display,window, ...) }

#endif # GRAPHICS_X

#ifdef GRAPHICS_SUN

#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include <suntool/textsw.h>
#include <suntool/panel.h>

static Frame screen;
static Canvas canvas;
static Pixwin* pw;
static Pixfont* font;

void sun_init (sintL width, sintL height, sintL colors)
{
    screen = window_create (NULL,
                            FRAME,
                            FRAME_LABEL, "CLISP graphics",
                          # WIN_ERROR_MSG, "must be in SunView/SunTools",
                            0);
    canvas = window_create (screen,
                            CANVAS,
                            WIN_WIDTH, width,
                            WIN_HEIGHT, height,
                            0);
    window_fit(screen);
    pw = canvas_pixwin(canvas);
    font = pw_pfsysopen();
    pw_vector(...);
    pw_char(pw,?,?,PIX_SRC|PIX_DST,font,ch);
    window_main_loop(screen);
}

#endif # GRAPHICS_SUN


# Lisp-Funktionen:

# (SYS::GRAPH-INIT [width [height [colors]]])
LISPFUN(gr_init,0,3,norest,nokey,0,NIL)
{ { var object width = STACK_2;
    var object height = STACK_1;
    var object colors = STACK_0;
    var sintL w = (eq(width,unbound) ? 400 : I_to_L(width));
    var sintL h = (eq(height,unbound) ? 3*(w>>2) : I_to_L(height));
    var sintL c = (eq(colors,unbound) ? 16 : I_to_L(colors));
    begin_system_call();
    if (gr_init(w, h, c) < 0)
      { pushSTACK(S(gr_init));
        fehler(error,
               DEUTSCH ? "~: Kann nicht in Grafik-Modus schalten." :
               ENGLISH ? "~: cannot switch to graphics mode" :
               FRANCAIS ? "~ : Impossible d'arriver au mode graphique." :
               ""
              );
      }
    end_system_call();
    skipSTACK(3);
  }
  # Aliste der Farben als Wert:
  { var struct named_color * p = gr_colors();
    var uintC count = 0;
    while (p->name) { p++; count++; }
    pushSTACK(NIL);
    dotimesC(count,count,
      {  p--;
         pushSTACK(allocate_cons());
         pushSTACK(allocate_cons());
       { var object name = intern_keyword(asciz_to_string(p->name));
         var object acons = popSTACK();
         Car(acons) = name; Cdr(acons) = fixnum(p->color);
        {var object lcons = popSTACK();
         Car(lcons) = acons; Cdr(lcons) = STACK_0;
         STACK_0 = lcons;
      }}});
    value1 = popSTACK(); mv_count=1;
} }

# (SYS::GRAPH-SHOW)
LISPFUNN(gr_show,0)
{ begin_system_call();
  gr_show();
  end_system_call();
  value1 = NIL; mv_count=0;
}

# (SYS::GRAPH-CLEAR [color])
LISPFUN(gr_clear,0,1,norest,nokey,0,NIL)
{ var object color = popSTACK();
  var sintL c = (eq(color,unbound) ? 0 : I_to_L(color));
  begin_system_call();
  gr_clear(c);
  end_system_call();
  value1 = NIL; mv_count=0;
}

# (SYS::GRAPH-DIMS)
LISPFUNN(gr_dims,0)
{ value1 = fixnum(gr_xdim); value2 = fixnum(gr_ydim); mv_count=2; }

# (SYS::GRAPH-DOT x y [color])
LISPFUN(gr_dot,2,1,norest,nokey,0,NIL)
{ var object color = STACK_0;
  var sintL x = I_to_L(STACK_2);
  var sintL y = I_to_L(STACK_1);
  if (eq(color,unbound))
    { value1 = fixnum(gr_get(x,y)); }
    else
    { var sintL c = I_to_L(color);
      begin_system_call();
      gr_dot(c,x,y);
      end_system_call();
      value1 = color;
    }
  mv_count=1;
  skipSTACK(3);
}

# (SYS::GRAPH-BOX x1 y1 x2 y2 color)
LISPFUNN(gr_box,5)
{ var object color = STACK_0;
  var sintL x1 = I_to_L(STACK_4);
  var sintL y1 = I_to_L(STACK_3);
  var sintL x2 = I_to_L(STACK_2);
  var sintL y2 = I_to_L(STACK_1);
  var sintL c = I_to_L(color);
  begin_system_call();
  gr_box(c,x1,y1,x2,y2);
  end_system_call();
  value1 = NIL; mv_count=0;
  skipSTACK(5);
}

# (SYS::GRAPH-LINE x1 y1 x2 y2 color)
LISPFUNN(gr_line,5)
{ var object color = STACK_0;
  var sintL x1 = I_to_L(STACK_4);
  var sintL y1 = I_to_L(STACK_3);
  var sintL x2 = I_to_L(STACK_2);
  var sintL y2 = I_to_L(STACK_1);
  var sintL c = I_to_L(color);
  begin_system_call();
  gr_line(c,x1,y1,x2,y2);
  end_system_call();
  value1 = NIL; mv_count=0;
  skipSTACK(5);
}

# (SYS::GRAPH-TEXT x y dir string color)
LISPFUNN(gr_text,5)
{ var object color = STACK_0;
  var sintL x = I_to_L(STACK_4);
  var sintL y = I_to_L(STACK_3);
  var sintL dir = I_to_L(STACK_2);
  var sintL c = I_to_L(color);
  var uintL len;
  var uintB* charptr = unpack_string(STACK_1,&len);
  begin_system_call();
  gr_text(c,&x,&y,dir,charptr,len);
  end_system_call();
  pushSTACK(L_to_I(y)); value1 = L_to_I(x); value2 = popSTACK(); mv_count=2;
  skipSTACK(5);
}

#endif # GRAPHICS

