pthom / hello_imgui

Hello, Dear ImGui: unleash your creativity in app development and prototyping
https://pthom.github.io/hello_imgui
MIT License
604 stars 91 forks source link

Enable asset load redirection #106

Open jbliesener opened 1 month ago

jbliesener commented 1 month ago

This patch allows to redirect the LoadAssetFileData function, so that other resource load mechanisms can be implemented. Specifically, assets can be loaded from resource data embedded in the executable. These resources can be produced with any resource compiler, including, for example https://github.com/vector-of-bool/cmrc.

This allows to create single-file-executables in Windows and Linux with all required resources embedded in the executable.

An alternative asset load implementation could look like this:

#include <cmrc/cmrc.hpp> // see https://github.com/vector-of-bool/cmrc
#include "hello_imgui/hello_imgui_assets.h"

CMRC_DECLARE(myAssets); // see https://github.com/vector-of-bool/cmrc 

auto resource_fs = cmrc::myAssets::get_filesystem();

[...]

HelloImGui::AssetFileData LoadAssetFileDataFromResource_Impl(const char *assetPath)
{
    HelloImGui::AssetFileData r;

    cmrc::file assetFile = resource_fs.open(assetPath);
    const char *begin = assetFile.cbegin();
    const char *end = assetFile.cend();
    r.dataSize = end - begin;
    if (r.dataSize)
    {
        r.data = malloc(r.dataSize);
        memcpy(r.data, begin, r.dataSize);
    }
    return r;
}

HelloImGui::AssetFileData LoadAssetFileDataFromResource(const char *assetPath)
{
    // assets starting with ":/" are ALWAYS loaded from the embedded resource file system
    if (strlen(assetPath)>2 && assetPath[0]==':' && assetPath[1] == '/') {
        assetPath++;
        if (!resource_fs.exists(assetPath))
        {
            std::stringstream msg;
            msg << "LoadAssetFileDataFromResource: cannot load " << assetPath << "\n";
            HIMG_ERROR(msg.str());
            return HelloImGui::AssetFileData();
        }
        else
        {
            return LoadAssetFileDataFromResource_Impl(assetPath);
        }
    }
    else
    {
        // other assets are searched on the embedded resource file system first.
        // If not found there, they are loaded from the standard assets folder
        if (resource_fs.exists(assetPath))
        {
            return LoadAssetFileDataFromResource_Impl(assetPath);
        }
        return HelloImGui::DefaultLoadAssetFileData(assetPath);
    }
}

int main(int, char **)
{
    HelloImGui::setLoadAssetFileDataFunction(LoadAssetFileDataFromResource);

    [...]
}

I'm not sure about the Doxygen comments, you may want to check them.

pthom commented 1 month ago

Hello Jorg,

Thanks for the nice suggestion ! I need to review that a bit more thoroughly in the next days. Normally, there is almost no API for Hello ImGui: everything is done via parameters and callbacks.

If we want to follow this philosophy, it might fit better inside runner_callbacks. However, since this is a quite advanced case, I'm not sure it is worth being added in the user facing callbacks, and your solution might be enough.

Let me think of it for a few days.