c-rez is a small tool to generate C
arrays of data from a list of
input files. You can then compile them in your project and reference
them just as regular variables.
It features:
- An easy to use command-line tool
- A neat CMake interface for CMake users
- Allows you to reference assets both as strings
(
c_rez_resource("sprites.png")
) and as a variables (sprites_png
) - Written in portable C89 code
- Generates portable C89 code
- Its MIT licensed
You might be wondering why would anyone ever need this tool since there are many ways of opening and reading a file, below are some of my reasons:
- Cross-platform resource loading is a pain in the arse (specially when targeting mobile devices (I'm looking at you, Android Assets))
- Cross-platform resource bundling is even worse
- No loading time, your assets are available as soon as
main
starts (even before!) - No loose files, you can distribute a single executable file
- Asset bundling is now part of the compile and link process.
Of course, there are downsides:
- Makes your executable very very big depending on the size of your assets
- Which in turn makes it slow to load
- Depending on the final size of your app, the device might decide not to load it
- You have no way of freeing up the loaded memory once you're done using the asset
- No way of deciding what not to load at runtime. It is always all or
nothing (you can go around this by making your assets a shared library
and then loading them with
dlopen
, but if you're doing this you might as well use plain oldfopen
)
A struct type is declared and used to represent each processed file. This is how the struct looks:
typedef struct c_rez_resource {
unsigned char const * const data;
unsigned int const length;
} c_rez_resource;
The path of input files given to the c-rez tool will be used to generate
an identifier. This identifier will be the variable name declared
in the .h
file and defined it in the .c
file. c-rez also accepts a key
that will be part of the generated identifiers.
For instance, if you pass a resource file img/sprites.png
and key
resources
, the .h
file will have a variable called
resources_img_sprites_png
that will have a data
member pointing to its
bytes and a length
member with the byte count.
You can also use the function c_rez_locate_resources("img/sprites.png")
, it
will return &resources_img_sprites_png
Suppose you generate an img.h
header file, it would look like this:
#ifndef c_rez_resources_img_h
#define c_rez_resources_img_h
#ifdef __cplusplus
extern "C" {
#endif
#ifndef c_rez_resource_struct
#define c_rez_resource_struct
typedef struct c_rez_resource {
unsigned char const * const data;
unsigned int const length;
} c_rez_resource;
#endif /* c_rez_resource_struct */
extern c_rez_resource const resources_img_sprites_png;
struct c_rez_resource const * c_rez_locate_resources(const char name[]);
#ifdef __cplusplus
}
#endif
#endif /* c_rez_resources_img_h */
Aftwewards you can #include
it in your project and use the generated structs
to get to your data:
#include "resources/img.h"
int main() {
printf("sprites.png length: %u\n", resources_img_sprites_png.length);
printf("address of sprites.png: %p\n", c_rez_locate_resources("img/sprites.png");
return 0;
}
You can then either commit these files to your project or make it part of your build process.
Refer to either CMake usage or Command-line tool on how to generate and use these files in your project.
c-rez is ready to be used as a sub-project. Simply download the
source archive and use add_subdirectory
before adding targets using
c-rez
add_subdirectory(path/to/c-rez)
You can either compile from source or install a release archive.
Compile from source
- Have a compiler environment ready (GCC, LLVM, MSVC, MinGW, etc);
- Have CMake 3.0 (minimum) installed;
- Download this repository;
- Create a
build
folder inside it; - Run
cmake
(orcmake-gui
), set the binary dir to the newly created build folder and the source dir to the repository folder; - build it with
cmake --build . --target c-rez
- Alternatively, you can open the generated project files and build them in your IDE
- Install it with
cmake --build . --target install
(you might need to use sudo here or to adjustCMAKE_INSTALL_PREFIX
)- If using it inside an IDE, run the INSTALL target
Install a release
- Download a suitable archive from the releases section
- Unzip it somewhere you can later find with CMake (you may need to
adjust the
CMAKE_PREFIX_PATH
of your project)
Add package
Use find_package
to add it to your project:
list(APPEND CMAKE_PREFIX_PATH /path/to/c-rez/prefix)
find_package(c-rez REQUIRED)
After using either find_package
or add_subdirectory
, a new CMake
function will be available: add_c_rez
. This function will create a new
C
STATIC library under the c-rez
namespace that you can link your
targets to:
add_executable(mygame mygame.c engine.c)
add_c_rez(images
assets/tileset.png
assets/sprites.png
assets/gui.png
)
target_link_libraries(mygame c-rez::images)
If you place the word TEXT
before a path, it will be treated as text and a
\0
terminating byte will be appended to its data:
add_c_rez(texts
TEXT texts/chapter01.txt
TEXT texts/chapter02.txt
TEXT texts/chapter03.txt
)
The header files for your target will be under a c-rez
folder in your build
path (different targets might not be in the same path, though)
#include "c-rez/images.h"
#include "c-rez/texts.h"
If added to your PATH
, you can call c-rez as a command line tool to
generate a header
and/or source files:
c-rez -k <resource key> [-h <output.h>] [-c <output.c>] [--text] <input_1> [[--text] <input_2>] [[--text] <input_n>]*
- -h <file.h>: specifies the header output file. If omitted, only source gets generated.
- -c <file.c>: specifies the source output file. If omitted, only header gets generated.
- -k <resource key>: specifies a key to identify this resource. It will be used in header guards and resource functions.
- --text: appends
\0
when processing the next <input> file. This helps when using its data as a string resource. - <input>: space separated list of files to read from.
Declarations and definitions will be generated based on the file name. If
--text
is specified before the file name,\0
will be appended after processing.
c-rez is MIT-licensed.