// ::Packer::Includes::CFiles::Start:: #include "packer.h" #include "xxhash/xxhash.c" #include "fastlz/fastlz.c" #include "platform/platform.c" #include "ds.c" #include "util.c" #include "allocators.c" #include "renderer.c" #include "game.c" // ::Packer::Includes::CFiles::End:: // ::Packer::Globals::Start:: const FileMapping g_Shader_File_Map[] = { { .file_name = "quad.frag.spv", .ix = QUAD_FRAG_SPIRV_SHADER }, { .file_name = "quad.vert.spv", .ix = QUAD_VERT_SPIRV_SHADER }, { .file_name = "gui.frag.spv", .ix = GUI_FRAG_SPIRV_SHADER }, { .file_name = "gui.vert.spv", .ix = GUI_VERT_SPIRV_SHADER }, }; const FileMapping g_Texture_File_Map[] = { { .file_name = "pattermon.png", .ix = PATTERMON_OBESE }, { .file_name = "patamon.png", .ix = PATTERMON_ORIENTAL }, { .file_name = "purplemon.png", .ix = PATTERMON_PURPLOID }, }; c8 *g_Shader_File_Names[SHADER_ASSET_MAX] = {0}; c8 *g_Texture_File_Names[TEXTURE_ASSET_MAX] = {0}; // ::Packer::Globals::End:: // ::Packer::Files::Functions::Start:: u64 FileLength(FILE *file) { Assert(fseek(file, 0, SEEK_END) == 0, "fseek failure"); return (u64)ftell(file); } u64 WriteData(void *buf, u64 pos, u64 size, FILE *file) { Assert(fseek(file, pos, SEEK_SET) == 0, "WriteData fseek failure"); u64 written = (u64)FWrite(buf, size, 1, file); fflush(file); return written; } u64 ReadData(void *buf, u64 pos, u64 size, FILE *file) { Assert(fseek(file, pos, SEEK_SET) == 0, "ReadData fseek failure"); return FRead(buf, size, 1, file); } FILE *OpenFile(c8 *name, c8 *mode) { FILE *file = fopen(name, mode); Assert(file != NULL, "OpenFile: file is null"); return file; } void CloseFile(FILE *file) { Assert(fclose(file) != EOF, "Error closing file"); } // ::Packer::Files::Functions::End:: // ::Packer::Packing::Functions::Start:: void SetArrayLookups() { for (i32 i = 0; i < Len(g_Shader_File_Map); i++) { FileMapping file_mapping = g_Shader_File_Map[i]; g_Shader_File_Names[file_mapping.ix] = file_mapping.file_name; } for (int i = 0; i < SHADER_ASSET_MAX; i++) { Assert(g_Shader_File_Names[i] != NULL, "Spirv shader file name is null"); } for (i32 i = 0; i < Len(g_Texture_File_Map); i++) { FileMapping file_mapping = g_Texture_File_Map[i]; g_Texture_File_Names[file_mapping.ix] = file_mapping.file_name; } for (int i = 0; i < TEXTURE_ASSET_MAX; i++) { Assert(g_Texture_File_Names[i] != NULL, "Texture file name is null"); } } i32 WriteHeader(FILE *file, FileHeader *header) { i32 offset = 0; return offset; } void MoveToShaderDir(c8 **return_dir) { if (DirVisible("build")) { Assert(ChangeDir("./build/shaders/glsl") == 0, "Unable to change to shader directory"); *return_dir = "../../.."; } else if (DirVisible("shaders")) { Assert(ChangeDir("./shaders/glsl") == 0 , "Unable to change to shader directory"); *return_dir = "../.."; } else Assert(false, "Unable to find shader directory"); } void MoveToTextureDir(c8 **return_dir) { if (DirVisible("assets")) { Assert(ChangeDir("./assets") == 0, "Unable to change to assets directory"); *return_dir = ".."; } else if (DirVisible("shaders")) { Assert(ChangeDir("../assets") == 0, "Unable to change to assets directory"); *return_dir = "../build"; } else Assert(false, "Unable to find assets directory"); } 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] = SHADER_ASSET_MAX; header->tag_counts[SHADER_ASSET] = 0; header->asset_counts[TEXTURE_ASSET] = TEXTURE_ASSET_MAX; header->tag_counts[TEXTURE_ASSET] = TEXTURE_ASSET_TAG_MAX; header->asset_counts[SOUND_ASSET] = SOUND_ASSET_MAX; header->tag_counts[SOUND_ASSET] = SOUND_ASSET_TAG_MAX; header->asset_counts[MODEL_ASSET] = MODEL_ASSET_MAX; header->tag_counts[MODEL_ASSET] = MODEL_ASSET_TAG_MAX; u64 offset = sizeof(FileHeader); for (u32 i = 0; i < ASSET_TYPE_MAX; i++) { if (header->tag_counts[i] > 0) { header->tag_offsets[i] = offset; offset += sizeof(AssetTag) * header->tag_counts[i]; } else header->tag_offsets[i] = 0; if (header->asset_counts[i] > 0) { header->asset_offsets[i] = offset; offset += sizeof(AssetFile) * header->asset_counts[i]; } else header->asset_offsets[i] = 0; } } void PackFiles(Arena *arena, FileHeader *header) { FILE *file = OpenFile("assets.sgp", "w+"); u64 file_pos = WriteData(header, 0, sizeof(FileHeader), file); u64 data_offset = 0; for (u32 i = 0; i < ASSET_TYPE_MAX; i++) { u64 tag_offset = header->tag_offsets[i] + (header->tag_counts[i] * sizeof(AssetTag)); if (tag_offset > data_offset) data_offset = tag_offset; u64 asset_offset = header->asset_offsets[i] + (header->asset_counts[i] * sizeof(AssetFile)); if (asset_offset > data_offset) data_offset = asset_offset; } c8 *return_dir = "."; u32 file_count; MoveToShaderDir(&return_dir); AssetFile *shader_assets = MakeArray(arena, AssetFile, SHADER_ASSET_MAX); for (u32 i = 0; i < SHADER_ASSET_MAX; i++) { c8 *asset_name = g_Shader_File_Names[i]; Printfln("Packing file: %s...", asset_name); FILE *asset_file = OpenFile(asset_name, "r"); u64 file_size = FileLength(asset_file); u8 *file_data = MakeArray(arena, u8, file_size); ReadData(file_data, 0, file_size, asset_file); u64 prev_offset = data_offset; data_offset += WriteData(file_data, data_offset, file_size, file); Assert((data_offset - prev_offset) == file_size, "File write size invalid"); shader_assets[i].data_offset = prev_offset; shader_assets[i].len = file_size; CloseFile(asset_file); } Assert(ChangeDir(return_dir) == 0, "Unable to return to previous directory"); MoveToTextureDir(&return_dir); AssetFile *texture_assets = MakeArray(arena, AssetFile, TEXTURE_ASSET_MAX); for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++) { c8 *asset_name = g_Texture_File_Names[i]; Printfln("Packing file: %s...", asset_name); FILE *asset_file = OpenFile(asset_name, "r"); u64 file_size = FileLength(asset_file); u8 *file_data = MakeArray(arena, u8, file_size); ReadData(file_data, 0, file_size, asset_file); u64 prev_offset = data_offset; Printfln("data_offset %llu", data_offset); data_offset += WriteData(file_data, data_offset, file_size, file); Assert((data_offset - prev_offset) == file_size, "File write size invalid"); texture_assets[i].data_offset = prev_offset; texture_assets[i].len = file_size; CloseFile(asset_file); } WriteData(shader_assets, header->asset_offsets[SHADER_ASSET], sizeof(AssetFile)*SHADER_ASSET_MAX, file); WriteData(texture_assets, header->asset_offsets[TEXTURE_ASSET], sizeof(AssetFile)*TEXTURE_ASSET_MAX, file); ChangeDir(return_dir); } // ::Packer::Packing::Functions::End:: // ::Packer::Tests::Functions::Start:: static inline void TestAssetIsCorrect(Arena *arena, c8 *file_name, AssetFile *file_info, FILE *file) { Printfln("Testing file %s...", file_name); FILE *asset_file = OpenFile(file_name, "r"); u64 size = FileLength(asset_file); u8 *file_data = MakeArray(arena, u8, size); u64 write_count = ReadData(file_data, 0, size, asset_file); Assert(write_count == size, "Incorrect asset size retrieved"); Printfln("len %llu size %llu", file_info->len, size); Assert(file_info->len == size, "file length incorrect"); u8 *packed_asset = MakeArray(arena, u8, file_info->len); ReadData(packed_asset, file_info->data_offset, file_info->len, file); for (u64 i = 0; i < size; i++) { Assert(file_data[i] == packed_asset[i], "Asset file data is invalid"); } CloseFile(asset_file); } void TestAssetPack(Arena *arena) { FILE *file = OpenFile("assets.sgp", "r"); FileHeader header; i64 offset = FRead(&header, sizeof(FileHeader), 1, file); Assert(header.magic_num == CreateMagicValue('s', 't', 'e', 'g'), "Magic number is incorrect"); Assert(header.version == FILE_VERSION, "File version is incorrect"); Assert(header.tag_counts[SHADER_ASSET] == 0, "Shader tag count incorrect"); Assert(header.asset_counts[SHADER_ASSET] == SHADER_ASSET_MAX, "Shader count incorrect"); Assert(header.tag_counts[TEXTURE_ASSET] == TEXTURE_ASSET_TAG_MAX, "Texture tag count incorrect"); Assert(header.asset_counts[TEXTURE_ASSET] == TEXTURE_ASSET_MAX, "Texture count incorrect"); Assert(header.tag_counts[SOUND_ASSET] == SOUND_ASSET_TAG_MAX, "Sound tag count incorrect"); Assert(header.asset_counts[SOUND_ASSET] == SOUND_ASSET_MAX, "Sound count incorrect"); Assert(header.tag_counts[MODEL_ASSET] == MODEL_ASSET_TAG_MAX, "Model tag count incorrect"); Assert(header.asset_counts[MODEL_ASSET] == MODEL_ASSET_MAX, "Model count incorrect"); AssetTag *tags[ASSET_TYPE_MAX]; AssetFile *files[ASSET_TYPE_MAX]; for (u32 i = 0; i < ASSET_TYPE_MAX; i++) { if (header.tag_counts[i] > 0) { tags[i] = MakeArray(arena, AssetTag, header.tag_counts[i]); ReadData(tags[i], header.tag_offsets[i], sizeof(AssetTag)*header.tag_counts[i], file); } if (header.asset_counts[i] > 0) { files[i] = MakeArray(arena, AssetFile, header.asset_counts[i]); Printfln("Reading asset info from %llu...", header.asset_offsets[i]); ReadData(files[i], header.asset_offsets[i], sizeof(AssetFile)*header.asset_counts[i], file); } } for (u32 i = 0; i < SHADER_ASSET_MAX; i++) { Printfln("offset %llu len %llu", files[SHADER_ASSET][i].data_offset, files[SHADER_ASSET][i].len); } for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++) { Printfln("offset %llu len %llu", files[TEXTURE_ASSET][i].data_offset, files[TEXTURE_ASSET][i].len); } c8 *return_dir = "."; MoveToShaderDir(&return_dir); for (u32 i = 0; i < SHADER_ASSET_MAX; i++) { TestAssetIsCorrect(arena, g_Shader_File_Names[i], &files[SHADER_ASSET][i], file); } ChangeDir(return_dir); MoveToTextureDir(&return_dir); for (u32 i = 0; i < TEXTURE_ASSET_MAX; i++) { TestAssetIsCorrect(arena, g_Texture_File_Names[i], &files[TEXTURE_ASSET][i], file); } } // ::Packer::Tests::Functions::End:: // ::Packer::Main::Functions::Start:: int main(int argc, c8 **argv) { Printfln("Header: %d", sizeof(FileHeader)); SetArrayLookups(); void *mem = MemAllocZeroed(GB(1)); Arena *arena = CreateArenaDebug(mem, GB(1), __LINE__); FILE *file = fopen("assets.sgp", "w+"); Assert(file != NULL, "File is null"); FileHeader header = {0}; InitHeader(&header); PackFiles(arena, &header); CloseFile(file); TestAssetPack(arena); } // ::Packer::Main::Functions::End::