module dlib.assets; import dlib.aliases; import dlib.util; import dlib.alloc; import std.file; import std.stdio; import std.exception; File Asset_File; FileHeader Asset_Header; AssetInfo[] Asset_Info; u8[][] Asset_Data; const u32 FILE_VERSION = 2; const u32 MODEL_VERSION = 1; enum AssetType : u32 { None, ModelM3D, Shader, Texture, } alias AT = AssetType; struct FileHeader { u32 magic; u32 file_version; u64 asset_count; u64 asset_info_offset; } struct ModelHeader { u32 magic; u32 model_version; u64 vertex_count; u64 vertex_offset; u64 index_count; u64 index_offset; u64 material_count; u64 material_offset; u64 texture_count; u64 texture_offset; } struct Vertex { Vec4 color; Vec4 tangent; Vec3 pos; Vec3 normal; Vec2 uv; } struct ModelData { Vertex[] vertices; u32[] indices; Material[] materials; TextureInfo[] textures; } struct Material { Vec4 ambient; Vec4 albedo; Vec4 specular; u32 albedo_texture; u32 ambient_texture; u32 specular_texture; u32 alpha_texture; b32 albedo_has_texture; b32 ambient_has_texture; b32 specular_has_texture; b32 alpha_has_texture; f32 shininess = 0.0; f32 alpha = 0.0; } struct TextureInfo { string name; u32 id; } struct TextureHeader { u64 str_length; u64 str_offset; u32 texture_id; } struct ModelMeta { u64 index_count; } struct TexData { void* data; TexMeta meta; } struct TexMeta { u32 w; u32 h; u32 ch; } struct AssetInfo { u64 hash; u64 offset; u64 length; AssetType type; } bool Asset_Pack_Opened = false; debug { bool g_DIR_SET = false; void SetDir() { if (exists("assets")) { chdir("./assets"); } else if (exists("Gears") || exists("Gears.exe")) { chdir("../assets"); } else { assert(false, "Unable to set directory"); } g_DIR_SET = true; } u8[] LoadAssetData(Arena* arena, string name) { if (!g_DIR_SET) { SetDir(); } File f; try { f = File(name, "rb"); } catch (ErrnoException e) { assert(false, "Unable to open file"); } u8[] mem = AllocArray!(u8)(arena, f.size()); return f.rawRead(mem); } } else { void OpenAssetPack() { if (!Asset_Pack_Opened) { bool success = true; string file_path = exists("build/assets.sgp") ? "build/assets.sgp" : "assets.sgp"; // TODO: replace this with something that doesn't throw an exception and figure out if this is the best way to handle thing (probably isnt) try { Asset_File = File(file_path, "rb"); } catch (ErrnoException e) { Logf("OpenAssetPack failure: Unable to open file %s", file_path); assert(false, "Unable to open asset pack file"); } FileHeader[1] header_arr; Asset_File.rawRead(header_arr); Asset_Header = header_arr[0]; Asset_Info = AllocArray!(AssetInfo)(Asset_Header.asset_count); Asset_Data = AllocArray!(u8[])(Asset_Header.asset_count); assert(Asset_Header.file_version == FILE_VERSION, "OpenAssetPack failure: file version incorrect"); Asset_File.seek(Asset_Header.asset_info_offset); Asset_File.rawRead(Asset_Info); } } pragma(inline) void CheckAssetPack() { if (!Asset_Pack_Opened) { OpenAssetPack(); } } AssetInfo GetAssetInfo(string name) { CheckAssetPack(); u64 hash = Hash(name); AssetInfo asset_info; foreach(i, info; Asset_Info) { if (info.hash == hash) { asset_info = info; break; } } assert(asset_info.hash != 0, "GetAssetInfo failure: unable to find matching asset"); return asset_info; } u8[] LoadAssetData(Arena* arena, string name) { CheckAssetPack(); u64 hash = Hash(name); u8[] data = null; foreach(i, info; Asset_Info) { if (info.hash == hash) { data = AllocArray!(u8)(arena, info.length); Asset_File.seek(info.offset); Asset_File.rawRead(data); assert(data != null && data.length == info.length, "LoadAssetData failure: Asset data loaded incorrectly"); break; } } return data; } u8[] LoadAssetData(string name) { CheckAssetPack(); u64 hash = Hash(name); u8[] data = null; foreach(i, info; Asset_Info) { if (info.hash == hash) { if (Asset_Data[i].ptr == null) { Asset_Data[i] = AllocArray!(u8)(info.length); Asset_File.seek(info.offset); Asset_File.rawRead(Asset_Data[i]); assert(Asset_Data[i] != null && Asset_Data[i].length == info.length, "LoadAssetData failure: Asset data loaded incorrectly."); } data = Asset_Data[i]; break; } } return data; } void UnloadAssetData(string name) { u64 hash = Hash(name); foreach(i, info; Asset_Info) { if (info.hash == hash) { if (Asset_Data[i] != null) { FreeArray(Asset_Data[i]); break; } } } } }