/* AllegroFont - a wrapper for FreeType 2 */
/* to render TTF and other font formats with Allegro */


/*
  This is AllegroFont 1.9.2 modified by me (Kirill Kryukov) to enable fair
  speed comparison with Glyph Keeper and to remove parts I did not need.
  Modifications are:

  1. AllegroFont can't set the exact text size you specify, so I modified
     alfont_set_font_size() to make it possible.

  2. AllegroFont uses left-top corner to position text, I changed it to
     use baseline positioning. (This should not impact performance though).

  3. I compile AllegroFont with current FreeType instead of outdated version
     included in AllegroFont distribution.

  4. Removed "alfont.h" and "alfontdll.h", so now you just include "alfont.c".

  5. Removed all ...centre, right, and printf functions.

  7. Added 'face_descender' for background bitmap positioning.
*/



/* AllegroFont - a wrapper for FreeType 2 */
/* to render TTF and other font formats with Allegro */

            
/* FreeType 2 is copyright (c) 1996-2000 */
/* David Turner, Robert Wilhelm, and Werner Lemberg */
/* AllegroFont is copyright (c) 2001, 2002 Javier Gonz lez */

/* See FTL.txt (FreeType Project License) for license */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <allegro.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H


/* common define */

#define ALFONT_MAJOR_VERSION        1
#define ALFONT_MINOR_VERSION        9
#define ALFONT_SUB_VERSION          2
#define ALFONT_VERSION_STR          "1.9.2"
#define ALFONT_DATE_STR             "08/04/2003"
#define ALFONT_DATE                 20030408    /* yyyymmdd */

/* error codes */

#define ALFONT_OK                   0
#define ALFONT_ERROR                -1


/* structs */
typedef struct ALFONT_FONT ALFONT_FONT;


/* API */

int alfont_init(void);
void alfont_exit(void);

ALFONT_FONT *alfont_load_font(const char *filepathname);
ALFONT_FONT *alfont_load_font_from_mem(const char *data, int data_len);
void alfont_destroy_font(ALFONT_FONT *f);

int alfont_set_font_size(ALFONT_FONT *f, int h);
int alfont_get_font_height(ALFONT_FONT *f);

int alfont_text_mode(int mode);

void alfont_textout_aa(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color);
void alfont_textout(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color);
void alfont_textout_aa_ex(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color, int bg);
void alfont_textout_ex(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color, int bg);

int alfont_text_height(ALFONT_FONT *f);
int alfont_text_length(ALFONT_FONT *f, const char *str);

int alfont_is_fixed_font(ALFONT_FONT *f);
int alfont_is_scalable_font(ALFONT_FONT *f);

const int *alfont_get_available_fixed_sizes(ALFONT_FONT *f);
int alfont_get_nof_available_fixed_sizes(ALFONT_FONT *f);

int alfont_get_char_extra_spacing(ALFONT_FONT *f);
void alfont_set_char_extra_spacing(ALFONT_FONT *f, int spacing);



/* structs */

struct ALFONT_FONT {
  FT_Face face;           /* face */
  int face_h;             /* face height */
  int real_face_h;        /* real face height */
  int face_ascender;      /* face ascender */
  int face_descender;     /* face descender */
  char *data;             /* if loaded from memory, the data chunk */
  int data_size;          /* and its size */
  int ch_spacing;         /* extra spacing */
  int num_fixed_sizes;    /* -1 if scalable, >=0 if fixed */
  struct _ALFONT_CACHED_GLYPH {
    char is_cached;
    int width, height, aawidth, aaheight;
    int left, top, aaleft, aatop;
    int advancex, advancey;
    int mono_available, aa_available;
    unsigned char *bmp;
    unsigned char *aabmp;
  } *cached_glyphs;       /* array to know which glyphs have been cached */
  int *fixed_sizes;       /* array with the fixed sizes */
};


/* global vars */

static FT_Library ft_library;
static int alfont_textmode = 0;
static int alfont_inited = 0;


