#include "gl.h"
#include "gldevice.h"
#include "linuxgl.h"

#include <string.h>
#include <stdio.h>
#include <ctype.h>

/* This is my really cool vector font stuff.  I am really proud of this
   regardless of how good or bad it is.  Okay, it sucks...  Just kidding.
   I'm sure that this is nothing new, but I came up with it on my own
   and without any outside references or help, so it is a small personal
   achievement.  I tried to make it easy to use, and I think it is, but
   I don't like the way I chose to open up tons of fonts throughout
   the game.  I guess it's okay; I mean do you care?  -  If you want
   to use this for yourself, check out the usage in the main() below
   that is "#if 0"'s out */

/* Functions visible to other modules see main in this module for usage */

int openvecfont(float columns,float rows,float scaledown);
void vmov2(int fid,float x,float y);
void vmovrel2(int fid,float x,float y);
void vchar(int fid,char *guide);
void vprint(int fid,char *string);
void vcprint(int fid,char *string);
void vlprint(int fid,char *string);
void vleprint(int fid,char *string,char *erase);
void vrprint(int fid,char *string);
void vreprint(int fid,char *string,char *erase);
float vstrwidth(int fid,char *string);
void vccprint(int fid,int dmode,unsigned int bgcolor,unsigned int fgcolor,
	      char *string);
void vdim(int d);

/* End of visible functions */

static void init_vec_font(void);

#define VWIDTH (1.0 / 80.0)
#define VHEIGHT (1.0 / 50.0)
#define MAX_NUM_VFONTS 256
#ifndef MAX
#define MAX(x,y) (((x)>(y))?(x):(y))
#endif


typedef struct {
  float left,top,x,y,width,height;
  float points[9][3];
} vec_font;

vec_font *vf[MAX_NUM_VFONTS];
static float vwidth = VWIDTH,vheight = VHEIGHT;
static int dim;
static char *symbol[256];
static float npoints[9][3] = {
  {-0.5 ,-0.5 , 0.0 },
  { 0.0 ,-0.5 , 0.0 },
  { 0.5 ,-0.5 , 0.0 },
  {-0.5 , 0.0 , 0.0 },
  { 0.0 , 0.0 , 0.0 },
  { 0.5 , 0.0 , 0.0 },
  {-0.5 , 0.5 , 0.0 },
  { 0.0 , 0.5 , 0.0 },
  { 0.5 , 0.5 , 0.0 },
};

#ifdef __TESTING_VECFONT__
/* This main routine was made for testing */
/* You can compile this ".c" file with -lgl and try it. */
void main(void)
{
  int font1,font2,font3;
  int rval=0;
  short val;

  winopen("test");
  qdevice(ESCKEY);
  RGBmode();
  gconfig();

  do {
    static int first = 1;
    static int count = 0;

    printf("Running %d\n",count++);

    if(rval==ESCKEY) break;
    if(rval==REDRAW) {
      reshapeviewport();
    }
    cpack(0);
/*     clear(); */
    cpack(0xFFFFFF);
    ortho2(-1,1,-1,1);
    if(first) {
      first = 0;
      font1 = openvecfont(40,12,0.7);
      font2 = openvecfont(80,50,0.7);
      font3 = openvecfont(40,25,0.7);
    }
    vcprint(font1,"This is Aaron Hightower's vector font\n");
    vccprint(font1,NORMALDRAW,0x7F0000,0xFFFFFF,"Isn't is just jim dandy?");
    vlprint(font1,"Hello world!!!");
    vrprint(font1,"Hello world #2!!!");

    vmov2(font2,-0.90,0.90);
    vlprint(font2,"abcdefghijklmnopqrstuvwxyz\nabc\n");
    vmovrel2(font3,0,-10);
    vcprint(font3,"0123456789");
    vrprint(font3,"~!@#$%^&*()_+{}|");
    vlprint(font3,":\"<>?,./;'[]\\-=");
    vchar(font3,symbol[1]);vchar(font3,symbol[2]);

  } while(1);
/*   while(rval = qread(&val),1); */

  exit(0);
}
#endif /* !__TESTING_VECFONT__ */

void printfontinfo(int fid)
{
  int i;

  if(fid < 0) return;

  for(i=0;i<9;i++) {
    printf("Point[%d][0] = %f\nPoint[%d][1] = %f\n\n",
         fid,vf[fid]->points[i][0],     fid,vf[fid]->points[i][1]);
  }
  printf("left = %f top = %f\nx = %f y = %f\nwidth = %f height = %f\n",
     vf[fid]->left, vf[fid]->top, vf[fid]->x, vf[fid]->y, vf[fid]->width,
     vf[fid]->height);
}

