/* this defines some routines for handling of Outline-Fonts */

#include "struct.c"
#include "OutlineFont.h"

#define CW 80
#define CH 35

static int   cwidth, cheight;
static ULONG XYdpi, PointSize;

struct Glyph
{
 int    top, left, width, height;
 int    basex, basey;
 int    bmsize, bpr;
 UBYTE *bitmap;
};

static struct Glyph *HGlyphs[256], *VGlyphs[256];

       struct Library     *BulletBase   = NULL;
static struct GlyphEngine *BulletEngine = NULL;


static BOOL IsOutlineFont(char *fontname)
{
 BPTR                       FontsDir, Font;
 char                       FullFontName[255];
 BOOL                       h = FALSE;
 struct FontContentsHeader *fch;

 /* hack to get the real font-directory incase of MultiAssign !! */
 strcpy(FullFontName, "FONTS:"); AddPart(FullFontName, fontname, 255);
 if (Font = Lock(FullFontName, ACCESS_READ))
  {
   FontsDir = ParentDir(Font);
   if (fch = NewFontContents(FontsDir, fontname))
    {
     if (fch->fch_FileID == OFCH_ID)
      h = TRUE;
     DisposeFontContents(fch);
    }
   UnLock(FontsDir);
   UnLock(Font);
  }

 return h;
}

static struct GlyphEngine *GetEngine(char *fontname, struct TagItem **OTags)
{
 BPTR                f;
 int                 l;
 char                enginename[80];
 struct TagItem     *Tags, *ti, *tstate;
 struct GlyphEngine *Engine = NULL;

 if (f = Open(fontname, MODE_OLDFILE))
  {
   Seek(f, 0, OFFSET_END);
   l = Seek(f, 0, OFFSET_BEGINNING);
   if (Tags = malloc(l))
    {
     Read(f, Tags, l);

     tstate = Tags;
     while (ti = NextTagItem(&tstate))
      if (ti->ti_Tag & OT_Indirect)
       ti->ti_Data += (ULONG)Tags;
     
     if ((ti = FindTagItem(OT_FileIdent, Tags)) && ti->ti_Data == l)
      {
       if (ti = FindTagItem(OT_Engine, Tags))
	{
	 strcpy(enginename, (char *)(ti->ti_Data));
	 strcat(enginename, ".library");
	 if (BulletBase = OpenLibrary(enginename, 0))
	  {
	   Engine = OpenEngine();
	   *OTags = Tags;
	  }
	}
      }
    }
   Close(f);
  }

 return Engine;
}

static struct Glyph *GetGlyph(char ch, BOOL Vertical)
{
 struct GlyphMap  *GlyphMap;
 struct Glyph    **glyphs;

 glyphs = (Vertical) ? VGlyphs : HGlyphs;
 if (!glyphs[ch])
  {
   glyphs[ch] = malloc(sizeof(struct Glyph));
   SetInfo(BulletEngine,
	   OT_GlyphCode, ch,
	   OT_RotateSin,   (Vertical) ? 0x00010000 : 0x00000000,
	   OT_RotateCos,   (Vertical) ? 0x00000000 : 0x00010000,
	   OT_PointHeight, PointSize,
	   OT_DeviceDPI,   XYdpi,
	   OT_DotSize,     0x00640064,
	   TAG_END);
   if (ObtainInfo(BulletEngine,
		  OT_GlyphMap, &GlyphMap,
		  TAG_END) == OTERR_Success)
    {
     glyphs[ch]->top = GlyphMap->glm_BlackTop;
     glyphs[ch]->left = GlyphMap->glm_BlackLeft;
     glyphs[ch]->height = GlyphMap->glm_BlackHeight+1;
     glyphs[ch]->width = GlyphMap->glm_BlackWidth+1;
     glyphs[ch]->basey = GlyphMap->glm_Y0-GlyphMap->glm_BlackTop;
     glyphs[ch]->basex = GlyphMap->glm_X0-GlyphMap->glm_BlackLeft;
     glyphs[ch]->bpr = GlyphMap->glm_BMModulo;
     glyphs[ch]->bmsize = GlyphMap->glm_BMModulo*GlyphMap->glm_BMRows;
     if (glyphs[ch]->bitmap = AllocMem(glyphs[ch]->bmsize, MEMF_CHIP))
      CopyMemQuick(GlyphMap->glm_BitMap, glyphs[ch]->bitmap, glyphs[ch]->bmsize);
     ReleaseInfo(BulletEngine,
		 OT_GlyphMap, GlyphMap,
		 TAG_END);
    }
   else
    {
     glyphs[ch]->top = 0;
     glyphs[ch]->left = 0;
     glyphs[ch]->height = cheight;
     glyphs[ch]->width = cwidth;
     glyphs[ch]->basey = 0;
     glyphs[ch]->basex = 0;
     glyphs[ch]->bpr = (cwidth/32 + 1) * 4;
     glyphs[ch]->bmsize = glyphs[ch]->bpr * cheight;
     glyphs[ch]->bitmap = AllocMem(glyphs[ch]->bmsize, MEMF_CHIP|MEMF_CLEAR);
    }
  }
 
 
 return glyphs[ch];
}