/* helpers */

static void _alfont_reget_fixed_sizes(ALFONT_FONT *f) {
  if (f->num_fixed_sizes < 0) {
    /* scalable font */
    f->fixed_sizes[0] = -1;
  }
  else {
    /* fixed */
    int i;
    for (i = 0; i < f->num_fixed_sizes; i++) {
      f->fixed_sizes[i] = f->face->available_sizes[i].height;
    }
    /* set last one to -1 */
    f->fixed_sizes[f->num_fixed_sizes] = -1;
  }
}


static void _alfont_uncache_glyphs(ALFONT_FONT *f) {
  if (f->cached_glyphs) {
    int i;
    for (i = 0; i < f->face->num_glyphs; i++) {
      if (f->cached_glyphs[i].is_cached) {
        f->cached_glyphs[i].is_cached = 0;
        if (f->cached_glyphs[i].bmp) {
          free(f->cached_glyphs[i].bmp);
          f->cached_glyphs[i].bmp = NULL;
        }
        if (f->cached_glyphs[i].aabmp) {
          free(f->cached_glyphs[i].aabmp);
          f->cached_glyphs[i].aabmp = NULL;
        }
      }
    }
  }
}


static void _alfont_delete_glyphs(ALFONT_FONT *f) {
  _alfont_uncache_glyphs(f);
  if (f->cached_glyphs) {
    free(f->cached_glyphs);
    f->cached_glyphs = NULL;
  }
}