int openvecfont(float columns,float rows,float scaledown)
{
  static int fontid = 0;
  int i,j;

  if(symbol['A'] == NULL) init_vec_font();
  if(fontid < MAX_NUM_VFONTS) {
    vf[fontid] = (vec_font *) calloc(sizeof(vec_font),1);
    vf[fontid]->width = (2.0/(float)columns);
    vf[fontid]->height= (2.0/(float)rows);
    vmov2(fontid,0.0,0.0);
    for(i=0;i<9;i++) {
      vf[fontid]->points[i][0] = npoints[i][0]*(vf[fontid]->width)*scaledown;
      vf[fontid]->points[i][1] = npoints[i][1]*(vf[fontid]->height)*scaledown;
      vf[fontid]->points[i][2] = npoints[i][2]*(vf[fontid]->height)*scaledown;
    }
    return fontid++;
  }
  else return -1;
}

static void init_vec_font(void)
{
  symbol[1]   = "7027"; /* Space ship - triangle pointed up */
  symbol[2]   = "367437 64"; /* Box with X inside - # kills - bowling strike */
  symbol[3]   = "173 75"; /* Up arrow (symbol for score) */
  symbol[4]   = "607 805"; /* Lines in diff directions (num shots) */
  symbol[5]   = "034";
  symbol[6]   = "8350";
  symbol[7]   = "13751 44"; /* (C) symbol */
  symbol[9]   = "6028615623781380750 35 17"; /* All lit up */
  symbol['A'] = symbol['a']= "0685352";
  symbol['B'] = symbol['b']= "06743520";
  symbol['C'] = symbol['c']= "8602";
  symbol['D'] = symbol['d']= "067510";
  symbol['E'] = symbol['e']= "8634302";
  symbol['F'] = symbol['f']= "068 34";
  symbol['G'] = symbol['g']= "860254";
  symbol['H'] = symbol['h']= "60 82 35";
  symbol['I'] = symbol['i']= "71";
  symbol['J'] = symbol['j']= "8203";
  symbol['K'] = symbol['k']= "60 832";
  symbol['L'] = symbol['l']= "602";
  symbol['M'] = symbol['m']= "06482";
  symbol['N'] = symbol['n']= "0628";
  symbol['O'] = symbol['o']= "06820";
  symbol['P'] = symbol['p']= "06853";
  symbol['Q'] = symbol['q']= "206824";
  symbol['R'] = symbol['r']= "068532";
  symbol['S'] = symbol['s']= "863520";
  symbol['T'] = symbol['t']= "1768";
  symbol['U'] = symbol['u']= "6028";
  symbol['V'] = symbol['v']= "618";
  symbol['W'] = symbol['w']= "60428";
  symbol['X'] = symbol['x']= "62 08";
  symbol['Y'] = symbol['y']= "6480";
  symbol['Z'] = symbol['z']= "6802";
  symbol['`']= "77";
  symbol['1']= "67102";
  symbol['2']= "685302";
  symbol['3']= "6853520";
  symbol['4']= "63582";
  symbol['5']= "863520";
  symbol['6']= "860253";
  symbol['7']= "682";
  symbol['8']= "3682035";
  symbol['9']= "28635";
  symbol['0']= "068208";
  symbol['-']= "35";
  symbol['=']= "35 02";
  symbol['~']= "3748";
  symbol['!']= "11 47";
  symbol['@']= "458602";
  symbol['#']= "07 18 32 65";
  symbol['$']= "863520 71";
  symbol['%']= "66 80 22";
  symbol['^']= "375";
  symbol['&']= "762 4015";
  symbol['*']= "043474542";
  symbol['(']= "842";
  symbol[')']= "640";
  symbol['_']= "02";
  symbol['+']= "71 35";
  symbol['.']= "11";
  symbol['"']= "66 77";
  symbol[':']= "44 11";
  symbol['/']= "08";
  symbol['<']= "832";
  symbol['>']= "650";
  symbol[',']= "41";
  symbol['?']= "6854 11";
  symbol['\'']= "77";
  symbol[';']= "77 41";
  symbol['[']= "8712";
  symbol[']']= "6710";
  symbol['\\']= "62";
  symbol['{']= "8743412";
  symbol['}']= "6745410";
  symbol['|']= "71";
}

void vmov2(int fid,float x,float y)
{
  vf[fid]->left = vf[fid]->x = x;
  vf[fid]->top  = vf[fid]->y = y;
}

void vmovrel2(int fid,float x,float y)
{
  vf[fid]->x += x * vf[fid]->width;
  vf[fid]->y -= y * vf[fid]->height;
}

float vcharpos(int fid,char *guide,float x)
{
  float pts[3];
  pts[2] = 0.0f;

  if(guide) {
    bgnline();
    while(*guide) {
      if(!isdigit(*guide)) {
	endline();
	bgnline();
      }
      else {
	pts[0] = vf[fid]->points[*guide-'0'][0] + x;
	pts[1] = vf[fid]->points[*guide-'0'][1] + vf[fid]->y;
	dim?v2f(pts):v3f(pts);
      }
      guide++;
    }
    endline();
  }
  return x+vf[fid]->width;
}

void vchar(int fid,char *guide)
{
  float pts[3];
  pts[2] = 0.0f;

  if(guide) {
    bgnline();
    while(*guide) {
      if(!isdigit(*guide)) {
	endline();
	bgnline();
      }
      else {
	pts[0] = vf[fid]->points[*guide-'0'][0] + vf[fid]->x;
	pts[1] = vf[fid]->points[*guide-'0'][1] + vf[fid]->y;
	dim?v2f(pts):v3f(pts);
      }
      guide++;
    }
    endline();
  }
  vf[fid]->x += vf[fid]->width;
}

