/****************************************************************************
 *    File: main-lsl.c
 * Purpose: Support for Linux-SVGALib Angband 
 *  Author: Jon Taylor (jon.taylor@gaia.ecs.csus.edu)
 * Version: 1.0, 17/09/95
 * 
 * See "term.c" for info on the "generic terminal" that we support.
 * See "recall.c"/"moria1.c" for info on the "recall"/"choice" windows.
 * 
 * Some of the ideas in this code came from main-win.c by Skirmantas Kligys
 * (kligys@scf.usc.edu).
 ***************************************************************************/

/* Standard C header files */
#include <stdio.h>
#include <stdlib.h>

/* SVGAlib header files */
#include <vga.h>
#include <vgagl.h>
#include <vgakeyboard.h>

/* Angband header files */
#include "angband.h"

/* Bitmap handling stuff */
#include "readbmp.h"

/* Define font/graphics cell width and height */
#define CHAR_W 8
#define CHAR_H 13

/* Define the number of columns in the source bitmap */
#define BM_COLS 64


/* ======================================================================= */


/* The main "term" structure */
static term term_screen_body;

/* The visible and virtual screens */
GraphicsContext *screen;
GraphicsContext *buffer;

/* The bitmap data */
void *bmap;

/* The font data */
void *font;

/* Initialize the screen font */
void initfont () {
  FILE *fontfile;
  void *temp;
  long junk;

  /* Use an 8x12 font.  The graphic symbols are 8x13, so much hackage =s
   * necessary to avoid problems from this.  Anyone have a bitmapped 8x13
   * font file laying around that they could send me? |-> */
  fontfile=fopen("/usr/lib/kbd/consolefonts/8x12alt.psf","r");

  /* Junk the 4-byte header */
  fread (&junk,4,1,fontfile);
  
  temp=malloc(12*256);
  fread (temp,1,3328,fontfile);
  font=malloc(256*8*12*BYTESPERPIXEL);
  gl_expandfont(8,12,15,temp,font);
  gl_setfont(8,12,font);
  free(temp);
  
}


/* Initialize palette values for colors 0-15 */
void setpal() {
  gl_setpalettecolor (0,00,00,00); /* Black */
  gl_setpalettecolor (3,63,63,63); /* White */
  gl_setpalettecolor (13,40,40,40); /* Gray */
  gl_setpalettecolor (11,25,15,05); /* Orange */
  gl_setpalettecolor (2,32,00,00); /* Red */
  gl_setpalettecolor (7,00,32,00); /* Green */
  gl_setpalettecolor (12,00,00,40); /* Blue */
  gl_setpalettecolor (5,50,25,00); /* Brown */
  gl_setpalettecolor (1,28,28,28); /* Dark Gray */
  gl_setpalettecolor (10,52,52,52); /* Light Gray */
  gl_setpalettecolor (15,41,00,63); /* Purple */
  gl_setpalettecolor (4,63,63,00); /* Yellow */
  gl_setpalettecolor (14,63,00,00); /* Light Red */
  gl_setpalettecolor (6,00,63,00); /* Light Green */
  gl_setpalettecolor (9,00,50,63); /* Light Blue */
  gl_setpalettecolor (8,63,52,32); /* Light Brown */
}

/* Translates raw palette index to Angband color index */
const char pal_trans[16]={0,3,13,11,2,7,12,5,1,10,15,4,14,6,9,8};


/****************************************************************************
 * Check for "events"
 * If block, then busy-loop waiting for event, else check once and exit
 ***************************************************************************/
static errr CheckEvents (int block) {
  int k=0;

  if (block) {
    k=vga_getkey();
    if (k<1) return (1);
  } else while ((k=vga_getkey())<1);
    
  Term_keypress(k);
  
  return(0);
}


/****************************************************************************
 * Low-level graphics routine (assumes valid input)
 * Do a "special thing"
 ***************************************************************************/
static errr term_xtra_svgalib (int n, int v) {
  
  switch (n) {
   case TERM_XTRA_CHECK: return(CheckEvents(TRUE));
   case TERM_XTRA_EVENT: return(CheckEvents(FALSE));
  }
  return(1);
  
}

/****************************************************************************
 * Low-level graphics routine (assumes valid input)
 * Draws a "cursor" at (x,y)
 ***************************************************************************/