static void _alfont_cache_glyph(ALFONT_FONT *f, int glyph_number) {
  /* if glyph not cached yet */
  if (!f->cached_glyphs[glyph_number].is_cached) {
    FT_Glyph new_glyph;
    /* load the font glyph */
    FT_Load_Glyph(f->face, glyph_number, FT_LOAD_DEFAULT);
    FT_Get_Glyph(f->face->glyph, &new_glyph);

    /* ok, this glyph is now cached */
    f->cached_glyphs[glyph_number].is_cached = 1;
    f->cached_glyphs[glyph_number].mono_available = 0;
    f->cached_glyphs[glyph_number].aa_available = 0;

    /* render the mono bmp */
    {
      FT_Bitmap *ft_bmp;
      FT_Glyph glyph;
      FT_BitmapGlyph bmp_glyph;

      FT_Glyph_Copy(new_glyph, &glyph);

      /* only render glyph if it is not already a bitmap */
      if (glyph->format != ft_glyph_format_bitmap)
        FT_Glyph_To_Bitmap(&glyph, ft_render_mode_mono, NULL, 1);

      /* the FT rendered bitmap */
      bmp_glyph = (FT_BitmapGlyph)glyph;
      ft_bmp = &bmp_glyph->bitmap;

      /* save only if the bitmap is really 1 bit */
      if (ft_bmp->pixel_mode == ft_pixel_mode_mono) {
        int memsize;

        f->cached_glyphs[glyph_number].mono_available = 1;

        /* set width, height, left, top */
        f->cached_glyphs[glyph_number].width = ft_bmp->width;
        f->cached_glyphs[glyph_number].height = ft_bmp->rows;
        f->cached_glyphs[glyph_number].left = bmp_glyph->left;
        f->cached_glyphs[glyph_number].top = bmp_glyph->top;

        /* allocate bitmap */
        memsize = ft_bmp->width * ft_bmp->rows * sizeof(unsigned char);
        if (memsize > 0)
          f->cached_glyphs[glyph_number].bmp = malloc(memsize);
        else
          f->cached_glyphs[glyph_number].bmp = NULL;

        /* monochrome drawing */
        if (memsize > 0) {
          unsigned char *outbmp_p = f->cached_glyphs[glyph_number].bmp;
          unsigned char *bmp_p;
          int bmp_x, bmp_y, bit;

          /* copy the FT character bitmap to ours */
          bmp_p = ft_bmp->buffer;
          for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) {
            unsigned char *next_bmp_p;
            next_bmp_p = bmp_p + ft_bmp->pitch;
            bit = 7;
            for (bmp_x = 0; bmp_x < ft_bmp->width; bmp_x++) {
              *outbmp_p = *bmp_p & (1 << bit);
              outbmp_p++;

              if (bit == 0) {
                bit = 7;
                bmp_p++;
              }
              else
                bit--;
            }
            bmp_p = next_bmp_p;
          }
        }
      }

      FT_Done_Glyph(glyph);
    }


    /* render the aa bmp */
    {
      FT_Bitmap *ft_bmp;
      FT_Glyph glyph;
      FT_BitmapGlyph bmp_glyph;
    
      FT_Glyph_Copy(new_glyph, &glyph);

      /* only render glyph if it is not already a bitmap */
      if (glyph->format != ft_glyph_format_bitmap)
        FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, NULL, 1);

      /* the FT rendered bitmap */
      bmp_glyph = (FT_BitmapGlyph)glyph;
      ft_bmp = &bmp_glyph->bitmap;

      /* save only if the bitmap is really 8 bit */
      if (ft_bmp->pixel_mode == ft_pixel_mode_grays) {
        int memsize;

        f->cached_glyphs[glyph_number].aa_available = 1;

        /* set width, height, left, top */
        f->cached_glyphs[glyph_number].aawidth = ft_bmp->width;
        f->cached_glyphs[glyph_number].aaheight = ft_bmp->rows;
        f->cached_glyphs[glyph_number].aaleft = bmp_glyph->left;
        f->cached_glyphs[glyph_number].aatop = bmp_glyph->top;

        /* allocate bitmap */
        memsize = ft_bmp->width * ft_bmp->rows * sizeof(unsigned char);
        if (memsize > 0)
          f->cached_glyphs[glyph_number].aabmp = malloc(memsize);
        else
          f->cached_glyphs[glyph_number].aabmp = NULL;

        /* aa drawing */
        if (memsize > 0) {
          unsigned char *outbmp_p = f->cached_glyphs[glyph_number].aabmp;
          unsigned char *bmp_p;
          int bmp_y;
          unsigned char mul = 256 / ft_bmp->num_grays;
          /* we set it to 0 because it is faster to test for false */
          if (mul == 1)
            mul = 0;

          /* copy the FT character bitmap to ours */
          bmp_p = ft_bmp->buffer;
          for (bmp_y = 0; bmp_y < ft_bmp->rows; bmp_y++) {
            unsigned char *next_bmp_p;
            next_bmp_p = bmp_p + ft_bmp->pitch;
            memcpy(outbmp_p, bmp_p, ft_bmp->width * sizeof(unsigned char));

            /* we have to change our pixels if the numgrays is not 256 */
            if (mul) {
              unsigned char *p = outbmp_p;
              unsigned char *p_end = p + ft_bmp->width;
              for (; p < p_end; p++)
                *p *= mul;
            }

            outbmp_p += ft_bmp->width;
            bmp_p = next_bmp_p;
          }
        }
      }

      FT_Done_Glyph(glyph);
    }

    f->cached_glyphs[glyph_number].advancex = f->face->glyph->advance.x >> 6;
    f->cached_glyphs[glyph_number].advancey = f->face->glyph->advance.y >> 6;

    /* delete the glyph */
    FT_Done_Glyph(new_glyph);
  }
}


static void _alfont_new_cache_glyph(ALFONT_FONT *f) {
  int i;

  if (!f->cached_glyphs)
    f->cached_glyphs = malloc(f->face->num_glyphs * sizeof(struct _ALFONT_CACHED_GLYPH));

  for (i = 0; i < f->face->num_glyphs; i++) {
    f->cached_glyphs[i].is_cached = 0;
    f->cached_glyphs[i].bmp = NULL;
    f->cached_glyphs[i].aabmp = NULL;
  }
}


/* API */

