What is SDL?
SDL (Simple DirectMedia Layer) is a cross-platform, Open Source development library designed to provide low level access to input and graphics hardware
Written in C, it is used by video playback software, emulators, and many popular games
It is not a full game engine, but rather a wrapper around OS-specific functions that software might need to access. It’s purpose is to add abstraction and help developers target multiple platforms from one code base
SDL officially supports Windows, Mac OS X, Linux, iOS, and Android - with unofficial support for many other platforms
SDL 1.2 vs SDL 2.0
There are two flavours of SDL:
- v1.2 - original version licensed under GNU LGPL. Deprecated but still in popular use
- v2.0 - major update with a different, not backwards-compatible API. Licensed under zLib. Improved support for hardware-accelerated 2D graphics
Does SDL have WebAssembly support?
Yes! Emscripten (which we’ll use to compile for WebAssembly) has a simple implementation of SDL 1.2’s API built in. This is hand-written in JavaScript and unrelated to the SDL codebase - but with compatibility high enough for most simple use cases
SDL 2.0 support is also included via Emscripten Ports - a collection of useful libraries, ported to Emscripten and integrated with the Emscripten compiler (emcc). This is an official, full release of SDL 2.0 - compatibility should be near 100%
We’ll take a look at both below
Running SDL 1.2 code in the browser
First, install and configure the Emscripten SDK (instructions here)
Next, copy-paste the C code below and save it on your local machine as sdl_1_2_sample.c
. It’s a tiny SDL program that renders random pixel data to the screen - it’ll look like white noise
Take special note of the emscripten_set_main_loop
call
Games and other graphical apps often contain infinite loops to sequentially render animation frames to the screen
This infinite loop is a problem in the browser environment because control is never returned to the browser to render graphics. The app will appear to hang - and after some time the browser will notify the user that the page is stuck and offer to halt or close it
Emscripten’s solution is emscripten_set_main_loop
. This simulates an infinite loop, but in actuality just calls the loop function - in our case drawRandomPixels()
- at a specified number of frames per second. After each call completes, control is returned to the browser for rendering
This is explored further in the next lesson
Build and Run
Still in the same directory, open a shell / command prompt. Invoke the following Emscripten build commands:
You’ll see three new files once the build completes:
sdl_1_2_sample.wasm
- the WebAssembly outputsdl_1_2_sample.js
- the asm.js outputsdl_1_2_sample.html
- a shell / wrapper file so you can launch your WebAssembly app in the browser
Use lightweight Web Server software like http-server to serve sdl_1_2_sample.html
and open it in a Web Browser. You should see a “white noise” animation:
Upgrading to SDL 2.0
Next, let’s upgrade our sample code to SDL 2.0
Copy-paste the modified C code below and save it on your local machine as sdl_2_0_sample.c
. It’s a modified version of the above code - but targeting SDL 2.0 instead of SDL 1.2
The main change here is that you can no longer Flip pixels directly to the screen. You need to push pixels into a texture (which resides in GPU RAM) and issue rendering calls to update the screen. More info here
Build and Run
To build this SDL 2.0 sample you’ll need a slightly different build command:
This time we’re passing in the USE_SDL=2
codegen option - which instructs Emscripten to switch off the built-in SDL 1.2 implementation and compile with the SDL 2.0 port instead
Similar to before, emcc will generate three files: sdl_2_0_sample.wasm
, sdl_2_0_sample.js
and sdl_2_0_sample.html
Serve sdl_2_0_sample.html
and open it in a Web Browser. You’ll see the same white noise animation, but this time powered by SDL 2.0:
Cross-platform capability
Our code samples have hardcodings for Emscripten/WebAssembly - hardcodings that break traditional C compilation with gcc. However with some adjustments we can use the same source code to target both native and WebAssembly platforms:
Here we’ve used #ifdef
statements to change compilation behaviour under native build scenarios:
- Avoid loading the
emscripten.h
headers - Replace
emscripten_set_main_loop
with a traditional infinite loop
With these changes, we can compile the above code into WebAssembly with Emscripten/emcc and native executables with gcc. Here’s what it looks like running as a Windows app:
That’s the end of Lesson 2! Next time we’ll look at Emscripten Loops
Other Posts in this Series
- Lesson 1: WebAssembly Hello World - 30 Nov 2019
- Lesson 2: Graphics with SDL - 01 Dec 2019
- Lesson 3: Emscripten Loops - 03 Dec 2019
- Lesson 4: File System Access - 08 Dec 2019
Comments