Chickpea: Emscripten

Today, I spent a bit of time figuring out how to build Chickpea with Emscripten. It turned out not to be too difficult. If you’re using a decently up to date browser with WebAssembly support, behold:

emscripten
Downloading...

There are no keyboard controls because I haven’t implemented them still, but to my surprise, game controller support works. I didn’t realize there was a Web API for that.

I want to be able to keep a log, not just of what I’m doing but of builds as well, and I think being able to include full builds of the game in these posts so easily will be fun.

Besides this, I haven’t done too much in the past three days, but, I did add the text box you see, and I added support for 8-bits per pixel graphics to both my asset tool & the engine itself for the portrait.

Static Assets

There is one thing I’m a little sad about as far as getting this to compile to for the web, and that has to do with static assets. The C programming language doesn’t have a standard way of including binary files in your build process, but you need to include things like images & palettes into your executable somehow.

For GBA and desktop targets, I thought, “I don’t fear assemblers,” and had a file like this:

;; src/game/embedded_data.s
.macro include_bin, name:req, path:req
    .global \name
    .global _\name
\name:
_\name:
    .align 4
    .incbin "\path"
.endm

    include_bin bismuth_font_4bpp, "../baked/fonts/bismuth_font.4bpp"
    include_bin bismuth_font_width, "../baked/fonts/bismuth_font.width"
    include_bin bismuth_font_pal, "../baked/fonts/bismuth_font.pal"
    include_bin speech_bubble_4bpp, "../baked/interface/speech_bubble.4bpp"
    include_bin speech_bubble_tiles, "../baked/interface/speech_bubble.tiles"
    ;; etc.

Which doesn’t syntax highlight well, but, essentially, assemblers do usually have a directive, like .incbin that allows you to add arbitary data to your object file. I had my own macro on top of that to deal with the fact that the MacOS toolchain wants to insert an extra underscore to all of your symbols, and an .align directive because I want to easily use the GBA’s fast memcpy-like BIOS routines which require the data to be aligned on a word boundary.

I admittedly didn’t try very hard, but I wasn’t able to get emscipten to understand the (data-only) object file the assembler put out.

The more standard solution is to use a tool to create one or more source files that declare arrays with the contents of your files:

const uint8_t interface_speech_bubble_pal[] __attribute__((aligned(4))) = {
	0xff, 0x7f, 0x86, 0x10, 0x54, 0x4a, 0x39, 0x5f,
	0x98, 0x46, 0xd3, 0x39, 0x90, 0x39, 0x29, 0x2d,
	0x00, 0x00, 0xb4, 0x14, 0xf5, 0x6e, 0x2e, 0x56,
	0x4e, 0x08, 0xdc, 0x39, 0xce, 0x18, 0x00, 0x00 
};

const uint8_t fonts_bismuth_font_4bpp[] __attribute__((aligned(4))) = {
	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	// continues for a long time...

Which is perhaps not so bad for something small like a palette, but for anything of a decent-size it just feels wrong. Each byte of data turns into slightly more than six bytes of source code.

Thankfully given the fact that I’m making a GBA game, the maximum size for any one asset is pretty bounded.

Emscripten does have support for it’s own virtual file system, and a way to include files that you could read with the usual C file functions, but I’m intentionally avoiding that because I want the code to be as close as possible between platforms.