int alfont_set_font_size(ALFONT_FONT *f, int h) {
  /* int error, test_h, direction; */
  /* check the font doesn't already use that w and h */
  if (h == f->face_h)
    return ALFONT_OK;
  else if (h <= 0)
    return ALFONT_ERROR;

  if (FT_Set_Pixel_Sizes(f->face, 0, h)) return ALFONT_ERROR;
  _alfont_uncache_glyphs(f);
  f->face_h = h;
  f->real_face_h = h;
  f->face_ascender = f->face->size->metrics.ascender >> 6;
  f->face_descender = f->face->size->metrics.descender >> 6;
  return ALFONT_OK;

#if 0
  /* keep changing the size until the real size is not the one */
  /* we want */
  test_h = h;
  direction = 0;
  while (1) {
    int real_height;
    error = FT_Set_Pixel_Sizes(f->face, 0, test_h);
    if (error)
      break;

    /* compare real height with asked height */
    real_height = abs(f->face->size->metrics.ascender >> 6) + abs(f->face->size->metrics.descender >> 6);
    if (real_height == h) {
      /* we found the wanted height */
      break;
    }

    /* check the direction */
    if (direction == 0) {
      /* direction still not set */
      if (real_height > h)
        direction = -1;
      else
        direction = 1;
    }
    
    /* check we didn't overpass it */
    else if ((direction > 0) && (real_height > h)) {
      /* decrease one and found */
      test_h--;
      FT_Set_Pixel_Sizes(f->face, 0, test_h);
      break;
    }

    /* check we didn't surpass it */
    else if ((direction < 0) && (real_height < h)) {
      break;
    }

    test_h += direction;

    /* check we arent at 0 */
    if (test_h <= 0) {
      error = TRUE;
      break;
    }

  }

  if (!error) {
    _alfont_uncache_glyphs(f);
    f->face_h = h;
    f->real_face_h = test_h;
    f->face_ascender = f->face->size->metrics.ascender >> 6;
    return ALFONT_OK;
  }
  else {
    FT_Set_Pixel_Sizes(f->face, 0, f->real_face_h);
    return ALFONT_ERROR;
  }
#endif
}


int alfont_get_font_height(ALFONT_FONT *f) {
  return f->face_h;
}


void alfont_exit(void) {
  if (alfont_inited) {
    alfont_inited = 0;
    FT_Done_FreeType(ft_library);
    memset(&ft_library, 0, sizeof(ft_library));
  }
}


int alfont_init(void) {
  if (alfont_inited)
    return 0;
  else {
    int error;
    memset(&ft_library, 0, sizeof(ft_library));
    error = FT_Init_FreeType(&ft_library);

    if (!error)
      alfont_inited = 1;
      
    return error;
  }
}


ALFONT_FONT *alfont_load_font(const char *filepathname) {
  int error;

  /* try to allocate the memory */
  ALFONT_FONT *font = malloc(sizeof(ALFONT_FONT));

  if (font == NULL)
    return NULL;

  /* clear the struct */
  memset(font, 0, sizeof(ALFONT_FONT));
  font->cached_glyphs = NULL;

  /* we are loading from file, no mem buffer needed */
  font->data = NULL;
  font->data_size = 0; 

  /* load the font */
  error = FT_New_Face(ft_library, filepathname, 0, &font->face);

  if (error) {
    free(font);
    return NULL;
  }

  /* get if the font contains only fixed sizes */
  if (!(font->face->face_flags & FT_FACE_FLAG_SCALABLE))
    font->num_fixed_sizes = font->face->num_fixed_sizes;
  else
    font->num_fixed_sizes = -1;

  _alfont_new_cache_glyph(font);

  if (font->num_fixed_sizes < 0) {
    font->fixed_sizes = malloc(sizeof(int));
    _alfont_reget_fixed_sizes(font);

    alfont_set_font_size(font, 8);
  }
  else {
    font->fixed_sizes = malloc(sizeof(int) * (font->num_fixed_sizes + 1));
    _alfont_reget_fixed_sizes(font);

    /* set as current size the first found fixed size */
    alfont_set_font_size(font, font->fixed_sizes[0]);
  }

  alfont_set_char_extra_spacing(font, 0);

  return font;
}


