Clover’s Toy Box 25.09

Clover’s Toy Box development: model lighting, secure networking, running WebAssembly, and more.

Overall

It’s a been a while since the last development update in September 2024. This post covers development from October 2024 to September 2025. (As written in January and February 2026.)

There was a lot less development in this time frame than usual. I burned out on reimplementing the Quake 3 renderer and stopped working on it after October 31, 2024. I started a few new things that I made good progress on but haven’t reached completion.

Completed: MD3 Normal Mapping, (Automated) Build for Android.

Progress on: Model Lighting, Secure Networking, WebAssembly Interpreter, Video Playback.

MD3 Normal Mapping

Summary: Normal maps are now supported on all model formats supported by Clover’s Toy Box. “stage normalmap” is supported in materials for compatibility with Reaction.

Reaction is a free game based on Quake 3 that utilizes the ioquake3 engine. Reaction’s knife and first-person hands/arms use MD3 models with a tangent-space normal map. Support for this was integrated into Clover’s Toy Box in October 2024.

Toy Box now has support for normal maps on vertex animated models (MD2, MD3, MDC, and TAN formats) and the ability to mark an image as a normal map using the “stage normalmap” material stage directive.

This includes the ability to generate vertex tangent and bitangent vectors for vertex animated models and the ability to setup the tangent matrix for the OpenGL accelerated vertex animated model rendering.

Specular maps are often paired with normal maps (including in Reaction). This has not been added to Toy Box yet.

Model Lighting

Summary: I worked on making model lighting match Quake 3. I made great progress on environment lighting. Model lighting, particularly from light entities, is not completely accurate and there is various issues.

Clover’s Toy Box has long had a global directional light to give a sense of space and test normal mapping on models. Toy Box also supports static lighting on Quake 3 levels (lightmaps and vertex lit surfaces).

There is work-in-progress support for replacing the global directional light with using the level’s colorful environment lighting and light entities such as weapon muzzle flash and explosions.

Quake 3 levels have a 3D light grid of the environment lighting over the area of the level and it’s interpolated between the points at a model’s lighting origin before being applied to the model.

I went through a lot to get sampling the level’s environment lighting to work correctly in Toy Box. Figuring out parsing the grid size, how to offset the grid to the correct place in 3D space, and how to interpolate light between points.

I added rendering lines with the color/direction of the light grid itself for a better idea of where the light grid is. (Quake 3 doesn’t have this but it seems pretty useful.) I also compared it to Spearmint’s opengl1 renderer using the “r_debugLight 1” config variable that prints light values at the first-person gun’s position.

Ironically I found and fixed an issue in Spearmint’s opengl1 renderer that caused the light grid to get brighter each time I switched renderers using Spearmint’s “vid_restart” command.

Quake 3 uses generic ambient and diffuse lighting for models and it should work correctly in Toy Box. This may be correct with only the environment light but light entities do not work correctly. Quake 3 combines all lights affecting the model into one light source to apply and I haven’t figured out how exactly that works.

I also haven’t addressed drawing light entities on the level itself. It’s going to be difficult to set up the light decal geometry but it wouldn’t be complicated to draw it.

I stopped working on model lighting after October 31, 2024 and it hasn’t been integrated into Toy Box yet. I hadn’t really looked it again until January 2026. The state of the code isn’t as bad as I remembered but it has issues.

Build for Android

Summary: Building for Android is now automated rather than a manual process.

I got Clover’s Toy Box working on Android a while back but the build process wasn’t completely automated and I somewhat forgot how to build it.

In October 2024 I add the SDL2’s android-project with customization to enable network access and builds of libSDL2.so for arm and arm64 to Toy Box along with a build script to put everything together. Now I can build the full Android app with a single command.

Secure Networking

Summary: Secure connections for HTTP and WebSocket now work on the Linux game client and server.

Clover’s Toy Box started out targeting OpenGL ES 2 and WebSocket to allow first-class support for running in a web browser and connecting to a game server.

However this only worked when hosting the website on the local network. Web browsers require using secure (encrypted) connection for WebSocket if the game’s HTML/JS/WASM files are hosted on the Internet.

I added support on Linux for secure connections using OpenSSL on both the game client and server. This means it’s possible to host games on the public Internet and connect from a web browser. The game client on Linux can also download files over HTTPS and connect to game servers using secure WebSocket.

