/*
 * Glyph Keeper benchmark with Allegro
 *
 * Copyright (c) 2003-2007 Kirill Kryukov
 *
 * This file is part of Glyph Keeper library, and may only be used,
 * modified, and distributed under the terms of the Glyph Keeper
 * license, located in the file 'license.txt' within this package.
 */


/*
 * This program benchmarks Allegro FONT objects created with
 * gk_create_allegro_font().
 */

/* Standard includes. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <ctype.h>
#include <math.h>

/* Target library. */
#include <allegro.h>

/* Glyph Keeper header. */
#ifndef GK_NO_LEGACY
#define GK_NO_LEGACY
#endif
#include "glyph.h"

/* Code shared by several benchmark programs. */
#include "bench_utils.c"

/* Code shared by Glyph Keeper benchmarks. */
#include "bench_gk_common.c"



time_t start_time, now, now1;
int char_count = 0;

int info_color;

BITMAP* bmp = 0;

FONT **fonts = 0;



void exit_handler()
{
    glyph_keeper_finish();
    if (fonts)
    {
        int i;
        for (i=0; i<number_of_renderers; i++)
        {
            if (fonts[i]) { destroy_font(fonts[i]); fonts[i] = 0; }
        }
        free(fonts);
        fonts = 0;
    }
}


void screen_message(int x,int y,char* text)
{
    textprintf_ex(screen,font,x,y,info_color,-1,text);
}


void screen_rect(int x1,int y1,int x2,int y2)
{
    rectfill(screen,x1,y1,x2,y2,info_color);
}


/* This function updates time and chars/sec count. */
/* Also updates screen if we are using memory bitmap. */
void update()
{
    int seconds = now1-start_time;
    int minutes = seconds/60;
    int hours;
    seconds -= minutes*60;
    hours = minutes/60;
    minutes -= hours*60;

    set_clip_rect(bmp,0,0,screen_width-1,screen_height-1);
    rectfill(bmp,0,0,screen_width-1,area_top-1,0);
    textprintf_ex(bmp,font,12,7,info_color,0,"%02d:%02d:%02d  %ld chars/sec",hours,minutes,seconds,char_count/(now1-start_time));
    textprintf_ex(bmp,font,12,19,info_color,0,"glyph cache: %d bytes",gk_keeper_byte_count(keep));
    if (clip_on) set_clip_rect(bmp,SCREEN_W/4,SCREEN_H/4,SCREEN_W*3/4,SCREEN_H*3/4);
    else set_clip_rect(bmp,0,23,SCREEN_W,SCREEN_H);
    if (bmp!=screen) blit(bmp,screen,0,0,0,0,screen_width,screen_height);
}


