From f89bd36b187dd2097ea17ee1966731bbcc12aec0 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 14 Nov 2025 16:25:57 +1100 Subject: [PATCH] delete stuff, start on gltf loading (again) --- assets.d | 642 +++++++++++++++++++++++------------------------ packer.d | 751 ------------------------------------------------------- test.sh | 2 +- util.d | 7 +- 4 files changed, 327 insertions(+), 1075 deletions(-) delete mode 100644 packer.d diff --git a/assets.d b/assets.d index f81f88c..3660e2b 100644 --- a/assets.d +++ b/assets.d @@ -6,21 +6,13 @@ import dlib.util; import dlib.alloc; import std.file; +import std.path; +import std.format; import std.stdio; import std.exception; -File Asset_File; - -FileHeader Asset_Header; - -AssetInfo[] Asset_Info; - -u8[][] Asset_Data; - -__gshared u8[] DEFAULT_TEXTURE = GenerateDefaultTexture(32, 32); - -const u32 FILE_VERSION = 3; -const u32 MODEL_VERSION = 2; +__gshared ImageData DEFAULT_IMAGE = GenerateDefaultTexture(32, 32); +__gshared Material DEFAULT_MATERIAL = GenerateDefaultMaterial(); // TODO: // Alignment? @@ -29,23 +21,6 @@ const u32 MODEL_VERSION = 2; ****** FILE PACKER ****** *************************/ -struct FileHeader -{ - u32 magic; - u32 file_version; - u64 asset_count; - u64 asset_info_offset; - DirHeader base_dir; -} - -struct DirHeader -{ - u32 magic; - u64 hash; - u64 dir_count; - u64 asset_count; -} - /************************* ****** FILE PACKER ****** *************************/ @@ -54,69 +29,18 @@ struct DirHeader *** ASSET STRUCTURES *** ************************/ -alias StringID = u64; - -enum AssetType : u32 +struct ImageData { - None, - Model, - Shader, - Texture, + u8[] data; + u32 w; + u32 h; + u32 ch; } -alias AT = AssetType; - -struct AssetInfo +struct ModelData { - u64 hash; - u64 offset; - u64 length; - AssetType type; -} - -struct Mesh -{ - Vertex[] vtx; - u32[] idx; -} - -struct MeshPart -{ - u64 start; - u64 length; -} - -struct Model -{ - string name; - Mesh[] meshes; - Material[] mats; -} - -struct MaterialMap -{ - u32 texture_id; - Vec4 color; - f32 value; -} - -struct Material -{ - u32 shader_id; - MaterialMap[] maps; - Vec4 params; -} - -struct StringHeader -{ - u32 id; - u32 length; -} - -struct AssetData -{ - AssetType type; - u8[] data; + Model model; + ImageData[] tex; } /************************ @@ -127,6 +51,39 @@ struct AssetData ***** GFX STRUCTURES ***** **************************/ +enum MaterialMapIndex +{ + Albedo, + Normal, + Metallic, + Roughness, + Occlusion, + Emission, + Height, + Cubemap, + Irradiance, + Prefilter, + BRDF, + + Max, +} + +alias MMI = MaterialMapIndex; + +struct MaterialMap +{ + u32 tex_id; + Vec4 col; + f32 value; +} + +struct Material +{ + u32 pipeline_id; + MaterialMap[MMI.max] maps; + Vec4 params; +} + struct Vertex { Vec4 color; @@ -137,281 +94,239 @@ struct Vertex Vec2 uv2; } -enum IllumModel : u32 +struct Mesh { - Color = 0, - ColorAmbient, - Highlight, - ReflectionRayTrace, - GlassRayTrace, - FresnelRayTrace, - RefractionRayTrace, - RefractionFresnelRayTrace, - Reflection, - Glass, - ShadowsInvis, + Vertex[] vtx; + u32 idx; + u32 mat_id; } -enum MatColor : u32 +struct Model { - Ambient, - Albedo, - Specular, - Transmission, - Emissive, + Mat4 transform; - Max, -} + Mesh[] meshes; + Material[] mats; -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, + // TODO: bones/animations } /************************** ***** GFX STRUCTURES ***** **************************/ -bool Asset_Pack_Opened = false; +__gshared string g_BASE_ASSETS_DIR; -debug +static u32 +MagicValue(string str) { - void - SetAssetsDir(string dir) + assert(str.length == 4, "Magic value must 4 characters"); + return cast(u32)(cast(u32)(str[0] << 24) | cast(u32)(str[1] << 16) | cast(u32)(str[2] << 8) | cast(u32)(str[3] << 0)); +} + +void +SetBaseAssetsDir(string dir) +{ + if(!isDir(dir)) { - assert(ChDir(dir)); + assert(false, "Unable to find assets directory"); } - u8[] - LoadAssetData(Arena* arena, string name) - { - File f; - try - { - f = File(name, "rb"); - } - catch (ErrnoException e) - { - assert(false, "Unable to open file"); - } + g_BASE_ASSETS_DIR = dir; +} - u8[] mem = Alloc!(u8)(arena, f.size()); - return f.rawRead(mem); +void +U32ColToVec4(u32 col, Vec4* vec) +{ + if(!col) + { + vec.rgb = 0.0; + vec.a = 1.0; } - - extern (C) cgltf_result - GLTFLoadCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, const(char)* path, cgltf_size* size, void** data) + else { - u8[] file_data = OpenFile(ConvToStr(path[0 .. strlen(path)])); - - if(file_data == null) return cgltf_result_io_error; - - *size = cast(cgltf_size)file_data.length; - *data = Alloc!(u8)(file_data).ptr; - - return cgltf_result_success; - } - - extern (C) void - GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, void* data, cgltf_size size) - { - Free(data[0 .. size]); + vec.r = cast(f32)((col >> 0)&0xFF) / 255; + vec.g = cast(f32)((col >> 8)&0xFF) / 255; + vec.b = cast(f32)((col >> 16)&0xFF) / 255; + vec.a = cast(f32)((col >> 24)&0xFF) / 255; } } -else + +// TODO: make better +u8[] +OpenFile(string file_name) { - void - OpenAssetPack(string file_path) + File f; + u8[] data; + + try { - 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); - } + f = File(file_name, "rb"); + data = Alloc!(u8)(f.size()); + f.rawRead(data); + } + catch(Exception e) + { + data = null; } - pragma(inline) void - CheckAssetPack() + f.close(); + + return data; +} + +extern (C) cgltf_result +GLTFLoadCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, const(char)* path, cgltf_size* size, void** data) +{ + u8[] file_data = OpenFile(ConvToStr(path[0 .. strlen(path)])); + + if(file_data == null) return cgltf_result_io_error; + + *size = cast(cgltf_size)file_data.length; + *data = file_data.ptr; + + return cgltf_result_success; +} + +extern (C) void +GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, void* data, cgltf_size size) +{ + Free(data); +} + +ImageData +LoadImage(void* data, i32 size) +{ + ImageData image; + + i32 w, h, has_ch; + u8* image_bytes = stbi_load_from_memory(cast(const(u8)*)data, size, &w, &h, &has_ch, 4); + if(w <= 0 || h <= 0 || has_ch <= 0) { - assert(Asset_Pack_Opened); + Logf("Failed to load image data"); + } + else + { + image.data = image_bytes[0 .. w*h*has_ch]; + image.w = w; + image.h = h; + image.ch = has_ch; } - AssetInfo - GetAssetInfo(string name) + return image; +} + +void +UnloadImage(ImageData* image) +{ + stbi_image_free(image.data.ptr); +} + +ImageData +LoadImage(cgltf_image* asset_image, string tex_path) +{ + ImageData image; + + if(asset_image) { - CheckAssetPack(); - - u64 hash = Hash(name); - - AssetInfo asset_info; - foreach(i, info; Asset_Info) + if(asset_image.uri != null) { - if(info.hash == hash) + if(strlen(asset_image.uri) > 5 && ConvToStr(asset_image.uri[0 .. 5]) == "data:") { - asset_info = info; - break; - } - } + u32 i; + for(; asset_image.uri[i] != ',' && asset_image.uri[i] != 0; i += 1) {} - 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) + if(asset_image.uri[i] == 0) { - 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."); + Logf("gltf data URI for is not a valid image"); } - - 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) + else { - Free(Asset_Data[i]); - break; + u64 base_64_size = strlen(asset_image.uri + i + 1); + for(; asset_image.uri[i + base_64_size] == '='; base_64_size -= 1) {} + + u64 bit_count = base_64_size*6 - (base_64_size*6) % 8; + i32 out_size = cast(i32)(bit_count/8); + + void* data; + cgltf_options options; + options.file.read = &GLTFLoadCallback; + options.file.release = &GLTFFreeCallback; + + cgltf_result result = cgltf_load_buffer_base64(&options, out_size, asset_image.uri + i + 1, &data); + if(result == cgltf_result_success) + { + image = LoadImage(data, out_size); + cgltf_free(cast(cgltf_data*)data); + } } } + else + { + char[512] buf; + char[] file_path = buf.sformat("%s%s%s", tex_path, dirSeparator, cast(char*)asset_image.uri); + u8[] image_file = OpenFile(ConvToStr(file_path)); + + image = LoadImage(image_file.ptr, cast(i32)image_file.length); + + Free(image_file); + } } - } -} - -static u8[] -GenerateDefaultTexture(u64 x, u64 y) -{ - u64 tex_size = x*y*4; - u8[] placeholder_tex = new u8[tex_size]; - - u8[4] magenta = [255, 0, 255, 255]; - u8[4] black = [0, 0, 0, 255]; - u64 half = tex_size/2; - for(u64 i = 0; i < tex_size; i += 32) - { - bool swap = i <= half; - for(u64 j = 0; j < 16; j += 4) + else if(asset_image.buffer_view != null && asset_image.buffer_view.buffer.data != null) { - placeholder_tex[i+j .. i+j+4] = !swap ? magenta[0 .. $] : black[0 .. $]; - placeholder_tex[i+j+16 .. i+j+16+4] = !swap ? black[0 .. $] : magenta[0 .. $]; + u8[] data = Alloc!(u8)(asset_image.buffer_view.size); + + i32 offset = cast(i32)(asset_image.buffer_view.offset); + i32 stride = cast(i32)(asset_image.buffer_view.stride ? asset_image.buffer_view.stride : 1); + + u64 len = asset_image.buffer_view.size - (asset_image.buffer_view.size % stride); + data[0 .. len] = (cast(u8*)(asset_image.buffer_view.buffer.data))[offset .. offset+len]; + + string mime_type = ConvToStr(asset_image.mime_type[0 .. strlen(asset_image.mime_type)]); + + const string[] accepted_types = ["image\\/png", "image/png", "image\\/jpeg", "image/jpeg", "image\\/tga", "image/tga", "image\\/bmp", "image/bmp"]; + bool accepted; + static foreach(type; accepted_types) + { + if(type == mime_type) + { + accepted = true; + goto PostTypeCheck; + } + } + + PostTypeCheck: + u8[] image_data; + if(accepted) + { + image = LoadImage(data.ptr, cast(i32)data.length); + } + else + { + Logf("Unknown image type [%s], unable to load", mime_type); + } + + Free(data); } } - return placeholder_tex; + if(image.data == null) + { + Logf("Failed to load GLTF image data/file"); + image = DEFAULT_IMAGE; + } + + return image; } -Model +ModelData LoadGLTF(Arena* arena, string file_name) { - Model model; + ModelData m_data; + Model* model = &m_data.model; - u8[] file_data; // = OpenFile(file_name); + u8[] file_data = OpenFile(file_name); + assert(file_data != null); cgltf_options opts; cgltf_data* data; @@ -446,23 +361,110 @@ LoadGLTF(Arena* arena, string file_name) } } - model.meshes = Alloc!(Mesh)(arena, primitive_count); - model.mats = Alloc!(Material)(arena, data.materials_count+1); + model.meshes = Alloc!(Mesh)(primitive_count); + model.mats = Alloc!(Material)(data.materials_count+1); + m_data.tex = Alloc!(ImageData)(data.textures_count+1); - // Make and load default material into model.mats[0] + model.mats[0] = DEFAULT_MATERIAL; + u32 tex_idx; string file_path = GetFilePath(file_name); for(u64 i = 0; i < data.materials_count; i += 1) { - // model.mats[i+1] = default_material; + u64 mat_idx = i+1; + + model.mats[mat_idx] = DEFAULT_MATERIAL; if(data.materials[i].has_pbr_metallic_roughness) { + auto pbr_mr = &data.materials[i].pbr_metallic_roughness; + if(pbr_mr.base_color_texture.texture) + { + m_data.tex[tex_idx] = LoadImage(pbr_mr.base_color_texture.texture.image, file_path); + model.mats[mat_idx].maps[MMI.Albedo].tex_id = tex_idx++; + } + model.mats[mat_idx].maps[MMI.Albedo].col.v = pbr_mr.base_color_factor; + + if(pbr_mr.metallic_roughness_texture.texture) + { + m_data.tex[tex_idx] = LoadImage(pbr_mr.base_color_texture.texture.image, file_path); + model.mats[mat_idx].maps[MMI.Metallic].tex_id = tex_idx; + model.mats[mat_idx].maps[MMI.Roughness].tex_id = tex_idx; + tex_idx += 1; + + model.mats[mat_idx].maps[MMI.Metallic].value = pbr_mr.metallic_factor; + model.mats[mat_idx].maps[MMI.Roughness].value = pbr_mr.roughness_factor; + } + + if(data.materials[i].normal_texture.texture) + { + m_data.tex[tex_idx] = LoadImage(data.materials[i].normal_texture.texture.image, file_path); + model.mats[mat_idx].maps[MMI.Normal].tex_id = tex_idx++; + } + + if(data.materials[i].occlusion_texture.texture) + { + m_data.tex[tex_idx] = LoadImage(data.materials[i].occlusion_texture.texture.image, file_path); + model.mats[mat_idx].maps[MMI.Occlusion].tex_id = tex_idx++; + } + + if(data.materials[i].emissive_texture.texture) + { + m_data.tex[tex_idx] = LoadImage(data.materials[i].emissive_texture.texture.image, file_path); + model.mats[mat_idx].maps[MMI.Emission].tex_id = tex_idx++; + + model.mats[mat_idx].maps[MMI.Emission].col.v[0 .. 3] = data.materials[i].emissive_factor; + model.mats[mat_idx].maps[MMI.Emission].col.v.a = 1.0; + } } } + + + } + + return m_data; +} + + +static ImageData +GenerateDefaultTexture(u32 x, u32 y) +{ + ImageData data = { + w: x, + h: y, + ch: 4, + }; + + u64 tex_size = x*y*4; + u8[] placeholder_tex = new u8[tex_size]; + + u8[4] magenta = [255, 0, 255, 255]; + u8[4] black = [0, 0, 0, 255]; + u64 half = tex_size/2; + for(u64 i = 0; i < tex_size; i += 32) + { + bool swap = i <= half; + for(u64 j = 0; j < 16; j += 4) + { + placeholder_tex[i+j .. i+j+4] = !swap ? magenta[0 .. $] : black[0 .. $]; + placeholder_tex[i+j+16 .. i+j+16+4] = !swap ? black[0 .. $] : magenta[0 .. $]; + } } - return model; + data.data = placeholder_tex; + + return data; +} + +static Material +GenerateDefaultMaterial() +{ + Material mat; + + mat.maps[MMI.Albedo].col = Vec4(1.0); + mat.maps[MMI.Metallic].col = Vec4(1.0); + + return mat; } diff --git a/packer.d b/packer.d deleted file mode 100644 index 2a66968..0000000 --- a/packer.d +++ /dev/null @@ -1,751 +0,0 @@ -module dlib.packer; - -import includes; -import dlib.util; -import dlib.aliases; -import dlib.assets; -import dlib.platform; -import dlib.alloc; - -import std.stdio; -import std.string; -import std.file; -import std.path; -import std.traits; -import std.algorithm.comparison; -import core.memory; -import std.conv; -import std.array; - -AssetType[string] Lookup = [ - ".obj": AT.Model, - ".png": AT.Texture, - ".jpg": AT.Texture, - ".spv": AT.Shader, -]; - -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, -} - -struct PackedString -{ - StringHeader header; - string str; - - alias header this; -} - -struct Texture -{ - string name; - u8[] data; - u32 w; - u32 h; - u32 ch; -} - -union MeshIdx -{ - struct - { - u32 v, uv, n, t; - }; - u32[4] arr; -} - -struct DirEntry -{ - string dir; - string[] files; - DirEntry[] sub_dirs; -} - -u64 g_asset_count = 0; -Texture[] g_model_textures = []; - -/************************************************** - ****** UPDATE FILE_VERSION AFTER CHANGES !! ****** - **************************************************/ - -void main(string[] argv) -{ - string assets_dir = null; - string asset_pack_path = null; - - for(u64 i = 0; i < argv.length; i += 1) - { - if(argv[i] == "-out" && i+1 < argv.length) - { - if(!exists(argv[i+1])) - { - mkdir(argv[i+1]); - } - - if(!isDir(argv[i+1])) - { - assert(false, "Out directory is not a directory"); - } - - asset_pack_path = argv[i+1]; - - i += 1; - - continue; - } - - if(argv[i] == "-assets") - { - if(!exists(argv[i+1])) - { - assert(false, "Assets directory not found"); - } - - assets_dir = argv[i+1]; - - i += 1; - continue; - } - } - - if(asset_pack_path != null) - { - if(!Cwd!(string)().endsWith("build")) - { - if(!exists("build")) - { - mkdir("build"); - } - - if(exists("build") && isDir("build")) - { - assets_pack_path = "./build/assets.sgp"; - } - else assert(false, "Unable to make default build directory"); - } - } - - if(assets_dir == null) - { - assert(false, "No assets directory provided"); - } - - if(pack) - { - PackFile(assets_pack_path, assets_dir); - debug TestFile(assets_pack_path, assets_dir); - } -} - -void -ScanDir(DirEntry* entry, string dir) -{ - string cwd = Cwd!(string)(); - - - foreach(string e; dirEntries(dir, SpanMode.shallow)) - { - if(e == ".." || e == ".") continue; - - if(isDir(e)) - { - entry.sub_dirs ~= DirEntry(e, []. []); - } - - if(isFile(e)) - { - entry.files ~= e; - } - } - - for(u64 i = 0; i < entry.sub_dirs.length; i += 1) - { - ScanDir(&entry.sub_dirs[i], entry.sub_dirs[i].dir); - } -} - -void -PackFile(string file_path, string assets_dir) -{ - string cwd = Cwd!(string)(); - - File ap = File(file_path, "wb"); - - ChDir(assets_dir); - - DirEntry base_dir = [ - { - dir: "", - files: [], - sub_dirs: [], - }, - ]; - - ScanDir(&base_dir, "."); - - FileHeader h = InitHeader(g_asset_count); - ap.rawWrite([h]); - - u64 offset = FileHeader.sizeof + (AssetInfo.sizeof * g_asset_count); - AssetInfo[] asset_info; - foreach(file; g_file_names) - { - AssetType type = AT.None; - foreach(extension, t; Lookup) - { - if (file.endsWith(extension)) - { - type = t; - break; - } - } - - assert(type != AT.None, "Asset Type is none, offending file " ~ file); - - auto f = File(file, "rb"); - - u64 length = cast(u64)f.size(); - - string base_name = chompPrefix(file, "./"); - AssetInfo info = { - hash: Hash(base_name), - offset: offset, - length: length, - type: type, - }; - - auto data = f.rawRead(new u8[length]); - - assert(length == data.length, "rawRead failure: data length returned doesn't match"); - - ap.seek(offset); - ap.rawWrite(data); - - offset += length; - - asset_info ~= info; - - f.close(); - } - - ap.seek(FileHeader.sizeof); - ap.rawWrite(asset_info); - ap.flush(); - ap.close(); - - ChDir(cwd); -} - -void -TestFile(string file_path, string assets_dir) -{ - File ap = File(file_path, "rb"); - scope(exit) - { - ap.flush(); - ap.close(); - } - - FileHeader file_header = ap.rawRead(new FileHeader[1])[0]; - FileHeader test_header = InitHeader(g_asset_count); - assert(file_header == test_header, "TestFile failure: Header is incorrect"); - - AssetInfo[] file_info = ap.rawRead(new AssetInfo[g_asset_count]); - assert(file_info.length == file_header.asset_count, "TestFile failure: Incorrect AssetInfo length returned"); - - u64 asset_index = 0; - foreach(i, file; g_file_names) - { - scope(exit) asset_index += 1; - - AssetInfo* info = file_info.ptr + asset_index; - File asset = File(file, "rb"); - - u8[] data = asset.rawRead(new u8[asset.size()]); - assert(data.length == info.length, "TestFile failure: File length read is incorrect"); - - string base_name = chompPrefix(file, "./"); - assert(Hash(base_name) == info.hash, "TestFile failure: File hash is incorrect"); - - ap.seek(info.offset); - u8[] pack_data = ap.rawRead(new u8[info.length]); - assert(equal!((a, b) => a == b)(data[], pack_data[]), "TestFile failure: Asset data does not match file data"); - } -} - -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)); -} - - -static u32 -MagicValue(string str) -{ - assert(str.length == 4, "Magic value must 4 characters"); - return cast(u32)(cast(u32)(str[0] << 24) | cast(u32)(str[1] << 16) | cast(u32)(str[2] << 8) | cast(u32)(str[3] << 0)); -} - -static FileHeader -InitHeader(u64 asset_count) -{ - FileHeader header = { - magic: MagicValue("steg"), - file_version: FILE_VERSION, - asset_count: asset_count, - asset_info_offset: FileHeader.sizeof, - }; - - return header; -} - -string[][] -TokenizeLines(u8[] data) -{ - string[][] tokens = []; - string[] line_tokens = []; - u64 start = -1; - for(u64 i = 0; i < data.length; i += 1) - { - if(i64(start) != -1 && CheckWhiteSpace(data[i])) - { - line_tokens ~= ConvString(data[start .. i]); - start = -1; - } - - if(data[i] == '\n') - { - tokens ~= line_tokens; - line_tokens = []; - - continue; - } - - if(i64(start) == -1 && !CheckWhiteSpace(data[i])) - { - start = i; - continue; - } - } - - return tokens; -} - -u8[] -OpenFile(string file_name) -{ - File f; - u8[] data; - - try - { - f = File(file_name, "rb"); - data = new u8[f.size()]; - f.rawRead(data); - } - catch(Exception e) - { - data = null; - } - - f.close(); - - return data; -} - -/* -Model -ConvertObj(string file_name) -{ - // TODO: - // - Deduplicate vertices - - u8[] data = OpenFile(file_name); - - Model model; - - u64 vcount, uvcount, ncount, fcount, gcount, mcount; - - string[][] tokens = TokenizeLines(data); - - for(u64 i = 0; i < tokens.length; i += 1) - { - if(tokens[i].length == 0) continue; - - switch(tokens[i][0]) - { - case "v": vcount += 1; break; - case "vt": uvcount += 1; break; - case "vn": ncount += 1; break; - case "f": fcount += 1; break; - case "g": gcount += 1; break; - case "usemtl": mcount += 1; break; - default: break; - } - } - - Vec3[] positions = new Vec3[vcount]; - Vec3[] normals = new Vec3[ncount]; - Vec2[] uvs = new Vec2[uvcount]; - MeshIdx[3][][] idx = []; - MaterialData[] mtls = []; - - vcount = 0; - ncount = 0; - uvcount = 0; - - MeshIdx[3][] part_idx = []; - for(u64 i = 0; i < tokens.length; i += 1) - { - if(tokens[i][0] == "#") continue; - - if(tokens[i][0] == "v") - { - if(tokens[i].length < 4) assert(false, "OBJ file error, not enough points for case [v]"); - - positions[vcount++] = Vec3(ToF32(tokens[i][1]), ToF32(tokens[i][2]), ToF32(tokens[i][3])); - continue; - } - - if(tokens[i][0] == "vn") - { - if(tokens[i].length < 4) assert(false, "OBJ file error, not enough points for case [vn]"); - - normals[ncount++] = Vec3(ToF32(tokens[i][1]), ToF32(tokens[i][2]), ToF32(tokens[i][3])); - continue; - } - - if(tokens[i][0] == "vt") - { - if(tokens[i].length < 3) assert(false, "OBJ file error, not enough points for case [vt]"); - - uvs[uvcount++] = Vec2(ToF32(tokens[i][1]), ToF32(tokens[i][2])); - continue; - } - - if(tokens[i][0] == "f") - { - u32 sep_count = StrCharCount(tokens[i][1], '/'); - - if(tokens[i].length == 4) - { - MeshIdx[3] face; - for(u64 j = 1; j < tokens[i].length; j += 1) - { - string[] parts = tokens[i][j].split('/'); - - if(sep_count == 0) - { - face[j-1] = MeshIdx(v: to!u32(parts[0])); - } - if(sep_count == 1) - { - face[j-1] = MeshIdx(v: to!u32(parts[0]), uv: to!u32(parts[1])); - } - if(sep_count == 2) - { - MeshIdx mesh_idx; - foreach(ipart, part; parts) - { - if(part == "") continue; - mesh_idx.arr[ipart] = to!u32(part); - } - - face[j-1] = mesh_idx; - } - } - - part_idx ~= face; - } - else assert(false, "Only triangles or quads supported for mesh face"); - - continue; - } - - if(tokens[i][0] == "g" && part_idx.length > 0) - { - idx ~= part_idx; - part_idx = []; - continue; - } - - if(tokens[i][0] == "mtllib") - { - u8[] mtl_data = OpenFile(GetFilePath(file_name) ~ tokens[i][1]); - - MaterialData* mtl = null; - string[][] mtl_tokens = TokenizeLines(mtl_data); - for(u64 j = 0; j < mtl_tokens.length; j += 1) - { - if(mtl_tokens[j].length == 0) - { - if(mtl) - { - mtls ~= *mtl; - mtl = null; - } - - continue; - } - - if(mtl_tokens[j][0] == "newmtl") - { - mtl = new MaterialData; - mtl.name = mtl_tokens[j][1]; - continue; - } - - if(!mtl) continue; - - switch(mtl_tokens[j][0]) - { - case "Ka", "Kd", "Ks", "Tf", "Ke": - { - mtl.colors[GetMatColor(mtl_tokens[j][0])] = Vec3(ToF32(mtl_tokens[j][1]), ToF32(mtl_tokens[j][2]), ToF32(mtl_tokens[j][3])); - } break; - case "Ns", "d", "Tr", "Ni", "Pr", "Pm", "Pc", "Pcr", "aniso", "Ps": - { - f32 v = ToF32(mtl_tokens[j][1]); - if(mtl_tokens[j][1] == "Tr") - { - v = 1.0 - v; - } - - mtl.props[GetMatFloat(mtl_tokens[j][0])] = v; - } break; - case "map_Ka", "map_Kd", "map_Ks", "map_Ns", "map_d", "map_bump", "anisor", - "bump", "map_Pr", "map_Pm", "map_Ke", "map_Ps", "norm", "disp", "decal": - { - mtl.maps[GetMatMap(mtl_tokens[j][0])] = mtl_tokens[j][1]; - } break; - case "illum": - { - mtl.illum = cast(IllumModel)(to!(u32)(mtl_tokens[j][1])); - } break; - default: break; - } - } - - if(mtl) - { - mtls ~= *mtl; - mtl = null; - } - } - } - - u64 face_count; - foreach(part; idx) - { - face_count += part.length; - } - - ModelData md = { - name: baseName(file_name, ".obj"), - meshes: [ - { vtx: new Vertex[face_count*3] }, - ] - }; - - Logf("%s %s", (Vertex.sizeof * md.vtx.length), (positions.length*Vec3.sizeof + uvs.length*Vec2.sizeof + normals.length*Vec3.sizeof)); - - u64 vtx_count = 0; - foreach(part; idx) - { - for(u64 i = 0; i < part.length; i += 1) - { - for(u64 j = 0; j < 3; j += 1) - { - MeshIdx* mi = part[i].ptr + j; - if(mi.v ) md.meshes[0].vtx[vtx_count+j].pos = positions[mi.v-1]; - if(mi.n ) md.meshes[0].vtx[vtx_count+j].normal = normals[mi.n-1]; - if(mi.uv) md.meshes[0].vtx[vtx_count+j].uv = uvs[mi.uv-1]; - } - - vtx_count += 3; - } - } - - return model; -} -*/ - -pragma(inline) f32 -ToF32(string str) -{ - return to!(f32)(str); -} - -pragma(inline) string -ConvString(u8[] bytes) -{ - return (cast(immutable(char)*)bytes.ptr)[0 .. bytes.length]; -} - -pragma(inline) bool -CheckWhiteSpace(u8 ch) -{ - return ch == ' ' || - ch == '\t'|| - ch == '\n'|| - ch == 0x0D|| - ch == 0x0A|| - ch == 0x0B|| - ch == 0x0C; -} - -unittest -{ - { // Obj test - //Model model = ConvertObj("./test/sponza.obj"); - } - - { - MatProp prop = GetMatProp("Ka"); - } -} diff --git a/test.sh b/test.sh index 3a304ad..ddcc007 100755 --- a/test.sh +++ b/test.sh @@ -2,7 +2,7 @@ name="Test_Runner" -ldc2 platform.d aliases.d math.d util.d alloc.d assets.d packer.d external/xxhash/xxhash.d -P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name +ldc2 platform.d aliases.d math.d util.d alloc.d assets.d external/xxhash/xxhash.d -P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name rm $name.o ./$name diff --git a/util.d b/util.d index 0902682..c15bc4e 100644 --- a/util.d +++ b/util.d @@ -6,7 +6,7 @@ import dlib.alloc; import xxhash3; import includes; -import std.stdio : write, writeln, writefln, stderr; +import std.stdio : write, writeln, writef, writefln, stderr; import std.conv; import std.string; import std.traits; @@ -72,11 +72,12 @@ Debugf(Args...)(string fmt, Args args) } void -Logf(Args...)(string fmt, Args args, string prefix = "[INFO]: ") +Logf(Args...)(string fmt, Args args, string prefix = "INFO", string func = __FUNCTION__) { try { - write(prefix); + debug writef("[%s] FUNC: [%s]: ", prefix, func); + else write("[%s]: ", prefix); writefln(fmt, args); } catch (Exception e)