I still want to add support on Windows, macOS, Android, and possibly the Wii. I want to make Linux not depend on having OpenSSL pre-installed. I’m not sure how to best address these.

WebAssembly Interpreter

Summary: I wrote an interpreter that runs WebAssembly code and passes 15,000 tests. I intend to overhaul the project for better security and performance. Though first I want to find a reasonable way to support running Quake 3’s QVM bytecode and maybe get it to pass more of the WebAssembly tests.

I worked on implementing a WebAssembly (WASM) interpreter in November 2024 though March 2025. This is standalone from Clover’s Toy Box and not integrated yet.

Source code can be compiled to a WebAssembly file (.wasm) that uses a instruction set that is independent of the operating system and CPU architecture and then it can be run with limited access to the system on any operating system and CPU. This is similar to Java, Microsoft’s .Net / C#, and Quake 3’s QVM. I’m writing code to execute the WebAsembly code. It’s kind of like emulating a CPU.

There are many WebAssembly interpreters / run-times available; there isn’t a strong reason for me to write one. However it’s something I’m interested in and it is documented and limited scope that it is feasible to do. Audio and video codecs on the other handle are more difficult to test and less interesting to implement, you know?

My WASM interpreter is passing ~15,000 tests from the reference WebAssembly interpreter repository. It is failing 200 tests related to what kind of Not-a-Number (NaN) is returned by some instructions. It would be good to ensure my interpreter is behaving correctly but I don’t think it matters for my usage in practice.

The reference WebAssembly interpreter test suite is for a Lisp program and there is no documentation or recommendation that other interpreters use the test suite. So figuring out how to run tests and check the result is part of the problem. (There is 10,000 other tests that I haven’t hook up yet. I think they’re mostly testing that invalid code is caught.)

I’m not 100% sure I’m checking the NaN results correctly for the “failing tests”. (I found some tests must allow multiple NaN types.) I tried to fix some tests and it broke others. As far as I know, no code in Toy Box or Quake 3 cares what kind of NaN it is. (I didn’t even know there was different kinds before I started this.)

My WASM interpreter should be functional for running software. Though I’ve only tested a few basic programs. My main focus was gaining understanding of how WebAssembly works. I haven’t profiled it but I expect it to be slow. I don’t expect it to catch all invalid code.

My intention is to add support for executing Quake 3’s QVM bytecode. QVM is similar to WASM; it’s a set of instructions to manipulate a memory stack and call functions in the host application. If I remember correctly, QVM has about 50 instructions while WASM has around 200 and WASM instructions have additional run-time rules that need to be handled.

It should be simpler to run QVM bytecode than WASM. However there isn’t a test suite for QVM. Notably QVM has a jump instruction to move code execution to an arbitrary location and WASM does not. (Executing QVM bytecode doesn’t mean it will run Quake 3 mods. They require specific functions in the application.)

Video Playback

Summary: Audio playback from RoQ and AVI files works in Clover’s Toy Box. I have Motion JPEG in AVI partially functional but it hasn’t been integrated yet. I haven’t started working on RoQ video decoding.

I saw that RoQ video format (used by Quake 3 and some other games) was reimplemented and used by homebrew for the Sega Genesis; “Sonic CD32X would be LIT!” (June 4, 2025). I wondered if I could implement RoQ in Clover’s Toy Box using a specification I found online. I worked on “video playback” around June-July 2025.

I implemented playing the audio from RoQ videos. However I decided to start with less complicated video decoding.

I decided to add support for Motion JPEG (MJPEG) in an .AVI container. In Motion JPEG all video frames are JPEG images. Motion JPEG has higher file size than RoQ but decoding JPEG images is already supported in Toy Box using the libjpeg-turbo library.

I implemented audio playback from AVI containers. It has the same audio header and possible formats as WAV files but it’s split up into chunks interleaved with the video frames. I reused code from my WAV reading implementation.

I got Motion JPEG in .AVI to play! However I didn’t get the audio and video to be in sync. Video files start with multiple frames of audio. I need to buffer audio samples and video frames instead of just displaying video frames immediately when reading more audio samples.

Over and out

Can’t spell clover without over. It’s so cl-over.


Posted

in

,

by