/* Pathogen Warrior
 * Copyright 2004 Jetro Lauha - http://iki.fi/jetro/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: Font.cpp,v 1.4 2004/07/14 15:37:09 tonic Exp $
 * $Revision: 1.4 $
 */
#pragma warning(disable : 4786)

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "SDL.h"
#include "SDL_opengl.h"
#include "SDL_image.h"

#include "types.h"
#include "gfx.h"
#include "Font.h"
#include "errormsg.h"
#include "main.h"


const static char defaultFontStr[] =
    " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~åäöÅÄÖ";



Font::Font(char *filename, const char *fontstr)
{
    mSpacing = 1;
    mLoaded = 0;
    mChars = 0;
    strncpy(mFilename, filename, 256);

    if (fontstr == NULL)
        fontstr = defaultFontStr;
    buildCharMap(fontstr);

    setDrawImageFunc(::drawImage);

    reload();
}


Font::~Font()
{
    memset(mFilename, 0, 256);
    memset(mCharMap, 0, 256);
    memset(mLetter, 0, 256 * sizeof(IMAGE));
    mLoaded = mChars = 0;
}


void Font::buildCharMap(const char *fontstr)
{
    UINT a, ch, mapped;

    mChars = strlen(fontstr);

    for (ch = 0; ch < 256; ++ch)
    {
        mapped = 0;

        for (a = 0; a < mChars; ++a)
        {
            if (fontstr[a] == (char)ch)
            {
                mapped = a;
                break;
            }
        }

        mCharMap[ch] = mapped;
    }
}


void Font::reload()
{
    SDL_Surface *image;
    UINT32 ch, chars, x, y, x1, x2;

    image = IMG_Load(mFilename);
    if (image == NULL)
    {
        errorMessage("Error", "Cannot load font image: %s", mFilename);
        exit(1);
    }

    chars = image->h / image->w;
    if (mChars < chars)
        chars = mChars;
    if (chars < 1)
    {
        errorMessage("Error", "No characters in font");
        exit(1);
    }

    mFontHeight = image->w;

    for (ch = 0; ch < chars; ++ch)
    {
        int w, h;
        SDL_LockSurface(image);
        x1 = image->w;
        x2 = 0;
        for (x = 0; (int)x < image->w; ++x)
        {
            for (y = ch * image->w; y < (ch + 1) * image->w; ++y)
            {
                Uint32 pixel = *(UINT32 *)((UINT8 *)image->pixels +
                    y * image->pitch + x * image->format->BytesPerPixel);
                Uint8 r, g, b, a = 0;
                SDL_GetRGBA(pixel, image->format, &r, &g, &b, &a);
                if ((image->flags & SDL_SRCALPHA) == 0)
                    a = r | g | b;
                if (a && x > x2)
                    x2 = x;
                if (a && x < x1)
                    x1 = x;
            }
        }
        SDL_UnlockSurface(image);
        if (x1 > x2)
        {
            w = image->w / 3;
            h = image->w;
            x1 = 0;
            x2 = w;
        }
        else
        {
            w = x2 - x1 + 1;
            h = image->w;
        }

        mLetter[ch].w = w;
        mLetter[ch].h = h;

        SDL_Rect area;
        area.x = x1;
        area.y = ch * image->w;
        area.w = w;
        area.h = h;
        
        /* Convert the image into an OpenGL texture */
        mLetter[ch].glid = SDL_GL_LoadTexture(image, mLetter[ch].uv, &area);
    }

    /* We don't need the original image anymore */
    SDL_FreeSurface(image);

    mLoaded = 1;
}


void Font::setDrawImageFunc(void (*func)(const IMAGE &img, FLOAT x, FLOAT y,
                                         FLOAT r, FLOAT g, FLOAT b, FLOAT a))
{
    assert(func != NULL);
    if (func != NULL)
        this->drawImage = func;
}


INT32 Font::getStringWidth(const char *str)
{
    if (str == NULL)
        return 0;

    INT32 strWidth = 0;
    UINT ch, strl = strlen(str);

    for (ch = 0; ch < strl; ++ch)
        strWidth += mLetter[mCharMap[(UINT8)str[ch]]].w + mSpacing;

    return strWidth;
}


void Font::drawString(INT32 x, INT32 y, UINT32 flags, const char *str,
                      GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
    if (str == NULL)
        return;

    int strWidth = 0, strHeight = 0;
    UINT ch, strl = strlen(str);
    
    if ((flags & FONT_ALIGN_HORIZ_CENTER) > 0 ||
        (flags & FONT_ALIGN_RIGHT) > 0)
    {
        // calculate row width and adjust x
        for (ch = 0; ch < strl; ++ch)
            strWidth += mLetter[mCharMap[(UINT8)str[ch]]].w + mSpacing;
        if ((flags & FONT_ALIGN_HORIZ_CENTER) > 0)
            x -= strWidth / 2;
        else if ((flags & FONT_ALIGN_RIGHT) > 0)
            x -= strWidth;
    }
    if ((flags & FONT_ALIGN_VERT_CENTER) > 0 ||
        (flags & FONT_ALIGN_BOTTOM) > 0)
    {
        // calculate row height and adjust y
        strHeight = mFontHeight;
        if ((flags & FONT_ALIGN_VERT_CENTER) > 0)
            y -= strHeight / 2;
        else if ((flags & FONT_ALIGN_BOTTOM) > 0)
            y -= strHeight;
    }
    
    for (ch = 0; ch < strl; ++ch)
    {
        IMAGE &letter = mLetter[mCharMap[(UINT8)str[ch]]];
        this->drawImage(letter, x, y, r, g, b, a);
        x += letter.w + mSpacing;
    }
}

