Skip to content

Commit

Permalink
Introduce interface to backends
Browse files Browse the repository at this point in the history
Functions twin_{create,destroy} are introduced along with the refined
backend interface, allowing for an incoming Linux framebuffer backend.
This commit simplifies backend development and consolidates consistent
APIs, meaning that a single source can be built for supported backends
without conditional compilation.
  • Loading branch information
jserv committed Jul 24, 2024
1 parent 2d85c45 commit d15970f
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 133 deletions.
41 changes: 19 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# FIXME: make these entries configurable
CONFIG_BACKEND_SDL := y
CONFIG_LOADER_JPEG := y
CONFIG_LOADER_PNG := y
CONFIG_BACKEND_SDL ?= y
CONFIG_LOADER_JPEG ?= y
CONFIG_LOADER_PNG ?= y

# Rules

Expand All @@ -10,9 +10,9 @@ target.o-y :=
TARGET_LIBS :=

target.a-y = \
libbackend.a \
libapps.a \
libtwin.a
libtwin.a \
libbackend.a

# Core library

Expand Down Expand Up @@ -46,7 +46,8 @@ libtwin.a_files-y = \
src/hull.c \
src/icon.c \
src/pixmap.c \
src/timeout.c
src/timeout.c \
src/api.c

libtwin.a_includes-y := include

Expand Down Expand Up @@ -77,32 +78,28 @@ libapps.a_files-y = \
libapps.a_includes-y := include

# Graphical backends
BACKEND := none

libbackend.a_files-y :=
libbackend.a_cflags-y :=
libbackend.a_includes-y := include
libbackend.a_includes-y := \
include \
src

ifeq ($(CONFIG_BACKEND_SDL), y)
BACKEND = sdl
libbackend.a_files-y += backend/sdl.c
libbackend.a_cflags-y += $(shell sdl2-config --cflags)
TARGET_LIBS += $(shell sdl2-config --libs)
endif

# Platform-specific executables

ifeq ($(CONFIG_BACKEND_SDL), y)
target-y += demo-sdl

demo-sdl_depends-y += $(target.a-y)
demo-sdl_files-y = \
apps/twin-sdl.c

demo-sdl_includes-y := include
demo-sdl_includes-y += backend

demo-sdl_cflags-y = $(shell sdl2-config --cflags)
demo-sdl_ldflags-y := $(target.a-y)
demo-sdl_ldflags-y += $(TARGET_LIBS)
endif # CONFIG_BACKEND_SDL
target-y += demo-$(BACKEND)
demo-$(BACKEND)_depends-y += $(target.a-y)
demo-$(BACKEND)_files-y = apps/main.c
demo-$(BACKEND)_includes-y := include
demo-$(BACKEND)_ldflags-y := \
$(target.a-y) \
$(TARGET_LIBS)

include mk/common.mk
20 changes: 10 additions & 10 deletions apps/twin-sdl.c → apps/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <time.h>
#include <unistd.h>

#include "twin_sdl.h"

#include "apps_calc.h"
#include "apps_clock.h"
#include "apps_demo.h"
Expand Down Expand Up @@ -70,18 +68,20 @@ static twin_pixmap_t *load_background(twin_screen_t *screen,

int main(void)
{
twin_sdl_t *sdl = twin_sdl_create(WIDTH, HEIGHT);
twin_context_t *x = twin_create(WIDTH, HEIGHT);

twin_screen_set_background(
sdl->screen, load_background(sdl->screen, ASSET_PATH "/tux.png"));
x->screen, load_background(x->screen, ASSET_PATH "/tux.png"));

apps_demo_start(sdl->screen, "Demo", 100, 100, 400, 400);
apps_hello_start(sdl->screen, "Hello, World", 0, 0, 200, 200);
apps_clock_start(sdl->screen, "Clock", 10, 10, 200, 200);
apps_calc_start(sdl->screen, "Calculator", 100, 100, 200, 200);
apps_line_start(sdl->screen, "Line", 0, 0, 200, 200);
apps_spline_start(sdl->screen, "Spline", 20, 20, 400, 400);
apps_demo_start(x->screen, "Demo", 100, 100, 400, 400);
apps_hello_start(x->screen, "Hello, World", 0, 0, 200, 200);
apps_clock_start(x->screen, "Clock", 10, 10, 200, 200);
apps_calc_start(x->screen, "Calculator", 100, 100, 200, 200);
apps_line_start(x->screen, "Line", 0, 0, 200, 200);
apps_spline_start(x->screen, "Spline", 20, 20, 400, 400);

twin_dispatch();

twin_destroy(x);
return 0;
}
153 changes: 92 additions & 61 deletions backend/sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@
* All rights reserved.
*/

