Logo Search packages:      
Sourcecode: xblast version File versions  Download package

graphics.c

/*
 * Program XBLAST V2.5.15 or higher
 * (C) by Oliver Vogel (e-mail: vogel@ikp.uni-koeln.de)
 * October 18, 1998
 * started August 1993
 *
 * File: graphics
 * graphics using X11 standard
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public Licence as by published
 * by the Free Software Foundation; either version 2; or (at your option)
 * any later version
 *
 * This program is distributed in the hope that it will entertaining,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: graphics.c,v 1.8 1999/10/03 09:41:44 xblast Exp $
 * $Log: graphics.c,v $
 * Revision 1.8  1999/10/03 09:41:44  xblast
 * bugfix from EPFL: some true color displays didn't work correctly
 *
 * Revision 1.7  1999/05/14 20:09:38  xblast
 * Bomb aniomation during init now with background
 * Too many player sprites initialized during init
 *
 * Revision 1.6  1999/04/02 18:34:41  xblast
 * #ifdef's für monochrome only version
 *
 * Revision 1.5  1999/04/02 14:22:28  xblast
 * ini_bombs now properly formatted
 *
 * Revision 1.4  1999/03/21 18:37:28  xblast
 * Bugfix: Wrong number of player-sprites initialzed in double-mode
 *
 * Revision 1.3  1999/03/21 13:44:20  xblast
 * Bugfix for XFree86?
 * - black and white mode gave strange results on color X-servers
 *
 * Revision 1.2  1998/10/18 12:30:04  xblast
 * Morphing Bomb extra
 *
 * Revision 1.1  1998/01/03 14:10:59  xblast
 * Initial revision
 *
 */

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Intrinsic.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#ifdef DEBUG
#include <time.h>
#endif


#define _GRAPHICS_C

#include "include.h"
#include "mytypes.h"
#include "const.h"
#include "image.h"
#include "graphics.h"
#include "setup.h"
#include "event.h"
#include "map.h"
#include "main.h"
#include "util.h"

#define BELL_VOLUME 80

#define QUIT_WITH_CONTROL_Q TRUE
#define USE_COPY_AREA FALSE

  /* Some constants */

#define NORMAL_EVENT_MASK ( ExposureMask | StructureNotifyMask | KeyPressMask \
                      | KeyReleaseMask )

/* 
 * local type defintions 
 */
typedef struct {
  Pixmap mask;
  Pixmap bits;
  unsigned width, height;
  int xoffset, yoffset;
} PlayerSpriteData ;

#ifndef MONO_XBLAST
typedef struct {
  unsigned short *red;
  unsigned short *green;
  unsigned short *blue;
} ColorTable;
#endif

/*
 * global variables
 */
ColorMode colorMode;
Display *dpy = NULL;

/*
 * local Variables 
 */
static Window win;
static Colormap cmap;
static Visual *def_visual;
static int def_depth;
static int bits_per_pixel;
static int white_pixel;
static int black_pixel;

static char *XBlastResName  = "xblast";
static char *XBlastResClass = "XBlast";

static Pixmap pix;
static Pixmap pix_block[MAX_BLOCK];
static Pixmap pix_bomb_mask[MAX_BOMBS][MAX_BOMB_ANIME];
static Pixmap pix_bomb_bits[MAX_BOMBS][MAX_BOMB_ANIME];
static Pixmap pix_expl_mask[MAX_EXPLOSION];
static Pixmap pix_expl_bits[MAX_EXPLOSION];
static Pixmap pix_expl_block[MAX_EXPLOSION];
static Pixmap pix_leds[2];
static Pixmap pix_score[MAX_SCORE_TILES];

static PlayerSpriteData sprite_data[MAX_PLAYER][MAX_ANIME];

static GC gc_frompix;
static GC gc_window;
static GC gc_clearpix;
static GC gc_drawblock;
static GC gc_addon;
static GC gc_sprite_mask;
static GC gc_sprite_bits;
static GC gc_text_black;
static GC gc_text_white;

static char *font_name[NUM_FONTS];
static XFontStruct *font_struct[NUM_FONTS];

static int winX,winY;
static int winW,winH;

static XRectangle xrec[MAZE_W*MAZE_H + STAT_W*STAT_H];
static XRectangle *xrec_max = xrec;

#ifndef MONO_XBLAST
static XBColorTriple col_triple[MAX_BLOCK];
#endif

static int iconified = FALSE;

static XBGraphicsSetup GfxSetup;

#ifndef MONO_XBLAST
static unsigned long rmask, gmask, bmask;
static int rbits, rshift;
static int gbits, gshift;
static int bbits, bshift;
static int rgb_color[6][6][6];

static int ini_bomb_anime = -1;
static int ini_bomb_count = 0;
static int ini_bomb_div;

#ifdef __STDC__
static void (*ppm_to_image) (unsigned char *ppm, int width, int height,
                       XImage *image);
static void (*rgb16_to_image) (unsigned short *rgb16, int width, int height,
                         XImage *image);
#else
static void (*ppm_to_image) ();
static void (*rgb16_to_image) ();
#endif
#endif


/*
 * color string constants
 */

static DisplayColor display_color;
static PlayerColor player_color [MAX_PLAYER];

/*
 * local protoptypes
 */


/* 
 * Local function : x_fatal 
 */

#ifdef __STDC__
static void 
x_fatal (char *text1, 
       char *text2)
#else
static void 
x_fatal (text1, text2)
     char *text1,*text2;
#endif
{
  fprintf(stderr, "ERROR: %s %s.\n", text1, text2);
  exit_prg(1);
}



/* 
 * Local function : x_warning 
 */

#ifdef __STDC__
static void 
x_warning (char *text1, 
         char *text2)
#else
static void 
x_warning (text1, text2)
     char *text1,*text2;
#endif
{
  fprintf(stderr,"WARNING: %s %s.\n", text1, text2);
}



#ifndef MONO_XBLAST
/*
 * local function alloc color
 */ 
#ifdef __STDC__
static int 
alloc_color (char *color_name,
           int subst)
#else
static int 
alloc_color (color_name, subst)
  char *color_name;
  int subst;
#endif
{
  XColor colorUsed, colorExact;

  /* get color from name */
  if ( (NULL == color_name) || 
      (! XParseColor(dpy, cmap, color_name, &colorExact) ) ) {
    x_warning("unknown color ", color_name ? color_name : "(null)");
    /* use substitute instead */
    return subst;
  }

  /* try to alloc color cell */
  colorUsed = colorExact;
  if (XAllocColor(dpy, cmap, &colorUsed) ) {
    return colorUsed.pixel;
  }
  /* if private colormap is in use return white */
  if (cmap != DefaultColormap(dpy, DefaultScreen(dpy) ) ) {
    return subst;
  }
  /* create private color map */
  cmap = XCopyColormapAndFree(dpy, cmap);
  XSetWindowColormap(dpy, win, cmap);
  /* alloc again */
  colorUsed = colorExact;
  if (XAllocColor(dpy, cmap, &colorUsed) ) {
    return colorUsed.pixel;
  }
  return subst;

}
#endif

#ifndef MONO_XBLAST
/* 
 * local function: alloc_color_or_white
 */
#ifdef __STDC__
static int 
alloc_color_or_white (char *color_name)
#else
static int 
alloc_color_or_white (color_name)
  char *color_name;
#endif
{
  return alloc_color(color_name, white_pixel);
}
#endif

#ifndef MONO_XBLAST
/* 
 * local function: alloc_color_or_white
 */
#ifdef __STDC__
static int 
alloc_color_or_black(char *color_name)
#else
static int 
alloc_color_or_black (color_name)
  char *color_name;
#endif
{
  return alloc_color(color_name, black_pixel);
}
#endif

#ifndef MONO_XBLAST
/*
 * local function: parse_color_or_white
 */
#ifdef __STDC__
static void
parse_color_or_white (XColor *color, 
                  char *name)
#else
static void
parse_color_or_white (color, name)
  XColor *color;
  char *name;
#endif
{
  if ( (NULL == name) || (! XParseColor(dpy, cmap, name, color) ) ) {
    x_warning("unknown color ", name ?  name : "(null)");
    /* use white instead */
    color->red = color->green = color->blue = (1<<16)-1; 
  }
}
#endif

#ifndef MONO_XBLAST
/*
 * local function: parse_color_or_white
 */
#ifdef __STDC__
static void
parse_color_or_gray (XColor *color, 
                  char *name)
#else
static void
parse_color_or_gray (color, name)
  XColor *color; 
  char *name;
#endif
{
  if ( (NULL == name) || (! XParseColor(dpy, cmap, name, color) ) ) {
    x_warning("unknown color ", name ?  name : "(null)");
    /* use white instead */
    color->red = color->green = color->blue = (1<<15)-1; 
  }
}
#endif

#ifndef MONO_XBLAST
/*
 * local function: parse_color_or_white
 */
#ifdef __STDC__
static void
parse_color_or_black (XColor *color, 
                  char *name)
#else
static void
parse_color_or_black (color, name)
  XColor *color;
  char *name;
#endif
{
  if ( (NULL == name) || (! XParseColor(dpy, cmap, name, color) ) ) {
    x_warning("unknown color ", name ?  name : "(null)");
    /* use white instead */
    color->red = color->green = color->blue = 0; 
  }
}
#endif

#ifndef MONO_XBLAST
/*
 * local function: create_color_table
 */
#ifdef __STDC__
static void
create_color_table (ColorTable *col_table,
                char *name) 
#else
static void
create_color_table (col_table, name) 
  ColorTable *col_table;
  char *name;
#endif
{
  unsigned i;
  unsigned short *ptr;
  XColor color;
  
  /* alloc data */
  if (NULL == (ptr = malloc(sizeof(unsigned short)*3*256))) {
    x_fatal ("Failed to alloc color table data", "");
  } 

  col_table->red   = ptr;
  col_table->green = ptr + 256;
  col_table->blue  = ptr + 512;

  /* parse color */
  parse_color_or_white (&color, name);
  
  /* build table */
  for (i=0; i<256; i++) {
    col_table->red[i]   = (unsigned short)((i*color.red)   >> 8);
    col_table->green[i] = (unsigned short)((i*color.green) >> 8);
    col_table->blue[i]  = (unsigned short)((i*color.blue)  >> 8);
  }
}
#endif

#ifndef MONO_XBLAST
/*
 * local function free_color_table;
 */
#ifdef __STDC__
static void
free_color_table (ColorTable *color)
#else
static void
free_color_table (color)
  ColorTable *color;
