Gears-C/src/packer.c
2025-06-02 06:21:44 +10:00

300 lines
7.9 KiB
C

// ::Packer::Includes::CFiles::Start::
#include "packer.h"
#include "fastlz/fastlz.c"
#include "assets.c"
#ifdef _WIN32
# include <fcntl.h>
#endif
// ::Packer::Packing::Functions::Start::
i32
WriteHeader(pFile file, FileHeader *header)
{
i32 offset = 0;
return offset;
}
void
MoveToShaderDir(c8 **return_dir)
{
Assert(pDirNavigate("../assets/shaders") == 0, "Unable to change to shader directory");
*return_dir = "../../build";
}
void
MoveToTextureDir(c8 **return_dir)
{
Assert(pDirNavigate("../assets/textures") == 0, "Unable to change to assets directory");
*return_dir = "../../build";
}
void
MoveToModelDir(c8 **return_dir)
{
Assert(pDirNavigate("../assets/models") == 0, "Unable to change to assets directory");
*return_dir = "../../build";
}
void
InitHeader(FileHeader *header)
{
Assert(header != NULL, "File header is null");
header->magic_num = CreateMagicValue('s', 't', 'e', 'g');
header->version = FILE_VERSION;
header->asset_counts = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
header->asset_offset = sizeof(FileHeader);
}
void
PackFiles(Arena *arena, FileHeader *header)
{
pFile file = pFileOpen("assets.sgp", pFS_WRITE | pFS_TRUNC | pFS_CREATE);
u64 file_pos = pFileWrite(file, 0, header, sizeof(FileHeader));
Assert(pDirNavigate("../assets") == 0, "Unable to move to assets directory");
u64 total_assets = SHADER_ASSET_MAX + TEXTURE_ASSET_MAX + MODEL_ASSET_MAX;
u64 asset_count = 0;
AssetFile *assets = MakeArray(arena, AssetFile, total_assets);
u64 data_offset = header->asset_offset + (sizeof(AssetFile) * total_assets);
Printfln("%llu %d", data_offset, sizeof(FileHeader));
for (u32 i = 0; i < SHADER_ASSET_MAX; i++, asset_count++)
{
c8 *asset_name = g_Shader_Asset_Names[i];
Printfln("Packing file: %s at offset %llu...", asset_name, data_offset);
pFile asset_file = pFileOpen(asset_name, pFS_READ);
u64 file_size = pFileLength(asset_file);
u8 *file_data = MakeArray(arena, u8, file_size);
pFileRead(asset_file, 0, file_data, file_size);
u64 prev_offset = data_offset;
data_offset += pFileWrite(file, prev_offset, file_data, file_size);
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
assets[asset_count].data_offset = prev_offset;
assets[asset_count].len = file_size;
assets[asset_count].type = AT_SHADER;
assets[asset_count].hash = g_Shader_Asset_Hashes[i];
pFileClose(asset_file);
}
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, asset_count++)
{
c8 *asset_name = g_Texture_Asset_Names[i];
Printfln("Packing file: %s at offset %llu...", asset_name, data_offset);
pFile asset_file = pFileOpen(asset_name, pFS_READ);
u64 file_size = pFileLength(asset_file);
u8 *file_data = MakeArray(arena, u8, file_size);
pFileRead(asset_file, 0, file_data, file_size);
int ch = 4;
int w, h, has_ch;
u8 *image_bytes = stbi_load_from_memory(file_data, file_size, &w, &h, &has_ch, ch);
if (w <= 0 || h <= 0 || has_ch <= 0)
{
Printfln("%s", stbi_failure_reason());
Assert(0, "stbi_load_from_memory failure");
}
u64 loaded_length = u64(w * h * ch);
u64 prev_offset = data_offset;
data_offset += pFileWrite(file, data_offset, image_bytes, loaded_length);
Assert((data_offset - prev_offset) == loaded_length, "File write size invalid");
assets[asset_count].data_offset = prev_offset;
assets[asset_count].len = loaded_length;
assets[asset_count].type = AT_TEXTURE;
assets[asset_count].hash = g_Texture_Asset_Hashes[i];
assets[asset_count].texture_meta.w = u32(w);
assets[asset_count].texture_meta.h = u32(h);
assets[asset_count].texture_meta.ch = u32(ch);
stbi_image_free(image_bytes);
pFileClose(asset_file);
}
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, asset_count++)
{
c8 *asset_name = g_Model_Asset_Names[i];
Printfln("Packing file: %s at offset %llu...", asset_name, data_offset);
pFile asset_file = pFileOpen(asset_name, pFS_READ);
u64 file_size = pFileLength(asset_file);
u8 *file_data = MakeArray(arena, u8, file_size);
pFileRead(asset_file, 0, file_data, file_size);
u64 prev_offset = data_offset;
data_offset += pFileWrite(file, data_offset, file_data, file_size);
Assert((data_offset - prev_offset) == file_size, "File write size invalid");
m3d_t *model = m3d_load(file_data, NULL, NULL, NULL);
assets[asset_count].data_offset = prev_offset;
assets[asset_count].type = AT_MODEL;
assets[asset_count].len = file_size;
assets[asset_count].hash = g_Model_Asset_Hashes[i];
assets[asset_count].model_meta.i_count = u64(model->numface * 3);
m3d_free(model);
pFileClose(asset_file);
}
pFileWrite(file, header->asset_offset, assets, sizeof(AssetFile)*asset_count);
pFileClose(file);
Assert(pDirNavigate("../build") == 0, "Unable to navigate back to build directory");
}
// ::Packer::Packing::Functions::End::
// ::Packer::Tests::Functions::Start::
static inline void
TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, pFile file)
{
pFile asset_file = pFileOpen(file_name, pFS_READ);
u64 size = pFileLength(asset_file);
u8 *file_data = MakeArray(arena, u8, size);
u64 write_count = pFileRead(asset_file, 0, file_data, size);
Assert(write_count == size, "Incorrect asset size retrieved");
u8 *packed_asset = MakeArray(arena, u8, file_info->len);
pFileRead(file, file_info->data_offset, packed_asset, file_info->len);
u8 *image_bytes;
u64 image_length;
if (file_info->type == TEXTURE_ASSET)
{
int ch = 4;
int w, h, has_ch;
image_bytes = stbi_load_from_memory(file_data, size, &w, &h, &has_ch, ch);
image_length = u64(w * h * ch);
Assert(file_info->len == image_length, "file length incorrect");
for (u64 i = 0; i < image_length; i++)
{
Assert(image_bytes[i] == packed_asset[i], "Asset file data is invalid");
}
stbi_image_free(image_bytes);
}
else
{
Assert(file_info->len == size, "file length incorrect");
for (u64 i = 0; i < size; i++)
{
Assert(file_data[i] == packed_asset[i], "Asset file data is invalid");
}
}
pFileClose(asset_file);
}
void
TestAssetPack(Arena *arena)
{
pFile file = pFileOpen("assets.sgp", pFS_READ);
Assert(pDirNavigate("../assets") == 0, "Unable to navigate back to assets directory");
FileHeader header;
i64 offset = pFileRead(file, 0, &header, sizeof(FileHeader));
u64 asset_count = SHADER_ASSET_MAX + MODEL_ASSET_MAX + TEXTURE_ASSET_MAX;
Assert(header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic number is incorrect");
Assert(header.version == FILE_VERSION, "File version is incorrect");
Assert(header.asset_counts == asset_count, "Asset count incorrect");
AssetFile *files = MakeArray(arena, AssetFile, asset_count);
pFileRead(file, header.asset_offset, files, sizeof(AssetFile)*header.asset_counts);
u64 current_asset = 0;
for (u32 i = 0; i < SHADER_ASSET_MAX; i++, current_asset++)
{
TestAssetIsCorrect(arena, g_Shader_Asset_Names[i], files + current_asset, file);
Assert(files[current_asset].hash == g_Shader_Asset_Hashes[i], "Shader asset hash mismatch");
}
for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++, current_asset++)
{
TestAssetIsCorrect(arena, g_Texture_Asset_Names[i], files + current_asset, file);
Assert(files[current_asset].hash == g_Texture_Asset_Hashes[i], "Texture asset hash mismatch");
}
for (u32 i = 0; i < MODEL_ASSET_MAX; i++, current_asset++)
{
TestAssetIsCorrect(arena, g_Model_Asset_Names[i], files + current_asset, file);
Assert(files[current_asset].hash == g_Model_Asset_Hashes[i], "Model asset hash mismatch");
}
}
// ::Packer::Tests::Functions::End::
// ::Packer::Main::Functions::Start::
int
main(int argc, c8 **argv)
{
#ifdef _WIN32
{
_set_fmode(_O_BINARY);
}
#endif
if (pDirIsVisible("build"))
{
Assert(pDirNavigate("./build") == 0, "Unable to change to build directory");
}
void *mem = pMemAllocZeroed(GB(1));
Arena *arena = ArenaInitDebug(mem, GB(1), __LINE__);
FileHeader header = {0};
InitHeader(&header);
PackFiles(arena, &header);
TestAssetPack(arena);
}
// ::Packer::Main::Functions::End::