ALFONT_FONT *alfont_load_font_from_mem(const char *data, int data_len) {
  int error;
  char *new_data;

  /* try to allocate the memory */
  ALFONT_FONT *font = malloc(sizeof(ALFONT_FONT));
  new_data = malloc(data_len);

  if ((font == NULL) || (new_data == NULL)) {
    if (font)
      free(font);
    if (new_data)
      free(new_data);
    return NULL;
  }

  /* clear the struct */
  memset(font, 0, sizeof(ALFONT_FONT));
  font->cached_glyphs = NULL;

  /* copy user data to internal buffer */
  font->data = new_data;
  font->data_size = data_len;
  memcpy((void *)font->data, (void *)data, data_len);

  /* load the font */
  error = FT_New_Memory_Face(ft_library, font->data, font->data_size, 0, &font->face);

  if (error) {
    free(font->data);
    free(font);
    return NULL;
  }

  /* get if the font contains only fixed sizes */
  if (!(font->face->face_flags & FT_FACE_FLAG_SCALABLE))
    font->num_fixed_sizes = font->face->num_fixed_sizes;
  else
    font->num_fixed_sizes = -1;

  _alfont_new_cache_glyph(font);

  if (font->num_fixed_sizes < 0) {
    font->fixed_sizes = malloc(sizeof(int));
    _alfont_reget_fixed_sizes(font);

    alfont_set_font_size(font, 8);
  }
  else {
    font->fixed_sizes = malloc(sizeof(int) * (font->num_fixed_sizes + 1));
    _alfont_reget_fixed_sizes(font);

    /* set as current size the first found fixed size */
    alfont_set_font_size(font, font->fixed_sizes[0]);
  }

  alfont_set_char_extra_spacing(font, 0);

  return font;
}


int alfont_text_mode(int mode) {
  int old_mode = alfont_textmode;
  alfont_textmode = mode;
  return old_mode;
}


void alfont_destroy_font(ALFONT_FONT *f) {
  if (f == NULL)
    return;

  /* delete old glyphs */
  _alfont_delete_glyphs(f);

  /* delete the face */
  FT_Done_Face(f->face);

  if (f->fixed_sizes)
    free(f->fixed_sizes);

  /* deallocate the data */
  if (f->data)
    free(f->data);

  free(f);
}


void alfont_textout_aa(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color) {
  alfont_textout_aa_ex(bmp, f, s, x, y, color, alfont_textmode);
}