#endif
{
  free(color->red);
  color->red = color->green = color->blue = NULL;
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static void 
analyze_color_mask (unsigned long mask,
                int *bits,
                int *shift)
#else
static void 
analyze_color_mask (mask, bits, shift)
  unsigned long mask;
  int *bits;
  int *shift;
#endif
{
  *shift = 0;
  *bits = 0;

  if (mask) {
    while (0 == (mask % 2) ) {
      (*shift) ++;
      mask >>= 1;
    }
    while (1== (mask % 2) ){
      (*bits) ++;
      mask >>= 1;
    }
  }    
}
#endif


/*
 * local_function: read_bitmap
 */
#ifdef __STDC__
static Pixmap 
read_pbm_bitmap (char *path,
             char *filename)
#else
static Pixmap 
read_pbm_bitmap (path, filename)
     char *path, *filename;
#endif
{
  int width, height;
  unsigned char *pbm;
  Pixmap tmp;

  /* load ppm file */
  if (NULL == (pbm = read_pbm_file (path, filename, &width, &height) ) ) {
    x_warning("Failed to load bitmap",filename);
    return None;
  }

  /* create bitmap data */
  tmp = XCreateBitmapFromData (dpy, win, (char *)pbm, width, height);

  /* free ppm data */
  free(pbm);

  return tmp;
}     



/*
 * local_function: read_pbm_pixmap
 */
#ifdef __STDC__
static Pixmap 
read_pbm_black_white_map (char *path,
                    char *filename)
#else
static Pixmap 
read_pbm_black_white_map (path, filename)
  char *path, *filename;
#endif
{
  int width, height;
  unsigned char *pbm;
  Pixmap tmp;

  /* load ppm file */
  if (NULL == (pbm = read_pbm_file (path, filename, &width, &height) ) ) {
    x_warning("Failed to load bitmap",filename);
    return None;
  }

  /* create bitmap data */
  if (1 != def_depth) {
    tmp = XCreatePixmapFromBitmapData (dpy, win, (char *)pbm, width, height,
                               1, 0, 1);
  } else {
    tmp = XCreatePixmapFromBitmapData (dpy, win, (char *)pbm, width, height,
                               black_pixel, white_pixel, def_depth);
  }
  /* free ppm data */
  free(pbm);

  return tmp;
}     

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
ppm_to_image_rgb (unsigned char *ppm,
              int width, int height,
              XImage *image)
#else
static void
ppm_to_image_rgb (ppm, width, height, image)
  unsigned char *ppm;
  int width, height;
  XImage *image;
#endif
{
  int x, y, i;
  int pixel;
  int base[3], scale[3], shift[3], mask[3];
    
  base[0] = GfxSetup.rbase;
  base[1] = GfxSetup.gbase;
  base[2] = GfxSetup.bbase;

  scale[0] = 65535 - base[0];
  scale[1] = 65535 - base[1];
  scale[2] = 65535 - base[2];

  shift[0] = 16 - rshift - rbits ;
  shift[1] = 16 - gshift - gbits ;
  shift[2] = 16 - bshift - bbits ;

  mask[0] = rmask;
  mask[1] = gmask;
  mask[2] = bmask;

  for (y=0; y<height; y++) {
    for (x=0; x<width; x++) {
      /* calculate renormalized rgb values */
      pixel = 0;
      for (i=0; i<3; i++, ppm++) {
      /* EPFL: shift[0] or shift[2] can be positive or negative, depending of the colordepth and hardware */
      if (shift[i] > 0) {
        pixel |= ( ( (scale[i]*(*ppm))/255 + base[i]) >> shift[i] ) & mask[i];
      } else {
        pixel |= ( ( (scale[i]*(*ppm))/255 + base[i]) << -shift[i] ) & mask[i];
      }
      }
      XPutPixel(image, x, y, pixel);
    }
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
alloc_rgb_color (int red, int green, int blue)
#else
static void
alloc_rgb_color (red, green, blue)
  int red, green, blue;
#endif
{
#ifdef DEBUG
  static int num_rgb_colors = 0;
#endif

  /* alloc color */
  XColor colorUsed;
  
#ifdef DEBUG
  fprintf(stderr, "Allocating RGB color %d\n", ++ num_rgb_colors);
#endif
  
  /* default pixel is white */
  rgb_color[red][green][blue] = white_pixel;
  
  /* try to alloc a new color cell */
  colorUsed.red   = (65535-GfxSetup.rbase) * red   /5 
    + GfxSetup.rbase;
  colorUsed.green = (65535-GfxSetup.gbase) * green /5 
    + GfxSetup.gbase;
  colorUsed.blue  = (65535-GfxSetup.bbase) * blue  /5 
    + GfxSetup.bbase;
  colorUsed.flags = DoRed | DoGreen | DoBlue;
  if (XAllocColor(dpy, cmap, &colorUsed) ) {
    rgb_color[red][green][blue] = colorUsed.pixel;
  } else {
    /* if private colormap is in not in use,try agaian white */
    if (cmap == DefaultColormap(dpy, DefaultScreen(dpy) ) ) {
      /* create private color map */
      cmap = XCopyColormapAndFree(dpy, cmap);
      XSetWindowColormap(dpy, win, cmap);
      /* alloc again */
      colorUsed.red   = 65535 * red   /5;
      colorUsed.green = 65535 * green /5;
      colorUsed.blue  = 65535 * blue  /5;
      colorUsed.flags = DoRed | DoGreen | DoBlue;
      if (XAllocColor(dpy, cmap, &colorUsed) ) {
      rgb_color[red][green][blue] = colorUsed.pixel;
      }
    }
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
ppm_to_image_8bit (unsigned char *ppm,
               int width, int height,
               XImage *image)
#else
static void
ppm_to_image_8bit (ppm, width, height, image)
  unsigned char *ppm;
  int width, height;
  XImage *image;
#endif
{
  int x, y;
  unsigned char *ptr;
  int red, green, blue;
  
  /* upper left pixels */
  ptr = ppm;
  for (y=0; y<height; y+=2) {
    for (x=0; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = (20*ptr[0]/255 )/4;
      green = (20*ptr[1]/255 )/4;
      blue  = (20*ptr[2]/255 )/4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* upper right pixels */
  ptr = ppm + 3;
  for (y=0; y<height; y+=2) {
    for (x=1; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = (20*ptr[0]/255 + 1)/4;
      green = (20*ptr[1]/255 + 1)/4;
      blue  = (20*ptr[2]/255 + 1)/4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* lower left pixels */
  ptr = ppm + 3*width;
  for (y=1; y<height; y+=2) {
    for (x=0; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = (20*ptr[0]/255 + 2)/4;
      green = (20*ptr[1]/255 + 2)/4;
      blue  = (20*ptr[2]/255 + 2)/4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* lower right pixels */
  ptr = ppm + 3*width + 3;
  for (y=1; y<height; y+=2) {
    for (x=1; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = (20*ptr[0]/255 + 3)/4;
      green = (20*ptr[1]/255 + 3)/4;
      blue  = (20*ptr[2]/255 + 3)/4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static Pixmap
read_rgb_pixmap (char *path,
             char *filename)
#else
static Pixmap
read_rgb_pixmap (path, filename)
    char *path, *filename;
#endif
{
  XImage *image;
  Pixmap tmp;
  int width, height;
  char *data;
  unsigned char *ppm;

  /* looad ppm file */
  if (NULL == (ppm = read_ppm_file (path, filename, &width, &height) ) ) {
    x_fatal("Failed to load pixmap",filename);
  }

  /* alloc ppm and image data */
  if  (NULL == (data = malloc( ((bits_per_pixel+7)/8) * width * height ) ) ) { 
    x_fatal("failed to alloc image data", "");
  }

  /* create image */
  image 
    = XCreateImage (dpy, def_visual, def_depth,
                ZPixmap, 0, data, width, height, 32, 0 );
  if (image == NULL) {
    x_fatal ("create image failed", "");
  }

  /* convert ppm to image */
  (*ppm_to_image)(ppm, width, height, image);

  /* free ppm data */
  free(ppm);

  /* create pixmap */
  tmp = XCreatePixmap(dpy, win, width, height, def_depth);
  
  /* put image */
  XPutImage (dpy, tmp, gc_window, image, 0, 0, 0, 0, width, height);

  /* delete image */
  XDestroyImage (image);

  return tmp;
}
#endif
      
#ifndef MONO_XBLAST 
#ifdef __STDC__
static void
ppm_to_cch (unsigned char *ppm,
          int width, int height,
          char *fg_name, 
          char *bg_name,
          char *add_name)
#else
static void
ppm_to_cch (ppm, width, height, fg_name, bg_name, add_name)
    unsigned char *ppm;
  int width, height;
  char *fg_name, *bg_name, *add_name;
#endif
{
  int x,y;
  unsigned red, green, blue;
  XColor fg, bg, add;

  /* get colors  */
  parse_color_or_black (&fg, fg_name);
  parse_color_or_white (&bg, bg_name);
  parse_color_or_gray  (&add, add_name);

  for (y=0; y<height; y++) {
    for (x=0; x<width; x++) {
      /* convert pixels */
      /* blue is highlight only */
      ppm[0] -= ppm[2];
      ppm[1] -= ppm[2];
      /* red */
      red =  ppm[2]*255 + fg.red 
      + ( (bg.red-fg.red)*ppm[0] + add.red *ppm[1] )/255 ;
      if (red > 65535) {
      red = 65535;
      }
      /* green */
      green =  ppm[2]*255 + fg.green 
      + ( (bg.green-fg.green)*ppm[0] + add.green *ppm[1] )/255 ;
      if (green > 65535) {
      green = 65535;
      }

      /* blue */
      blue = ppm[2]*255 + fg.blue 
      + ( (bg.blue-fg.blue)*ppm[0] + add.blue *ppm[1] )/255 ;
      if (blue > 65535) {
      blue = 65535;
      }

      /* rgb values are 16bit here */
      ppm[0] = red   >> 8;
      ppm[1] = green >> 8;
      ppm[2] = blue  >> 8;
      
      ppm += 3;
    }
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static Pixmap
read_cch_pixmap (char *path,
             char *filename,
             char *fg_name,
             char *bg_name,
             char *add_name)
#else
static Pixmap
read_cch_pixmap (path, filename, fg_name, bg_name, add_name)
  char *path, *filename;
  char *fg_name, *bg_name, *add_name;
#endif
{
  XImage *image;
  Pixmap tmp;
  int width, height;
  unsigned char *ppm;
  char *data;

  /* looad ppm file */
  if (NULL == (ppm = read_ppm_file (path, filename, &width, &height) ) ) {
    x_fatal("Failed to load pixmap",filename);
  }

  /* alloc ppm and image data */
  if  (NULL == (data = malloc( ((bits_per_pixel+7)/8) * width * height ) ) ) { 
    x_fatal("failed to alloc image data", "");
  }

  /* create image */
  image = XCreateImage (dpy, def_visual, def_depth,
                ZPixmap, 0, data, width, height, 32, 0 );
  if (image == NULL) {
    x_fatal ("create image failed", "");
  }

  /* recolor ppm image */
  ppm_to_cch(ppm, width, height, fg_name, bg_name, add_name);

  /* convert ppm to image */
  (*ppm_to_image)(ppm, width, height, image);

  /* free ppm data */
  free(ppm);

  /* create pixmap */
  tmp = XCreatePixmap(dpy, win, width, height, def_depth);
  
  /* put image */
  XPutImage (dpy, tmp, gc_window, image, 0, 0, 0, 0, width, height);

  /* delete image */
  XDestroyImage (image);

  return tmp;
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
rgb16_to_image_rgb (unsigned short *rgb16,
                int width, int height,
                XImage *image)
#else
static void
rgb16_to_image_rgb (rgb16, width, height, image)
  unsigned short *rgb16;
  int width, height;
  XImage *image;
#endif
{
  int i, x, y;
  unsigned pixel;
  unsigned base[3], scale[3], mask[3];
  int shift[3];

  base[0] = GfxSetup.rbase;
  base[1] = GfxSetup.gbase;
  base[2] = GfxSetup.bbase;

  scale[0] = 65535 - base[0];
  scale[1] = 65535 - base[1];
  scale[2] = 65535 - base[2];

  shift[0] = 16 - rshift - rbits ;
  shift[1] = 16 - gshift - gbits ;
  shift[2] = 16 - bshift - bbits ;

  mask[0] = rmask;
  mask[1] = gmask;
  mask[2] = bmask;

  for (y=0; y<height; y++) {
    for (x=0; x<width; x++) {
      /* calculate renormalized rgb values
       EPFL: we need to convert rgb16 to unsigned int, otherwise we 
       may have overflows in multiplication
      */
      pixel = 0;
      for (i = 0; i < 3; i++) {
      if (shift[i] > 0) {
        pixel |= ( ( ( (scale[i] * (unsigned int) rgb16[i]) >> 16 ) 
                   + base[i]) >> shift[i]) & mask[i];
      } else {
        pixel |= ( ( ( (scale[i] * (unsigned int) rgb16 [i]) >> 16) 
                   + base[i]) << -shift[i]) & mask[i];      
      }
      }
      rgb16 += 3;
      XPutPixel(image, x, y, pixel);
    }
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
rgb16_to_image_8bit (unsigned short *rgb16,
                 int width, int height,
                 XImage *image)
#else
static void
rgb16_to_image_8bit (rgb16, width, height, image)
  unsigned short *rgb16;
  int width, height;
  XImage *image;
#endif
{
  int x, y;
  unsigned short *ptr;
  int red, green, blue;
  
  /* upper left pixels */
  ptr = rgb16;
  for (y=0; y<height; y+=2) {
    for (x=0; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = ((20*ptr[0]) >> 16 )/4;
      green = ((20*ptr[1]) >> 16 )/4;
      blue  = ((20*ptr[2]) >> 16 )/4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* upper right pixels */
  ptr = rgb16 + 3;
  for (y=0; y<height; y+=2) {
    for (x=1; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = ( ( (20*ptr[0]) >> 16) + 1) / 4;
      green = ( ( (20*ptr[1]) >> 16) + 1) / 4;
      blue  = ( ( (20*ptr[2]) >> 16) + 1) / 4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* lower left pixels */
  ptr = rgb16 + 3*width;
  for (y=1; y<height; y+=2) {
    for (x=0; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = ( ( (20*ptr[0]) >> 16 ) + 2) / 4;
      green = ( ( (20*ptr[1]) >> 16 ) + 2) / 4;
      blue  = ( ( (20*ptr[2]) >> 16 ) + 2) / 4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
  /* lower right pixels */
  ptr = rgb16 + 3*width + 3;
  for (y=1; y<height; y+=2) {
    for (x=1; x<width; x+=2) {
      /* calculate renormalized rgb values */
      red   = ( ( (20*ptr[0]) >> 16 ) + 3) / 4;
      green = ( ( (20*ptr[1]) >> 16 ) + 3) / 4;
      blue  = ( ( (20*ptr[2]) >> 16 ) + 3) / 4;
      if (rgb_color[red][green][blue] < 0) {
      alloc_rgb_color(red, green, blue);
      }
      XPutPixel(image, x, y, rgb_color[red][green][blue] );
      ptr +=6;
    }
    ptr += 3*width;
  }
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static unsigned short *
epm_to_rgb16 (unsigned char *epm,
            int width, int height, 
            int ncolors,
            ColorTable *color)
#else
static unsigned short *
epm_to_rgb16 (epm, width, height, ncolors, color)
  unsigned char *epm;
  int width, height; 
  int ncolors;
  ColorTable *color;
#endif
{
  int i,j;
  unsigned short *rgb16;
  unsigned char  *ptr; 
  unsigned short *dest;
  unsigned red, green, blue;

  int n_pixel;

  /* alloc rgb16 data buffer, color, and data ptr arrays */
  if (NULL == (rgb16 = malloc(3*width*height*sizeof(unsigned short) ) ) ) { 
    return NULL;
  }
  n_pixel =width*height;


  /* now calculated rgb values */
  for (j=0, dest=rgb16; j<n_pixel; j++, dest+=3) {
    ptr = epm + j;
    red   =  color[0].red  [*ptr];
    green =  color[0].green[*ptr];
    blue  =  color[0].blue [*ptr];
    for (i=1; i<ncolors; i++) {
      ptr += n_pixel;
      /* colors values have depth of 16 bits */
      red   +=  color[i].red  [*ptr];
      green +=  color[i].green[*ptr];
      blue  +=  color[i].blue [*ptr];
    }
    /* cut off to maxval to 2**16 - 1 */
    if (red > USHRT_MAX)  {
      dest[0] = USHRT_MAX;
    } else {
      dest[0] = red;
    }
    if (green > USHRT_MAX ) {
      dest[1] = USHRT_MAX;
    } else {
      dest[1] = green;
    }
    if (blue > USHRT_MAX ) {
      dest[2] = USHRT_MAX;
    } else {
      dest[2] = blue;
    }
  }

  return rgb16;
}
#endif

#ifndef MONO_XBLAST
#ifdef __STDC__
static Pixmap
create_epm_pixmap (unsigned char *epm,
               int width, int height,
               int ncolors,
               ColorTable *color)
#else
static Pixmap
create_epm_pixmap (epm, width, height, ncolors, color)
  unsigned char *epm;
  int width, height;
  int ncolors;
  ColorTable *color;
#endif
{
  XImage *image;
  Pixmap tmp;
  unsigned short *rgb16;
  char *data;

  /* alloc image data */
  if  (NULL == (data = malloc( ((bits_per_pixel+7)/8) * width * height ) ) ) { 
    x_fatal("failed to alloc image data", "");
  }

  /* create image */
  image = XCreateImage (dpy, def_visual, def_depth,
                  ZPixmap, 0, data, width, height, 32, 0 );
  if (image == NULL) {
    x_fatal ("create image failed", "");
  }

  /* convert epm image to rgb16 image*/
  if (NULL == (rgb16 = epm_to_rgb16(epm, width, height, ncolors, color) ) ) {
    x_fatal ("failed to convert epm to rgb16", "");
  }

  /* convert rgb16 to image */
  (*rgb16_to_image)(rgb16, width, height, image);

  /* free rgb16 and epm data */
  free(rgb16);

  /* create pixmap */
  tmp = XCreatePixmap(dpy, win, width, height, def_depth);
  
  /* put image */
  XPutImage (dpy, tmp, gc_window, image, 0, 0, 0, 0, width, height);

  /* delete image */
  XDestroyImage (image);

  return tmp;
}
#endif
      

#ifndef MONO_XBLAST
/*
 * local_functions init_fonts_color
 */
#ifdef __STDC__
static void
init_fonts_color (void) 
#else
static void
init_fonts_color () 
#endif
{
  XGCValues xgcv;
  int i;
  
  /* get resources */
  get_font_resources(font_name);

  /* gc black text */
  xgcv.fill_style = FillTiled;
  xgcv.tile = read_cch_pixmap ("image/misc", text_bg_data.bits,
                         "Black", display_color.darktext1, 
                         display_color.darktext2 );
  xgcv.line_width = 2;
  gc_text_black = XCreateGC(dpy, pix, GCTile|GCFillStyle|GCLineWidth, &xgcv);
  /* gc white text */
  xgcv.fill_style = FillTiled;
  xgcv.tile = read_cch_pixmap ("image/misc", text_fg_data.bits,
                         "Black", display_color.lighttext1, 
                         display_color.lighttext2 );
  xgcv.line_width = 2;
  gc_text_white = XCreateGC(dpy, pix, GCTile|GCFillStyle| GCLineWidth, &xgcv);

  for (i=0; i<NUM_FONTS; i++) {
    /* try to load font */
#ifdef DEBUG
    fprintf (stderr, "Loading font \"%s\".\n", font_name[i]);
#endif
    if (NULL == (font_struct[i] 
             = XLoadQueryFont(dpy, font_name[i]) ) ) {
      x_warning("could not load font",font_name[i]);
      /* otherwise get default font struct */
      font_struct[i] 
      = XQueryFont( dpy, XGContextFromGC(gc_text_black) );
    }
  }
}
#endif

/*
 * local_functions init_fonts_bbw
 */
#ifdef __STDC__
static void
init_fonts_bw (void) 
#else
static void
init_fonts_bw () 
#endif
{
  XGCValues xgcv;
  int black, white;
  int i;

  /* get resources */
  get_font_resources(font_name);

  /* set black and white */
  if (1 == def_depth) {
    black = black_pixel;
    white = white_pixel;
  } else {
    black = 1;
    white = 0;
  }

  /* gc black text */
  xgcv.foreground = black;
  xgcv.background = white;
  xgcv.line_width = 3;
  gc_text_black = XCreateGC(dpy, pix,
                          GCForeground | GCBackground | GCLineWidth,
                          &xgcv);
  /* gc white text */
  xgcv.foreground = white;
  xgcv.background = black;
  xgcv.line_width = 2;
  gc_text_white = XCreateGC(dpy, pix,
                            GCForeground | GCBackground| GCLineWidth,
                            &xgcv);
  for (i=0; i<NUM_FONTS; i++) {
    /* try to load font */
    if (NULL == (font_struct[i] 
             = XLoadQueryFont(dpy, font_name[i]) ) ) {
      x_warning("could not load font",font_name[i]);
      /* otherwise get default font struct */
      font_struct[i] 
      = XQueryFont( dpy, XGContextFromGC(gc_text_black) );
    }
  }
}

#ifndef MONO_XBLAST
#ifdef __STDC__
static void
init_color (int visual_class)
#else
static void
init_color (visual_class)
    int visual_class;
#endif
{
  XVisualInfo vinfo;
  XVisualInfo *result;
  int nitems;

  if (def_depth > 8) {
    /* true color display */
    vinfo.class = visual_class;
    result = XGetVisualInfo (dpy, VisualClassMask, &vinfo, &nitems);
    
    /* EPFL: Check bpp to get the correct XVisualInfo instance */
    while ((nitems--) > 0 && result->depth != def_depth)
      result++;

    if (result->depth != def_depth) {
      result -= nitems;
      x_warning ("cannot find VisalInfo for current bpp. Expect color problems", "");
    }

    rmask = result->red_mask;
    gmask = result->green_mask;
    bmask = result->blue_mask;
    analyze_color_mask (rmask, &rbits, &rshift);
    analyze_color_mask (gmask, &gbits, &gshift);
    analyze_color_mask (bmask, &bbits, &bshift);
    
#ifdef DEBUG
    fprintf(stderr, "Red:   mask=%08lx, bits=%d, shift=%d\n",
          rmask,rbits,rshift);
    fprintf(stderr, "Green: mask=%08lx, bits=%d, shift=%d\n",
          gmask,gbits,gshift);
    fprintf(stderr, "Blue:  mask=%08lx, bits=%d, shift=%d\n",
          bmask,bbits,bshift);
#endif

    ppm_to_image = ppm_to_image_rgb;
    rgb16_to_image = rgb16_to_image_rgb;
  } else {
    int r,g,b;

    for (r=0; r<6; r++) {
      for (g=0; g<6; g++) {
      for (b=0; b<6; b++) {
        rgb_color[r][g][b] = -1;
      }
      }
    }

    ppm_to_image = ppm_to_image_8bit;
    rgb16_to_image = rgb16_to_image_8bit;
  }

  /* get resources for various colors */
  get_color_resources(&display_color, player_color);
}
#endif

#ifndef MONO_XBLAST
/*
 * local function init_score_tiles_color
 */
#ifdef __STDC__
static void 
init_score_tiles_color (void)
#else
static void 
init_score_tiles_color ()
#endif
{
  int i, j, k;
  ColorTable color[MAX_PLAYER][7];
  unsigned char *epm;
  int width, height, depth;

  /* init led tiles  */
  for (i=0; i<2; i++) {
    pix_leds[i] = read_cch_pixmap ("image/score", score_led_data[i].bits,
                           "Black", display_color.statusfg,
                           display_color.statusled);
  }
  
  /* init other score tiles */
  for (i=0; i < SBDead ; i++) {
    pix_score[i] = read_cch_pixmap("image/score", score_tile_data[i].bits, 
                           "Black", display_color.statusfg, 
                           display_color.statusbg);
  }
  
  /* init player score tiles */
  for (i=0; i<MAX_PLAYER; i++) {
    /* parse player colors */
    create_color_table(&(color[i][0]), player_color[i].helmet);
    create_color_table(&(color[i][1]), player_color[i].face);
    create_color_table(&(color[i][2]), player_color[i].hands_feet);
    create_color_table(&(color[i][3]), player_color[i].arms_legs);
    create_color_table(&(color[i][4]), display_color.statusfg);
    create_color_table(&(color[i][5]), display_color.statusbg);
    create_color_table(&(color[i][6]), "White");
  }
  for (i=SBDead, k=0; i< MAX_SCORE_TILES; i+=MAX_PLAYER, k++) {
    /* load extended pixmap */
    epm = read_epm_file("image/score", score_player_data[k].bits, 
                  &width, &height, &depth); 
    if (NULL == epm) {
      x_fatal("Failed to load extended pixmap",sprite_image[i].bits);
    }
    /* correct depth if too large */
    if (depth > 7) {
      depth = 7;
    }
    for (j=0; j<MAX_PLAYER; j++) {
      pix_score[i+j] = create_epm_pixmap(epm, width, height, depth, color[j]);
    }
    free(epm);
  }
  /* free color table data */
  for (i=0; i<MAX_PLAYER; i++) {
    for (j=0; j<7; j++) {
      free_color_table(color[i]+j);
    }
  }
}
#endif


/*
 * local function: init_score_tiles_bw
 */
#ifdef __STDC__
static void 
init_score_tiles_bw (void)
#else
static void 
init_score_tiles_bw ()
#endif
{
  int i;

  /* init led tiles  */
  for (i=0; i<2; i++) {
    pix_leds[i] = 
      read_pbm_black_white_map ("bitmap/score", score_led_data[i].bits);
  }
  /* init normal score tiles */
  for (i=0; i < MAX_SCORE_TILES; i++) {
    pix_score[i] = 
      read_pbm_black_white_map ("bitmap/score", score_bitmap_data[i].bits);
  }
}

/* 
 * local function : init_window 
 */
#ifdef __STDC__
static void 
init_window_normal (char *win_title,
                char *icon_title)
#else
static void 
init_window_normal (win_title, icon_title)
  char *win_title, *icon_title;
#endif
{
  XWindowAttributes xwa;
  XSetWindowAttributes xswa;
  XWMHints *wmh;
  XSizeHints *xsh;
  XClassHint *xch;
  XEvent xev;
  XGCValues xgcv;
  int fg, bg;

  fg = black_pixel;
  bg = white_pixel;

  /* Get Root Window Size */
  if ( XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &xwa)
       == 0 ) {
    x_fatal("couldn't get root window size","");
  }

  winX =  0;
  winY =  0;
  winW =  PIXW;
  winH =  PIXH + SCOREH;

  /* Set Window Attributes */
  xswa.event_mask = NORMAL_EVENT_MASK;
  xswa.background_pixel = fg;
  xswa.border_pixel = fg;
  xswa.override_redirect = False;
  xswa.colormap = cmap;

  /* Open the Window */
  win
    = XCreateWindow(dpy, DefaultRootWindow(dpy),
                    winX,winY, winW,winH, 0,
                    def_depth,
                    InputOutput, def_visual,
                    CWEventMask | CWBackPixel | CWBorderPixel 
                | CWOverrideRedirect | CWColormap,
                    &xswa );

  /* Change Window and icon Title */
  XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING,
                  8, PropModeReplace, (unsigned char *) win_title,
                  strlen(win_title) );
  XChangeProperty(dpy, win, XA_WM_ICON_NAME, XA_STRING,
                  8, PropModeReplace, (unsigned char *) icon_title,
                  strlen(icon_title) );

  /* Set Icon */
  if (NULL == (wmh = XAllocWMHints())) {
    x_fatal("alloc failed", "");
  }
  wmh->flags = IconPixmapHint;
  wmh->icon_pixmap 
    = read_pbm_black_white_map ("bitmap/sprite", sprite_bitmap[0].bits[0]);
  XSetWMHints(dpy, win, wmh);
  
  /* set class */
  if (NULL == (xch = XAllocClassHint())) {
    x_fatal("alloc failed", "");
  }
  xch->res_name = XBlastResName;
  xch->res_class = XBlastResClass;

  XSetClassHint(dpy, win, xch);

  /* set min and max geometry */
  if (NULL == (xsh = XAllocSizeHints())) {
    x_fatal("alloc failed", "");
  }
  xsh->flags = PPosition | PSize | PMinSize | PMaxSize;
  xsh->min_width = PIXW;
  xsh->max_width = PIXW;
  xsh->min_height = PIXH+SCOREH;
  xsh->max_height = PIXH+SCOREH;
  XSetWMSizeHints(dpy, win, xsh, XA_WM_NORMAL_HINTS);

  xgcv.foreground = fg;
  xgcv.background = bg;
  gc_window = XCreateGC(dpy, win, 
                        GCForeground | GCBackground, &xgcv);

  /* Set Cursor */
  XDefineCursor(dpy, win,
                XCreateFontCursor(dpy, XC_trek) );

  /* Map the Window */
  XMapRaised(dpy, win);

  /* wait for an ExposeEvent */
  do {
    XNextEvent(dpy, &xev);
  } while (xev.type != Expose );

  /* get actual window size */
  if ( XGetWindowAttributes(dpy, win , &xwa) == 0) {
    x_fatal("could not get window size","");
  }

  winW = xwa.width;
  winH = xwa.height;

  if ( (winW < PIXW) || (winH <PIXH) ) {
    x_warning("display is to small","");
  }
}

/* 
 * local function : init_window_override
 */
#ifdef __STDC__
static void 
init_window_override (void)
#else
static void 
init_window_override ()
#endif
{
  XWindowAttributes xwa;
  XSetWindowAttributes xswa;
  XEvent xev;
  XGCValues xgcv;
  int fg, bg;

  fg = black_pixel;
  bg = white_pixel;

  /* Get Root Window Size */
  if ( XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &xwa)
       == 0 ) {
    x_fatal("couldn't get root window size","");
  }

  winX =  0;
  winY =  0;
  winW =  PIXW;
  winH =  PIXH + SCOREH;

  /* Set Window Attributes */
  xswa.event_mask = NORMAL_EVENT_MASK;
  xswa.background_pixel = fg;
  xswa.border_pixel = fg;
  xswa.override_redirect = True;

  /* Open the Window */
  win
    = XCreateWindow(dpy, DefaultRootWindow(dpy),
                    winX,winY, winW,winH, 0,
                    def_depth,
                    InputOutput, def_visual,
                    CWEventMask | CWBackPixel | CWBorderPixel 
                | CWOverrideRedirect,
                    &xswa );

  xgcv.foreground = fg;
  xgcv.background = bg;
  gc_window = XCreateGC(dpy, win, 
                        GCForeground | GCBackground, &xgcv);

  /* Set Cursor */
  XDefineCursor(dpy, win,
                XCreateFontCursor(dpy, XC_trek) );

  /* Map the Window */
  XMapRaised(dpy, win);

  /* wait for an ExposeEvent */
  do {
    XNextEvent(dpy, &xev);
  } while (xev.type != Expose );

  /* get actual window size */
  if ( XGetWindowAttributes(dpy, win , &xwa) == 0) {
    x_fatal("could not get window size","");
  }

  winW = xwa.width;
  winH = xwa.height;

  if ( (winW < PIXW) || (winH <PIXH) ) {
    x_warning("display is to small","");
  }
}

#ifndef MONO_XBLAST
/* 
 * Local function : init_pixmap_color
 */
#ifdef __STDC__
static void 
init_pixmap_color (void)
#else 
static void 
init_pixmap_color ()
#endif
{
  XGCValues xgcv;

  /* where to draw pixmap */
  pix = XCreatePixmap(dpy, win, PIXW, PIXH+SCOREH, def_depth);

  /* gc: add on graphics */
  xgcv.fill_style = FillStippled;
  gc_addon = XCreateGC(dpy, win,
                       GCFillStyle, &xgcv );

  /* gc : copy pixmap to window */
  xgcv.fill_style = FillTiled;
  xgcv.tile = pix;
  gc_frompix = XCreateGC(dpy, win, GCTile | GCFillStyle, &xgcv );

  /* gc : clear pixmap */
  xgcv.tile = read_cch_pixmap ("image/misc", title_data.bits, "Black", 
                         display_color.title1, display_color.title2 );
  xgcv.fill_style = FillTiled;
  gc_clearpix = XCreateGC(dpy, pix, GCFillStyle | GCTile,
                        &xgcv );

  /* gc : draw block */
  xgcv.fill_style = FillTiled;
  gc_drawblock = XCreateGC(dpy, pix, GCFillStyle, &xgcv );

}
#endif

/* 
 * Local function : init_pixmap_bw
 */
#ifdef __STDC__
static void 
init_pixmap_bw (void)
#else 
static void 
init_pixmap_bw ()
#endif
{
  XGCValues xgcv;

  /* where to draw pixmap */
  pix
    = XCreatePixmap(dpy, win, PIXW, PIXH + SCOREH, 1);

  /* gc : copy pixmap to window */
  if (1 != def_depth) {
    /* for non monochrome display in bw mode */
    xgcv.foreground = black_pixel;
    xgcv.background = white_pixel;
    xgcv.fill_style = FillOpaqueStippled;
    xgcv.stipple = pix;
    gc_frompix = XCreateGC(dpy, win,
                         GCForeground | GCBackground | GCStipple 
                         | GCFillStyle, &xgcv );
  } else {
    /* for monochrome displays in bw mode */
    xgcv.fill_style = FillTiled;
    xgcv.tile = pix;
    gc_frompix = XCreateGC(dpy, win,
                         GCTile | GCFillStyle, 
                         &xgcv );
  }

  /* gc : clear pixmap */
  xgcv.tile = read_pbm_black_white_map ("bitmap/misc", "title");
  xgcv.fill_style = FillTiled;
  gc_clearpix = XCreateGC(dpy, pix,
                        GCFillStyle | GCTile,
                        &xgcv );

  /* gc : draw block */
  xgcv.fill_style = FillTiled;
  gc_drawblock = XCreateGC(dpy, pix, GCFillStyle, &xgcv );

}

#ifndef MONO_XBLAST
/* local_function init_ini_bomb */
#ifdef __STDC__
static void 
init_ini_bomb (int num)
#else
static void 
init_ini_bomb (num)
     int num;
#endif
{
  ini_bomb_div = num;
  /* "clear" window */
  XFillRectangle(dpy, win, gc_clearpix, 0, 0, PIXW, PIXH+SCOREH);
  XFlush(dpy);
}

/* local_function init_ini_bomb */
#ifdef __STDC__
static void 
next_ini_bomb (void)
#else
static void 
next_ini_bomb ()
#endif
{
  int anime;

  anime = ini_bomb_count / ini_bomb_div;
  if (anime > ini_bomb_anime) {
    /* set anime */
    ini_bomb_anime = anime;
    /* clear background */
    XFillRectangle(dpy, win, gc_clearpix, (PIXW-BLOCK_WIDTH)/2, (PIXH-BLOCK_HEIGHT)/2,
               BLOCK_WIDTH, BLOCK_HEIGHT);
    /* draw the bomb */
    XSetClipOrigin(dpy, gc_sprite_bits, (PIXW-BLOCK_WIDTH)/2, (PIXH-BLOCK_HEIGHT)/2);
    XSetTSOrigin(dpy, gc_sprite_bits, (PIXW-BLOCK_WIDTH)/2, (PIXH-BLOCK_HEIGHT)/2);
    XSetTile(dpy, gc_sprite_bits, pix_bomb_bits[0][anime]);
    XSetClipMask(dpy, gc_sprite_bits, pix_bomb_mask[0][anime]);
    XFillRectangle(dpy, win, gc_sprite_bits, (PIXW-BLOCK_WIDTH)/2, (PIXH-BLOCK_HEIGHT)/2,
               BLOCK_WIDTH, BLOCK_HEIGHT);
    XFlush(dpy);
#ifdef DEBUG
    fprintf(stderr, "Bomb %d\n", anime);
#endif
  }
  ini_bomb_count += MAX_BOMB_ANIME;
}
#endif

#ifndef MONO_XBLAST
/* 
 * local function init_sprites_color
 */
#ifdef __STDC__
static void 
init_sprites_color (int num_player)
#else
static void 
init_sprites_color (num_player)
  int num_player;
#endif
{
  XGCValues xgcv;
  int i,j;
  ColorTable color[MAX_PLAYER][7];
  int epm_index[MAX_PLAYER];

  /* gc for drawing mask */
  xgcv.foreground = white_pixel;
  xgcv.fill_style = FillStippled;
  gc_sprite_mask = XCreateGC(dpy, pix,
                           GCFillStyle | GCForeground, &xgcv);
  /* gc for drawing sprite bits */
  xgcv.fill_style = FillTiled;
  gc_sprite_bits = XCreateGC(dpy, pix, GCFillStyle, &xgcv);

  init_ini_bomb(MAX_BOMBS*MAX_BOMB_ANIME + MAX_PLAYER*MAX_ANIME + MAX_EXPLOSION);

  /* bomb sprites */
  for (i = 0; i < MAX_BOMBS; i++) {
    for (j=0; j < MAX_BOMB_ANIME; j++) {
      pix_bomb_mask[i][j] = 
      read_pbm_bitmap("image/explosion", bomb_image_data[i][j].bits);
      pix_bomb_bits[i][j] =
      read_rgb_pixmap("image/explosion", bomb_image_data[i][j].bits);
      next_ini_bomb();
    }
  }

  /* set index table for shared epm files */
  for (i=0; i < MAX_PLAYER; i++) {
    epm_index[i] = i;
    for (j=0; j<i; j++) {
      if (0 == strcmp(player_color[j].shape, player_color[i].shape) ) {
#ifdef DEBUG
      fprintf (stderr, "Sharing EPM for %d with %d\n", i, j);
#endif
      epm_index[i] = j;
      break;
      }
    }
  }
  
  /* parse player colors */
  for (i=0; i<MAX_PLAYER; i++) {
    create_color_table(&(color[i][0]), player_color[i].helmet);
    create_color_table(&(color[i][1]), player_color[i].face);
    create_color_table(&(color[i][2]), player_color[i].body);
    create_color_table(&(color[i][3]), player_color[i].hands_feet);
    create_color_table(&(color[i][4]), player_color[i].arms_legs);
    create_color_table(&(color[i][5]), player_color[i].backpack);
    create_color_table(&(color[i][6]), "White");
  }

  /* pixmaps for sprite_masks and bits */
  for (i = 0; i < MAX_ANIME; i++) {
    for (j=0; j<MAX_PLAYER; j++) {
      /* set width, height and offsets */
      sprite_data[j][i].width   = sprite_image_size[i].w;
      sprite_data[j][i].height  = sprite_image_size[i].h;
      sprite_data[j][i].xoffset = sprite_image_size[i].x;
      sprite_data[j][i].yoffset = sprite_image_size[i].y;
    }
    if (! sprite_image[i].is_epm) {
      /* else read ppm file */
      Pixmap bits, mask;
      /* read ppm bits */
      bits = read_rgb_pixmap ("image/sprite", sprite_image[i].bits);;
      /* read mask file */
      mask  = read_pbm_bitmap ("image/sprite", sprite_image[i].bits);
      /* set for all players */
      for (j=0; j<MAX_PLAYER; j++) {
      sprite_data[j][i].mask = mask;
      sprite_data[j][i].bits = bits;
      next_ini_bomb();
      }
    } else {
      unsigned char *epm[MAX_PLAYER];
      
      for (j=0; j<MAX_PLAYER; j++) {
      epm[j] = NULL;
      /* check if sprite is really in use */
      if ( (j >= num_player) && (! sprite_image[i].always) ) {
        sprite_data[j][i].mask = None;
        sprite_data[j][i].bits = None;
        next_ini_bomb();
      } else {
        int width, height, depth;
        /* check if epm already exists */
        if (epm_index[j] == j) {
          static char epmfile[1024];
          /* create epmfile */
          sprintf(epmfile, sprite_image[i].bits, player_color[j].shape);
          /* read .epm file */
          epm[j] = read_epm_file ("image/sprite", epmfile, &width, &height, 
                            &depth);
          if (NULL == epm[j]) {
            x_fatal("Failed to load extended pixmap", epmfile);
          }
          /* correct depth if too large */
          if (depth > 7) {
            depth = 7;
          }
          /* read mask file */
          sprite_data[j][i].mask = read_pbm_bitmap ("image/sprite", epmfile);
        } else {
          sprite_data[j][i].mask = sprite_data[epm_index[j]][i].mask;
        }
        /* create pixmap from epm file */
        sprite_data[j][i].bits = 
          create_epm_pixmap(epm[epm_index[j]], width, height, depth, color[j]);
        next_ini_bomb();
      }
      }
      /* remove shared epm's */
      for (j=0; j<MAX_PLAYER; j++) {
      if (NULL != epm[j]) {
        free(epm[j]);
      }
      }
    }
  }
  /* free color table data */
  for (i=0; i<MAX_PLAYER; i++) {
    for (j=0; j<7; j++) {
      free_color_table(color[i]+j);
    }
  }

  /* create explosion sprites */
  for (i = 0; i < MAX_EXPLOSION; i++) {
    /* mask */
    pix_expl_mask[i] = 
      read_pbm_bitmap("image/explosion", expl_data[i].mask);
    pix_expl_bits[i] =
      read_rgb_pixmap("image/explosion", expl_data[i].bits);
    next_ini_bomb();
  }
}
#endif

/* 
 * local function init_sprites_bw 
 */
#ifdef __STDC__
static void 
init_sprites_bw (int num_player)
#else
static void 
init_sprites_bw (num_player)
  int num_player;
#endif
{
  XGCValues xgcv;
  int i,j;
  int fg, bg;
  int k;
  Pixmap mask[MAX_ANIME_BITS];
  Pixmap bits[MAX_PLAYER][MAX_ANIME_BITS];

  if (1 == def_depth) {
    fg = black_pixel;
    bg = white_pixel;
  } else {
    fg = 1;
    bg = 0;
  }

  /* gc for drawing mask */
  xgcv.foreground = bg;
  xgcv.fill_style = FillStippled;
  gc_sprite_mask = XCreateGC(dpy, pix,
                           GCFillStyle | GCForeground, &xgcv);
  /* gc for drawing bitmap */
  xgcv.fill_style = FillStippled;
  xgcv.foreground = fg;
  gc_sprite_bits = XCreateGC(dpy, pix,
                           GCFillStyle | GCForeground, &xgcv);

  /* disp sprites */
  for (i = 0; i < MAX_ANIME_BITS; i++) {
    mask[i] = read_pbm_bitmap ("bitmap/sprite", sprite_bitmap[i].mask);
    for (j=0; j < num_player; j++) {
      bits[j][i] = read_pbm_bitmap ("bitmap/sprite", sprite_bitmap[i].bits[j]);
    }
    if (sprite_bitmap[i].always) {
      for (j=num_player; j < MAX_PLAYER; j++) {
      bits[j][i] = read_pbm_bitmap ("bitmap/sprite", sprite_bitmap[i].bits[j]);
      }
    } else {
      for (j=num_player; j < MAX_PLAYER; j++) {
      bits[j][i] = None;
      }
    }
  }
  /* now store data in correct order */
  for (i = 0; i < MAX_ANIME; i++) {
    k = sprite_bitmap_table[i];
    
    /* set width, height and offsets */
    for (j = 0; j < MAX_PLAYER; j++) {
      sprite_data[j][i].width   = sprite_bitmap_size[k].w;
      sprite_data[j][i].height  = sprite_bitmap_size[k].h;
      sprite_data[j][i].xoffset = sprite_bitmap_size[k].x;
      sprite_data[j][i].yoffset = sprite_bitmap_size[k].y;

      sprite_data[j][i].mask = mask[k];
    }
      
    /* this saves some of X-server memory */
    if (sprite_bitmap[k].always) {
      for (j =0; j < MAX_PLAYER; j++) {
      sprite_data[j][i].bits = bits[j][k];
      }
    } else {
      for (j =0; j < num_player; j++) {
      sprite_data[j][i].bits = bits[j][k];
      }
    }
  }

  /* bomb sprites */
  for (i = 0; i < MAX_BOMBS; i++) { 
    /* mask */
    pix_bomb_mask[i][0] = 
      read_pbm_bitmap ("bitmap/explosion", bomb_bitmap_data[i].mask);
    pix_bomb_bits[i][0] = 
      read_pbm_bitmap ("bitmap/explosion", bomb_bitmap_data[i].bits);
    for (j=1; j < MAX_BOMB_ANIME; j++) {
      pix_bomb_mask[i][j] = pix_bomb_mask[i][0];
      pix_bomb_bits[i][j] = pix_bomb_bits[i][0];
    }
  }

  for (i = 0; i < MAX_EXPLOSION; i++) {
    /* mask */
    pix_expl_mask[i] = read_pbm_bitmap ("bitmap/explosion", expl_data[i].mask);
    pix_expl_bits[i] = read_pbm_bitmap ("bitmap/explosion", expl_data[i].bits);
  }
}

/*
 * public function : init_display
 */
#ifdef __STDC__
void 
init_display (char *display)
#else
  void 
init_display (display)
  char *display;
#endif
{
  XPixmapFormatValues *xpfv;
  int npfv;
#ifdef DEBUG
  fprintf(stderr, "Display is \"%s\"\n", display ? display : "(null)");
#endif
  /* open display */
  if ( !(dpy = XOpenDisplay(display)) ) {
    x_fatal("Couldn't open Display",display);
  }

  /* init x databases */
  create_display_database();

  /* set depth variable */
  def_depth = DefaultDepth(dpy, DefaultScreen(dpy));

  /* set bits-per-pixel variable */
  bits_per_pixel = def_depth;
  if (NULL != (xpfv = XListPixmapFormats (dpy, &npfv) ) ) {
    int i;
    for (i=0; i<npfv; i++) {
      if (def_depth == xpfv[i].depth) {
      bits_per_pixel = xpfv[i].bits_per_pixel;
      }
    }
    XFree (xpfv);
  }

  /* set default visual */
  def_visual = DefaultVisual(dpy, DefaultScreen(dpy) ),

  /* set colormap to default */
  cmap = DefaultColormap(dpy, DefaultScreen(dpy));

  /* set standard pixel values */
  white_pixel = WhitePixel(dpy, DefaultScreen(dpy));
  black_pixel = BlackPixel(dpy, DefaultScreen(dpy));
#ifndef MONO_XBLAST
  /* alloc black and white, we still have them if we a use private colormap */
  white_pixel = alloc_color_or_white("White");
  black_pixel = alloc_color_or_black("Black");
#endif
}

#ifdef __STDC__
void
finish_display (void)
#else
void
finish_display ()
#endif
{
  if (dpy != NULL) {
    XCloseDisplay(dpy);
  }
}


/*
 * Public function : init_graphics 
 */
#ifdef __STDC__
void 
init_graphics (XBConfig *config,
             char *win_title,
             char *icon_title)
#else
void 
init_graphics (config, win_title, icon_title)
  XBConfig *config;
  char *win_title, *icon_title;
#endif
{
  int visual_class;
  XVisualInfo visual_info;
#ifdef DEBUG
  time_t t0;
#endif

  /* set key tables */
  set_game_keys(config);

  /* get setup from database */
  graphics_setup_from_database(&GfxSetup);

#ifdef DEBUG
  fprintf(stderr, "Base red   = 0x%04x\n", GfxSetup.rbase);
  fprintf(stderr, "Base green = 0x%04x\n", GfxSetup.gbase);
  fprintf(stderr, "Base blue  = 0x%04x\n", GfxSetup.bbase);
#endif

  /* get visual class */
  visual_class = DirectColor;
  while (!XMatchVisualInfo(dpy, DefaultScreen(dpy), 
                     def_depth, visual_class, &visual_info) ) {
    visual_class--;
  }
#ifdef DEBUG
  switch (visual_class) {
  case StaticGray:
    fprintf(stderr, "Visual class is  StaticGray\n");
    break;
  case GrayScale:
    fprintf(stderr, "Visual class is  GrayScale\n");
    break;
  case StaticColor:
    fprintf(stderr, "Visual class is  StaticColor\n");
    break;
  case PseudoColor:
    fprintf(stderr, "Visual class is  PseudoColor\n");
    break;
  case TrueColor:
    fprintf(stderr, "Visual class is  TrueColor\n");
    break;
  case DirectColor:
    fprintf(stderr, "Visual class is  DirectColor\n");
    break;
  }
#endif
  /* get color mode from visual */
  colorMode = COL_MONO;
#ifndef MONO_XBLAST
  if (visual_class >= TrueColor) {
      colorMode = COL_HICOLOR;
  }
  if (colorMode > GfxSetup.max_color_mode) {
    colorMode = GfxSetup.max_color_mode;
  }
#endif

#ifdef DEBUG
  switch (colorMode) {
  case COL_MONO:
    fprintf(stderr,"Color mode is monchrome\n");
    break;
  case COL_COLOR:
    fprintf(stderr,"Color mode is normal color\n");
    break;
  case COL_HICOLOR:
    fprintf(stderr,"Color mode is hicolor\n");
    break;
  }
#endif

  /* init window, either override or normal */
  if (override_from_database()) {
    init_window_override();
  } else {
    init_window_normal(win_title, icon_title);
  }
#ifndef MONO_XBLAST
  /* init graphics either color or black an white */
  switch (colorMode) {
    /* monchrome display */
  case COL_MONO:
  case COL_COLOR:
#endif
    init_pixmap_bw();
    init_fonts_bw();
    init_score_tiles_bw();
#ifdef DEBUG
    t0 = time(NULL);
#endif
    if (config->record_mode == RM_PLAYBACK) {
      init_sprites_bw (MAX_PLAYER);
    } else if (config->team_mode == TM_Double) {
      init_sprites_bw (config->num_player / 2);
    } else {
      init_sprites_bw (config->num_player);
    }
#ifdef DEBUG
    fprintf(stderr, "Time to load sprites: %ld s.\n",time(NULL)-t0);
#endif
#ifndef MONO_XBLAST
    break;
    /* support for (rendered) hi color graphics */
  case COL_HICOLOR:
    init_color(visual_class);
    init_pixmap_color();
    init_fonts_color();
    init_score_tiles_color();
#ifdef DEBUG
    t0 = time(NULL);
#endif
    if (config->record_mode == RM_PLAYBACK) {
      init_sprites_color (MAX_PLAYER);
    } else if (config->team_mode == TM_Double) {
      init_sprites_color (config->num_player / 2);
    } else {
      init_sprites_color (config->num_player);
    }
#ifdef DEBUG
    fprintf(stderr, "Time to load sprites: %ld s.\n",time(NULL)-t0);
#endif
    break;
  }
#endif
}


#ifndef MONO_XBLAST
#ifdef __STDC__
void
dump_rgb_image (FILE *fp, XImage *image)
#else
void
dump_rgb_image (fp, image)
  FILE *fp; 
  XImage *image;
#endif
{
  unsigned char rgb[4];
  unsigned long pixel;
  int x,y;

  /* write header */
  fprintf(fp, "P6\n");
  fprintf(fp, "%d %d\n", image->width, image->height);
  fprintf(fp, "%d\n",255);

  for (y=0; y<image->height; y++) {
    for (x=0; x<image->width; x++) {
      pixel = XGetPixel(image, x, y);
      rgb[0] = ((pixel & rmask) >> rshift) << (8 - rbits);
      rgb[1] = ((pixel & gmask) >> gshift) << (8 - gbits);
      rgb[2] = ((pixel & bmask) >> bshift) << (8 - bbits);
      fwrite(rgb, sizeof(char), 3, fp);
    }
  }
}
#endif


#ifdef __STDC__
void
dump_mapped_image (FILE *fp, XImage *image)
#else
void
dump_mapped_image (fp, image)
  FILE *fp; 
  XImage *image;
#endif
{
  unsigned char rgb[4];
  unsigned long pixel;
  int x,y;
  XColor color[256];
  int i, ncolors;

  /* write header */
  fprintf(fp, "P6\n");
  fprintf(fp, "%d %d\n", image->width, image->height);
  fprintf(fp, "%d\n",255);

  /* create copy of colormap */
  ncolors = (1 << image->depth);
  for (i=0; i<ncolors; i++) {
    color[i].pixel = i;
  }
  XQueryColors (dpy, cmap, color, ncolors);
  for (i=0; i<ncolors; i++) {
    color[i].red   >>= 8;
    color[i].green >>= 8;
    color[i].blue  >>= 8;
  }

  for (y=0; y<image->height; y++) {
    for (x=0; x<image->width; x++) {
      pixel = XGetPixel(image, x, y);
      rgb[0] = color[pixel].red;
      rgb[1] = color[pixel].green;
      rgb[2] = color[pixel].blue;
      fwrite(rgb, sizeof(char), 3, fp);
    }
  }
}



/*
 * local function print_screen
 */
#ifdef __STDC__
void
print_screen (void)
#else
void
print_screen ()
#endif
{
  XImage *image;
  FILE *fp;
  static int count = 1;
  char zeile[1024];

  /* get image */
  image = XGetImage (dpy, win, 0, 0, PIXW, PIXH+SCOREH, AllPlanes,
                 ZPixmap);
  
#ifdef DEBUG
  fprintf(stderr, "Bits per Pixel %d\n", image->bits_per_pixel);
#endif
  
  sprintf(zeile, "xblast%03d.ppm", count ++);
  /* open output file */
  if (NULL == (fp = fopen(zeile,"w") ) ) {
    x_warning ("Failed to open file",zeile);
    return;
  }

  /* choose method */
  switch (image->bits_per_pixel) {
#ifndef MONO_XBLAST
  case 15:
  case 16:
  case 24:
  case 32:
    dump_rgb_image (fp, image);
    break;
#endif
  case 1:
  case 4:
  case 8:
    dump_mapped_image (fp, image);
    break;
  }

  /* close file */
  pclose(fp);

  /* delete image */
  XDestroyImage(image);
}

/*
 * local variables for key translations
 */

#define KEYCODE_MAX 255
#define KEYCODE_MIN 8
#define NUM_KEYCODE 256

static KeyPressAction *key_press_table;
static KeyPressAction *key_release_table;
static KeySym code2sym[2][NUM_KEYCODE];

/*
 * public link_keysyms
 */
#ifdef __STDC__
void
link_keysyms (int nkeypress, KeyPressDefine *keypress,
            int nkeyrelease, KeyPressDefine *keyrelease)
#else
void
link_keysyms (nkeypress, keypress, nkeyrelease, keyrelease)
  int nkeypress;
  KeyPressDefine *keypress;
  int nkeyrelease;
  KeyPressDefine *keyrelease;
#endif
{

  int i;
  KeySym keysym;
  KeyCode keycode;
  char **keyv;
  int keyc;

  /* fill simple translation table */
  for (keycode = KEYCODE_MIN; (keycode<KEYCODE_MAX) && (keycode!=0); keycode++) {
    code2sym[0][keycode] = XKeycodeToKeysym(dpy, keycode, 0);
    code2sym[1][keycode] = XKeycodeToKeysym(dpy, keycode, 1);
  }

  /* alloc key table */
  if ( (NULL == (key_press_table = 
             calloc (NUM_KEYCODE, sizeof(KeyPressAction) ) ) ) || 
       (NULL == (key_release_table = 
             calloc (NUM_KEYCODE, sizeof(KeyPressAction) ) ) ) ) {
    x_fatal("failed to alloc key table", "");
  }

  /* set key press table */
  for (i=0; i<nkeypress; i++) {
    keyv = split_string(keypress[i].keysym, &keyc);
    for (--keyc; keyc >= 0; keyc--) {
      if (NULL == keyv[keyc]) {
      x_fatal("undefined keysymbol", "");
      }
      if (NoSymbol == (keysym = XStringToKeysym(keyv[keyc]))) {
      x_warning("unknown keysymbol", keyv[keyc]);
      continue;
      }
      /* set entries in table */
      for (keycode=KEYCODE_MIN; (keycode<KEYCODE_MAX)&&(keycode!=0);keycode ++) {
      if ( (keysym == code2sym[0][keycode]) 
          || (keysym == code2sym[1][keycode])) {
        key_press_table[keycode].addr  = keypress[i].addr;
        key_press_table[keycode].value = keypress[i].value;
      }
      }
    }
  }
  /* set key release table */
  for (i=0; i<nkeyrelease; i++) {
    keyv = split_string(keyrelease[i].keysym, &keyc);
    for (--keyc; keyc >= 0; keyc--) {
      if (NULL == keyv[keyc]) {
      x_fatal("undefined keysymbol", "");
      }
      if (NoSymbol == (keysym = XStringToKeysym(keyv[keyc]))) {
      x_warning("unknown keysymbol", keyv[keyc]);
      continue;
      }
      /* set entries in table */
      for (keycode=KEYCODE_MIN; (keycode<KEYCODE_MAX)&&(keycode!=0);keycode ++) {
      if ( (keysym == code2sym[0][keycode]) 
          || (keysym == code2sym[1][keycode])) {
        key_release_table[keycode].addr  = keyrelease[i].addr;
        key_release_table[keycode].value = keyrelease[i].value;
      }
      }
    }
  }

}



/*
 * public function: check_event
 */
#ifdef __STDC__
void 
check_event (void) 
#else
void 
check_event ()
#endif
{
  XEvent xev;
  int num_events;

  /* first get number of events */
  XSync (dpy, FALSE);
  num_events = XEventsQueued(dpy,QueuedAlready);

  while (num_events !=0) {
    num_events --;

    /* get event */
    XNextEvent(dpy, &xev);
      
    switch (xev.type) {
      /* windows is iconfied */
    case UnmapNotify:
#ifdef DEBUG
      fprintf(stderr, "Window unmapped\n");
#endif
      iconified = TRUE;
      break;
      
      /* window is mapped again */
    case MapNotify:
#ifdef DEBUG
      fprintf(stderr, "Window mapped\n");
#endif
      iconified = FALSE;
      break;

      /* part of the window was exposed */
    case Expose:
      flush_pixmap(FALSE);
      break;
      
    case KeyPress:
      {
      unsigned keycode;
      KeyPressAction *ptr;
      
      keycode = xev.xkey.keycode;
      ptr = &(key_press_table[keycode]);
      if (NULL != ptr->addr) {
        *(ptr->addr) = ptr->value;
      } else {
        /* dirty quick hack to be changed soon */
        if (XK_Print == XLookupKeysym(&xev.xkey, 0)) {
          print_screen();
        }
        if (XK_Escape == XLookupKeysym(&xev.xkey, 0)) {
          (*quit_function)();
        }
        /* first boss key, works only with window manager */
        if (XK_BackSpace == XLookupKeysym(&xev.xkey, 0)) {
          XIconifyWindow(dpy,win,DefaultScreen(dpy));
        }
      }
      }

      break;

    case KeyRelease:
      {
      unsigned keycode;
      KeyPressAction *ptr;
      
      keycode = xev.xkey.keycode;
      ptr = &(key_release_table[keycode]);
      if (NULL != ptr->addr) {
        *(ptr->addr) = ptr->value;
      } 
      }
      break;
    }
  }
  return;
}

/* local function : init_block_bw */
#ifdef __STDC__
void 
init_block_bw (int in_pix, 
             BMBlockTile *tile)
#else
void 
init_block_bw (in_pix, tile)
  int in_pix;
  BMBlockTile *tile;
#endif
{
  /* black and white block */
  pix_block[in_pix] = read_pbm_black_white_map("bitmap/block", tile->id);
}

#ifndef MONO_XBLAST
/* local function : init_block_color */
#ifdef __STDC__
void 
init_block_color (int in_pix, BMBlockTile *tile)
#else
void 
init_block_color (in_pix, tile)
  int in_pix;
  BMBlockTile *tile;
#endif
{
  if (tile->fg != NULL) {
    /*  block is to be colored */
    pix_block[in_pix] 
      = read_cch_pixmap("image/block", tile->id, tile->fg, tile->bg, tile->add);
  } else {
    /* rgb block */
    pix_block[in_pix] = read_rgb_pixmap("image/block", tile->id);
  }
}
#endif

/* public function : init_block */
#ifdef __STDC__
void 
init_block (int in_pix,
          BMBlockTile *tile)
#else
void 
init_block (in_pix, tile)
  int in_pix;
  BMBlockTile *tile;
#endif
{
#ifndef MONO_XBLAST
  switch(colorMode) {
  case COL_MONO:
  case COL_COLOR:
#endif
    init_block_bw(in_pix, tile);
#ifndef MONO_XBLAST
    break;
  case COL_HICOLOR:
    init_block_color(in_pix, tile);
    break;
  }
#endif
}

#ifndef MONO_XBLAST
/* local function: init_explosion_blocks_color */
#ifdef __STDC__
void 
init_explosion_blocks_color (void)
#else
void 
init_explosion_blocks_color ()
#endif
{
  int i;
  static XGCValues xgcv;
    
  for (i=0; i < MAX_EXPLOSION; i++) {
    pix_expl_block[i] =
      XCreatePixmap(dpy, pix, BLOCK_WIDTH, BLOCK_HEIGHT,
                def_depth);
    
    xgcv.tile = pix_block[BTFree];
    XChangeGC(dpy, gc_drawblock, GCTile, &xgcv);
    XFillRectangle(dpy, pix_expl_block[i], 
               gc_drawblock,
               0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
    
    xgcv.clip_mask = pix_expl_mask[i];
    xgcv.clip_y_origin = 0;
    xgcv.clip_x_origin = 0;
    xgcv.tile = pix_expl_bits[i];
    xgcv.ts_y_origin = 0;
    xgcv.ts_x_origin = 0;
    XChangeGC(dpy, gc_sprite_bits,
            GCClipMask | GCClipXOrigin |GCClipYOrigin |
            GCTile | GCTileStipXOrigin |GCTileStipYOrigin,
            &xgcv);
    XFillRectangle(dpy, pix_expl_block[i], 
               gc_sprite_bits,
               0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
  }
}
#endif

/* local function: init_explosion_blocks_bw */
#ifdef __STDC__
void 
init_explosion_blocks_bw (void)
#else
void 
init_explosion_blocks_bw ()
#endif
{
  int i;
  static XGCValues xgcv;
    
  for (i=0; i < MAX_EXPLOSION; i++) {
    pix_expl_block[i] =
      XCreatePixmap(dpy, pix, BLOCK_WIDTH, BLOCK_HEIGHT, 1);
    
    xgcv.tile = pix_block[BTFree];
    XChangeGC(dpy, gc_drawblock,
            GCTile, &xgcv);
    XFillRectangle(dpy, pix_expl_block[i], 
               gc_drawblock,
               0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
    
    xgcv.stipple = pix_expl_mask[i];
    xgcv.ts_y_origin = 0;
    xgcv.ts_x_origin = 0;
    XChangeGC(dpy, gc_sprite_mask,
            GCStipple | GCTileStipXOrigin |GCTileStipYOrigin,
            &xgcv);
    XFillRectangle(dpy, pix_expl_block[i], 
               gc_sprite_mask,
               0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
    
    xgcv.stipple = pix_expl_bits[i];
    xgcv.ts_y_origin = 0;
    xgcv.ts_x_origin = 0;
    XChangeGC(dpy, gc_sprite_bits,
            GCStipple | GCTileStipXOrigin |GCTileStipYOrigin,
            &xgcv);
    XFillRectangle(dpy, pix_expl_block[i], 
               gc_sprite_bits,
               0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
  }
}

/* public function: init_explosion_blocks */
#ifdef __STDC__
void 
init_explosion_blocks (void)
#else
void 
init_explosion_blocks ()
#endif
{
#ifndef MONO_XBLAST
  switch (colorMode) {
  case COL_MONO:
#endif
    init_explosion_blocks_bw();
#ifndef MONO_XBLAST
    break;
  case COL_COLOR:
  case COL_HICOLOR:
    init_explosion_blocks_color();
    break;
  }
#endif
}

/* public function : free_block */
#ifdef __STDC__
void 
free_block (int in_pix)
#else
void 
free_block (in_pix)
  int in_pix;
#endif
{
  int num;
  unsigned long pix_val[3];

  /* free pixmap */
  XFreePixmap(dpy, pix_block[in_pix]);
  /* free read only colors cells */
#ifndef MONO_XBLAST
  if (colorMode == COL_COLOR) {
    num=0;
    if (col_triple[in_pix].fg != black_pixel) {
      pix_val[num++] = (unsigned long) col_triple[in_pix].fg;
    }
    if (col_triple[in_pix].bg != white_pixel) {
      pix_val[num++] = (unsigned long) col_triple[in_pix].bg;
    }
    if (col_triple[in_pix].add != white_pixel) {
      pix_val[num++] = (unsigned long) col_triple[in_pix].add;
    }
    if (num >0) {
      XFreeColors(dpy, cmap, pix_val, num, 0);
    }
  }
#endif
}

/* public function : free_explosion_blocks */
#ifdef __STDC__
void 
free_explosion_blocks (void)
#else
void 
free_explosion_blocks ()
#endif
{
  int i;
  
  for (i = 0; i < MAX_EXPLOSION; i ++ ) {
    XFreePixmap(dpy, pix_expl_block[i]);
  }
}


static XRectangle void_list[MAZE_W*MAZE_H];
static XRectangle *void_last = void_list;
static XRectangle block_list[MAX_BLOCK][MAZE_W*MAZE_H];
static XRectangle *block_last[MAX_BLOCK] = {
  block_list[0],
  block_list[1],
  block_list[2],
  block_list[3],
  block_list[4],
  block_list[5],
  block_list[6],
  block_list[7],
  block_list[8],
  block_list[9],
  block_list[10],
};

/* 
 * public function : draw_block 
 */
#ifdef __STDC__
void 
draw_block (int x, 
          int y, 
          int block)
#else
void 
draw_block (x, y, block)
     int x, y, block;
#endif
{
#ifdef DEBUG
  if ( (x < 0) || (x >= MAZE_W) 
      || (y < 0) || (y >= MAZE_H)
      || (block<-1) || (block >= MAX_BLOCK) ) {
    fprintf(stderr,"ERROR in draw_block\n");
    fprintf(stderr,"x = %d, y = %d, block =%d\n",x,y,block);
  }
#endif

  if (block >= 0) {
    block_last[block]->x = x*BLOCK_WIDTH;
    block_last[block]->y = y*BLOCK_HEIGHT;
    block_last[block]->width = BLOCK_WIDTH;
    block_last[block]->height = BLOCK_HEIGHT;

    block_last[block] ++;
  } else {
    void_last->x = x*BLOCK_WIDTH;
    void_last->y = y*BLOCK_HEIGHT;
    void_last->width = BLOCK_WIDTH;
    void_last->height = BLOCK_HEIGHT;

    void_last ++;
  }
}


#ifdef __STDC__
void 
draw_block_at (int x, int y, 
             int block)
#else
void 
draw_block_at (x, y, block)
     int x, y, block;
#endif
{
#ifdef DEBUG
  if ( (x < 0) || (x >= MAZE_W) 
      || (y < 0) || (y >= MAZE_H)
      || (block<-1) || (block >= MAX_BLOCK) ) {
    fprintf(stderr,"ERROR in draw_block\n");
    fprintf(stderr,"x = %d, y = %d, block =%d\n",x,y,block);
  }
#endif

  if (block >= 0) {
    XSetTile(dpy, gc_drawblock, pix_block[block]);
    XFillRectangle(dpy, pix, gc_drawblock,
               x*BLOCK_WIDTH, y*BLOCK_HEIGHT,
               BLOCK_WIDTH, BLOCK_HEIGHT );
  } else {
    XFillRectangle(dpy, pix, gc_clearpix,
               x*BLOCK_WIDTH, y*BLOCK_HEIGHT,
               BLOCK_WIDTH, BLOCK_HEIGHT );
  }
}

static XRectangle expl_list[MAX_EXPLOSION][MAZE_W*MAZE_H];
static XRectangle *expl_last[MAX_EXPLOSION] = {
  expl_list[0],
  expl_list[1],
  expl_list[2],
  expl_list[3],
  expl_list[4],
  expl_list[5],
  expl_list[6],
  expl_list[7],
  expl_list[8],
  expl_list[9],
  expl_list[10],
  expl_list[11],
  expl_list[12],
  expl_list[13],
  expl_list[14],
  expl_list[15],
};

/* 
 * public function : draw_explosion 
 */
#ifdef __STDC__
void 
draw_explosion (int x,
            int y, 
            int block)
#else
void 
draw_explosion(x, y, block)
     int x, y, block;
#endif
{
#ifdef DEBUG
  if (block < 0) {
    fprintf(stderr,"DRAW EXPLOSION: Negative Block Number %d\n",block);
  }
  if (block >= MAX_EXPLOSION) {
    fprintf(stderr,"DRAW EXPLOSION: Block Number %d to large\n",block);
  }
#endif

    expl_last[block]->x = x*BLOCK_WIDTH;
    expl_last[block]->y = y*BLOCK_HEIGHT;
    expl_last[block]->width = BLOCK_WIDTH;
    expl_last[block]->height = BLOCK_HEIGHT;

    expl_last[block] ++;
}


/* public function flush_blocks */
#ifdef __STDC__
void
flush_blocks (void )
#else
void
flush_blocks ()
#endif
{
  int i;

  /* void blocks */
  if (void_last != void_list) {
    XFillRectangles(dpy, pix, gc_clearpix,
                void_list, void_last - void_list);
    void_last = void_list;
  }

  /* normal blocks */
  for (i=0; i<MAX_BLOCK; i++) {
    if (block_last[i] != block_list[i]) {
      XSetTile(dpy, gc_drawblock, pix_block[i]);
      XFillRectangles(dpy, pix, gc_drawblock,
                  block_list[i], block_last[i] - block_list[i]);
      block_last[i] = block_list[i];
    }
  }

  /* explosion blocks */
  for (i=0; i<MAX_EXPLOSION; i++) {
    if (expl_last[i] != expl_list[i]) {
      XSetTile(dpy, gc_drawblock, pix_expl_block[i]);
      XFillRectangles(dpy, pix, gc_drawblock,
                  expl_list[i], expl_last[i] - expl_list[i]);
      expl_last[i] = expl_list[i];
    }
  }
}


/* public function : draw_explosion */
#ifdef __STDC__
void 
draw_explosion_sprite (int x,
                   int y, 
                   int block)
#else
void 
draw_explosion_sprite  (x, y, block)
     int x, y, block;
#endif
{
#ifndef MONO_XBLAST
  if (colorMode) {
    XSetTSOrigin(dpy, gc_sprite_bits, x*BLOCK_WIDTH, 
             y*BLOCK_HEIGHT);
    XSetClipOrigin(dpy, gc_sprite_bits, x*BLOCK_WIDTH, 
               y*BLOCK_HEIGHT);
    XSetClipMask(dpy, gc_sprite_bits, pix_expl_mask[block]);
    XSetTile(dpy, gc_sprite_bits, pix_expl_bits[block]);
    XFillRectangle(dpy, pix, gc_sprite_bits,
               BLOCK_WIDTH*x, BLOCK_HEIGHT*y,
               BLOCK_WIDTH, BLOCK_HEIGHT);
  } else {
#endif
    XSetTSOrigin(dpy, gc_sprite_mask, x*BLOCK_WIDTH, 
             y*BLOCK_HEIGHT);
    XSetStipple(dpy, gc_sprite_mask, pix_expl_mask[block]);
    XFillRectangle(dpy, pix, gc_sprite_mask,
               BLOCK_WIDTH*x, BLOCK_HEIGHT*y,
               BLOCK_WIDTH, BLOCK_HEIGHT);
    XSetTSOrigin(dpy, gc_sprite_bits, x*BLOCK_WIDTH, 
             y*BLOCK_HEIGHT);
    XSetStipple(dpy, gc_sprite_bits, pix_expl_bits[block]);
    XFillRectangle(dpy, pix, gc_sprite_bits,
               BLOCK_WIDTH*x, BLOCK_HEIGHT*y,
               BLOCK_WIDTH, BLOCK_HEIGHT);
#ifndef MONO_XBLAST
  }
#endif
}



/* local function flush_sync */
#ifdef __STDC__
static void 
flush_sync (void)
#else
static void 
flush_sync()
#endif
{
#ifdef hpux
  XSync(dpy, FALSE);
#else
  XFlush(dpy);
#endif
}



/* Public function clear_window */
#ifdef __STDC__
void 
clear_window (void)
#else
void 
clear_window ()
#endif
{
  XClearWindow(dpy, win);
}


/* globals for fade routines */

static XSegment line[PIXH+SCOREH];
static int fade_count;
static int fade_max;

#ifdef __STDC__
void 
set_fade_max (int max)
#else
void 
set_fade_max (max)
  int max;
#endif
{
  fade_max = max;
}


/* public function init_fade */
#ifdef __STDC__
void 
init_fade (int step)
#else
void 
init_fade(step)
     int step;
#endif
{
  int i;
  
  XSetForeground(dpy, gc_window, black_pixel);
  
  if (step == FADE_STEP) {
    fade_count = (fade_max/step);
    for (i=0; i<= fade_count; i+=1) {
      line[i].x1 = 0;
      line[i].x2 = PIXW-1;
      line[i].y2 = line[i].y1 = i*step;
    }
  } else {
    fade_count = ((fade_max - step)/step/2);
    for (i=0; i<= fade_count; i+=1) {
      line[i].x1 = 0;
      line[i].x2 = PIXW-1;
      line[i].y2 = line[i].y1 = (2*i+1)*step;
    }
  }
}


/* public function init_fade */
#ifdef __STDC__
void 
init_white (int step)
#else
void 
init_white(step)
     int step;
#endif
{
  int i;

  XSetForeground(dpy, gc_window, white_pixel);
  
  if (step == FADE_STEP) {
    fade_count = (fade_max/step);
    for (i=0; i<= fade_count; i+=1) {
      line[i].x1 = 0;
      line[i].x2 = PIXW-1;
      line[i].y2 = line[i].y1 = i*step;
    }
  } else {
    fade_count = ((fade_max - step)/step/2);
    for (i=0; i<= fade_count; i+=1) {
      line[i].x1 = 0;
      line[i].x2 = PIXW-1;
      line[i].y2 = line[i].y1 = (2*i+1)*step;
    }
  }
}



/* public function fade_out_window */
#ifdef __STDC__
void 
fade_out_window (void)
#else
void 
fade_out_window ()
#endif
{
  XDrawSegments(dpy, win, gc_window, line, fade_count);
  flush_sync();
}



/* public function fade_in_window */
#ifdef __STDC__
void 
fade_in_window (void)
#else
void 
fade_in_window ()
#endif
{
  XDrawSegments(dpy, win, gc_frompix, line, fade_count);
  flush_sync();
}



/* public function : clear_pixmap */
#ifdef __STDC__
void 
clear_pixmap (void)
#else
void 
clear_pixmap ()
#endif
{
  XFillRectangle(dpy, pix, gc_clearpix, 0, 0, PIXW, PIXH+SCOREH);
}


/* public fucntion add_rectangle */
#ifdef __STDC__
void 
add_maze_rectangle (int x,
                int y)
#else
void 
add_maze_rectangle (x,y)
  int x,y;
#endif
{
  xrec_max->height = BLOCK_HEIGHT;
  xrec_max->x      = x*BLOCK_WIDTH;
  xrec_max->y      = y*BLOCK_HEIGHT;
  xrec_max->width  = BLOCK_WIDTH;

  if (xrec_max != xrec) {
    XRectangle *prev = xrec_max - 1;
    
    if ( (prev->y == xrec_max->y) 
      && ((xrec_max->x - prev->x) == prev->width) ) {
      prev->width += BLOCK_WIDTH;
      xrec_max = prev;
    }
  }

  xrec_max ++;
}



#ifdef __STDC__
void 
add_stat_rectangle (int x,
                int y)
#else
void 
add_stat_rectangle (x,y)
  int x, y;
#endif
{
  if (y == 0) {
    xrec_max->height = STAT_HEIGHT;
  } else {
    xrec_max->height = LED_HEIGHT;
  }

  xrec_max->x      = x*STAT_WIDTH;
  xrec_max->y      = MAZE_H*BLOCK_HEIGHT + y*STAT_HEIGHT;
  xrec_max->width  = STAT_WIDTH;

  if (xrec_max != xrec) {
    XRectangle *prev = xrec_max - 1;
    
    if ( (prev->y == xrec_max->y) 
      && ((xrec_max->x - prev->x) == prev->width) ) {
      prev->width += BLOCK_WIDTH;
      xrec_max = prev;
    }
  }


  xrec_max ++;
}



/* public function flush_score_board */
#ifdef __STDC__
void 
flush_score_board (void)
#else
void 
flush_score_board ()
#endif
{
  XFillRectangle( dpy, win, gc_frompix, 0, PIXH, PIXW, SCOREH);
  flush_sync();
}



/* public function : flush_pixmap */
#ifdef __STDC__
void 
flush_pixmap (int flag)
#else
void 
flush_pixmap (flag)
     int flag;
#endif
{
  if (!flag) {
    /* Copy Pixmap to Window */
    int i;

    for (i = 0; i < 4; i ++) {
      XFillRectangle (dpy, win, gc_frompix, 0, (PIXH + SCOREH)/4 * i, 
                  PIXW, (PIXH + SCOREH)/4 );
    }
  } else {
#ifdef CLEAR_WINDOW
    XClearWindow( dpy, win );
#endif 
    if (!iconified) {
      XFillRectangles( dpy, win, gc_frompix, xrec, xrec_max - xrec );
    }
    xrec_max = xrec;
  }
  flush_sync();
}

/*
 * public function win_is_mapped
 */
#ifdef __STDC__
int
win_is_mapped (void)
#else
int
win_is_mapped ()
#endif
{
  return !iconified;
}

/* 
 * public function: rect_player_sprite
 */
#ifdef __STDC__
BMRectangle *
rect_player_sprite (Sprite *ptr)
#else
BMRectangle *
rect_player_sprite (ptr)
  Sprite *ptr;
#endif
{
  static BMRectangle result;
  PlayerSpriteData *spr = &(sprite_data[ptr->player.player][ptr->any.anime]);

  result.x = ptr->any.x + spr->xoffset;
  result.y = ptr->any.y + spr->yoffset;
  result.w = spr->width;
  result.h = spr->height;
   
  return &result;
}

#ifdef __STDC__
BMRectangle *
rect_bomb_sprite (Sprite *ptr)
#else
BMRectangle *
rect_bomb_sprite (ptr)
  Sprite *ptr;
#endif
{
  static BMRectangle result;

  result.x = ptr->any.x;
  result.y = ptr->any.y;
  result.w = BLOCK_WIDTH;
  result.h = BLOCK_HEIGHT;
   
  return &result;
}

/* public function draw_bomb_sprite */
#ifdef __STDC__
void 
draw_bomb_sprite (Sprite *ptr)
#else
  void 
draw_bomb_sprite (ptr)
          Sprite *ptr;
#endif
{
  BombSprite *spl = (BombSprite *)ptr;

#ifndef MONO_XBLAST
  /* draw sprite as clipped tile when in color mode */
  if ( !(spl->mode & SPM_MASKED) && colorMode ) {
    /* set drawing offset */
    XSetClipOrigin(dpy, gc_sprite_bits, spl->x, spl->y);
    XSetTSOrigin(dpy, gc_sprite_bits, spl->x, spl->y);
    XSetClipMask(dpy, gc_sprite_bits, pix_bomb_mask[spl->bomb][spl->anime] );
    XSetTile(dpy, gc_sprite_bits, pix_bomb_bits[spl->bomb][spl->anime] );
    XFillRectangle(dpy, pix, gc_sprite_bits,
               (int)spl->x, (int)spl->y, BLOCK_WIDTH, BLOCK_HEIGHT);
  } else {
#endif
    /* draw sprite mask if not in color mode or mask is needed*/
    XSetTSOrigin(dpy, gc_sprite_mask, spl->x, spl->y);
    XSetStipple(dpy, gc_sprite_mask, pix_bomb_mask[spl->bomb][spl->anime] );
    XFillRectangle(dpy, pix, gc_sprite_mask,
               (int)spl->x, (int)spl->y, BLOCK_WIDTH, BLOCK_HEIGHT);
#ifndef MONO_XBLAST
  }
#endif
  /* draw sprite as stipple when in monochrome mode */
  if (!colorMode && !(spl->mode & SPM_MASKED) ) {
    /* set drawing offset */
    XSetTSOrigin(dpy, gc_sprite_bits, spl->x, spl->y);
    XSetStipple(dpy, gc_sprite_bits, pix_bomb_bits[spl->bomb][spl->anime] );
    XFillRectangle(dpy, pix, gc_sprite_bits,
               (int)spl->x, (int)spl->y, BLOCK_WIDTH, BLOCK_HEIGHT);
  }
}


/* public function draw_player_sprite */
#ifdef __STDC__
void 
draw_player_sprite (Sprite *ptr)
#else
void 
draw_player_sprite (ptr)
          Sprite *ptr;
#endif
{
  int x, y;
  int width, height;

  PlayerSprite *spl = (PlayerSprite *)ptr;

  /* set dimensions */
  x = spl->x + sprite_data[spl->player][spl->anime].xoffset;
  y = spl->y + sprite_data[spl->player][spl->anime].yoffset;
  width  = sprite_data[spl->player][spl->anime].width;
  height = sprite_data[spl->player][spl->anime].height;
  
#ifndef MONO_XBLAST
  /* draw sprite as clipped tile when in color mode */
  if ( !(spl->mode & SPM_MASKED) && colorMode ) {
    /* set drawing offset */
    XSetClipOrigin(dpy, gc_sprite_bits, x, y);
    XSetTSOrigin(dpy, gc_sprite_bits, x, y);
    XSetClipMask(dpy, gc_sprite_bits, 
             sprite_data[spl->player][spl->anime].mask );
    XSetTile(dpy, gc_sprite_bits, 
           sprite_data[spl->player][spl->anime].bits);
    XFillRectangle(dpy, pix, gc_sprite_bits,
               x, y, width, height );
  } else {
#endif
    /* draw sprite mask if not in color mode or mask is needed*/
    XSetTSOrigin(dpy, gc_sprite_mask, x, y);
    XSetStipple(dpy, gc_sprite_mask,
            sprite_data[spl->player][spl->anime].mask );
    XFillRectangle(dpy, pix, gc_sprite_mask,
               x, y, width, height );
#ifndef MONO_XBLAST
  }
#endif
  /* draw sprite as stipple when in monochrome mode */
  if (!colorMode && !(spl->mode & SPM_MASKED) ) {
    /* set drawing offset */
    XSetTSOrigin(dpy, gc_sprite_bits, x, y);
    XSetStipple(dpy, gc_sprite_bits, 
            sprite_data[spl->player][spl->anime].bits);
    XFillRectangle(dpy, pix, gc_sprite_bits,
               x, y, width, height );
  }
}

/* public function draw_time_led */
#ifdef __STDC__
void 
draw_time_led (int x, 
             int block)
#else
void 
draw_time_led (x, block)
     int x, block;
#endif
{
  XSetTile(dpy, gc_drawblock, pix_leds[block]);
  XFillRectangle(dpy, pix, gc_drawblock,
                 x*LED_WIDTH, MAZE_H*BLOCK_HEIGHT + STAT_HEIGHT, 
             LED_WIDTH, LED_HEIGHT);
}



/* public function draw_score_block */
#ifdef __STDC__
void 
draw_score_block (int x, 
              int block)
#else
void 
draw_score_block (x, block)
     int x, block;
#endif
{
  XSetTile(dpy, gc_drawblock, pix_score[block]);
  XFillRectangle(dpy, pix, gc_drawblock,
             x*STAT_WIDTH, MAZE_H*BLOCK_HEIGHT,
             STAT_WIDTH, STAT_HEIGHT );
}


/* public function draw_score_block */
#ifdef __STDC__
void 
draw_score_block_half (int x, 
                   int block,
                   int left)
                   
#else
void 
draw_score_block_half (x, block, left)
     int x, block, left;
#endif
{
  XSetTile(dpy, gc_drawblock, pix_score[block]);
  if (left) {
    XFillRectangle(dpy, pix, gc_drawblock,
               x*STAT_WIDTH, MAZE_H*BLOCK_HEIGHT,
               7*STAT_WIDTH/12, STAT_HEIGHT );
  } else {
    XFillRectangle(dpy, pix, gc_drawblock,
               (12*x+7)*STAT_WIDTH/12, MAZE_H*BLOCK_HEIGHT,
               5*STAT_WIDTH/12, STAT_HEIGHT );
  }
}



/* public draw_polygon */
#ifdef __STDC__
void 
draw_polygon (int x, 
            int y, 
            int w, 
            int h,
            BMPoint *points,
            int npoints, 
            int black_white)
#else
void 
draw_polygon (x, y, w, h, points, npoints, black_white )
          int x, y, w, h;
     BMPoint *points;
     int npoints,black_white ;
#endif
{
  XPoint *xp;
  int i;

  xp = (XPoint *)calloc(sizeof(XPoint),npoints+1);
  
  for (i=0; i < npoints; i++) {
    xp[i].x = (int)(x + w*points[i].x);
    xp[i].y = (int)(y + h*points[i].y);
  }
  xp[npoints]=xp[0];

  if (black_white) {
    XFillPolygon(dpy, pix, gc_text_black, xp, npoints, 
             Complex, CoordModeOrigin);
    XDrawLines(dpy, pix, gc_text_white, xp, npoints+1, 
             CoordModeOrigin);
  } else {
    XFillPolygon(dpy, pix, gc_text_white, xp, npoints, 
             Complex, CoordModeOrigin);
    XDrawLines(dpy, pix, gc_text_black, xp, npoints+1, 
             CoordModeOrigin);
  }

  free(xp);
}     


/*
 * public draw_textbox
 */
#ifdef __STDC__
void
draw_textbox (char *text,
            int flags,
            BMRectangle *rect)
#else
void
draw_textbox (text, flags, rect)
          char *text;
     int flags;
     BMRectangle *rect;
#endif
{
  XFontStruct *font;
  int y, width, height;
  GC gc_fg, gc_bg;
  XRectangle clip;

  /* first get used font */
  font = font_struct[FM_Size & flags];

  /* set gc for foreground and background */
  if (flags & FM_Color) {
    gc_fg = gc_text_white;
    gc_bg = gc_text_black;
  } else {
    gc_fg = gc_text_black;
    gc_bg = gc_text_white;
  }

  /* draw boxes if needed */
  XSetTSOrigin(dpy, gc_fg, 0, rect->y + (rect->h-BLOCK_HEIGHT)/2);
  if (flags & FM_Boxed) {
    if ( !(flags & FM_Transparent)) {
      XSetTSOrigin(dpy, gc_bg, 0, rect->y + (rect->h-BLOCK_HEIGHT)/2);
      XFillRectangle(dpy, pix, gc_bg, rect->x, rect->y, rect->w, rect->h);
    } else {
      XGCValues xgcv;

      xgcv.line_width = 1;
      XChangeGC(dpy, gc_bg, GCLineWidth , &xgcv);
      for (y=0; y < rect->h; y+=2) {
      XDrawLine(dpy, pix, gc_bg, rect->x, rect->y + y, 
              rect->x + rect->w -1, rect->y + y);
      } 
      xgcv.line_width = colorMode ? 3 : 2;
      XChangeGC(dpy, gc_bg, GCLineWidth , &xgcv);
    }
    XDrawRectangle(dpy, pix, gc_fg, rect->x, rect->y, 
               rect->w, rect->h);
  }

  /* draw string */
  if (NULL != text) {
    /* set clipping rectangles */
    clip.x = rect->x;
    clip.y = rect->y;
    clip.width = rect->w;
    clip.height = rect->h;
    XSetClipRectangles(dpy, gc_fg, 0, 0, &clip, 1, YXBanded);
    /* dimensions of text */
    width = XTextWidth(font, text, strlen(text) );
    height = font->max_bounds.ascent - font->max_bounds.descent;
    /* draw it */
    XSetFont(dpy, gc_fg, font->fid);
    if (flags & FM_Outlined) {
      int dx, dy;
      XSetFont(dpy, gc_bg, font->fid);
      XSetClipRectangles(dpy, gc_bg, 0, 0, &clip, 1, YXBanded);

      for (dx=(-2); dx<=2; dx+=2) {
      for (dy=(-2); dy<=2; dy+=2) {
        XDrawString(dpy, pix, gc_bg, 
                  rect->x + dx + (rect->w - width)/2, 
                  rect->y + dy + (rect->h + height)/2,
                  text, strlen(text));
      }
      }
      XSetClipMask(dpy, gc_bg, None);
    }
    XDrawString(dpy, pix, gc_fg, 
            rect->x + (rect->w-width)/2, rect->y + (height+rect->h)/2,
            text, strlen(text));
    /* reset clip mask */
    XSetClipMask(dpy, gc_fg, None);
  }
}



/* public function do_bell */
#ifdef __STDC__
void 
do_bell (void)
#else
void 
do_bell ()
#endif
{
  XBell(dpy,BELL_VOLUME);
}

#ifdef __STDC__
void 
no_bell (void)
#else
void 
no_bell ()
#endif
{
}

/*
 * end of file graphics.c
 */

Generated by  Doxygen 1.6.0   Back to index