#include #include #include #include #include #include #include #define BUF_W 256 #define BUF_H 256 #define DISP_SCALE 3 #define SEED_BITS 4096 #define FPS 30.0 #define DO_INIT(check, desc) \ if (!(check)) { \ fprintf(stderr, "err: can't initialise %s\n", desc); \ rval = 1; \ goto done; \ } int main(int argc, char **argv) { int rval = 0; uint8_t bits1[BUF_H][BUF_W] = {0}; uint8_t bits2[BUF_H][BUF_W] = {0}; uint8_t framerate = 8; unsigned goframes = 1; unsigned x, y, sum; bool pause = true; bool mouse_down = false; ALLEGRO_MOUSE_STATE ms; 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(al_install_mouse(), "mouse"); 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_SCALE * BUF_W, DISP_SCALE * BUF_H ), "display" ); al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); DO_INIT(b = al_create_bitmap(BUF_W, BUF_H), "buffer"); al_register_event_source(eq, al_get_keyboard_event_source()); al_register_event_source(eq, al_get_mouse_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); reset: memset(bits1, 0, sizeof(bits1)); memset(bits2, 0, sizeof(bits1)); while(true) { al_wait_for_event(eq, &e); switch (e.type) { case ALLEGRO_EVENT_DISPLAY_CLOSE: goto done; case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: bits1[e.mouse.y / DISP_SCALE][e.mouse.x / DISP_SCALE] = 3; mouse_down = true; break; case ALLEGRO_EVENT_MOUSE_BUTTON_UP: mouse_down = false; break; case ALLEGRO_EVENT_KEY_DOWN: switch(e.keyboard.keycode) { case ALLEGRO_KEY_Q: goto done; case ALLEGRO_KEY_1: framerate = (framerate == 1 ? 16 : framerate / 2); printf("fps: %.1f\n", FPS / ((float)framerate) ); break; case ALLEGRO_KEY_2: memset(bits1, 0, sizeof(bits1)); memset(bits2, 0, sizeof(bits2)); for (x = 0; x < SEED_BITS; x++) { bits1[randombytes_random() % BUF_H][randombytes_random() % BUF_W] = 3; } break; case ALLEGRO_KEY_3: goto reset; case ALLEGRO_KEY_ENTER: pause = !pause; printf("%s\n", pause ? "pause" : "play"); break; default: break; } break; case ALLEGRO_EVENT_TIMER: if (mouse_down) { al_get_mouse_state(&ms); bits1[ms.y / DISP_SCALE][ms.x / DISP_SCALE] = 3; } /* step */ if (goframes) { goframes--; } else if (!pause) { for (y = 0; y < BUF_H; y++) { for (x = 0; x < BUF_W; x++) { if (bits1[y][x]) { bits2[y][x] = bits1[y][x] - 1; continue; } sum = (3 == bits1[(y-1) % BUF_H][(x-1) % BUF_W]) + (3 == bits1[(y-1) % BUF_H][ x ]) + (3 == bits1[(y-1) % BUF_H][(x+1) % BUF_W]) + (3 == bits1[ y ][(x-1) % BUF_W]) + (3 == bits1[ y ][(x+1) % BUF_W]) + (3 == bits1[(y+1) % BUF_H][(x-1) % BUF_W]) + (3 == bits1[(y+1) % BUF_H][ x ]) + (3 == bits1[(y+1) % BUF_H][(x+1) % BUF_W]) ; sum *= 2; sum += (2 == bits1[(y-1) % BUF_H][(x-1) % BUF_W]) + (2 == bits1[(y-1) % BUF_H][ x ]) + (2 == bits1[(y-1) % BUF_H][(x+1) % BUF_W]) + (2 == bits1[ y ][(x-1) % BUF_W]) + (2 == bits1[ y ][(x+1) % BUF_W]) + (2 == bits1[(y+1) % BUF_H][(x-1) % BUF_W]) + (2 == bits1[(y+1) % BUF_H][ x ]) + (2 == bits1[(y+1) % BUF_H][(x+1) % BUF_W]) ; if (sum == 5 || sum == 4) bits2[y][x] = 3; } } memcpy(bits1, bits2, sizeof(bits1)); goframes = framerate; } /* draw frame */ al_lock_bitmap(b, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); al_set_target_bitmap(b); for (y = 0; y < BUF_H; y++) { for (x = 0; x < BUF_W; x++) { switch (bits1[y][x]) { case 0: al_put_pixel(x, y, al_map_rgb(0, 0, 0)); break; case 1: al_put_pixel(x, y, al_map_rgb(255, 0, 0)); break; case 2: al_put_pixel(x, y, al_map_rgb(255, 255, 0)); break; case 3: al_put_pixel(x, y, al_map_rgb(255, 255, 255)); break; } } } al_unlock_bitmap(b); al_set_target_backbuffer(d); al_draw_scaled_bitmap(b, 0, 0, BUF_W, BUF_H, 0, 0, DISP_SCALE * BUF_W, DISP_SCALE * BUF_H, 0 ); al_flip_display(); } } 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; }