/*
  Hack to Erase and print at the same time - this is to ease the burden
  of flicker on machines that don't have double buffering - AMH
*/
veprint(int fid,char *string,float x,char *erase)
{
#ifndef __LINUX__
  short rgb[3];
#endif
  int tcolor;

#ifdef __LINUX__
  tcolor = getcpack();
#else
  gRGBcolor(rgb,rgb+1,rgb+2);
#endif
  
  if(string && erase && vf[fid]) {
    while(*string || *erase) {
      cpack(0);
      if(*erase) x = vcharpos(fid,symbol[*erase++],x);
#ifdef __LINUX__
      cpack(tcolor);
#else
      c3s(rgb);
#endif
      if(*string) vchar(fid,symbol[*string++]);
    }
  }
}

/* vector print right justified - doesn't handle '\n's */
void vlprint(int fid,char *string)
{
  vf[fid]->x = -1.0 + vf[fid]->width;
  vprint(fid,string);
  vf[fid]->y -= vf[fid]->height;
}

void vleprint(int fid,char *string,char *erase)
{
  vf[fid]->x = -1.0 + vf[fid]->width;
  veprint(fid,string,vf[fid]->x,erase);
  vf[fid]->y -= vf[fid]->height;
}

/* vector print right justified - doesn't handle '\n's */
void vrprint(int fid,char *string)
{
  vf[fid]->x = 1.0 - vf[fid]->width;
  vmovrel2(fid,-((float) strlen(string)),0.0);
  vprint(fid,string);
  vf[fid]->y -= vf[fid]->height;
}

void vreprint(int fid,char *string,char *erase)
{
  float x;
  vf[fid]->x = 1.0 - vf[fid]->width;
  vmovrel2(fid,-((float) strlen(erase)),0.0);
  x = vf[fid]->x;
  vf[fid]->x = 1.0 - vf[fid]->width;
  vmovrel2(fid,-((float) strlen(string)),0.0);
  veprint(fid,string,x,erase);
  vf[fid]->y -= vf[fid]->height;
}

/* vector print centered - doesn't handle '\n's */
void vcprint(int fid,char *string)
{
  float tx = vf[fid]->x;

  vf[fid]->x -= ((strlen(string)-1) * vf[fid]->width * 0.5);
  vprint(fid,string);

  vf[fid]->x = tx;
  vf[fid]->y -= vf[fid]->height;
}

void vprint(int fid,char *string)
{
  if(string && vf[fid]) {
    while(*string) {
      if(*string == '\r') vf[fid]->x = vf[fid]->left;
      else if(*string == '\n') {
	vf[fid]->x = vf[fid]->left;
	vmovrel2(fid, 0.0, 1.0);
      }
      else vchar(fid,symbol[*string]);
      string++;
    }
  }
}

float vstrwidth(int fid,char *string)
{
  if(fid >=0 && fid <MAX_NUM_VFONTS && vf[fid])
    return(strlen(string)*vf[fid]->width);
  else return 0;
}

/* Clear box where print is going to go */
void vccprint(int fid,int dmode,unsigned int bgcolor,unsigned int fgcolor,
	      char *string)
{
  short red,green,blue;
  struct {float x,y;} v;

#ifdef __LINUX__
  if(bgcolor < 32 ) color(bgcolor);
  else              cpack(bgcolor);

  gl_myfillbox(vf[fid]->x - (strlen(string)*vf[fid]->width * 0.5),
       vf[fid]->y + vf[fid]->height * 0.5,
       strlen(string)*vf[fid]->width,
       vf[fid]->height);
#else
  if(dmode==PUPDRAW) color(bgcolor);
  else cpack(bgcolor);

  bgnpolygon();

  v.x = vf[fid]->x - (strlen(string)*vf[fid]->width * 0.5);
  v.y = vf[fid]->y + vf[fid]->height * 0.5;
  v2f(&v.x);

  v.x = vf[fid]->x - (strlen(string)*vf[fid]->width * 0.5);
  v.y = vf[fid]->y - vf[fid]->height * 0.5;
  v2f(&v.x);
/*  -vf[fid]->width*0.5 */
  v.x = vf[fid]->x + (strlen(string)*vf[fid]->width * 0.5);
  v.y = vf[fid]->y - vf[fid]->height * 0.5;
  v2f(&v.x);

  v.x = vf[fid]->x + (strlen(string)*vf[fid]->width * 0.5);
  v.y = vf[fid]->y + vf[fid]->height * 0.5;
  v2f(&v.x);

  endpolygon();
#endif

  if(dmode==PUPDRAW) color(fgcolor);
  else cpack(fgcolor);

  vcprint(fid,string);
}

void vdim(int d)
{
  switch(d) {
    case 2:
      dim=0;
    case 3:
      dim=1;
      break;
    default:
      fprintf(stderr,"Vector font: unknown dimension (no effect)\n");
  }
}
