import dlib; import std.stdio; import std.string; import std.file; import std.path; import std.traits; import std.algorithm.comparison; import core.memory; import std.json; AssetType[string] Lookup = [ ".m3d": AT.ModelM3D, ".obj": AT.ModelObj, ".png": AT.Texture, ".jpg": AT.Texture, ".spv": AT.Shader, ]; struct Texture { string name; u8[] data; u32 w; u32 h; u32 ch; } struct Model { MaterialData[] mats; } u64 g_asset_count = 0; string[] g_file_names = []; Texture[] g_model_textures = []; /************************************************** ****** UPDATE FILE_VERSION AFTER CHANGES !! ****** **************************************************/ void main(string[] argv) { Log("running"); if(isDir("build")) { chdir("build"); } bool pack = false; bool font = false; string font_file; for(u64 i = 0; i < argv.length; i += 1) { if(argv[i] == "-pack") { pack = true; } } if(pack) { PackFile(); TestFile(); } } void PackFile() { File ap = File("./assets.sgp", "wb"); scope(exit) { ap.flush(); ap.close(); chdir("../build"); } chdir("../assets"); foreach(string file; dirEntries(".", SpanMode.depth)) { if (isDir(file)) continue; g_file_names ~= file; g_asset_count += 1; } 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); } TexMeta GetTexMeta(u8[] data) { int ch = 4; int width, height, has_ch; auto img = stbi_load_from_memory(data.ptr, cast(int)data.length, &width, &height, &has_ch, ch); assert(img != null, "stbi_load_from_image failure: image is NULL"); assert(width > 0 && height > 0 && has_ch > 0, "stbi_load_from_image failure: dimensions are invalid"); stbi_image_free(img); return TexMeta(w: width, h: height, ch: has_ch); } void TestFile() { File ap = File("assets.sgp", "rb"); scope(exit) { ap.flush(); ap.close(); chdir("../build"); } 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"); chdir("../assets"); 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"); } } 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; } static ModelHeader InitModelHeader() { ModelHeader header = { magic: MagicValue("stgm"), model_version: MODEL_VERSION, }; return header; } Model ConvertM3D(u8[] data) { Model model; m3d_t* m3d = m3d_load(data.ptr, null, null, null); m3dm_t[] mats = m3d.material[0 .. m3d.nummaterial]; foreach(mat; mats) { MaterialData matd; m3dp_t[] props = mat.prop[0 .. mat.numprop]; foreach(prop; props) { switch(prop.type) { case m3dp_Kd: } } } return model; }