axui-growth-chamber/src/backend/sdl.c

300 lines
7.4 KiB
C

#include "../backend.h"
#include "../ctxt/theme.h"
#include "../ctxt/window.h"
#include "../util.h"
#include "../util/region.h"
#include "../concurrent/msgq.h"
#include "../concurrent/msg.h"
#include <unistd.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
/* -----------------------------------------------------------------------------
* Backend type
* -------------------------------------------------------------------------- */
struct window_list;
const char* ax__backend_impl_name = "SDL";
size_t ax__backend_desired_region_size = MEDIUM;
struct ax_backend {
struct rgn* rgn;
struct msgq* inbox;
bool shutdown;
struct window_list* windows;
};
/* -----------------------------------------------------------------------------
* Backend functions
* -------------------------------------------------------------------------- */
static void backend_cleanup(struct ax_backend* bac);
int ax__backend_new(
struct rgn* init_rgn,
struct ax_backend** out_bac,
const char** out_err)
{
const char* err;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
err = SDL_GetError();
goto fail;
}
if (TTF_Init() != 0) {
err = TTF_GetError();
goto fail;
}
struct ax_backend* bac = ralloc_typed(init_rgn, struct ax_backend, 1);
rgn_pin(init_rgn, bac, (void*) backend_cleanup);
bac->rgn = init_rgn;
bac->inbox = msgq_new(init_rgn);
bac->shutdown = false;
bac->windows = NULL;
if (out_bac != NULL) {
*out_bac = bac;
}
printf("hello from SDL\n");
return 0;
fail:
if (out_err != NULL) {
*out_err = err;
}
return 1;
}
static void backend_cleanup(struct ax_backend* bac)
{
TTF_Quit();
SDL_Quit();
printf("bye from SDL\n");
}
struct msgq* ax__backend_msgq(struct ax_backend* bac)
{
return bac->inbox;
}
bool ax__backend_is_shutdown(struct ax_backend* bac)
{
return bac->shutdown;
}
void ax__backend_wait_for_event(struct ax_backend* bac)
{
(void) bac;
usleep(1000 * 100);
}
/* -----------------------------------------------------------------------------
* Event handling
* -------------------------------------------------------------------------- */
struct font_list {
struct font_list* next;
struct ax_theme* thm;
size_t cat;
};
struct window_args_list {
struct window_args_list* next;
struct ax_window* win;
const char* title;
uint32_t width, height;
};
static void load_fonts(struct ax_backend* bac, struct font_list* fl);
static void make_windows(struct ax_backend* bac, struct window_args_list* wl);
static void render_windows(struct window_list* wl);
void ax__backend_step(struct ax_backend* bac)
{
struct rgn tmp_rgn;
rgn_init(&tmp_rgn, SMALL);
struct font_list* fonts = NULL;
struct window_args_list* windows = NULL;
size_t nmsg = 0;
msgq_begin_recv(bac->inbox);
MSGQ_RECV_ALL(bac->inbox) {
ON(ax_msg_shutdown,
{
nmsg++;
(void) m;
bac->shutdown = true;
break;
});
ON(ax_msg_load_font,
{
nmsg++;
struct font_list* l =
ralloc_typed(&tmp_rgn, struct font_list, 1);
l->next = fonts;
l->thm = m.theme;
l->cat = m.category;
fonts = l;
break;
});
ON(ax_msg_make_window,
{
nmsg++;
struct window_args_list* l =
ralloc_typed(&tmp_rgn, struct window_args_list, 1);
l->next = windows;
l->win = m.dst_win;
l->title = rstrdup(&tmp_rgn, m.title);
l->width = m.width;
l->height = m.height;
windows = l;
break;
});
default:
nmsg++;
printf("Got a weird message: `%s'\n", ax__msg_name(mqr__type));
break;
}
msgq_end_recv(bac->inbox);
load_fonts(bac, fonts);
make_windows(bac, windows);
render_windows(bac->windows);
rgn_cleanup(&tmp_rgn);
// printf("ping. %zu message(s)\n", nmsg);
}
/* -----------------------------------------------------------------------------
* Fonts
* -------------------------------------------------------------------------- */
struct ax_font_h {
TTF_Font* font;
};
static int load_font(
struct rgn* rgn, const char* path, size_t size,
struct ax_font_h** out_fh, const char** out_err)
{
printf("loading `%s' (size %zu)\n", path, size);
struct ax_font_h* fh = ralloc_typed(rgn, struct ax_font_h, 1);
if ((fh->font = TTF_OpenFont(path, size)) == NULL) {
*out_err = TTF_GetError();
return 1;
}
*out_fh = fh;
return 0;
}
static void load_fonts(struct ax_backend* bac, struct font_list* fl)
{
int rv = 0;
const char* err;
for (; fl != NULL; fl = fl->next) {
struct ax_theme* thm = fl->thm;
struct ax_font_h* fh;
if ((rv = load_font(bac->rgn,
thm->font_path[fl->cat],
thm->font_size[fl->cat],
&fh, &err)) != 0) {
goto fail;
}
ax__theme_set_font_handle(thm, fl->cat, fh);
}
fail:
ASSERT(rv == 0, "error loading font: %s", err);
}
/* -----------------------------------------------------------------------------
* Window management
* -------------------------------------------------------------------------- */
struct window_list {
struct window_list* next;
struct ax_window* win;
struct window_handle* handle;
};
struct window_handle {
SDL_Window* win;
SDL_Renderer* rnd;
};
static void cleanup_window_handle(struct window_handle*);
static int new_window_handle(
struct rgn* rgn,
struct window_args_list* args,
struct window_handle** out_wh,
const char** out_err)
{
struct window_handle* wh = ralloc_typed(rgn, struct window_handle, 1);
wh->win = NULL;
wh->rnd = NULL;
rgn_pin(rgn, wh, (void*) cleanup_window_handle);
int rv;
if ((rv = SDL_CreateWindowAndRenderer((int) args->width,
(int) args->height,
SDL_WINDOW_SHOWN,
&wh->win, &wh->rnd)) != 0) {
*out_err = SDL_GetError();
return rv;
}
SDL_SetWindowTitle(wh->win, args->title);
*out_wh = wh;
return 0;
}
static void cleanup_window_handle(struct window_handle* wh)
{
SDL_DestroyRenderer(wh->rnd);
SDL_DestroyWindow(wh->win);
}
static void make_windows(struct ax_backend* bac, struct window_args_list* args)
{
int rv = 0;
const char* err;
struct window_handle* wh;
struct window_list* wl;
for (; args != NULL; args = args->next) {
if ((rv = new_window_handle(bac->rgn, args, &wh, &err)) != 0) {
goto fail;
}
wl = ralloc_typed(bac->rgn, struct window_list, 1);
wl->win = args->win;
wl->handle = wh;
wl->next = bac->windows;
bac->windows = wl;
}
fail:
ASSERT(rv == 0, "error: %s", SDL_GetError());
}
static void render_windows(struct window_list* wl)
{
for (; wl != NULL; wl = wl->next) {
// SDL_Window* sdl_win = wl->handle->win;
SDL_Renderer* r = wl->handle->rnd;
SDL_SetRenderDrawColor(r, 255, 255, 255, 255);
SDL_RenderClear(r);
SDL_RenderPresent(r);
}
}