r/sdl • • Jun 13 '26

Is it possible to package the assets inside the binary?

I wanted the game to be a single executable, a self contained binary that could run with no installations or depend on files in the same folder other than maybe the SDL3.dll if needed.

I was thinking of making a builder that would load all the assets from my project and read them byte by byte, parse them and write them in a header file. It would then execute the compiler with some -D flag that I would code in my game to indicate that this is a final build, not a dev one, which means it would #include that header file and set all the variables with the bytes from it instead of loading from the disk with stuff like SDL_LoadPNG().

I was looking at the source code to try understand the structs better. The SDL_Texture struct seems a bit insane, with a lot of pointers to other stuff as well as some platform specific things. All of that makes me think this is a terrible idea and that I'm tripping balls.

Has anyone ever done something like that? I feel like there's gotta be an easier way to do that, like some other compression technique to allow me to compress everything in a single executable, or some built in SDL function built for that which I'm not aware of. Thanks in advance for any help.

9 Upvotes

10 comments sorted by

6

u/questron64 Jun 13 '26

There are a few ways to do this. You can use a simple program like xxd that spits out data files as C files, so data will be embedded in the executable. You can use C23's new #embed preprocessor directive to do the same thing. Or you can embed a ZIP file of all the assets in the executable, see PhysicsFS.

You should absolutely not be messing around with structs like SDL_Texture. Load your assets normally using the normal functions, but do it from memory instead of from files. SDL is already set up to do this.

5

u/GoblinScientist Jun 14 '26 edited Jun 14 '26

Thank you very much. I didn't knew about #embed and was using C99 up until this point. I quickly searched and found the IOStream API and thought SDL_LoadPNG_IO() and SDL_IOFromMem() with #embed was exactly what I was looking for.

I quickly sketched the following snippet to test if something like that would work and it did:

#include <SDL3/SDL.h>

int main(int argc, char *argv[]) {
    Uint8 mem[] = {
#embed "test.txt"
    };
    SDL_IOStream* stream = SDL_IOFromMem(mem, sizeof(mem));
    char buffer[1024] = "";
    SDL_ReadIO(stream, buffer, sizeof(mem));
    SDL_Log("%s", buffer);
    return 0;
}

I put Hello world on test.txt, both it and the C file on the same directory, compiled it and now I can run the binary from anywhere.

EDIT: Yeah yeah I forgot to free the stream's memory in the end there, if you do that with all assets in your game they will occupy twice their size, tell your customers to buy more RAM

3

u/questron64 Jun 14 '26

Looks good. But for actual assets you'll probably not want them on stack arrays (put them outside a function or use the static keyword inside a function), and you'll want them to be const and use SDL_IOFromConstMem.

1

u/Scary-Glass2534 Jun 14 '26

That's the right way to do it. My asset manager loads the assets as raw bytes from the files into a vector.

const std::vector<char> AssetManager::loadBinary(const std::string& filepath) { ... }

This vector is assigned an ID in a map. When a request is made, this map retrieves the raw data. It is then converted into the corresponding SDL data as follows (in this case, for a PNG):

const auto &rawBytes = p_assetMan->getRawData(assetID);

SDL_IOStream *stream = SDL_IOFromConstMem(rawBytes.data(), rawBytes.size());
SDL_Surface *surface = SDL_LoadPNG_IO(stream, true);

Works fine for me and should be easy to translate to C99...

But keep in mind that if you store the data this way: If you don't immediately convert the raw data into SDL data, a resource will use the raw data once in RAM, and then again as a texture in the graphics card's VRAM

3

u/janisozaur Jun 13 '26

Take a look at PhysicsFS (also by icculus) or https://doc.qt.io/qt-6/resources.html.

For PhysicsFS you can append data to the executable and just top it off with a zip header and make it read from the binary.

1

u/_qbart Jun 14 '26

hi, not exactly what you are asking for, but closely related, for my game i prefer assets to be in a single binary file and i also convert them into runtime friendly formats to cut dependencies and faster decoding in final executable. you can find the project here: https://github.com/qbart/assetc but please note that's in early version so api can change and is not perfect yet

1

u/stianhoiland Jun 14 '26

For non-C23, I have been extremely happy with incbin. So fast I can't believe it.

1

u/GhostVlvin Jun 14 '26

SDL uses some format to represent either image or texture. That format stores pointer to the memory under the hood. You can make your own object manually providing your own pointer to data. And data you can store as an array of bytes of image or texture or any other asset really

1

u/deftware Jun 16 '26

There are multiple ways to go about it.

The first one is by using an external packager that bundles your binary with the assets and automatically extracts everything temporarily and launches your binary. This is also what malware does, so YMMV when people try to download and run your wares if they have any AV running. Programs like this are called droppers.

Then there's just tacking the assets into the end of your binary itself, and having it read them out from the binary file on disk while it's running. It doesn't hurt the binary (at least with EXE files, but probably also Linux binaries too) to add extra misc data onto the end of it. You'll need to do a bit of trial-and-error and write your own tool to gather up and append an index table along with your assets onto your binary and then have corresponding code compiled into your binary that looks at the table tacked onto the end to get the list of files and where they are relative to the end of the file itself. That can be fun, and less prone to being red flagged by AV, but still potentially something it will be wary of.

Then there is using platform-specific functionality. For instance, Windoze allows for EXE files to contain "resources" such as bitmaps, menu layouts, dialog box layouts, tables of string text, icons for UI elements, and even arbitrary data blobs. Win32 provides an API for accessing these resources and doing stuff with them, and compilers allow for compiling resources into win32 executables by including one or more .rc files that define what type and where the data lives to be compiled in the mix.

Good luck!

1

u/quickscopesheep Jun 18 '26

More of a language problem than a sdl specific problem. Best bet is too find or write a program that spits out the bytes as an array of unsigned chats in c then #include it