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; enum AssetType : u32 { None, ModelObj, 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; MaterialData[] materials; TextureInfo[] textures; } struct MaterialData { string name; Vec3[MatColor.max] colors; string[MatMap.max] maps; f32[MatFloat.max] props = 0.0; IllumModel illum; } 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; } enum MatProp { None, Ambient, Albedo, Specular, SpecularExp, Dissolve, // Transparency 1.0 -> opaque Transparency, // Transparency 0.0 -> opaque Transmission, OpticalDensity, Illumination, AmbientMap, AlbedoMap, SpecularMap, SpecularHighlightMap, AlphaMap, BumpMap, DisplacementMap, Stencil, Roughness, RoughnessMap, Metallic, MetallicMap, Sheen, SheenMap, ClearcoatThickness, ClearcoatRoughness, Emissive, EmissiveMap, Anisotropy, AnisotropyMap, NormalMap, } 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, } bool Asset_Pack_Opened = false; MatProp GetMatProp(string str) { switch(str) with(MatProp) { // Vec3 case "Ka": return Ambient; case "Kd": return Albedo; case "Ks": return Specular; case "Tf": return Transmission; case "Ke": return Emissive; // Illum case "illum": return Illumination; // string case "map_Ka": return AmbientMap; case "map_Kd": return AlbedoMap; case "map_Ks": return SpecularMap; case "map_Ns": return SpecularHighlightMap; case "map_d": return AlphaMap; case "map_bump": case "bump": return BumpMap; case "map_Pr": return RoughnessMap; case "map_Pm": return MetallicMap; case "map_Ke": return EmissiveMap; case "map_Ps": return SheenMap; case "norm": return NormalMap; case "anisor": return AnisotropyMap; case "disp": return DisplacementMap; case "decal": return Stencil; // f32 case "Ns": return SpecularExp; case "d": return Dissolve; case "Tr": return Transparency; case "Ni": return OpticalDensity; case "Pr": return Roughness; case "Pm": return Metallic; case "Pc": return ClearcoatThickness; case "Pcr": return ClearcoatRoughness; case "aniso": return Anisotropy; case "Ps": return Sheen; default: return None; } } MatColor GetMatColor(MatProp prop) { switch(prop) with(MatProp) { case Ambient: return MatColor.Ambient; case Albedo: return MatColor.Albedo; case Specular: return MatColor.Specular; case Transmission: return MatColor.Transmission; case Emissive: return MatColor.Emissive; default: assert(false, "Unknown MatProp to MatColor conversion"); } } MatFloat GetMatFloat(MatProp prop) { switch(prop) with(MatProp) { case SpecularExp: return MatFloat.SpecularExp; case Transparency: case Dissolve: return MatFloat.Alpha; case OpticalDensity: return MatFloat.OpticalDensity; case Roughness: return MatFloat.Roughness; case Metallic: return MatFloat.Metallic; case ClearcoatThickness: return MatFloat.ClearcoatThickness; case ClearcoatRoughness: return MatFloat.ClearcoatRoughness; case Anisotropy: return MatFloat.Anisotropy; case Sheen: return MatFloat.Sheen; default: assert(false, "Unknown MatProp to MatFloat conversion"); } } MatMap GetMatMap(MatProp prop) { switch(prop) with(MatProp) { case AmbientMap: return MatMap.Ambient; case AlbedoMap: return MatMap.Albedo; case SpecularMap: return MatMap.Specular; case SpecularHighlightMap: return MatMap.SpecularHighlight; case AlphaMap: return MatMap.Alpha; case BumpMap: return MatMap.Bump; case RoughnessMap: return MatMap.Roughness; case MetallicMap: return MatMap.Metallic; case EmissiveMap: return MatMap.Emissive; case SheenMap: return MatMap.Sheen; case NormalMap: return MatMap.Normal; case AnisotropyMap: return MatMap.Anisotropy; case DisplacementMap: return MatMap.Displacement; case Stencil: return MatMap.Ambient; default: assert(false, "Unknown MatProp to MatMap conversion"); } } MatMap GetMatMap(string str) { return GetMatMap(GetMatProp(str)); } MatFloat GetMatFloat(string str) { return GetMatFloat(GetMatProp(str)); } MatColor GetMatColor(string str) { return GetMatColor(GetMatProp(str)); } 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; } } } } } unittest { { MatProp prop = GetMatProp("Ka"); } }