#include <SDL.h>
#include <SDL_render.h>
#include <stdio.h>
#include <twin.h>

#include "twin_private.h"
#include "twin_sdl.h"
#include "twin_backend.h"

typedef struct {
SDL_Window *win;
int *pixels;
SDL_Renderer *render;
SDL_Texture *texture;
twin_coord_t width, height;
int image_y;
} twin_sdl_t;

#define PRIV(x) ((twin_sdl_t *) ((twin_context_t *) x)->priv)

static void _twin_sdl_put_begin(twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_coord_t bottom,
void *closure)
{
twin_sdl_t *tx = closure;
twin_sdl_t *tx = PRIV(closure);
tx->width = right - left;
tx->height = bottom - top;
tx->image_y = top;
Expand All @@ -27,41 +40,55 @@ static void _twin_sdl_put_span(twin_coord_t left,
twin_argb32_t *pixels,
void *closure)
{
twin_sdl_t *tx = closure;
twin_screen_t *screen = ((twin_context_t *) closure)->screen;
twin_sdl_t *tx = PRIV(closure);

for (twin_coord_t ix = left, iy = top; ix < right; ix++) {
twin_argb32_t pixel = *pixels++;

if (tx->depth == 16)
pixel = twin_argb32_to_rgb16(pixel);

tx->pixels[iy * tx->screen->width + ix] = pixel;
tx->pixels[iy * screen->width + ix] = pixel;
}
if ((top + 1 - tx->image_y) == tx->height) {
SDL_UpdateTexture(tx->texture, NULL, tx->pixels,
tx->screen->width * sizeof(uint32_t));
screen->width * sizeof(uint32_t));
SDL_RenderCopy(tx->render, tx->texture, NULL, NULL);
SDL_RenderPresent(tx->render);
}
}

static void _twin_sdl_destroy(twin_screen_t *screen, twin_sdl_t *tx)
{
twin_screen_destroy(screen);
SDL_DestroyRenderer(tx->render);
SDL_DestroyWindow(tx->win);
SDL_Quit();
}

static void twin_sdl_damage(twin_screen_t *screen, twin_sdl_t *tx)
{
int width, height;
SDL_GetWindowSize(tx->win, &width, &height);
twin_screen_damage(screen, 0, 0, width, height);
}

