// fntutil.c : Contains routines for decoding the FNT format into an
// OpenGL-readable format.
//
// Written by Eric C. Peterson, licensed under UoI/NCSA.
// Revision history:
//      + 2009 May 13 : Clean up, public release on mw2.jjaro.net
//      + 2006 Nov 01 : Initial version written

#include <stdlib.h>

typedef struct {
    unsigned char r, g, b, a;
} RGBA;

typedef struct {
    long count;
    long height;
    long *width;
    RGBA **bitmaps;
    void *filedata;
} FNT_OBJECT;

typedef struct {
    char version[4];
    long char_count;
    long char_height;
    long font_background;
    long offsets[];
} FNT_HEADER;

typedef struct {
    long char_width;
    unsigned char pixels[];
} FNT_ENTRY;

FNT_OBJECT* OpenFNTObject(void* memory) {
    FNT_HEADER* file;
    FNT_OBJECT* object;
    int i; // loop index

    // obviously we bail if we're passed a null memory pointer
    if (!memory)
        return NULL;

    // otherwise, set up the pointer correctly
    file = (FNT_HEADER*)memory;

    // now check to see if the version string is alright
    if (!((file->version[0] == '1' ) &&
          (file->version[1] == '.' ) &&
          (file->version[2] == '\0') &&
          (file->version[3] == '\0')))
        return NULL; // and if it isn't, leave

    // now that we've checked those two things out, allocate the object
    // and initiailize the easy things
    object = malloc(sizeof(FNT_OBJECT));
    object->count = file->char_count;
    object->height = file->char_height;
    object->filedata = (void*)file;

    // then allocate another couple arrays
    object->width = malloc(sizeof(long) * object->count);
    object->bitmaps = malloc(sizeof(unsigned char*) * object->count);

    // for each possible bitmap...
    for (i = 0; i < object->count; i++) {
        int j; // loop index

        // set cur_entry to put to our current slot in the file
        FNT_ENTRY* cur_entry = (FNT_ENTRY*)((char*)memory + file->offsets[i]);

        // grab the character width information and store to the object
        object->width[i] = cur_entry->char_width;

        // now allocate the current amount of space to hold the bitmap
        object->bitmaps[i] = calloc(object->height * cur_entry->char_width,
                                    sizeof(RGBA));

        // now expand the palettized bitmap into an OpenGL-readable bitmap
        for (j = 0; j < object->height * cur_entry->char_width; j++)
            if (cur_entry->pixels[j] != file->font_background) {
                RGBA conv_color;

                conv_color.r = 255;
                conv_color.g = 255;
                conv_color.b = 255;
                conv_color.a = 255;

                // set the pixel value
                object->bitmaps[i][j] = conv_color;
            }
    }

    return object;
}

FNT_OBJECT* CloseFNTObject(FNT_OBJECT* object) {
    // if we're not passed a null pointer
    if (object) {
        // free the width array if it exists
        if (object->width)
            free(object->width);

        // work on freeing the bitmaps
        if (object->bitmaps) {
            int i;

            // free each bitmap individually
            for (i = 0; i < object->count; i++)
                if (object->bitmaps[i])
                    free(object->bitmaps[i]);

            // free the bitmap list
            free(object->bitmaps);
        }
    }

    // free the object itself, now that we don't need the arrays
    free(object);

    return NULL;
}