void alfont_textout_aa_ex(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color, int backg) {
  int character;
  int alpha_table[256];
  int last_glyph_index;

  /* is it under or over or too far to the right of the clipping rect then
     we can assume the string is clipped */
  if ((y + f->face_h < bmp->ct) || (y > bmp->cb) || (x > bmp->cr))
    return;

  /* if we are doing opaque mode, draw a rect and init our table*/
  if (backg >= 0) {
    int i, r, g, b, br, bg, bb, ir, ig, ib;
    int blendr, blendg, blendb;
    
    rectfill(bmp, x, y - f->face_ascender, x + alfont_text_length(f, s) - 1, y - f->face_descender, backg);

    /* get the color rgb */
    r = getr(color); g = getg(color); b = getb(color);

    /* get the background rgb */   
    br = getr(backg); bg = getg(backg); bb = getb(backg);

    /* get increments */
    ir = (r == br) ? 0 : (r + 1) - br;
    ig = (g == bg) ? 0 : (g + 1) - bg;
    ib = (b == bb) ? 0 : (b + 1) - bb;

    blendr = br << 8;
    blendg = bg << 8;
    blendb = bb << 8;
    
    /* blend both values and make our alpha table */
    for (i = 0; i < 256; i++) {
      alpha_table[i] = makecol(blendr >> 8, blendg >> 8, blendb >> 8);
      blendr += ir;
      blendg += ig;
      blendb += ib;
    }
  }

  /* draw char by char (using allegro unicode funcs) */
  acquire_bitmap(bmp);
  last_glyph_index = 0;
  for (character = ugetxc(&s); character != 0; character = ugetxc(&s))
  {
    int real_x, real_y, glyph_index;
    struct _ALFONT_CACHED_GLYPH cglyph;
    
    /* if left side of char farther than right side of clipping, we are done */
    if (x > bmp->cr)
      break;

    /* get the character out of the font */
    if (f->face->charmap)
      glyph_index = FT_Get_Char_Index(f->face, character);
    else
      glyph_index = character;

    /* cache the glyph */
    _alfont_cache_glyph(f, glyph_index);
    cglyph = f->cached_glyphs[glyph_index];

    /* calculate drawing coords */
    real_x = x + cglyph.aaleft;
    real_y = (y - cglyph.aatop) /* + f->face_ascender */;

    /* apply kerning */
    /*if (last_glyph_index) {
      FT_Vector v;
      FT_Get_Kerning(f->face, last_glyph_index, glyph_index, ft_kerning_default, &v);
      real_x += v.x >> 6;
      real_y += v.y >> 6;
    }*/
    last_glyph_index = glyph_index;

    /* draw only if exists */
    if ((cglyph.aa_available) && (cglyph.aabmp)) {
        
      int bmp_x, bmp_y;
      unsigned char *bmp_p = cglyph.aabmp;
      const int max_bmp_x = cglyph.aawidth + real_x;
      const int max_bmp_y = cglyph.aaheight + real_y;
      
      /* if in opaque mode */
      if (backg >= 0) {

        for (bmp_y = real_y; bmp_y < max_bmp_y; bmp_y++) {
          for (bmp_x = real_x; bmp_x < max_bmp_x; bmp_x++) {
            const int alpha = *bmp_p++;
            
            if (alpha)
               putpixel(bmp, bmp_x, bmp_y, alpha_table[alpha]);
          }
        }
      }

      /* if in transparent mode */
      else {

        for (bmp_y = real_y; bmp_y < max_bmp_y; bmp_y++) {
          for (bmp_x = real_x; bmp_x < max_bmp_x; bmp_x++) {
            const int alpha = *bmp_p++;
            
            if (alpha) {
               if (alpha >= 255)
                 solid_mode();
               else {
                 drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
                 set_trans_blender(0, 0, 0, alpha);
               }
               putpixel(bmp, bmp_x, bmp_y, color);
            }
          }
        }
      }
    }

    /* advance */
    if (cglyph.advancex)
      x += cglyph.advancex + f->ch_spacing;
    if (cglyph.advancey)
      y += cglyph.advancey + f->ch_spacing;
  }
  release_bitmap(bmp);

  /* reset blender */
  if (backg < 0)
    solid_mode();
}


void alfont_textout(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color) {
  alfont_textout_ex(bmp, f, s, x, y, color, alfont_textmode);
}