int main(int argc,char *argv[])
{
    int i;

    /* Registering exit handler. */
    atexit(exit_handler);

    /* Reading the configuration file. */
    init_benchmark("bench_gk_convert_1_alleg",argv[0],(argc>1)?argv[1]:0);
    if (!logfile) { exit(1); }

    /* Initializing Allegro and setting graphics mode. */
    if (allegro_init()) { fprintf(logfile,"Can't init Allegro\n"); exit(1); }
    if (install_keyboard()) { fprintf(logfile,"Can't initialize keyboard\n"); exit(1); }
    set_color_depth(color_depth);
    if (set_gfx_mode(GFX_AUTODETECT_WINDOWED,screen_width,screen_height,0,0) || !screen)
        if (set_gfx_mode(GFX_AUTODETECT_FULLSCREEN,screen_width,screen_height,0,0) || !screen)
            { fprintf(logfile,"Can't set graphics mode\n"); exit(1); }
    fprintf(logfile,"Graphics mode %dx%dx%d set, draw_to_screen: %s, clipping: %s\n",
        SCREEN_W,SCREEN_H,(bitmap_color_depth(screen)),draw_to_screen?"ON":"OFF",clip_on?"ON":"OFF");

    info_color = makecol(128,192,128);

    /* Initializing target bitmap. */
    if (draw_to_screen) bmp = screen;
    else
    {
        bmp = create_bitmap(screen_width,screen_height);
        if (!bmp) { fprintf(logfile,"Can't create buffer bitmap\n"); exit(1); }
    }



    /* Loading a font from file, creating a glyph cache, etc. */
    glyph_keeper_startup();

    /* Creating and configuring font renderers. */
    create_font_renderers();

    /* Creating Allegro FONT objects. */
    fonts = (FONT**)calloc(sizeof(FONT*),number_of_renderers);
    if (!fonts) { fprintf(logfile,"Can't allocate memory for Allegro FONTs\n"); exit(1); }
    for (i=0; i<number_of_renderers; i++)
    {
        fonts[i] = gk_create_allegro_font(rends[i]);
        if (!fonts[i]) { fprintf(logfile,"Can't create FONT #%d\n",i); exit(1); }
    }

    /* Pre-caching the glyphs. */
    /* It will work without pre-caching about the same way, */
    /* just I think pre-caching may give slightly more accurate benchmark result. */
    if (cache_on) precache_all_glyphs();

    /* Filling the test dataset. */
    if (test_dataset_num_elements > 0)
    {
        int ri = 0;
        int xmin = 220, xmax = xmin+78, xl = xmin, xr = xl;
        int i;

        fprintf(logfile,"Filling the test dataset of %d elements\n",test_dataset_num_elements);
        screen_message(text_x,text_y,"Filling the test dataset [          ]");

        for (i=0; i<test_dataset_num_elements; i++)
        {
            int w, h, px, py, c, n = 0;
            int asc, dx, dy;
            int col, r, g, b;

            /* Trying to create a random string which will fit within the screen. */
            /* Because theoretically you can set font size to 100x100 and what should I do then. */
            do
            {
                test_dataset[i].length = min_string_length + rand_4() % string_length_variety;
                for (c=0; c<test_dataset[i].length; c++)
                {
                    do
                    {
                        ((char*)test_dataset[i].text)[c] = range_8_start + (rand_4() % range_8_length);
                    }
                    while (!gk_rend_has_character(rends[ri],((char*)test_dataset[i].text)[c]));
                }
                ((char*)test_dataset[i].text)[c] = 0;

                gk_text_dimensions_utf8(rends[ri],(char*)test_dataset[i].text,&w,&h,&px,&py);

                n++;
            }
            while ( (w >= area_width || h >= area_height) && n<100 );

            /* No way, man! This font size is too big! You can't benchmark with it. */
            /* At least try to set a larger screen (window) size. */
            /* ("screen_width" and "screen_height" options in bench.cfg file). */
            if (n >= 100)
            {
                fprintf(logfile,"Error: Font size is too large! One line of text does not even fit the screen!\n");
                exit(1);
            }

            asc = gk_rend_ascender_pixels(rends[ri]);
            dx = (int)(sin(gk_rend_get_angle_in_radians(rends[ri])) * asc);
            dy = (int)(cos(gk_rend_get_angle_in_radians(rends[ri])) * asc);

            /* Nicely placing the text so that it will never run out of screen. */
            /* Running out of screen is bad because it the prints instantly */
            /* and distorts the benchmark result. */
            test_dataset[i].x = area_left + rand_4()%(area_width-w) + px - dx;
            test_dataset[i].y = area_top + rand_4()%(area_height-h) + py - dy;

            col = gk_rend_get_text_color(rends[ri]);
            r = (col >> 16) & 0xFF;
            g = (col >> 8) & 0xFF;
            b = col & 0xFF;
            test_dataset[i].text_color = makecol(r,g,b);

            if (background_on)
            {
                col = gk_rend_get_back_color(rends[ri]);
                r = (col >> 16) & 0xFF;
                g = (col >> 8) & 0xFF;
                b = col & 0xFF;
                test_dataset[i].back_color = makecol(r,g,b);
            }
            else test_dataset[i].back_color = -1;

            /* Going to the next renderer. */
            ri = (ri+1)%number_of_renderers;

            /* Updating progress bar. */
            xr = xmin+(i*(xmax-xmin)/test_dataset_num_elements);
            if (xr > xl) { screen_rect(xl,text_y,xr,text_y+6); xl = xr; }
        }
        fprintf(logfile,"Test dataset filled!\n");
        screen_message(text_x,text_y,"Filling the test dataset [          ] OK");
        text_y += text_line_height;
    }



    /* Waiting for the start of new second. */
    { int zero = time(0); do time(&start_time); while (start_time==zero); }
    now = start_time;

    if (bmp==screen) clear(screen);
    if (clip_on) set_clip_rect(bmp,SCREEN_W/4,SCREEN_H/4,SCREEN_W*3/4,SCREEN_H*3/4);



    /* Running the benchmark until the ESC or SPACE is hit. */
    if (test_dataset_num_elements > 0)
    {
        int di = 0, ri = 0;
        int go_on = 1;
        int i;

        while (go_on)
        {
            for (i=0; i<100; i++)
            {
                textout_ex ( bmp, fonts[ri], (char*)test_dataset[di].text,
                             test_dataset[di].x, test_dataset[di].y,
                             test_dataset[di].text_color, test_dataset[di].back_color );

                char_count += test_dataset[di].length;

                di++;
                if (di == test_dataset_num_elements) { di = 0; ri = 0; }
                else { ri = (ri+1)%number_of_renderers; }
            }
            now1 = time(0);
            if (now1!=now) { update(); now = now1; }

            while (keypressed())
            {
                int k = readkey() >> 8;
                if (k == KEY_ESC || k == KEY_SPACE) go_on = 0;
                if (k == KEY_C) clear(bmp);
            }
        }
    }
    else
    {
        int go_on = 1;

        while (go_on)
        {
            int i;
            for (i=0; i<100; i++)
            {
                int x,y,w,h,px,py,dx,dy,asc,length,text_color,back_color;
                reset_str8();

                if (transparent_on) gk_rend_set_text_alpha_color(rends[0],rand_4());
                else gk_rend_set_text_alpha_color(rends[0],0xFF000000|rand_4());
                if (background_on) gk_rend_set_back_color(rends[0],rand_4()&0xFFFFFF);
                if (angle_on) gk_rend_set_angle_in_radians(rends[0],ONE_DEGREE*(rand_4()&0xFF));

                if (random_italic_on)
                    gk_rend_set_italic_angle_in_degrees( rends[0], (double)(rand_4()%(90*1000+1)) / 1000 - 45 );
                else if (fixed_italic)
                    gk_rend_set_italic_angle_in_degrees( rends[0], fixed_italic );

                if (random_bold_on)
                    gk_rend_set_bold_strength( rends[0], rand_4()%601-300 );
                else if (fixed_bold)
                    gk_rend_set_bold_strength( rends[0], fixed_bold );

                asc = gk_rend_ascender_pixels(rends[0]);
                dx = (int)(sin(gk_rend_get_angle_in_radians(rends[0])) * asc);
                dy = (int)(cos(gk_rend_get_angle_in_radians(rends[0])) * asc);

                gk_text_dimensions_utf8(rends[0],str8,&w,&h,&px,&py);

                x = area_left + rand_4()%(area_width-w) + px - dx;
                y = area_top + rand_4()%(area_height-h) + py - dy;

                text_color = rand_4() & 0xFFFFFF;
                if (background_on) back_color = rand_4() & 0xFFFFFF;
                else back_color = -1;

                textout_ex ( bmp, fonts[0], str8, x, y, text_color, back_color );

                char_count += length;
            }
            now1 = time(0);
            if (now1!=now) { update(); now = now1; }

            while (keypressed())
            {
                int k = readkey() >> 8;
                if (k == KEY_ESC || k == KEY_SPACE) go_on = 0;
                if (k == KEY_C) clear(bmp);
            }
        }
    }

    while (key[KEY_SPACE] || key[KEY_ESC]) { rest(1); }
    while (!key[KEY_SPACE] && !key[KEY_ESC]) { rest(1); }

    gk_library_cleanup();

    return 0;
}
END_OF_MAIN()
