Add Emscripten/WebAssembly build target
Builds a browser-playable .html/.js/.wasm/.data via `./build-web.sh` (no
new CMake top-level target — Emscripten is detected at configure time and
takes the existing kobodl through a web-flavored pipeline).
Key pieces:
- CMakeLists.txt: route SDL3 through `--use-port=sdl3`; substitute
`--use-port=libpng` for the missing sdl3_image port (Emscripten 5.0.7
ships only sdl3 + sdl3_ttf). pthread (atomics+bulk-memory) lifted to
kobo_deps so every TU agrees with wasm-ld's --shared-memory. Link with
-sASYNCIFY (avoids rewriting kobo's blocking main loop around
emscripten_set_main_loop), -sALLOW_MEMORY_GROWTH/-sMAXIMUM_MEMORY=1gb,
-sPTHREAD_POOL_SIZE=4, -lidbfs.js, and --preload-file data@/data.
- graphics/img_compat.{h,c}: libpng-backed IMG_Load shim, used in
sprite.c / gfxengine.cpp / filters.c via #include "img_compat.h".
Native builds passthrough to <SDL3_image/SDL_image.h> unchanged.
- web/shell.html: HTML wrapper that mounts /home as IDBFS for persistent
scores/config. Startup gated on addRunDependency until syncfs(true)
finishes, then /home/scores is mkdir'd post-load (the game's addPlayer
doesn't auto-create the score dir; see TODO in score.cpp).
beforeunload + visibilitychange flushes /home back to IndexedDB.
- build-web.sh: emcmake wrapper + a static server that sets the
COOP/COEP headers SharedArrayBuffer/pthreads require.
Source fixes needed to build under Emscripten's libc/libcxx:
- Renamed enemy_kind `pipe2` -> `pipe2k` (collided with libc pipe2(2)
always declared in Emscripten's <unistd.h>).
- graphics/toolkit.cpp: added missing <stdio.h> for snprintf (Emscripten's
libcxx headers don't pull it in transitively).
- states.cpp: gated the "Quit Kobo Deluxe" main-menu button on
!__EMSCRIPTEN__; exit() on the web leaves a dead canvas.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ add_library(graphics STATIC
|
||||
toolkit.cpp
|
||||
vidmodes.c
|
||||
region.c
|
||||
img_compat.c
|
||||
)
|
||||
|
||||
target_include_directories(graphics
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
#include <math.h>
|
||||
#include "logger.h"
|
||||
#include "sdl_compat.h"
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include "img_compat.h"
|
||||
#include "sprite.h"
|
||||
#include "filters.h"
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "gfxengine.h"
|
||||
#include "filters.h"
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include "img_compat.h"
|
||||
#include "sdl_compat.h"
|
||||
#include "sofont.h"
|
||||
#include "window.h"
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* img_compat.c — libpng-backed IMG_Load for the Emscripten build.
|
||||
*
|
||||
* Returns an RGBA8 SDL_Surface. Handles palette, grayscale, tRNS, and 16-bit
|
||||
* inputs by normalizing to 8-bit RGBA in the read pipeline.
|
||||
*/
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
#include "img_compat.h"
|
||||
|
||||
#include <png.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
SDL_Surface *IMG_Load(const char *file)
|
||||
{
|
||||
FILE *fp = fopen(file, "rb");
|
||||
if(!fp)
|
||||
return NULL;
|
||||
|
||||
unsigned char hdr[8];
|
||||
if(fread(hdr, 1, 8, fp) != 8 || png_sig_cmp(hdr, 0, 8))
|
||||
{
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, NULL, NULL);
|
||||
if(!png) { fclose(fp); return NULL; }
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if(!info)
|
||||
{
|
||||
png_destroy_read_struct(&png, NULL, NULL);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_Surface *surf = NULL;
|
||||
png_bytep *rows = NULL;
|
||||
|
||||
if(setjmp(png_jmpbuf(png)))
|
||||
{
|
||||
if(rows) free(rows);
|
||||
if(surf) SDL_DestroySurface(surf);
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
png_init_io(png, fp);
|
||||
png_set_sig_bytes(png, 8);
|
||||
png_read_info(png, info);
|
||||
|
||||
png_uint_32 w, h;
|
||||
int depth, ctype;
|
||||
png_get_IHDR(png, info, &w, &h, &depth, &ctype, NULL, NULL, NULL);
|
||||
|
||||
if(depth == 16) png_set_strip_16(png);
|
||||
if(ctype == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
||||
if(ctype == PNG_COLOR_TYPE_GRAY && depth < 8)
|
||||
png_set_expand_gray_1_2_4_to_8(png);
|
||||
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha(png);
|
||||
if(ctype == PNG_COLOR_TYPE_GRAY || ctype == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png);
|
||||
if(ctype == PNG_COLOR_TYPE_RGB || ctype == PNG_COLOR_TYPE_GRAY
|
||||
|| ctype == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
|
||||
|
||||
png_read_update_info(png, info);
|
||||
|
||||
surf = SDL_CreateSurface((int)w, (int)h, SDL_PIXELFORMAT_RGBA32);
|
||||
if(!surf)
|
||||
png_error(png, "SDL_CreateSurface failed");
|
||||
|
||||
rows = (png_bytep *)malloc(sizeof(png_bytep) * h);
|
||||
if(!rows)
|
||||
png_error(png, "row table alloc failed");
|
||||
for(png_uint_32 y = 0; y < h; ++y)
|
||||
rows[y] = (png_bytep)((unsigned char *)surf->pixels + y * surf->pitch);
|
||||
|
||||
png_read_image(png, rows);
|
||||
png_read_end(png, NULL);
|
||||
|
||||
free(rows);
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
fclose(fp);
|
||||
return surf;
|
||||
}
|
||||
|
||||
#endif /* __EMSCRIPTEN__ */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* img_compat.h — SDL3_image shim.
|
||||
*
|
||||
* On native builds, this is just a passthrough to <SDL3_image/SDL_image.h>.
|
||||
* On Emscripten there is no SDL3_image port yet (only sdl3 and sdl3_ttf), so
|
||||
* we provide an IMG_Load implementation backed by the libpng port. Only PNG
|
||||
* decoding is needed — Kobo Deluxe's assets are all .png.
|
||||
*/
|
||||
#ifndef KOBO_IMG_COMPAT_H
|
||||
#define KOBO_IMG_COMPAT_H
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
SDL_Surface *IMG_Load(const char *file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else /* native */
|
||||
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* KOBO_IMG_COMPAT_H */
|
||||
+1
-1
@@ -30,7 +30,7 @@ TODO: tables as needed when loading banks.
|
||||
#include <string.h>
|
||||
#include "logger.h"
|
||||
#include "sdl_compat.h"
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
#include "img_compat.h"
|
||||
#include "sprite.h"
|
||||
#include "filters.h"
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "window.h"
|
||||
#include "toolkit.h"
|
||||
|
||||
Reference in New Issue
Block a user