void alfont_textout_ex(BITMAP *bmp, ALFONT_FONT *f, const char *s, int x, int y, int color, int backg) {
  int character, last_glyph_index;

  /* is it under or over or too far to the right of the clipping rect then
     we can assume the string is clipped */
  if ((y + f->face_h < bmp->ct) || (y > bmp->cb) || (x > bmp->cr))
    return;

  /* if we are doing opaque mode, draw a rect */
  if (backg >= 0)
    rectfill(bmp, x, y - f->face_ascender, x + alfont_text_length(f, s) - 1, y - f->face_descender, backg);

  /* draw char by char (using allegro unicode funcs) */
  acquire_bitmap(bmp);
  last_glyph_index = 0;
  for (character = ugetxc(&s); character != 0; character = ugetxc(&s)) {
    int real_x, real_y, glyph_index;
    struct _ALFONT_CACHED_GLYPH cglyph;
    
    /* if left side of char farther than right side of clipping, we are done */
    if (x > bmp->cr)
      break;

    /* get the character out of the font */
    if (f->face->charmap)
      glyph_index = FT_Get_Char_Index(f->face, character);
    else
      glyph_index = character;

    /* cache the glyph */
    _alfont_cache_glyph(f, glyph_index);
    cglyph = f->cached_glyphs[glyph_index];

    /* calculate drawing coords */
    real_x = x + cglyph.left;
    real_y = (y - cglyph.top) /* + f->face_ascender */;

    /* apply kerning */
    /*if (last_glyph_index) {
      FT_Vector v;
      FT_Get_Kerning(f->face, last_glyph_index, glyph_index, ft_kerning_default, &v);
      real_x += v.x >> 6;
      real_y += v.y >> 6;
    }*/
    last_glyph_index = glyph_index;

    /* draw only if exists */
    if ((cglyph.mono_available) && (cglyph.bmp)) {
      unsigned char *bmp_p = cglyph.bmp;
    
      /* monochrome drawing */
      int bmp_x, bmp_y;

      /* copy the character bitmap to our allegro one */
      const int max_bmp_x = cglyph.width + real_x;
      const int max_bmp_y = cglyph.height + real_y;
      for (bmp_y = real_y; bmp_y < max_bmp_y; bmp_y++) {
        for (bmp_x = real_x; bmp_x < max_bmp_x; bmp_x++) {
          if (*bmp_p++)
            putpixel(bmp, bmp_x, bmp_y, color);
        }
      }
    }

    /* advance */
    if (cglyph.advancex)
      x += cglyph.advancex + f->ch_spacing;
    if (cglyph.advancey)
      y += cglyph.advancey + f->ch_spacing;
  }
  release_bitmap(bmp);

}


int alfont_text_height(ALFONT_FONT *f) {
  return f->face_h;
}


int alfont_text_length(ALFONT_FONT *f, const char *str) {
  int total_length = 0, character, last_glyph_index;

  /* virtually draw char by char */
  last_glyph_index = 0;
  for (character = ugetxc(&str); character != 0; character = ugetxc(&str)) {
    /* get the character out of the font */
    int glyph_index;
    if (f->face->charmap)
      glyph_index = FT_Get_Char_Index(f->face, character);
    else
      glyph_index = character;
    
    /* apply kerning */
    /*if (last_glyph_index) {
      FT_Vector v;
      FT_Get_Kerning(f->face, last_glyph_index, glyph_index, ft_kerning_default, &v);
      total_length += v.x >> 6;
    }*/
    last_glyph_index = glyph_index;

    /* cache */
    _alfont_cache_glyph(f, glyph_index);

    /* advance */
    if (f->cached_glyphs[glyph_index].advancex)
      total_length += f->cached_glyphs[glyph_index].advancex + f->ch_spacing;
  }

  return total_length;
}


int alfont_is_fixed_font(ALFONT_FONT *f) {
  if (f->num_fixed_sizes < 0)
    return FALSE;
  else
    return TRUE;
}


int alfont_is_scalable_font(ALFONT_FONT *f) {
  if (f->num_fixed_sizes < 0)
    return TRUE;
  else
    return FALSE;
}


const int *alfont_get_available_fixed_sizes(ALFONT_FONT *f) {
  /* we reget them just to make sure the contents where not changed */
  _alfont_reget_fixed_sizes(f);
  return f->fixed_sizes;
}


int alfont_get_nof_available_fixed_sizes(ALFONT_FONT *f) {
  return f->num_fixed_sizes;
}


int alfont_get_char_extra_spacing(ALFONT_FONT *f) {
  return f->ch_spacing;
}


void alfont_set_char_extra_spacing(ALFONT_FONT *f, int spacing) {
  if (spacing  < 0)
    f->ch_spacing = 0;
  else if (spacing > 4096)
    f->ch_spacing = 4096;
  else
    f->ch_spacing = spacing;
}
