/* Amiga bitmapped font builder.  
 * by Roger Ang, 1994.
 *
 * You may freely copy, use, and modify this file.
 *
 * This program builds a set of Amiga format bitmapped screen font files
 * from a BDF text file.  It is totally Amiga specific.  This program was 
 * originally written to convert Japanese kanji fonts (JIS) to Amiga format.
 * Only fixed width fonts are handled 
 *
 * NOTE: the font files output by this program are compatible with the
 *       FED font editor!!! 
 *
 * WARNING: No effort was made to make this robust.  It worked for me on
 *          two n x n fonts. 
 */

# include <dos.h>
# include <exec/exec.h>
# include <libraries/diskfont.h>
# include <proto/diskfont.h>
# include <proto/dos.h>
# include <proto/exec.h>
# include <string.h>
# include <stdarg.h>
# include <stdio.h>
# include <assert.h>

/* The following definitions appear to be missing from the Lattice headers */

# ifdef LATTICE
extern struct FontContentsHeader *NewFontContents(BPTR lock, char *name);
extern void DisposeFontContents(struct FontContentsHeader *fc);

# pragma libcall DiskfontBase NewFontContents     2a   9802 ; d0 = (a0, a1)
# pragma libcall DiskfontBase DisposeFontContents 30    901 ;      (a1)
# endif

/* Object module hunks */

# define Hunk_Header  0x3F3
# define Hunk_Code    0x3E9
# define Hunk_Reloc32 0x3EC
# define Hunk_End     0x3F2

# define MOVFFD0RTS   0x70FF4E75

