/* * See Copyright Notice in main.h */ #include #include #include "main.h" const float FPS = 60.0; // Maximum FPS. const int SCREEN_W = 800; const int SCREEN_H = 600; const int MORPH_W = 128; // Width of the morph. Should be at most the width of the input image. const int MORPH_H = 128; // Height of the morph. Should be at most the height of the input image. const int ATOMS = 10000; // Number of atoms used in one thread. const size_t THREAD_N = 5; // Number of threads to use to find a perfect morph. const size_t SLOWNESS = 50; // How many frames to render per animation cycle. size_t morph_time = 0; int view_frame = 0; bool pressed_keys[ALLEGRO_KEY_MAX]; size_t active_thread = 0; // When render is ON, morph only one thread at a time. int color_fade = AM_NONE; // Color interpolation method. int trajectory = AM_NONE; // Atom trajectory interpolation method. bool median_combining = false; // Noise reduction method. FALSE for averaging. bool stop_morphing = false; // To halt the morph time temporarily. bool no_render = false; // When TRUE no blending is done, just atom morphing. ALLEGRO_DISPLAY *display = NULL; ALLEGRO_EVENT_QUEUE *event_queue = NULL; ALLEGRO_TIMER *timer = NULL; ALLEGRO_FONT *font = NULL; ALLEGRO_BITMAP *morph_bmp = NULL; // Holds the final morph as a bitmap. ALLEGRO_BITMAP *thread_bmp[THREAD_N]; // Holds the results of the morphing threads. // Helper function to initially populate the AM_SCENE object according to the provided // image file. bool fill_scene(AM_SCENE *scene, size_t frame, const char *png_file) { std::random_device rd; std::default_random_engine re(rd()); std::uniform_real_distribution uniform_dist(0.0, 1.0); ALLEGRO_BITMAP * bmp = al_load_bitmap(png_file); int bmp_w = al_get_bitmap_width(bmp); int bmp_h = al_get_bitmap_height(bmp); al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); for (int j=0; jpush_atom(frame, am_create_atom(px,py,r,g,b,a)); } } al_unlock_bitmap(bmp); al_destroy_bitmap(bmp); return true; } int main(int argc, char **argv) { if (!init(argc, argv)) { fprintf(stderr, "Failed to initialize!\n"); return -1; } std::random_device rd; std::default_random_engine seed_engine(rd()); std::uniform_int_distribution uniform_dist(1, std::numeric_limits::max()); morph_bmp = al_create_bitmap(MORPH_W, MORPH_H); al_set_target_bitmap(morph_bmp); al_clear_to_color(al_map_rgba(0,0,0,0)); AM_BLENDER blender; // Used to combine the thread results into the final morph. blender.set_resolution(MORPH_W, MORPH_H); blender.set_median_combining(median_combining); blender.start(); AM_THREAD scene_thread[THREAD_N]; // Each of these will morph its own version of the animation. AM_SCENE scene_buf [THREAD_N]; // Temporarily holds the last results of the morphing threads. AM_IMAGE image_buf [THREAD_N]; // Used to render the final image of the provided scene. { AM_SCENE scene; // Needed temporarily to store the raw input data. scene.init(ATOMS, 6); // Reserve 6 frames for this scene. fill_scene(&scene, 0, "../tests/data/battlelord_1.png"); fill_scene(&scene, 1, "../tests/data/battlelord_2.png"); fill_scene(&scene, 2, "../tests/data/battlelord_3.png"); fill_scene(&scene, 3, "../tests/data/battlelord_4.png"); fill_scene(&scene, 4, "../tests/data/battlelord_5.png"); fill_scene(&scene, 5, "../tests/data/battlelord_6.png"); for (size_t i=0; ipixel_count(); for (size_t i=0; iget_xy(i, &x, &y); img->get_rgba(i, &r, &g, &b, &a); al_put_pixel(x, y, al_map_rgba(r,g,b,a)); } // Finally unlock the bitmap: if (lock) al_unlock_bitmap(to); } void blend_morphs(AM_BLENDER *blender, ALLEGRO_BITMAP *to) { // Clear old bitmap: al_set_target_bitmap(to); al_set_blender(ALLEGRO_DEST_MINUS_SRC, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); al_draw_filled_rectangle(0.0, 0.0, MORPH_W, MORPH_H, al_map_rgba(0,0,0,255)); // Prepare to render: al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); ALLEGRO_LOCKED_REGION * lock = al_lock_bitmap(to,ALLEGRO_PIXEL_FORMAT_ANY,ALLEGRO_LOCK_READWRITE); if (lock == NULL) return; // Put the pixels: size_t pixels = blender->pixel_count(); for (size_t i=0; iget_xy(i, &x, &y); blender->get_rgba(i, &r, &g, &b, &a); al_put_pixel(x, y, al_map_rgba(r,g,b,a)); } // Finally unlock the bitmap: if (lock) al_unlock_bitmap(to); } bool init(int argc, char **argv) { if (true == (am_get_warning()&AM_WARN_POINTER_SIZE)) { fprintf(stderr, "Pointer size is insufficiently small.\n"); } if (true == (am_get_warning()&AM_WARN_ATOM_SIZE)) { fprintf(stderr, "Atom size (%lu) is larger than optimal (%lu).\n", sizeof(AM_ATOM), sizeof(void *) ); } if(!al_init()) { fprintf(stderr, "failed to initialize allegro!\n"); return false; } if(!al_install_keyboard()) { fprintf(stderr, "failed to initialize the keyboard!\n"); return false; } al_install_mouse(); al_init_image_addon(); al_init_font_addon(); al_init_primitives_addon(); timer = al_create_timer(1.0 / FPS); if(!timer) { fprintf(stderr, "failed to create timer!\n"); return false; } display = al_create_display(SCREEN_W, SCREEN_H); if(!display) { fprintf(stderr, "failed to create display!\n"); al_destroy_timer(timer); return false; } al_set_new_bitmap_flags(ALLEGRO_MAG_LINEAR|ALLEGRO_MIN_LINEAR); font = al_load_font("data/fixed_font.tga", 0, 0); if (font==NULL) { fprintf(stderr, "failed to load font!\n"); al_destroy_display(display); al_destroy_timer(timer); return false; } al_set_target_bitmap(al_get_backbuffer(display)); event_queue = al_create_event_queue(); if(!event_queue) { fprintf(stderr, "failed to create event_queue!\n"); al_destroy_display(display); al_destroy_timer(timer); al_destroy_font(font); return false; } al_register_event_source(event_queue, al_get_display_event_source(display)); al_register_event_source(event_queue, al_get_timer_event_source(timer)); al_register_event_source(event_queue, al_get_keyboard_event_source()); al_register_event_source(event_queue, al_get_mouse_event_source()); al_clear_to_color(al_map_rgb(0,0,0)); al_draw_textf(font, al_map_rgb(0,255,0), SCREEN_W/2, SCREEN_H/2, ALLEGRO_ALIGN_CENTRE, "LOADING..."); al_flip_display(); al_start_timer(timer); calculate_fps(); return true; } int round_int( double r ) { return (r > 0.0) ? (r + 0.5) : (r - 0.5); } int calculate_fps() { static int times = 0; static double old_time = 0.0; static double delta_sum = 0.0; static int old_fps = -1; static bool first = true; if (first) { first = false; old_time = al_get_time(); return -1; } int rec_times = 0; int max_times = round_int(FPS); double new_time = al_get_time(); double delta = new_time - old_time; delta_sum += delta; old_time = new_time; double p = delta_sum * max_times; rec_times = round_int(p); if (times > rec_times) { return -1; } times++; int fps = 0; if (delta_sum >= 1.0 || times>=max_times) { fps = times; old_fps = fps; times=0; delta_sum=0.0; } else { if (old_fps == -1) fps = times; else fps = old_fps; } return fps; }