To improve rendering performance the game builds a texture atlas from all the images. This process is quick enough to be done at load time. I wanted to have a clear idea about the atlas layout. Xcode does have some support for viewing OpenGL textures but it’s been crashing on me almost every time I used that feature. So I did what I usually do when a 3rd party tool fails me: I built my own inspection tool to look at the OpenGL textures directly in-game.
Even in its initial simple form it has already helped fix a few issues.
I’m planning to extend it with zoom & pan and a way to track usage of the individual images in the atlas.
As I keep adding assets to the game, the load time keeps increasing. Who would have thought? A 5 second startup may not sound like much but it quickly adds up during development.
One way to fix it would be to load assets on demand. This might cause stuttering, but that’s OK for development. However, improving the load time would benefit the final game as well. Let’s do that!
I added a job system that allows the preload to happen on multiple threads. Load time: 1.5 seconds. Nice! Now that I’ve “jobified” the tasks that need to run, further improvements can be made with relatively little effort.
A brand new “single-header” library for decoding MPEG1 video, by Dominic Szablewski. Simple API, easy to integrate. It’s great!
In fact, I spent more time looking for my .blend source file than writing code to use the library. In Blender, I switched render output from image to video and set the codec to MPEG1. It all worked the first time I ran the game.
Built a simple particle editor. I had been using Particle Designer previously, which is a nice app but its PEX format has some limitations I didn’t like. So I used PEX as a starting point to build my own editor and will extend it later.
The new Blender 2.8 is great. Unfortunately it broke my batch render script.
Fixing the script and the rendering setup were quite a challenge due to the major UI changes in 2.8, but eventually I figured it out. Even learned a few new tricks along the way. How did I manage to write the original script without the built-in scripting console? So helpful!
My Blender export pipeline looks like this:
master.blend file with fixed camera & lighting setup
extra .blend file for each asset
link assets into master
for each asset, render object & shadow into separate PNG
First draft of the new script for 2.8:
# Requires Blender 2.8
# /Applications/blender.app/Contents/MacOS/Blender -b -P render28.py
# Node setup: see master.blend -> Compositing
# Render menu -> Film -> transparent
# Shadow catcher plane -> Object menu -> Visibility -> Shadow catcher
# Adding more objects: File -> Link... -> "Collection" from ext. file -> Move to Assets collection in master
basepath = os.path.normpath(os.path.dirname(os.path.abspath(__file__)))
master_blend = "blender28-batch-render-test-master.blend"
src = os.path.join(basepath, master_blend)
bpy.context.scene.render.resolution_percentage = 50
bpy.context.scene.render.resolution_x = 1280
bpy.context.scene.render.resolution_y = 960
bpy.context.scene.cycles.samples = 20
assets_name = "Assets" # name of collection in master.blend
assets_collection = None
for collection in bpy.data.collections:
if collection.name == assets_name:
assets_collection = collection
if assets_collection is None:
print( "Error: %s collection not found in master" % assets_name )
# Save original filenames for output nodes
output_nodes = 
for node in bpy.context.scene.node_tree.nodes:
if ( node.type == "OUTPUT_FILE" ):
output_nodes.append( ( node, node.file_slots.path ) )
for target in assets_collection.objects:
# Show only the current object
for obj in assets_collection.objects:
obj.hide_render = obj.name != target.name
# Set output filename
for node, path in output_nodes:
node.file_slots.path = target.name + "_" + path
Additionally, I created a simple pipeline for rendering weapon silhouettes for the HUD. With a single click, it pulls in each weapon model, renders it from a side-view, then uses just the alpha to write a single-color transparent PNG.
And similar setup for pickup icons, with a subtle “glow” pass.
iCloud, Google Drive and OneDrive might seem like the obvious candidates but I’d rather avoid them. Why? They are too much like Dropbox. Sooner or later they are going to introduce a similarly annoying UI blunder, crippling limitation or an unfriendly plan.
So I decided to try Syncthing instead. Simple, free, self-hosted, with Linux, Mac and Windows clients. Sounds good…
From a business standpoint it probably makes sense that Dropbox doesn’t offer a pay-for-what-you-use plan but that is exactly what I want. With Syncthing, it’s no problem.
I set up a simple DigitalOcean VPS as a “master” node that’s always online and adding extra storage space is super easy and cheap.
I’ve been using Syncthing for about two weeks now and it seems to be working really well. It is solid software, complete and functional with no extra fluff. Filesystem changes are picked up and synced quickly.