module dlib.assets; import includes; 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 = 3; const u32 MODEL_VERSION = 2; /************************* ****** FILE PACKER ****** *************************/ 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; } struct PackedMaterial { StringID name; Vec3[MatColor.max] colors; StringHeader[MatMap.max] maps; } struct PackedModel { StringID name; PackedMaterial[] mats; Vertex[] vtx; u32[] idx; string[] strs; } /************************* ****** FILE PACKER ****** *************************/ /************************ *** ASSET STRUCTURES *** ************************/ alias StringID = u64; enum AssetType : u32 { None, Model, Shader, Texture, } alias AT = AssetType; struct AssetInfo { u64 hash; u64 offset; u64 length; AssetType type; } struct Mesh { Vertex[] vtx; u32[] idx; } struct MeshPart { u64 start; u64 length; } struct ModelData { string name; Mesh[] meshes; MaterialData[] mats; } struct MaterialMap { u32 texture_id; Vec4 color; f32 value; } struct Material { u32 shader_id; MaterialMap[] maps; Vec4 params; } struct MaterialData { string name; Vec3[MatColor.max] colors; string[MatMap.max] maps; f32[MatFloat.max] props = 0.0; IllumModel illum; } struct StringHeader { u32 id; u32 length; } /************************ *** ASSET STRUCTURES *** ************************/ /************************** ***** GFX STRUCTURES ***** **************************/ struct Vertex { Vec4 color; Vec4 tangent; Vec3 pos; Vec3 normal; Vec2 uv; Vec2 uv2; } enum IllumModel : u32 { Color = 0, ColorAmbient, Highlight, ReflectionRayTrace, GlassRayTrace, FresnelRayTrace, RefractionRayTrace, RefractionFresnelRayTrace, Reflection, Glass, ShadowsInvis, } enum MatColor : u32 { Ambient, Albedo, Specular, Transmission, Emissive, Max, } enum MatFloat : u32 { SpecularExp, Alpha, OpticalDensity, Roughness, Metallic, ClearcoatThickness, ClearcoatRoughness, Anisotropy, Sheen, Max, } enum MatMap : u32 { Ambient, Albedo, Specular, SpecularHighlight, Alpha, Bump, Displacement, Roughness, Metallic, Emissive, Anisotropy, Normal, Sheen, Stencil, Max, } /************************** ***** GFX STRUCTURES ***** **************************/ bool Asset_Pack_Opened = false; debug { void SetAssetsDir(string dir) { assert(ChDir(dir)); } u8[] LoadAssetData(Arena* arena, string name) { File f; try { f = File(name, "rb"); } catch (ErrnoException e) { assert(false, "Unable to open file"); } u8[] mem = Alloc!(u8)(arena, f.size()); return f.rawRead(mem); } } else { void OpenAssetPack(string file_path) { if(!Asset_Pack_Opened) { bool success = true; // 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 = Alloc!(AssetInfo)(Asset_Header.asset_count); Asset_Data = Alloc!(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() { assert(Asset_Pack_Opened); } 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 = Alloc!(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] = Alloc!(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) { Free(Asset_Data[i]); break; } } } } } PackedModel Convert(Arena* arena, ModelData* md) { PackedModel packed = { name: 0, strs: Alloc!(string)(arena, 1+md.mats.length), }; packed.strs[0] = Alloc(arena, md.name); return packed; }