toaruos/userspace/extra/csnow.c
2013-03-26 23:30:09 -07:00

157 lines
3.5 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define MAX_SPEED 2
#define INITIAL_SNOW 40
#define INCREMENTAL_SNOW 10
#define BUFFER_SIZE 10
#define BLANK_SPACE " "
#define NUM_FLAKE_TEXTURES 4
char * flake_textures[] = {
"",
"",
"",
"*",
};
typedef struct {
int width;
int height;
char ** backingstore;
} screen_t;
typedef struct {
char * display;
signed short x;
signed short y;
signed char speed;
char gravity;
} flake_t;
screen_t * init_screen() {
char * term = getenv("TERM");
screen_t * screen = malloc(sizeof(screen_t));
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
screen->width = w.ws_col;
screen->height = w.ws_row;
screen->backingstore = malloc(sizeof(char *) * screen->width * screen->height);
return screen;
}
flake_t * make_some_flakes(screen_t * screen, int how_many) {
flake_t * out = malloc(sizeof(flake_t) * (how_many + 1));
for (int i = 0; i < how_many; ++i) {
out[i].display = flake_textures[rand() % NUM_FLAKE_TEXTURES];
out[i].x = rand() % screen->width;
out[i].y = -(rand() % BUFFER_SIZE);
out[i].speed = rand() % MAX_SPEED - (MAX_SPEED / 2);
out[i].gravity = 1;
}
out[how_many].display = NULL;
return out;
}
flake_t * add_flakes(screen_t * screen, flake_t * flakes, int how_many) {
flake_t * more = make_some_flakes(screen, how_many);
int len = 0; for (; flakes[len].display; ++len);
flakes = realloc(flakes, sizeof(flake_t) * (how_many + len + 1));
memcpy(&flakes[len], more, sizeof(flake_t) * (how_many + 1));
free(more);
return flakes;
}
int detect_collisions(screen_t * screen, flake_t * flakes, int i) {
int x = flakes[i].x;
int y = flakes[i].y;
if (flakes[i].y >= screen->height - 1) {
flakes[i].gravity = 0;
return 1;
}
for (int j = 0; flakes[j].display; ++j) {
if (flakes[j].gravity) continue;
if (flakes[j].x == x && flakes[j].y == (y + 1)) {
flakes[i].gravity = 0;
return 1;
}
}
return 0;
}
void update_flakes(screen_t * screen, flake_t * flakes) {
for (int i = 0; flakes[i].display; ++i) {
if (flakes[i].gravity) {
flakes[i].x += flakes[i].speed;
if (flakes[i].x < 0) {
flakes[i].x = screen->width - 1;
} else if (flakes[i].x >= screen->width) {
flakes[i].x = 0;
}
if (!detect_collisions(screen, flakes, i)) {
flakes[i].y += flakes[i].gravity;
}
}
}
}
void write_screen(screen_t * screen, flake_t * flakes) {
for (int y = 0; y < screen->height; ++y) {
for (int x = 0; x < screen->width; ++x) {
screen->backingstore[x + y * screen->width] = BLANK_SPACE;
}
}
for (int i = 0; flakes[i].display; ++i) {
if (flakes[i].y >= 0 && flakes[i].y < screen->height && flakes[i].x >= 0 && flakes[i].x < screen->width) {
screen->backingstore[flakes[i].x + flakes[i].y * screen->width] = flakes[i].display;
}
}
}
void flip_screen(screen_t * screen) {
printf("\033[H");
for (int y = 0; y < screen->height; ++y) {
for (int x = 0; x < screen->width; ++x) {
if ((y == screen->height - 1) && (x == screen->width - 1)) {
fflush(stdout);
return;
}
printf("%s", screen->backingstore[x + y * screen->width]);
}
printf("\n");
}
}
int main(int argc, char * argv) {
screen_t * main_screen = init_screen();
flake_t * flakes = make_some_flakes(main_screen, INITIAL_SNOW);
for (;;) {
write_screen(main_screen, flakes);
flip_screen(main_screen);
update_flakes(main_screen, flakes);
flakes = add_flakes(main_screen, flakes, INCREMENTAL_SNOW);
usleep(90000);
}
return 0;
}