#include #include #include #include #include #include #include #define DISP_WIDTH 640 #define DISP_HEIGHT 480 #define FPS 20.0 #define DO_INIT(check, desc) \ if (!(check)) { \ fprintf(stderr, "err: can't initialise %s\n", desc); \ rval = 1; \ goto done; \ } static bool bit_get(uint8_t *bline, unsigned off) { return (bline[off / 8] >> (off % 8)) & 0x01; } static void bit_set(uint8_t *bline, unsigned off) { bline[off / 8] = (bline[off / 8] | (0x01 << (off % 8)) ); } static void bit_toggle(uint8_t *bline, unsigned off) { bline[off / 8] = (bline[off / 8] ^ (0x01 << (off % 8)) ); } int main(int argc, char **argv) { int rval = 0; uint8_t bits[DISP_HEIGHT][DISP_WIDTH / 8]; uint8_t automaton = 0, randomness = 4, framerate = 2; unsigned goframes = 1; unsigned x, y; bool pause = 0; ALLEGRO_DISPLAY *d = NULL; ALLEGRO_BITMAP *b = NULL; ALLEGRO_TIMER *t = NULL; ALLEGRO_EVENT_QUEUE *eq = NULL; ALLEGRO_EVENT e; DO_INIT(sodium_init() >= 0, "sodium"); DO_INIT(al_init(), "allegro"); DO_INIT(al_init_primitives_addon(), "primitives"); DO_INIT(al_install_keyboard(), "keyboard"); DO_INIT(t = al_create_timer(1.0 / FPS), "timer"); DO_INIT(eq = al_create_event_queue(), "event queue"); al_set_new_display_option(ALLEGRO_SINGLE_BUFFER, 1, ALLEGRO_REQUIRE); DO_INIT(d = al_create_display(DISP_WIDTH, DISP_HEIGHT), "display"); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); DO_INIT(b = al_create_bitmap(DISP_WIDTH, DISP_HEIGHT), "buffer"); al_register_event_source(eq, al_get_keyboard_event_source()); al_register_event_source(eq, al_get_display_event_source(d)); al_register_event_source(eq, al_get_timer_event_source(t)); al_start_timer(t); al_clear_to_color(al_map_rgb(0, 0, 0)); while(true) { al_wait_for_event(eq, &e); switch (e.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_KEY_DOWN: switch(e.keyboard.keycode) { case ALLEGRO_KEY_1: randomness = (randomness == 64 ? 4 : randomness * 2); break; case ALLEGRO_KEY_2: framerate = (framerate == 1 ? 8 : framerate / 2); break; case ALLEGRO_KEY_UP: automaton += 10; printf("%d\n", automaton); break; case ALLEGRO_KEY_DOWN: automaton -= 10; printf("%d\n", automaton); break; case ALLEGRO_KEY_LEFT: automaton -= 1; printf("%d\n", automaton); break; case ALLEGRO_KEY_RIGHT: automaton += 1; printf("%d\n", automaton); break; case ALLEGRO_KEY_ENTER: pause = !pause; printf("%s\n", pause ? "pause" : "play"); break; default: break; } break; case ALLEGRO_EVENT_TIMER: if (pause) break; if (goframes > 1) { goframes--; break; } /* seed bits */ memset(bits[1], 0, (DISP_HEIGHT - 1) * DISP_WIDTH / 8); for (x = 1; x < DISP_WIDTH - 1; x++) { if (! (randombytes_random() % randomness) ) bit_toggle(bits[0], x); } /* propagate */ for (y = 0; y < DISP_HEIGHT - 1; y++) { for (x = 1; x < DISP_WIDTH - 2; x++) { if ( bit_get(&automaton, bit_get(bits[y], x + 2) + bit_get(bits[y], x + 1) * 2 + bit_get(bits[y], x) * 4 ) ) { bit_set(bits[y + 1], x + 1); } } } /* draw frame */ al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); al_set_target_bitmap(b); for (y = 0; y < DISP_HEIGHT; y++) { for (x = 0; x < DISP_WIDTH; x++) { if (bit_get(bits[y], x)) al_put_pixel(x, y, al_map_rgb(255, 255, 255)); else al_put_pixel(x, y, al_map_rgb(0, 0, 0)); } } al_unlock_bitmap(b); al_set_target_backbuffer(d); al_draw_bitmap(b, 0, 0, 0); al_flip_display(); goframes = framerate; } } done: if (d) al_destroy_display(d); if (b) al_destroy_bitmap(b); if (t) al_destroy_timer(t); if (eq) al_destroy_event_queue(eq); return rval; }