cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit 12b2a89c050b3b79107dde6cadfbd43f00e3c5eb
parent 8876d156020f15a77460eaf698b024ae239faf8e
Author: hhvn <dev@hhvn.uk>
Date:   Thu, 25 Aug 2022 22:15:39 +0100

Loading window

Diffstat:
Msrc/data.c | 6+++++-
Asrc/loading.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.c | 16++++++++++++++--
Msrc/main.h | 11+++++++++--
Msrc/save.c | 11++++++++++-
Msrc/struct.h | 9+++++++++
Msrc/ui.c | 4++--
7 files changed, 183 insertions(+), 8 deletions(-)

diff --git a/src/data.c b/src/data.c @@ -47,15 +47,19 @@ unsigned char settings_png[] = { }; #define IMAGE_LOAD(name) \ + loading_update(lscr, "Loading image"); \ raw_image_##name = LoadImageFromMemory(".png", \ name##_png, sizeof(name##_png)); \ image_##name = LoadTextureFromImage(raw_image_##name); \ UnloadImage(raw_image_##name) void -data_load(void) { +data_load(Loader *lscr) { + /* update main.h when adding loading steps */ + loading_update(lscr, "Loading fonts"); font = LoadFontFromMemory(".ttf", DejaVuSansMono_ttf, sizeof(DejaVuSansMono_ttf), FONT_SIZE, NULL, 0); + /* one step per IMAGE_LOAD() */ IMAGE_LOAD(tactical); IMAGE_LOAD(colonies); IMAGE_LOAD(bodies); diff --git a/src/loading.c b/src/loading.c @@ -0,0 +1,134 @@ +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include <signal.h> +#include <string.h> +#include <sys/mman.h> +#include <raylib.h> +#include "main.h" + +#define LOADING_FPS 60 +#define LOADING_W 500 +#define LOADING_H 50 +#define LOADING_FONT 30 +#define LOADING_PAD ((LOADING_H - LOADING_FONT) / 2) + +struct shmdata { + int step; + char str[LOAD_STR_MAX]; +}; + +static int recv_winch = 0; + +static void +loading_sighandler(int signal) { + fflush(stdout); + if (signal == SIGWINCH) + recv_winch = 1; +} + +Loader * +loading_open(int steps, char *initstr) { + Loader *ret; + int fd; + struct shmdata *shmdata; + /* child only */ + struct shmdata *data; + char curstr[LOAD_STR_MAX]; + struct sigaction sa; + int step = 0; + + ret = malloc(sizeof(Loader)); + if (!ret) return NULL; + + snprintf(ret->path, sizeof(ret->path), "/%ld-loading", (long)getpid()); + if ((fd = shm_open(ret->path, O_CREAT|O_RDWR, 0600)) == -1) + goto fail; + + if (ftruncate(fd, sizeof(struct shmdata)) == -1) + goto fail; + + if ((shmdata = mmap(NULL, sizeof(struct shmdata), PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0)) == MAP_FAILED) + goto fail; + + shmdata->step = 0; + ret->step = &shmdata->step; + ret->data = &shmdata->str; + + if ((ret->pid = fork()) == -1) + goto unmap; + + if (ret->pid == 0) { + /* we're the child */ + sa.sa_handler = loading_sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGWINCH, &sa, NULL); + + fd = shm_open(ret->path, O_RDONLY, 0); + data = mmap(NULL, sizeof(struct shmdata), PROT_READ, + MAP_SHARED, fd, 0); + if (fd == -1 || data == MAP_FAILED) + data = initstr; + + SetWindowState(FLAG_WINDOW_TOPMOST); + SetTargetFPS(LOADING_FPS); + SetExitKey(KEY_NULL); + InitWindow(LOADING_W, LOADING_H, "Loading..."); + snprintf(curstr, sizeof(curstr), "%s...", initstr); + + while (!WindowShouldClose()) { + if (recv_winch) { + recv_winch = 0; + memcpy(curstr, data->str, LOAD_STR_MAX); + } + + BeginDrawing(); + + ClearBackground(col_bg); + DrawText(curstr, LOADING_PAD, LOADING_PAD, LOADING_FONT, col_fg); + + BeginScissorMode(0, 0, data->step * LOADING_W / steps, LOADING_H); + DrawRectangle(0, 0, data->step * LOADING_W / steps, LOADING_H, col_fg); + DrawText(curstr, LOADING_PAD, LOADING_PAD, LOADING_FONT, col_bg); + EndScissorMode(); + + EndDrawing(); + } + exit(0); + } + + return ret; + +unmap: + munmap(ret->data, sizeof(struct shmdata)); +fail: + free(ret); + return NULL; +} + +void +loading_update(Loader *hand, char *str) { + (*hand->step)++; + snprintf(hand->data, LOAD_STR_MAX, "%s...", str); + kill(hand->pid, SIGWINCH); +} + +void +loading(Loader **hand, int steps, char *str) { + if (!*hand) + *hand = loading_open(steps, str); + else + loading_update(*hand, str); +} + +void +loading_close(Loader *hand) { + kill(hand->pid, SIGTERM); + shm_unlink(hand->path); + munmap(hand->data, sizeof(struct shmdata)); + free(hand); +} diff --git a/src/main.c b/src/main.c @@ -12,13 +12,25 @@ main(void) { int draw; int view_prev = -1; time_t lastevent; + Loader *loader; + + + loader = loading_open(DATA_LOAD_STEPS + SAVE_READ_STEPS + 3, "Initializing UI"); ui_init(); - data_load(); - save_read(TESTSAVE); + + data_load(loader); + save_read(loader, TESTSAVE); + + loading_close(loader); lastevent = time(NULL); + /* The window is hidden so that only the loading bar is shown. Hiding + * and unhiding the window also has the added effect of making it + * behave like a normal window in window managers, rather than having + * it float in the middle of the screen. */ + ClearWindowState(FLAG_WINDOW_HIDDEN); ui_update_screen(); while (!WindowShouldClose()) { diff --git a/src/main.h b/src/main.h @@ -90,7 +90,8 @@ System *sys_get(char *name); System *sys_default(void); /* save.c */ -void save_read(char *dir); +#define SAVE_READ_STEPS 2 +void save_read(Loader *lscr, char *dir); void save_write(void); /* data.c */ @@ -102,7 +103,8 @@ extern Texture image_fleet; extern Texture image_design; extern Texture image_sys; extern Texture image_settings; -void data_load(void); +#define DATA_LOAD_STEPS (1 + 7) +void data_load(Loader *lscr); void data_unload(void); /* db.c */ @@ -115,3 +117,8 @@ int vdbgetf(char *dir, char *group, char *key, char *fmt, va_list args); int dbgetf(char *dir, char *group, char *key, char *fmt, ...); int dbgetint(char *dir, char *group, char *key); float dbgetfloat(char *dir, char *group, char *key); + +/* loading.c */ +Loader *loading_open(int steps, char *initstr); +void loading_update(Loader *hand, char *str); +void loading_close(Loader *hand); diff --git a/src/save.c b/src/save.c @@ -2,6 +2,13 @@ #include <string.h> #include "main.h" +/* Plan for dealing with multiple saves: + * - saves: linked list with all saves that have been loaded (some data pruned) + * - save: the current save + * - save_get(name): get a save from saves/disk by name and load necessary data + * - save_select(name): set save to save_get(name) + housekeeping + */ + static void save_free(void) { free(save->db.dir); @@ -13,7 +20,7 @@ save_free(void) { } void -save_read(char *dir) { +save_read(Loader *lscr, char *dir) { char *str; if (save) @@ -22,11 +29,13 @@ save_read(char *dir) { if (!dir || !(save = malloc(sizeof(Save)))) return; + loading_update(lscr, "Initializing DB"); dbdeclare(dir); save->db.dir = nstrdup(dir); save->db.races = smprintf("%s/Races", dir); save->db.systems = smprintf("%s/Systems", dir); save->db.fleets = smprintf("%s/Fleets", dir); + loading_update(lscr, "Loading systems"); if ((str = dbget(save->db.dir, "index", "homesystem"))) save->homesys = sys_get(str); return; diff --git a/src/struct.h b/src/struct.h @@ -1,4 +1,5 @@ #include <stddef.h> +#include <sys/types.h> /* system.c */ typedef struct { @@ -152,4 +153,12 @@ typedef struct { void *elem; } Clickable; +#define LOAD_STR_MAX 512 +typedef struct { + char path[64]; + pid_t pid; + int *step; + char *data; +} Loader; + #include "views.h" /* unique structures */ diff --git a/src/ui.c b/src/ui.c @@ -134,10 +134,10 @@ View_sys view_sys = { void ui_init(void) { - InitWindow(500, 500, ""); - SetWindowState(FLAG_WINDOW_RESIZABLE); + SetWindowState(FLAG_WINDOW_RESIZABLE|FLAG_WINDOW_HIDDEN); SetTargetFPS(TARGET_FPS); SetExitKey(KEY_NULL); + InitWindow(500, 500, ""); } void