// ::Packer::Includes::CFiles::Start:: #include "packer.h" #include "fastlz/fastlz.c" #include "assets.c" #ifdef _WIN32 # include #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::