/* Main program */
void main(int argc, char **argv)
{
  char namebuf[80], inbuf[256], keyword[80], byte_str[3];
  int lochar, hichar, baseline, fontnum, tmpnum, tmpnum1;
  void *fontmem = NULL;
  int baselen, font1;
  int actfontlen, actcharlen, actmodulo, actwidth; 
  int hunklen, hunknum, *hunkptr;

  struct DiskFontHeader *dfheader = NULL;

  unsigned char *chardata = NULL;
  short *charloc = NULL;
  int i, l, ch, ind, byte_num;
  int fontwidth, fontheight, bmapwidth;
  int tmpch;
  FILE *BDFfile = NULL;
  BPTR newfh = NULL;
  long CurFontStart, tmp_pos;

  struct FileLock *dirlock;

  hunkptr = NULL;
  lochar = hichar = baseline = fontnum = tmpnum = tmpnum1 = 0;
  hunklen = hunknum = actfontlen = actcharlen = actmodulo = actwidth = 0; 

  /* assuming bitmap in BDF file given in even number of hex digits per
     row of character bitmap, i.e. bitmap width should be multiple of 8 */

  if (argc < 3) {
    printf("Usage: %s <bdf file> <bitmap width in bits>\n", argv[0]);
    exit();
  }
  else
    if ((argv[1] == NULL) || (argv[2] == NULL)) {
      printf("Usage: %s <bdf file> <bitmap width in bits>\n", argv[0]);
      exit();
    }

  BDFfile = fopen(argv[1], "r");
  if (BDFfile == NULL) {
    fprintf(stderr, "%: Could not open file %s.\n", argv[0], argv[1]);
    exit();
  }

  sscanf(argv[2], "%d", &bmapwidth);

  while(!feof(BDFfile)) {
    tmp_pos = ftell(BDFfile);
    if (fgets(inbuf, 255, BDFfile) == NULL)   continue;

    keyword[0] = 0;
    sscanf(inbuf, "%s", keyword);

    if (strcmp(keyword, "ENDFONT") == 0)  goto STARTFONT;

    if (strcmp(keyword, "FONTBOUNDINGBOX") == 0)
      sscanf(inbuf, "%s %d %d", keyword, &fontwidth, &fontheight);

    if (strcmp(keyword, "FONT_ASCENT") == 0) {
      sscanf(inbuf, "%s %d", keyword, &baseline);
      baseline--;
    }

    if (strcmp(keyword, "STARTCHAR") == 0) {
      /* check if need to start a new bitmap font */
      sscanf(inbuf, "%s %x", keyword, &tmpnum);
      /* keyword = STARTCHAR, tmpnum = JIS code for character */
      tmpnum1 = (tmpnum >> 9);
      if (tmpnum1 != fontnum) {
        /* Start new font.  */

STARTFONT: /* bad programming, but I'm too lazy to make this a subroutine */
        if (fontnum != 0 ) {
          /* Write old font file, find high character, allocate memory, 
             and rewind to start bitmapping.  Assume characters 
             in BDF file are encoded low to high */

          /* Finish font: special 'not in font character' */
          for (l = 0; l < fontheight; l++) {
            ind = (actwidth>>3) + ((actmodulo) * l);
            for (byte_num = (bmapwidth >> 3) - 1; byte_num >= 0; byte_num--) 
              chardata[(ind+byte_num)] = 255;
          }
          ind = (hichar - lochar + 1) * 2;
          charloc[ind] = actwidth;     /* bitmap loc */
          charloc[ind+1] = fontwidth;  /* width of character */
          charloc[ind+2] = actwidth;   /* bitmap loc */

          /* write font file */
          hunkptr[0] = Hunk_Header;
          hunkptr[1] = 0;
          hunkptr[2] = 1;
          hunkptr[3] = 0;
          hunkptr[4] = 0;
          hunkptr[5] = hunknum;
          hunkptr[6] = Hunk_Code;
          hunkptr[7] = hunknum;
          hunkptr += 8;

          hunkptr[0] = MOVFFD0RTS;

          dfheader->dfh_DF.ln_Type = NT_FONT;
          dfheader->dfh_DF.ln_Name = (char *) 0x0000001A;
          dfheader->dfh_FileID = DFH_ID;
          strncpy((char *)&dfheader->dfh_Name, "myfont", MAXFONTNAME);
          dfheader->dfh_TF.tf_Message.mn_Node.ln_Type = NT_FONT;
          dfheader->dfh_TF.tf_Message.mn_Node.ln_Name = (char *) 0x0000001A;
          dfheader->dfh_TF.tf_Message.mn_Length = hunklen - 58;
          dfheader->dfh_TF.tf_YSize = fontheight;
          dfheader->dfh_TF.tf_Style = 0;
          dfheader->dfh_TF.tf_Flags = FPF_DISKFONT | FPF_DESIGNED;
          dfheader->dfh_TF.tf_XSize = fontwidth;
          dfheader->dfh_TF.tf_Baseline = baseline;
          dfheader->dfh_TF.tf_BoldSmear = 1;
          dfheader->dfh_TF.tf_LoChar = lochar;
          dfheader->dfh_TF.tf_HiChar = hichar;
          dfheader->dfh_TF.tf_CharData = 
            (APTR) ((char *) chardata - (char *) hunkptr);
          dfheader->dfh_TF.tf_Modulo = actmodulo;
          dfheader->dfh_TF.tf_CharLoc = 
            (APTR) ((char *) charloc - (char *) hunkptr);
        /* used by proportional fonts, ignore */
          dfheader->dfh_TF.tf_CharSpace = NULL;
          dfheader->dfh_TF.tf_CharKern = NULL;

          hunkptr += hunknum;
      
          hunkptr[0] = Hunk_Reloc32;
          hunkptr[1] = 4;
          hunkptr[2] = 0;
          hunkptr[3] = 0x0000000E;
          hunkptr[4] = 0x00000044;
          hunkptr[5] = 0x0000005C;
          hunkptr[6] = 0x00000062;
          hunkptr[7] = 0;
          hunkptr[8] = Hunk_End;

          /* check/create directory */
          dirlock = (struct FileLock *) CreateDir("kanji");
          if (dirlock) 
            UnLock((BPTR) dirlock);

          sprintf(namebuf, "kanji/jis%d", (fontnum-font1+1));
          dirlock = (struct FileLock *) CreateDir(namebuf);
          if (dirlock)
            UnLock((BPTR) dirlock);

          sprintf(namebuf, "kanji/jis%d/%d", (fontnum-font1+1), fontheight);
          newfh = Open(namebuf, MODE_NEWFILE);
          if (newfh == NULL) {
            fprintf(stderr, "Can't open bmap file %s\n", namebuf);
            exit();
          }

          i = Write(newfh, (UBYTE *) fontmem, actfontlen);
          Close(newfh);
          if (i == -1) {
            fprintf(stderr, "Error writing bmap file %s\n", namebuf);
            exit();
          }

          /* due to goto */
          if (strcmp(keyword, "ENDFONT") == 0)  continue;
   	}
        else /* first font file */
          font1 = tmpnum1;

        /* file written, figure out low and high char of new font */
        lochar = tmpnum & 255;  /* same as MOD 256 */
        if ((tmpnum & 256) != 0)  lochar += 128;

        CurFontStart = tmp_pos;
        hichar = lochar;
        fontnum = tmpnum1;
        /* find high char */
        while(!feof(BDFfile)) {
          if (fgets(inbuf, 255, BDFfile) == NULL)   continue;

          keyword[0] = 0;
          sscanf(inbuf, "%s", keyword);
          if ((strcmp(keyword, "ENDFONT") == 0) ||
              (strcmp(keyword, "STARTCHAR") == 0)) {
            sscanf(inbuf, "%s %x", keyword, &tmpnum);
            tmpnum1 = (tmpnum >> 9);  /* same as DIV 256 */
            if (tmpnum1 != fontnum)
               break;
            else {
               hichar = tmpnum & 255;  /* same as MOD 256 */
               if ((tmpnum & 256) != 0)  hichar += 128;
     	    }
          }
    	}

        /* allocate new font */
        if ((lochar > hichar) || (hichar > 255)) {
          fprintf(stderr, 
                  "%s: LoChar/HiChar out of range (0 <= Lo <= Hi <= 255)\n",
                  argv[0]);
          exit();
        }

        if (fontmem != NULL)
          FreeMem(fontmem,actfontlen);

        /* allocate memory for building font */
        baselen = 4 + sizeof (struct DiskFontHeader) +
                  4 * (hichar - lochar + 2);
        /* (hichar - lochar + 2): + 1 for the special 'out of font character' */

        actmodulo = (((hichar - lochar + 2) * bmapwidth) >> 3) & ~1;
        actcharlen = actmodulo * fontheight;
        hunklen = baselen + actcharlen;
        if (hunklen & 2) hunklen += 2;
        hunknum = hunklen >> 2;
        actfontlen = hunklen + 68;
        
        fontmem = AllocMem(actfontlen, MEMF_PUBLIC|MEMF_CLEAR);

        if (fontmem == NULL) {
          fprintf(stderr, "%s: can't get font memory\n", argv[0]);
          exit();  
        }

        hunkptr   = fontmem;
        dfheader  = (void *) &hunkptr[9];
        chardata  = (void *) &dfheader[1];
        charloc  = (void *) &chardata[actcharlen];
        actwidth = 0;

        /* rewind to beginning of this font */
        fseek(BDFfile, CurFontStart, 0);
      }
      else { 
        /* (tmpnum1 == fontnum)  Character for the current font. 
           Build the bitmapped font in allocated memory.  */

        /* find bitmap in BDF file */
        while(!feof(BDFfile)) {
          if (fgets(inbuf, 255, BDFfile) == NULL)   continue;

          keyword[0] = 0;
          sscanf(inbuf, "%s", keyword);
          if (strcmp(keyword, "BITMAP") == 0)  break; 
   	}

        assert(strcmp(keyword, "BITMAP") == 0); 
        /* get the character code */
        ch = tmpnum & 255;  /* same as MOD 256 */
        if ((tmpnum & 256) != 0)  ch += 128;

        assert((lochar <= ch) && (hichar >= ch));

        i = ch - lochar;

        /* do bitmap for this character */
        for (l = 0; l < fontheight; l++) {
          ind = (actwidth>>3) + ((actmodulo) * l);
          assert (fgets(inbuf, 255, BDFfile) != NULL);
          assert ((strlen(inbuf) - 1) * 4 == bmapwidth);
          /* assuming newline char at end of string */
          for (byte_num = (bmapwidth >> 3) - 1; byte_num >= 0; byte_num--) { 
            byte_str[0] = inbuf[(byte_num * 2)];
            byte_str[1] = inbuf[(byte_num * 2) + 1];
            byte_str[2] = 0;
            sscanf(byte_str, "%x", &tmpch);
            assert ((tmpch >= 0) && (tmpch <= 255));
            chardata[(ind+byte_num)] = (unsigned char) tmpch;
     	  }
        }
        charloc[i * 2] = actwidth;  /* bitmap loc */
        charloc[i * 2 + 1] = fontwidth; /* width of character */
        actwidth += bmapwidth;

        /* make sure it's the end of this character */
        assert (fgets(inbuf, 255, BDFfile) != NULL);
        keyword[0] = 0;
        sscanf(inbuf, "%s", keyword);
        assert(strcmp(keyword, "ENDCHAR") == 0); 
      }
    }
  }

  /* done */
  if (fontmem != NULL)
    FreeMem(fontmem,actfontlen);

  fclose(BDFfile);
}

