/* raster.c TIGGR */

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

/* Header of a f9999x9999 file.  The DESCR_BEGIN field marks the start of the
   textual description of of the font.  It is included to make the size of
   the struct a multiple of 32bits.  */

struct font_header
{
  int magic;                                      /* "FONT"  */
  unsigned int bpp:8, version:8, flags:16;        /* 4, 4, 0 */
  int x0:16, y0:16, w:16, h:16;                   /* font bb */
  unsigned int ch_offset[9];                      /*         */
  unsigned int n:16, x_size:16, x_res:16, y_size:16, y_res:16, descr_begin:16;
};


struct fontdata
{
  int xds, yds, xdpi, ydpi;
  signed char x0, y0, x1, y1;
  unsigned short offsets[256];
};


/* Header of IntMetrics file.  */

struct intmetrics_header
{
  char f_name[40];
  int  sixteens[2];
  char num_chars[4];   /* only nc[0] should be defined.  */
  char mapping[256];
};


int bb[256][4];
int bbw[256];
char xoff[256], yoff[256];

int *pixmap[256];
int horpixsize, *curmap;
int numchars = 0;
int dpi;
int minx = 1 << 30, miny = 1 << 30, maxx = - (1 << 30), maxy = - (1 << 30);
char *dirname;
extern int designsize;

void
fatal (char *fmt, ...)
{
 va_list ap;

  va_start (ap, fmt);
  vfprintf (stderr, fmt, ap);
  fprintf (stderr, "\n");
  va_end (ap);
  exit (1);
}


/* NAME is something like `font.300GF'.  */

void
make_sprites (char *name)
{
  char *s = strrchr (name, '.'), *t;

  dpi = atoi (&s[1]);

  if (s == NULL)
    {
      dirname = malloc (1 + strlen (name));
      strcpy (dirname, name);
    }
  else
    {
      dirname = malloc ((s - name) + 1);
      strncpy (dirname, name, s - name);
      dirname[s - name] = '\0';
    }
}


void
select_char2 (int chno, int w, int px)
{
  bbw[chno] = ((w * 250) / (designsize / 16));

  fprintf(stderr, "\n%d\n", bbw[chno]);
}

void
select_char (int chno, int xl, int xr, int yb, int yt)
{
  int w, h;

  fprintf(stderr, "select_char(c=%d xl=%d,yb=%d, xr=%d,yt=%d)\n", chno, xl,yb, xr,yt);

  bb[chno][0] = xl;
  bb[chno][1] = yb;
  bb[chno][2] = xr;
  bb[chno][3] = yt;
  if (xl < minx) minx = xl;
  if (xr > maxx) maxx = xr;
  if (yb < miny) miny = yb;
  if (yt > maxy) maxy = yt;

  h = yt - yb + 1;
  w = (31 + xr - xl) & ~31;
  horpixsize = w / 32;
  if (!horpixsize)
    horpixsize = 1;

  if (pixmap[chno])
    fatal ("char %d already handled?!?", chno);

  curmap = pixmap[chno] = calloc (1, h * horpixsize * 4);
  if (curmap == NULL)
    fatal ("Out of VM (char-card=%d, rw=%d, h=%d)", numchars, horpixsize * 32, h);
  numchars++;
} /* select_char */



void
set_pixel (int row, int col)
{
  curmap[row * horpixsize + (col / 32)] |= 1 << (col & 31);
}



void
dump_char (void)
{
}


void
begin_dump_sprites (void)
{
}


void
write_nibble (int value, int *ff, int *state, FILE *f)
{
  register int q;

  if (*state == 0)
    {
      *ff = value & 0xf;
      *state = 1;
    }
  else
    {
      q = *ff | ((value & 0xf) << 4);
      fputc (q, f);
      *state = 0;
    }
}


