// THIS IS A WORK-IN-PROGRESS ... translated from GIMMS.imp, which was hosted on
// a big-endian machine, as opposed to the Intel system I'm testing the port on.

// The ported version doesn't look right, for several reasons, not just the
// obvious scaling/rounding issues.

// (Gimms-based) symbol drawing routines
#include <stdio.h>
#include <stdlib.h>

const float defaultscale=0.12;
//const float defaultscale=0.5; // using larger numbers and a smaller scale may be faster on the vectrex

#define byte char
#define half short
#define integer int

typedef struct charheader {
  byte xbias,xmax,ybias,ymax;
  half data;
} charheader;

typedef struct gimmsheader {
  integer fontlength,gimm,number,dummy0,dummy1,dummy2,dummy3;
  half scale;
  byte xx,yy;
  half start[128];
} gimmsheader;

const integer penup=1<<15,lastvector=1<<7;

static struct gimmsheader *header=NULL;

static struct charheader *ch;

static byte *chdata;
static integer xmax,ymax;
static float factor;

void readregion(FILE *f, int offset, int length, void *address) {
  static int last_offset = 0;
  char *put = (char *)address;
  int i, c;
  //DEBUG: fprintf(stderr, "Read %d byte block at offset %d\n", length, offset);
  if (offset != last_offset) fseek(f, offset, SEEK_SET);
  //DEBUG: fputc('[', stderr);
  for (i = 0; i < length; i++) {
    c = fgetc(f);
    //DEBUG: if (c >= 32 && c < 127) fputc(c, stderr); else fputc('.', stderr);
    *put++ = c; last_offset++;
  }
  //DEBUG: fputc(']', stderr);
  //DEBUG: fputc('\n', stderr);
}

void lineabs(integer fromx, integer fromy, integer tox, integer toy) {
  fprintf(stdout, "lineabs(%d,%d, %d,%d);\n", fromx, fromy, tox, toy);
}

void moveabs(integer tox, integer toy) {
  fprintf(stdout, "moveabs(%d,%d);\n", tox, toy);
}

void linerel(integer tox, integer toy) {
  fprintf(stdout, "linerel(%d,%d);\n", tox, toy);
}

int sexswap2(half x) {
  return ((x>>8)&255) | ((x&255)<<8);
}

int sexswap4(integer x) {
  return (sexswap2((x>>16)&65535)) | ((sexswap2(x&65535))<<16);
}


void setup(void);
void setscale(float r, float rawfactor) {
  if (!header) setup();
  factor = rawfactor*r;
}

void setup(void) {
  FILE *filetoken;
  integer filepos=0,i;

  header = malloc((sizeof(*header)));
  filetoken = fopen("GIMMS.BIN","rb");
  if (filetoken == NULL) {
    fprintf(stderr, "Cannot open GIMMS.BIN\n");
    exit(1);
  }
  do {
    
    readregion(filetoken,filepos,sizeof(*header),header);
    header->fontlength = sexswap4(header->fontlength); /*header->gimm = sexswap4(header->gimm);*/ /*header->number = sexswap4(header->number);*/
    header->scale = sexswap2(header->scale);

    for (i = 0; i < 128; i++) header->start[i] = sexswap2(header->start[i]);    
    //DEBUG: fprintf(stderr, "font length = %d (%04x)\n",  header->fontlength,  header->fontlength);

    filepos = filepos+header->fontlength;
    if (header->gimm != (*(int *) (char[]) {'G', 'I', 'M', 'M'})) {fprintf(stderr, "GIMMS file corrupt"); exit(1);}
  } while (header->number != (*(int *) (char[]) {'0', '0', '0', '5'}));
  filepos = filepos-header->fontlength+sizeof(*header);

  i = header->fontlength-sizeof(*header);
  chdata = (byte *)malloc(i);
  readregion(filetoken,filepos,i,chdata); fclose(filetoken);

  xmax = 0; ymax = 0;
  for (i = 0; i < 128; i++) {
    if (header->start[i]==0) continue;

    ch = (charheader *)(&chdata[header->start[i]-256]);

    if (ch->xmax>xmax) xmax = ch->xmax;
    if (ch->ymax>ymax) ymax = ch->ymax;
  }
  setscale(defaultscale, 511.0 / (float)ymax); // NOTE: using 511.0 gives results that sometimes differ by 1 unit from using 511. 
}

void sizesymbol(integer i, integer *n, integer *s, integer *e, integer *w) {
  integer xpos,ypos,x,y;
  half *d;
  if (!header) setup();
  *n = 0; *s = 0; *e = 0; *w = 0;
  if (header->start[i]==0) return;
  ch = (charheader *)(&chdata[header->start[i]-256]); d = &ch->data; // d not used, may have had sex problem anyway
  *w = (int)(ch->xbias*factor); *s = (int)(ch->ybias*factor);
  *e = (int)(ch->xmax*factor)-*w; *n = (int)(ch->ymax*factor)-*s;
}

void drawsymbol(integer i, integer xbase, integer ybase) {
  integer xpos,ypos,x,y;
  half *d;
  if (!header) setup();
  if (header->start[i]==0) return;
  
  ch = (charheader *)(&chdata[header->start[i]-256]);
  d = &ch->data; *d = sexswap2(*d); // WATCH OUT FOR SEX OF *d
  
  //DEBUG: fprintf(stderr, "xbias: %d  xmax: %d  ybias: %d  ymax: %d  data: %d\n",  ch->xbias,ch->xmax,ch->ybias,ch->ymax, ch->data);


  x = (int)(ch->xbias*factor); y = (int)(ch->ybias*factor);
  xbase = xbase-x; ybase = ybase-y;
  xpos = 0; ypos = 0;
  for (;;) {
    // fprintf(stderr, "*d = %d\n", *d);
    x = (int)((((*d)>>8)&127)*factor);
    y = (int)(((*d)&127)*factor);
#ifdef ABS_LINES
    if ((*d)&penup) {
      xpos = x; ypos = y;
    } else {
      lineabs(xpos+xbase,ypos+ybase,x+xbase,y+ybase); xpos = x; ypos = y;
    }
#else
    if ((*d)&penup) {
      xpos = x; ypos = y;
      moveabs(xbase+x,ybase+y);
    } else { // xbase+xpos to xbase+x
      linerel(x-xpos,y-ypos); xpos = x; ypos = y;
    }
#endif
    if ((*d)&lastvector) break;
    d++; *d = sexswap2(*d); //???
  }
}

int main(int argc, char **argv) {
  int i;
  for (i = 0; i < 162; i++) {
    fprintf(stdout, "// GIMMS %d\n", i);
    drawsymbol(i,0,0);
  }
  exit(0);
  return 1;
}