using System;

using sharpallegro5;

using ALLEGRO_DISPLAY = System.IntPtr;
using ALLEGRO_BITMAP = System.IntPtr;
using ALLEGRO_TIMER = System.IntPtr;
using ALLEGRO_EVENT_QUEUE = System.IntPtr;
using ALLEGRO_FONT = System.IntPtr;

/* An example comparing FPS when drawing to a bitmap with the
 * ALLEGRO_FORCE_LOCKING flag and without. Mainly meant as a test how much
 * speedup direct drawing can give over the slow locking.
 */
public class ex_bitmap_target : AllegroExample
{
    const int W = 300, H = 300; /* Size of target bitmap. */
    const int RW = 50, RH = 50; /* Size of rectangle we draw to it. */
    static ALLEGRO_DISPLAY display;
    static ALLEGRO_BITMAP target; /* The target bitmap. */
    static float x, y, dx, dy; /* Position and velocity of moving rectangle. */
    static double last_time; /* For controling speed. */
    static bool quit; /* Flag to record Esc key or X button. */
    static ALLEGRO_FONT myfont; /* Our font. */
    static ALLEGRO_EVENT_QUEUE queue; /* Our events queue. */

    /* Print some text with a shadow. */
    static void print(int x, int y, string format, params object[] arg)
    {
        //va_list list;
        //char message[1024];
        string message;

        //va_start(list, format);
        //vsnprintf(message, sizeof message, format, list);
        //va_end(list);
        message = string.Format(format, arg);

        al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);

        al_draw_text(myfont, al_map_rgb(0, 0, 0), x + 2, y + 2, 0, message, __arglist());
        al_draw_text(myfont, al_map_rgb(255, 255, 255), x, y, 0, message, __arglist());
    }

    /* Draw our example scene. */
    static void draw()
    {
        float xs, ys, a;
        double dt = 0;
        double t = al_get_time();
        if (last_time > 0)
        {
            dt = t - last_time;
        }
        last_time = t;

        al_set_target_bitmap(target);
        al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);

        al_draw_filled_rectangle(x, y, x + RW, y + RH, al_map_rgba_f(1, 0, 0, 1));
        al_draw_filled_rectangle(0, 0, W, H, al_map_rgba_f(1, 1, 0, 0.1f));

        x += (float)(dx * dt);
        if (x < 0)
        {
            x = 0;
            dx = -dx;
        }
        if (x + RW > W)
        {
            x = W - RW;
            dx = -dx;
        }
        y += (float)(dy * dt);
        if (y < 0)
        {
            y = 0;
            dy = -dy;
        }
        if (y + RH > H)
        {
            y = H - RH;
            dy = -dy;
        }

        al_set_target_backbuffer(display);
        al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
        al_clear_to_color(al_map_rgba_f(0, 0, 1, 1));
        xs = (float)(1 + 0.2 * Math.Sin(t * ALLEGRO_PI * 2));
        ys = (float)(1 + 0.2 * Math.Sin(t * ALLEGRO_PI * 2));
        a = (float)(t * ALLEGRO_PI * 2 / 3);
        al_draw_scaled_rotated_bitmap(target, W / 2, H / 2, 320, 240, xs, ys, a, 0);
    }

    /* Run the FPS test. */
    static void run()
    {
        ALLEGRO_EVENT @event = new ALLEGRO_EVENT();
        int frames = 0;
        double start;

        target = al_create_bitmap(W, H);
        al_set_target_bitmap(target);
        al_clear_to_color(al_map_rgba_f(1, 1, 0, 1));

        al_set_target_backbuffer(display);

        dx = 81;
        dy = 63;

        start = al_get_time();
        while (true)
        {
            /* Check for ESC key or close button event and quit in either case. */
            if (!al_is_event_queue_empty(queue))
            {
                while (al_get_next_event(queue, ref @event))
                {
                    switch (@event.type)
                    {
                        case ALLEGRO_EVENT_DISPLAY_CLOSE:
                            quit = true;
                            goto done;

                        case ALLEGRO_EVENT_KEY_DOWN:
                            if (@event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                                quit = true;
                            goto done;
                            if (@event.keyboard.keycode == ALLEGRO_KEY_SPACE)
                                goto done;
                            break;
                    }
                }
            }
            draw();
            print(0, 0, "FPS: {0:0.0}", frames / (al_get_time() - start));
            if ((al_get_new_bitmap_flags() & ALLEGRO_FORCE_LOCKING) > 0)
            {
                print(0, al_get_font_line_height(myfont), "using forced bitmap locking");
            }
            else
            {
                print(0, al_get_font_line_height(myfont), "drawing directly to bitmap");
            }
            print(0, al_get_font_line_height(myfont) * 2,
               "Press SPACE to toggle drawing method.");
            al_flip_display();
            frames++;
        }

    done:

        al_destroy_bitmap(target);
    }

    static int Main()
    {
        if (!al_init())
        {
            abort_example("Could not init Allegro.\n");
            return 1;
        }

        al_init_primitives_addon();
        al_install_keyboard();
        al_init_image_addon();
        al_init_font_addon();

        display = al_create_display(640, 480);
        if (display == IntPtr.Zero)
        {
            abort_example("Error creating display\n");
            return 1;
        }

        queue = al_create_event_queue();
        al_register_event_source(queue, al_get_keyboard_event_source());
        al_register_event_source(queue, al_get_display_event_source(display));

        myfont = al_load_font("data/font.tga", 0, 0);
        if (myfont == IntPtr.Zero)
        {
            abort_example("font.tga not found\n");
            return 1;
        }

        while (!quit)
        {
            if ((al_get_new_bitmap_flags() & ALLEGRO_FORCE_LOCKING) > 0)
                al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
            else
                al_set_new_bitmap_flags(ALLEGRO_FORCE_LOCKING);
            run();
        }

        al_destroy_event_queue(queue);

        return 0;
    }
}