static bool twin_sdl_read_events(int file maybe_unused,
twin_file_op_t ops maybe_unused,
void *closure)
{
twin_sdl_t *tx = closure;
twin_screen_t *screen = ((twin_context_t *) closure)->screen;
twin_sdl_t *tx = PRIV(closure);

SDL_Event ev;
while (SDL_PollEvent(&ev)) {
twin_event_t tev;
switch (ev.type) {
case SDL_WINDOWEVENT:
if (ev.window.event == SDL_WINDOWEVENT_EXPOSED ||
ev.window.event == SDL_WINDOWEVENT_SHOWN) {
twin_sdl_damage(tx, &ev);
twin_sdl_damage(screen, tx);
}
break;
case SDL_QUIT:
twin_sdl_destroy(tx);
_twin_sdl_destroy(screen, tx);
return false;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
Expand All @@ -71,21 +98,21 @@ static bool twin_sdl_read_events(int file maybe_unused,
((ev.button.state >> 8) | (1 << (ev.button.button - 1)));
tev.kind = ((ev.type == SDL_MOUSEBUTTONDOWN) ? TwinEventButtonDown
: TwinEventButtonUp);
twin_screen_dispatch(tx->screen, &tev);
twin_screen_dispatch(screen, &tev);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
tev.u.key.key = ev.key.keysym.sym;
tev.kind = ((ev.key.type == SDL_KEYDOWN) ? TwinEventKeyDown
: TwinEventKeyUp);
twin_screen_dispatch(tx->screen, &tev);
twin_screen_dispatch(screen, &tev);
break;
case SDL_MOUSEMOTION:
tev.u.pointer.screen_x = ev.motion.x;
tev.u.pointer.screen_y = ev.motion.y;
tev.kind = TwinEventMotion;
tev.u.pointer.button = ev.motion.state;
twin_screen_dispatch(tx->screen, &tev);
twin_screen_dispatch(screen, &tev);
break;
}
}
Expand All @@ -94,85 +121,89 @@ static bool twin_sdl_read_events(int file maybe_unused,

static bool twin_sdl_work(void *closure)
{
twin_sdl_t *tx = closure;
twin_screen_t *screen = ((twin_context_t *) closure)->screen;

if (twin_screen_damaged(tx->screen))
twin_sdl_update(tx);
if (twin_screen_damaged(screen))
twin_screen_update(screen);
return true;
}

twin_sdl_t *twin_sdl_create(int width, int height)
twin_context_t *twin_sdl_init(int width, int height)
{
static char *title = "twin-sdl";

twin_sdl_t *tx = malloc(sizeof(twin_sdl_t));
if (!tx)
twin_context_t *ctx = calloc(1, sizeof(twin_context_t));
if (!ctx)
return NULL;
ctx->priv = calloc(1, sizeof(twin_sdl_t));
if (!ctx->priv)
return NULL;

if (SDL_Init(SDL_INIT_VIDEO) < 0)
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("error : %s\n", SDL_GetError());
goto bail;
}

twin_sdl_t *tx = ctx->priv;

static char *title = "twin-sdl";
tx->win = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, width, height,
SDL_WINDOW_SHOWN);
if (!tx->win)
if (!tx->win) {
printf("error : %s\n", SDL_GetError());
goto bail;
}

tx->pixels = malloc(width * height * sizeof(uint32_t));
memset(tx->pixels, 255, width * height * sizeof(uint32_t));

tx->render = SDL_CreateRenderer(tx->win, -1, SDL_RENDERER_ACCELERATED);
if (!tx->render)
if (!tx->render) {
printf("error : %s\n", SDL_GetError());
goto bail_pixels;
}
SDL_SetRenderDrawColor(tx->render, 255, 255, 255, 255);
SDL_RenderClear(tx->render);

tx->texture = SDL_CreateTexture(tx->render, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, width, height);

tx->screen = twin_screen_create(width, height, _twin_sdl_put_begin,
_twin_sdl_put_span, tx);

twin_set_file(twin_sdl_read_events, 0, TWIN_READ, tx);
ctx->screen = twin_screen_create(width, height, _twin_sdl_put_begin,
_twin_sdl_put_span, ctx);

twin_set_work(twin_sdl_work, TWIN_WORK_REDISPLAY, tx);
twin_set_file(twin_sdl_read_events, 0, TWIN_READ, ctx);

return tx;
}
twin_set_work(twin_sdl_work, TWIN_WORK_REDISPLAY, ctx);

void twin_sdl_destroy(twin_sdl_t *tx)
{
SDL_DestroyRenderer(tx->render);
SDL_DestroyWindow(tx->win);
tx->win = 0;
twin_screen_destroy(tx->screen);
SDL_Quit();
}
return ctx;

void twin_sdl_damage(twin_sdl_t *tx, SDL_Event *ev maybe_unused)
{
int width, height;
SDL_GetWindowSize(tx->win, &width, &height);
twin_screen_damage(tx->screen, 0, 0, width, height);
bail_pixels:
free(tx->pixels);
bail:
free(ctx->priv);
free(ctx);
return NULL;
}

void twin_sdl_configure(twin_sdl_t *tx, SDL_Event *ev maybe_unused)
static void twin_sdl_configure(twin_context_t *ctx)
{
int width, height;
SDL_GetWindowSize(tx->win, &width, &height);
twin_screen_resize(tx->screen, width, height);
SDL_GetWindowSize(PRIV(ctx)->win, &width, &height);
twin_screen_resize(ctx->screen, width, height);
}

void twin_sdl_update(twin_sdl_t *tx)
static void twin_sdl_exit(twin_context_t *ctx)
{
twin_screen_update(tx->screen);
if (!ctx)
return;
free(PRIV(ctx)->pixels);
free(ctx->priv);
free(ctx);
}

bool twin_sdl_process_events(twin_sdl_t *tx)
{
bool result;
/* Register the SDL backend */

_twin_run_work();
result = twin_sdl_read_events(0, 0, tx);
_twin_run_work();

return result;
}
const twin_backend_t g_twin_backend = {
.init = twin_sdl_init,
.configure = twin_sdl_configure,
.exit = twin_sdl_exit,
};
Loading

0 comments on commit d15970f

Please sign in to comment.