Clover’s Toy Box development: rendering Heavy Metal FAKK2 models, supporting more SDL features, fixing platforms I don’t usually test, and more.
- Added support for .SKB models and .SKA animations (version 1 to 3) from Heavy Metal: F.A.K.K.² / American McGee’s Alice and (version 4) from Star Trek Elite Force 2.
- Added support for loading animations from .IQE models.
- Added support for drawing skeletal models with separate animation files (works with all support skeletal formats; IQM, IQE, MD4, MD5, MDR, SKB).
- Clover Resource Utility now automatically loads a mesh model (.md5mesh, .SKB) in the same directory when an animation-only file is viewed (.md5anim, .SKA). It makes browsing animation files more fun.
SKB support is missing dynamic legs rotation, collapse map level of detail support, and an API to get object movement specified for each animation frame.
Quake 3’s MD4 skeletal format was split into separate skeletal base mesh (.SKB) and animation (.SKA) files. They use quaternions similar to Doom 3’s MD5 format. Though material names have been removed as they are in a separate file.
The SKB/SKA files are not standalone; they both require information from the other to be usable.
To fit with my model system, when loading .SKB (FAKK/Alice versions) the renderer looks for a .SKA in the same directory to get the animation pose to convert vertexes from bone space to model space (this is needed for GPU bone skinning and it seems annoying to deal with supporting per-bone vertex positions). EF2 version of SKB includes the skeleton bind pose, so loading .SKA is not needed.
When loading .SKA the renderer has to load .SKB from the same directory to get the joint hierarchy / names. EF2 has to match SKA joints to SKB using names instead of listed order.
- Added SDL 2.24.0 libraries for Windows, Linux, and macOS.
- Added support for PS4 touchpad button (and other controller buttons added in SDL 2.0.14).
- I can get data for touching PS4 touchpad and moving accel/gyro sensors but I don’t support using them yet.
- Added support for SDL’s Input Method Editor (IME) composition API. (I still need to add support for rendering more text glyphs for this to be useful.)
- SDL text input is now only enabled when needed, for IME support. So on-screen keyboard should only show when it’s needed and not immediately at start up (on Android / PinePhone).
- Added support for pasting primary selection (Linux middle click). I’m still missing setting primary selection.
Dynamic geometry streaming
Fixed macOS running Clover’s Toy Box menu at 5 FPS and Raspberry Pi 3B crashing.
- Added support for client-side vertex/index arrays.
- Changed vertex/index buffer objects from quad-buffer to double-buffer due to out of memory issues / performance.
Current preference order:
- Persistent mapped buffer (OpenGL 4.3).
- Client-side arrays (OpenGL 1.1, not supported by OpenGL Core contexts and WebGL).
- Double-buffered vertex/index buffer objects (OpenGL 1.5).
I tried Clover’s Toy Box on my MacBook Pro (2008, OpenGL 4.1) and Raspberry Pi 3B (2016, OpenGL ES 2.0) for the first time in two years. On macOS the menu ran at 5 frames per-seconds (instead of the desired 60+) and on Raspberry Pi it crashed.
This was a result of increasing the size of the dynamic geometry buffer. Reverting the size fixed them but I want to be able to draw more.
On macOS and Raspberry Pi my renderer used round-robin cycling between vertex/index buffers for 4 frames (to avoid stalling if the buffer is still in use).
Raspberry Pi threw GL_OUT_OF_MEMORY for the fourth vertex buffer and crashed when trying to use it. macOS didn’t give a clear indication what the problem was (from testing; I only know it was the result of increased memory usage).
Using vertex/index buffer objects for dynamic geometry streaming is kind of known to potentially have performance issues.
I added support for client-side array (a feature added in OpenGL 1.1). You issue draw calls using CPU memory buffer instead of copying to a GPU buffer which the OpenGL driver has to manage the memory / reuse of the buffer. It probably has to make it’s own buffer internally of the client-side array data (how is this different?) but I guess old OpenGL drivers are more optimized for client-side arrays.
Client-side arrays worked fine on Raspberry Pi and macOS (when using legacy OpenGL 2.1 context). To use modern features on macOS you have to use an OpenGL Core context; which doesn’t support client-side arrays.
Buffer orphaning, double-, and triple-buffering worked on Raspberry Pi and GTX 750 Ti. Buffer orphaning didn’t work on macOS. Three buffers worked but two was faster. (This matches Apple’s OpenGL documentation that recommends double-buffering.)
I changed vertex/index buffer objects for dynamic geometry (including 2D quads for menu images/text) from quad-buffering to double-buffering.
OpenGL ES 2.0
My renderer now only require 8 shader vertex attributes; the minimum that OpenGL ES 2.0 will have.
- Merged GLSL attributes for texture coordinates and lightmap texture coordinates.
- Use separate vertex attribute index lists for for skeletal and vertex morph animation attributes. Before the attributes were all unique indexes even though they were not used simultaneously.
- I switched ARM from uint32 indexes to uint16. Mainly to silence Raspberry Pi GL_KHR_debug messages about converting uint32 to uint16.
After I got past Clover’s Toy Box crashing on Raspberry Pi 3B, I was met with the level being rendered black. This was due to lightmap texture coords GLSL vertex attribute being index 10 but only 8 are supported on the Raspberry Pi 3B / required for OpenGL 2.0.
I also fixed MD3 vertex morph animation to use attribute indexes less than 8 by remapping them to skeletal attributes that aren’t used with vertex morph shaders.
- Replaced WideCharToMultiByte( WC_ERR_INVALID_CHARS ) which requires Windows Vista, and MultiByteToWideChar(), with custom UTF-16 conversion functions.
- Fixed crash due to NULL pointer dereference using my fixed-function rendering. It crashed on my main system as well.
- Fixed out of bounds read for IQM triangle indexes when the model is loaded. It crashed on ReactOS but not my main system.
I fixed running Clover’s Toy Box on ReactOS—a Windows XP/2003 clone—and probably Windows XP.
It runs at 1 frame per-second in a virtual machine running ReactOS with the default OpenGL 1.1 software implementation. There are also a lot of warnings about my internal loopback system dropping packets. My internal loopback doesn’t buffer enough for the client to run at less than 20 FPS… which I should probably fix.
- Added support for controlling LEDs (e.g., PC case) via OpenRGB network protocol and SDL joystick API (e.g., PS4 controller).
- Added basic support for running emulators via the libretro API.
Controlling LEDs and running other games isn’t really useful for making a game but it’s entertaining.
I can now have external flashing lights like the arcade game Hatsune Miku: Project DIVA Arcade Future Tone. Held controller buttons affect lights. I can run it in the background to control lights while playing Hatsune Miku: Project DIVA Mega Mix+ on Steam.
RetroArch providing a single user-interface for multiple emulators is cool but I don’t like RetroArch’s user experience. I started adding support for the libretro API so I can run the emulators with my own UI/input/window-management. It’s surprising how little is needed to get SEGA Genesis and SNES emulators working. I haven’t started working on a UI yet though.