static void FreeGlyph(struct Glyph *glyph)
{
 FreeMem(glyph->bitmap, glyph->bmsize);
}

static void FreeGlyphs(void)
{
 int ch;

 for(ch=0; ch <= 255; ch++)
  {
   if (HGlyphs[ch])
    {
     FreeGlyph(HGlyphs[ch]);
     free(HGlyphs[ch]);
     HGlyphs[ch] = NULL;
    }
   if (VGlyphs[ch])
    {
     FreeGlyph(VGlyphs[ch]);
     free(VGlyphs[ch]);
     VGlyphs[ch] = NULL;
    }
  }
}

BOOL OpenOutlineFont(char *font)
{
 char            fontname[80], otagname[80];
 struct TagItem *OTags;
 int             ch;

 strcpy(fontname, font); strcat(fontname, ".font");
 if (IsOutlineFont(fontname))
  {
   strcpy(otagname, "FONTS:"); strcat(otagname, font); strcat(otagname, ".otag");
   if (BulletEngine = GetEngine(otagname, &OTags))
    {
     strcpy(fontname, "FONTS:"); strcat(fontname, font); strcat(fontname, ".font");
     SetInfo(BulletEngine,
	     OT_OTagPath, fontname,
	     OT_OTagList, OTags,
	     TAG_END);

     for(ch=0; ch <= 255; ch++)
      HGlyphs[ch] = VGlyphs[ch] = NULL;

     return TRUE;
    }
  }
 return FALSE;
}

void CloseOutlineFont(void)
{
 FreeGlyphs();
 if (BulletEngine) CloseEngine(BulletEngine);
 if (BulletBase)   CloseLibrary(BulletBase);
}

void PrintString(struct RastPort *rp, int x0, int y0, char *s, BOOL Vertical)
{
 char         *ch;
 int           x, y;
 struct Glyph *glyph;

 x = x0; y = y0;
 for(ch = s; *ch; ch++)
  {
   glyph = GetGlyph(*ch, Vertical);
   BltTemplate(glyph->bitmap+glyph->top*glyph->bpr,
	       glyph->left, glyph->bpr,
	       rp,
	       x-glyph->basex, 
	       y-glyph->basey,
	       glyph->width, glyph->height);
   WaitBlit();
   if (Vertical)
    y -= glyph->height;
   else
    x += glyph->width;
  }
}

void SetFontSize(int w, int h)
{
 static int last_x = 0, last_y = 0, last_p = 0;
 int x, y, p;

 cwidth = w/CW; cheight = h/CH;

 if (w*CH < h*CW)
  {
   x = 100;
   y = (100 * h * CW) / (w * CH);
   p = (w * 65536L) / CW;
  }
 else
  {
   y = 100;
   x = (100 * w * CH) / (h * CW);
   p = (h * 65536L) / CH;
  }

 PointSize = p;
 XYdpi = x<<16 | y;

 if (last_x != x || last_y != y || last_p != PointSize)
  {
   FreeGlyphs();
   last_x = x;
   last_y = y;
   last_p = PointSize;
  }
}

int TextLen(char *s)
{
 char *ch;
 int   txtlen = 0;

 for(ch = s; *ch; ch++)
  txtlen += (GetGlyph(*ch, FALSE))->width;
 
 return txtlen;
}

static int _STI_10000_InitGlyphs(void)
{
 char ch;

 for(ch=0; ch <= 255; ch++)
  HGlyphs[ch] = VGlyphs[ch] = NULL;

 return 0;
}

static void _STD_10000_CloseOutlineFonts(void)
{
 CloseOutlineFont();
}
