MichaelPidde.com

AssetManager Overhaul

I was scanning through my Boreal Darkness code the other day looking for some simple housecleaning chores that I could knock out in an evening to make things better. One area of the program that has always been less than optimal is the way that image assets are loaded. What I had been doing since the start because it was quick and easy was manually loading all of the assets in one big init function, like this:

state->textures.emplace(
    "walk", 
    loadTexture(state->renderer, "assets/player.png")
);

state->textures.emplace(
    "axe",
    loadTexture(state->renderer, "assets/player_axe.png")
);

state->textures.emplace(
    "objects",
    loadTexture(state->renderer, "assets/objects.png")
);

The loadTexture function takes the PNG and loads it into an SDL_Texture which gets stored in the more-or-less global state structure, and those textures can be referenced by key wherever they happen to be needed. Anyhow, obviously adding a new asset means you have to add another emplace which, while not exactly difficult, is still not optimal. I don't care about the recompile since you would need to recompile once you start using the new asset somewhere in the code anyway, but on principle, this can just be better.

My solution leverages the GetDirectoryFiles function that I wrote about in the previous post. I have now split up my assets into sub-directories, so I'll have a directory for fonts, icons, effects, etc. The initialization will now call GetDirectoryFiles for each of those directories and emplace the PNG files using a key that can contain a prefix denoting the asset type. It will use the file name sans extension for the key. For example, a file called fire_glow.png in .\assets\effects\ given a prefix of "effects_" will get emplaced with a final key of "effects_fire_glow".

Another factor that crops up from time to time is the desire to change an asset name in the physical path but not the key name referenced in the rest of the code. If I wanted to create a different fire glow effect and put it in a file called exteme_sparkly_blue_fire_glow_test.png and swap that in for the current glow effect, I don't want to have to change all instances of the key in the code (though it should only be used in probably one place anyway). The workaround for that kind of situation is the creation of a per-directory file called alias.json. This file, if found, gets loaded in the same process that emplaces the assets and allows you to alias the files to have different keys. For example:

{
    "aliases": {
        "exteme_sparkly_blue_fire_glow_test.png": "fire_glow"
    }
}

Ultimately I can continue referencing the key effects_fire_glow to use the new sparkly blue glow texture.

One final thing that I've done is wrap every call to the state->textures unordered_map in a function AssetManager::getTexture. This checks if the requested texture actually exists in the unordered_map, and if not, will use a dud texture in its place. This allows me to easily see if a texture is misconfigured in some way or otherwise altogether missing. It also lends to a coherent asset API so I'm not referencing a global container in a willy-nilly manner just because it was quick and dirty in the past. Anyhow, here's what missing textures would look like:

Code Stats

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C++                             24            419            122           2927
C/C++ Header                    40            124             35           1502
PHP                              3             23             50             94
JSON                             2              0              0             85
DOS Batch                        3              8              1             34
Bourne Shell                     1              0              0              5
-------------------------------------------------------------------------------
SUM:                            73            574            208           4647
-------------------------------------------------------------------------------