void
end_dump_sprites (void)
{
  FILE *f, *f_im;
  char s[1024], s2[1024], s_im[1024];
  int i, h, j, w, x, y, pos, l;
  struct font_header hdr;
  struct intmetrics_header im;
  int fudge_pos = (char *) &hdr.ch_offset[0] - (char *) &hdr;
  int offsets[32];
  int nibble_state, nibble;

  memset (&hdr, 0, sizeof (struct font_header));
  memset (&im, 0, sizeof (struct intmetrics_header));

  memset (&im.f_name, 13, sizeof (im.f_name));
  sprintf (im.f_name, "%s", dirname);
  im.f_name[strlen (dirname)] = 13;

  im.sixteens[0] = im.sixteens[1] = 16;
  im.num_chars[0] = numchars + 1;

  strncpy ((char *) &hdr.magic, "FONT", 4);
  hdr.bpp = 4;
  hdr.version = 4;
  hdr.flags = 0;
  hdr.x0 = minx;
  hdr.y0 = miny;
  hdr.w = maxx - minx + 1;
  hdr.w = maxy - miny + 1;
  hdr.n = 10;
  hdr.descr_begin = dirname[0] | (dirname[1] << 8);

  fprintf (stderr, "Begin writeout of font\nnumchars = %d\n", numchars);

  hdr.x_size = hdr.y_size = designsize >> 16;
  fprintf (stderr, "size = %dpt\n", hdr.y_size / 16);
  fprintf (stderr, "dpi = %d\n", dpi);

  if (dpi)
    hdr.x_res = hdr.y_res = dpi;
  else
    {
      fprintf (stdout, "dpi? ");
      fflush (stdout);
      fscanf (stdin, "%s", s);
      hdr.x_res = hdr.y_res = atoi (s);
      if (hdr.x_res == 0)
        fatal ("dpi can't be 0");
    }

  i = hdr.x_size * hdr.x_res / 72;
  sprintf (s, "%s.f%dx%d", dirname, i, i);
  sprintf (s2, "%s.x90y45", dirname);
  sprintf (s_im, "%s.IntMetrics", dirname);

  f = fopen (s2, "w");
  if (f == NULL)
    fatal ("Can't open file `%s'", s2);
  fprintf (f, "f%dx%d", i, i);
  fclose (f);

  f_im = fopen (s_im, "wb");
  if (f_im == NULL)
    fatal ("Can't open file `%s'", s_im);

  f = fopen (s, "wb");
  if (!f)
    fatal ("Can't open file `%s'", s);
  if (strlen (dirname) < 2)
    fatal ("bogus fontname"); /* To make sure hdr.descr_begin and following stuff is correct.  */

  fwrite (&hdr, 1, sizeof (hdr), f);
  fprintf (f, "%s", &dirname[2]);
  fputc (0, f);
  fprintf (f, "%dx%d point at %dx%d dpi", hdr.x_size / 16, hdr.y_size / 16, hdr.x_res, hdr.y_res);
  fputc (0, f);
  while (ftell (f) % 4)
    fputc (0, f);

  /* All characters should have the top bit set.  */

  for (i = 0; i < 128; i++)
    {
      if (pixmap[128 + i])
        fatal ("Can't shuffle characters (char=%d)", i);
      pixmap[128 + i] = pixmap[i];
      pixmap[i] = 0;
      bbw[128 + i] = bbw[i];
      for (j = 0; j < 4; j++)
        bb[128 + i][j] = bb[i][j];
    }

  fprintf (stderr, "Writing bitmaps... ");
  fflush (stderr);

  for (i = 0; i < 9; i++)
    {
      /* POS holds the current EOF, and the start of this chunk.  It will be
         used to search back to this spot because of the character offsets.  */

      pos = ftell (f);
      fseek (f, fudge_pos + 4 * i, SEEK_SET);
      fwrite (&pos, 1, 4, f);
      fseek (f, pos, SEEK_SET);

      /* If the offset written was last exit, or if the corresponding chunks
         was empty continue with next chunk.  */

      if (i == 8)
        break;

      for (j = 0, l = 0; j < 32; j++)
        l = l || pixmap[i * 32 + j];
      if (!l)
        continue;

      memset (offsets, 0, sizeof (offsets));
      fwrite (offsets, 4, 32, f);

      for (j = 0; j < 32; j++)
        if (pixmap[j + i * 32])
          {
            fprintf (stderr, "%d ", i * 32 + j);
            fflush (stderr);

            offsets[j] = ftell (f) - pos;
            fputc (0, f);
            fputc (bb[i * 32 + j][0], f);
            fputc (bb[i * 32 + j][1], f);
            w = bb[i * 32 + j][2] - bb[i * 32 + j][0];
            h = bb[i * 32 + j][3] - bb[i * 32 + j][1] + 1;
            fputc (w, f);
            fputc (h, f);

            nibble_state = 0;
            horpixsize = ((w  + 31) & ~31)/ 32;
            for (y = h - 1; y >= 0; y--)
              for (x = 0; x < w; x++)
                write_nibble (pixmap[i * 32 + j][y * horpixsize + (x / 32)] & (1 << (x & 31)) ? 15 : 0, &nibble, &nibble_state, f);
            if (nibble_state)
              write_nibble (0, &nibble, &nibble_state, f);
          }
      while (ftell (f) % 4)
        fputc (nibble_state, f);

      l = ftell (f);
      fseek (f, pos, SEEK_SET);
      fwrite (offsets, 4, 32, f);
      fseek (f, l, SEEK_SET);
    }

  fclose (f);

  fprintf (stderr, "\nWriting metrix... ");
  fflush (stderr);

  for (i = 0, j = 1; i < 256; i++)
    if (pixmap[i])
      im.mapping[i] = j++;

  /* header + character mapping */
  fwrite (&im, 1, sizeof (struct intmetrics_header), f_im);


#define PATCH fputc (0, f_im); fputc (0, f_im)


  /* x0 y0 x1 y1 */
  for (j = 0; j < 4; j++)
{PATCH;
    for (i = 0; i < 256; i++)
      if (pixmap[i])
        {
          l = (int) ((double) bb[i][j] / (double) dpi * 72.0 / ((double) designsize / (16.0 * 65536.0)) * 1000.0);


/*

l = pixels

 / pixels-per-inch

 ->  inches

 * points per inch

 -> points

 / (16 * 64K points per em)

 -> em

 * 1000

 -> thousandths of an em


*/


fprintf (stderr, "%c[%d]: %d\n", i, j, l);

          fwrite (&l, 1, 2, f_im);       /* SYSDEP */
        }
    }

PATCH;

  /* x offset */
  for (i = 0; i < 256; i++)
    if (pixmap[i])
      {
        l = bbw[i];
        fwrite (&l, 1, 2, f_im);              /* SYSDEP */
      }

PATCH;
  
  /* y offset */
  for (i = 0, j = 0; i < 256; i++)
    if (pixmap[i])
      fwrite (&j, 1, 2, f_im);

  fprintf (stderr, " DONE!\n");
}
