/*
 *    Example program for the Allegro library.
 *
 *    Test that shaders are applied per target bitmap.
 */

#include "allegro5/allegro.h"
#include "allegro5/allegro_image.h"

#include "common.c"

static const int MAX_REGION = 4;

static float tints[12] =
{
   4.0, 0.0, 1.0,
   0.0, 4.0, 1.0,
   1.0, 0.0, 4.0,
   4.0, 4.0, 1.0
};

static void choose_shader_source(ALLEGRO_SHADER_PLATFORM platform,
   char const **vsource, char const **psource)
{
   if (platform == ALLEGRO_SHADER_HLSL) {
      *vsource = "data/ex_shader_vertex.hlsl";
      *psource = "data/ex_shader_pixel.hlsl";
   }
   else if (platform == ALLEGRO_SHADER_GLSL) {
      *vsource = "data/ex_shader_vertex.glsl";
      *psource = "data/ex_shader_pixel.glsl";
   }
   else {
      /* Shouldn't happen. */
      *vsource = NULL;
      *psource = NULL;
   }
}

static ALLEGRO_BITMAP *make_region(ALLEGRO_BITMAP *parent,
   int x, int y, int w, int h, ALLEGRO_SHADER *shader)
{
   ALLEGRO_BITMAP *sub = al_create_sub_bitmap(parent, x, y, w, h);
   if (sub) {
      al_set_target_bitmap(sub);
      al_use_shader(shader);
      /* Not bothering to restore old target bitmap. */
   }
   return sub;
}

int main(int argc, char **argv)
{
   ALLEGRO_DISPLAY *display;
   ALLEGRO_BITMAP *image;
   ALLEGRO_BITMAP *backbuffer;
   ALLEGRO_BITMAP *region[4];
   ALLEGRO_SHADER *shader;
   const char *vsource;
   const char *psource;
   ALLEGRO_TRANSFORM t;
   int i;

   (void)argc;
   (void)argv;

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
   }
   al_install_keyboard();
   al_init_image_addon();
   init_platform_specific();

   al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE);
   display = al_create_display(640, 480);
   if (!display) {
      abort_example("Could not create display.\n");
   }

   image = al_load_bitmap("data/mysha.pcx");
   if (!image) {
      abort_example("Could not load image.\n");
   }

   /* Create the shader. */
   shader = al_create_shader(ALLEGRO_SHADER_AUTO);
   if (!shader) {
      abort_example("Could not create shader.\n");
   }
   choose_shader_source(al_get_shader_platform(shader), &vsource, &psource);
   if (!vsource|| !psource) {
      abort_example("Could not load source files.\n");
   }
   if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vsource)) {
      abort_example("al_attach_shader_source_file failed: %s\n",
         al_get_shader_log(shader));
   }
   if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, psource)) {
      abort_example("al_attach_shader_source_file failed: %s\n",
         al_get_shader_log(shader));
   }
   if (!al_build_shader(shader)) {
      abort_example("al_build_shader failed: %s\n", al_get_shader_log(shader));
   }

   /* Create four sub-bitmaps of the backbuffer sharing a shader. */
   backbuffer = al_get_backbuffer(display);
   region[0] = make_region(backbuffer, 0, 0, 320, 200, shader);
   region[1] = make_region(backbuffer, 320, 0, 320, 200, shader);
   region[2] = make_region(backbuffer, 0, 240, 320, 200, shader);
   region[3] = make_region(backbuffer, 320, 240, 320, 200, shader);
   if (!region[0] || !region[1] || !region[2] || !region[3]) {
      abort_example("make_region failed\n");
   }

   /* Apply a transformation to the last region (the current target). */
   al_identity_transform(&t);
   al_scale_transform(&t, 2.0, 2.0);
   al_translate_transform(&t, -160, -100);
   al_use_transform(&t);

   for (;;) {
      ALLEGRO_KEYBOARD_STATE s;
      al_get_keyboard_state(&s);
      if (al_key_down(&s, ALLEGRO_KEY_ESCAPE))
         break;

      for (i = 0; i < MAX_REGION; i++) {
         /* When we change the target bitmap, the shader that was last used on
          * that bitmap is automatically in effect.  All of our region
          * sub-bitmaps use the same shader so we need to set the tint variable
          * each time, as it was clobbered when drawing to the previous region.
          */
         al_set_target_bitmap(region[i]);
         al_set_shader_float_vector("tint", 3, &tints[i * 3], 1);
         al_draw_bitmap(image, 0, 0, 0);
      }

      al_set_target_backbuffer(display);
      al_draw_tinted_bitmap(image, al_map_rgba_f(0.5, 0.5, 0.5, 0.5),
         320/2, 240/2, 0);

      al_flip_display();
   }

   al_set_target_backbuffer(display);
   al_use_shader(NULL);
   al_destroy_shader(shader);

   return 0;
}

/* vim: set sts=3 sw=3 et: */
