Hot Loading Assets

After a random discussion on in the #LudumDare irc channel about directory watching and the desire to get a normal mapping shader implemented one Saturday morning I decided to develop and integrate “hot loading” shaders scripts. Never heard of hot-loading assets, well the best description I can give is: Flipping Magical. No really, I can open Game Project and change an asset file, like the script, hit save, and watch the effects be applied immediately. It is not that difficult to setup.

Hot loading of assets really hinges on one thing, having a cache system that hides the actual data from user.[1] See the following interface for loading, and using, shaders.

typedef int ShaderHandle;
ShaderHandle CreateShaderFromFile(const std::string& shaderFile);
void DestroyShader(ShaderHandle& shaderHandle);
void BindShader(const ShaderHandle& shaderHandle);

Do notice that no details regarding a shader (or texture, or any other asset) are given to the user of the interface, and to use the shader the user supplies this handle. In the internals, CreateShaderFromFile() checks for a cached shader and returns the handle if found, or loads and caches the new file returning a handle for later use. To get hot-loading to work I added a new function, TryReloadingShaderFromFile(). This function is responsible for loading the asset, verifying it is valid, (can the shader compile/link) and only if valid switch out the cached asset.

void WatchFilesForModifications(FileList& modifiedFiles)
  FILETIME lastWriteTime;
  SYSTEMTIME systemTime;

  for (FileToWatch watchedFile : mFilesToWatch)
    HANDLE fileHandle = CreateFile(watchedFile.filePath, ...);
    if (INVALID_HANDLE_VALUE != fileHandle)
      GetFileTime(fileHandle, NULL, NULL, &lastWriteTime);
      FileTimeToSystemTime(&lastWriteTime, &systemTime);

      if (systemTime more recent watchedFile.lastTime)
        watchFile.lastTime = systemTime;

The above function will check for modified files on Windows, not shown is the initialization of the mFilesToWatch which is similar, except, of course, that it initializes the time of the watched file. I also left out the details regarding checking the more recent time and I probably wouldn’t keep watchedFile.lastTime as a SYSTEMTIME type, but you can figure that out.



[1] User being a programmer using the interface.

Comments are closed.