static errr term_curs_svgalib (int x, int y, int z) {
  gl_fillbox (x*CHAR_W,y*CHAR_H,CHAR_W,CHAR_H-1,15); 
  return(0);
}

/****************************************************************************
 * Low-level graphics routine (assumes valid input) 
 * Erases a rectangular block of characters from (x,y) to (x+w,y+h)
 ***************************************************************************/
static errr term_wipe_svgalib (int x,int y,int w,int h) {
  gl_fillbox (x*CHAR_W,y*CHAR_H,w*CHAR_W,h*CHAR_H,0);
  return(0);
}

/* Translates "normal" attribute code to a bitmap offset */
unsigned int char_to_grfx (unsigned char a, unsigned char c) {
  if (c==32) return 32; /* Spaces don't have attributes */
  else return (c+(a-128)*128);
}

/****************************************************************************
 * Low-level graphics routine (assumes valid input)
 * Draw n chars at location (x,y) with value s and attribute a
 ***************************************************************************/
errr term_text_svgalib (int x, int y, int n, unsigned char a, cptr s) {
  unsigned int g;
  int i;
  
  /* If we see a "text" (a<=127) attribute, output colored text */
  if (a<=127) {  
    gl_colorfont (8,12,pal_trans[a],font);
    gl_writen (x*CHAR_W,y*CHAR_H,n,(char *)s);
    
  }
  
  /* Otherwise, we are displaying graphics */
  else {
    for (i=0;i<n;i++) {
      
      g=char_to_grfx (a,s[i]); /* Translates attribute into bitmap offset */
      
      /* Hack - draw only the top 12 lines of the graphic so that lines
       * aren't left lying around on the screen when character spaces from 
       * the 12-point font are used to overwrite 13-point graphic blocks. */
      gl_copyboxfromcontext (buffer,g%BM_COLS*CHAR_W,g/BM_COLS*CHAR_H,CHAR_W,
			     CHAR_H-1,(x+i)*CHAR_W,y*CHAR_H);
    }
  }
  
  return(0);
}

void term_load_bitmap() {
  void *temp;
  
  temp=read_bmp_file();
  gl_putbox(0,0,512,221,temp); /* Blit bitmap into buffer */
  free (temp);
  
  return;
  
}

/****************************************************************************
 * Term hook
 * Initialize a new term
 ***************************************************************************/
static void term_init_svgalib (term *t) {
  int VGAMODE, VIRTUAL;

  vga_init();
  VGAMODE=G640x480x256; /* Hardwire this mode in for now */
  VIRTUAL=1;
  
  /* Set up the bitmap buffer context */
  gl_setcontextvgavirtual(VGAMODE);
  buffer=gl_allocatecontext();
  gl_getcontext(buffer);
  
  term_load_bitmap(); /* Load bitmap into virtual screen */
  
  /* Set up the physical screen context */
  vga_setmode(VGAMODE);
  gl_setcontextvga(VGAMODE);
  screen=gl_allocatecontext();
  gl_getcontext(screen);
  
  
  initfont(); /* Load the character font data */

  /* Zeros in the bitmap overwrite other colors */
  gl_setwritemode(WRITEMODE_OVERWRITE);
  
  setpal(); /* Set up palette colors */
}

/****************************************************************************
 * Term hook
 * Nuke an old term
 ***************************************************************************/
static void term_nuke_svgalib (term *t) {
  vga_setmode (TEXT); 
}

/****************************************************************************
 * Hook SVGAlib routines into term.c
 ***************************************************************************/
errr init_lsl (void) {
  term *t=&term_screen_body;
  
  term_init(t,80,24,1024); /* Initialize the term */
 
  use_graphics=TRUE; /* Show the wear/wield inventory as graphics */
  
  view_yellow_lite=FALSE; /* No yellow pool of light around character */
  view_bright_lite=FALSE; /* No drawing "hidden" grids as dimmer (gray) */
  
  t->soft_cursor=TRUE; /* The cursor is done via software and needs erasing */
  
  /* Add hooks */
  t->init_hook=term_init_svgalib;
  t->nuke_hook=term_nuke_svgalib;
  t->text_hook=term_text_svgalib;
  t->wipe_hook=term_wipe_svgalib;
  t->curs_hook=term_curs_svgalib;
  t->xtra_hook=term_xtra_svgalib;
  
  term_screen=t; /* Save the term */
  Term_activate(term_screen);

  
  return(0);
}
