terminal snow
This commit is contained in:
parent
79be121b93
commit
ae7c7f66ae
174
userspace/csnow.c
Normal file
174
userspace/csnow.c
Normal file
@ -0,0 +1,174 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __toaru__
|
||||
#include <syscall.h>
|
||||
DEFN_SYSCALL2(nanosleep, 46, unsigned long, unsigned long);
|
||||
int usleep(useconds_t time) { syscall_nanosleep(0, time / 10000); }
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#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));
|
||||
|
||||
#ifdef __toaru__
|
||||
if (strstr(term, "toaru")) {
|
||||
printf("\033[1003z");
|
||||
fflush(stdout);
|
||||
scanf("%d,%d", &screen->width, &screen->height);
|
||||
} else {
|
||||
screen->width = 80; /* better safe than sorry */
|
||||
screen->height = 24;
|
||||
}
|
||||
#else
|
||||
struct winsize w;
|
||||
ioctl(0, TIOCGWINSZ, &w);
|
||||
screen->width = w.ws_col;
|
||||
screen->height = w.ws_row;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user