362 lines
7.8 KiB
D
362 lines
7.8 KiB
D
import aliases;
|
|
import includes;
|
|
import std.stdio;
|
|
import std.string;
|
|
import std.file;
|
|
import util;
|
|
import std.path;
|
|
import assets;
|
|
import std.traits;
|
|
import std.algorithm.comparison;
|
|
import core.memory;
|
|
import std.json;
|
|
|
|
AssetType[string] Lookup = [
|
|
".m3d": AT.ModelM3D,
|
|
".png": AT.Texture,
|
|
".jpg": AT.Texture,
|
|
".spv": AT.Shader,
|
|
];
|
|
|
|
u64 ASSET_COUNT = 0;
|
|
string[] FILE_NAMES = [];
|
|
|
|
/**************************************************
|
|
****** UPDATE FILE_VERSION AFTER CHANGES !! ******
|
|
**************************************************/
|
|
|
|
void main(string[] argv)
|
|
{
|
|
Log("running");
|
|
if (isDir("build"))
|
|
{
|
|
chdir("build");
|
|
}
|
|
|
|
bool pack = false;
|
|
|
|
foreach(arg; argv)
|
|
{
|
|
if (arg == "pack")
|
|
{
|
|
pack = true;
|
|
}
|
|
}
|
|
|
|
if (pack)
|
|
{
|
|
PackFile();
|
|
TestFile();
|
|
}
|
|
|
|
CodegenFontLookup();
|
|
}
|
|
|
|
void
|
|
CodegenFontLookup()
|
|
{
|
|
mkdirRecurse("../src/codegen");
|
|
auto f = File("../src/codegen/fonts.d", "w");
|
|
string font_json = readText("atlas.json");
|
|
|
|
JSONValue j = parseJSON(font_json);
|
|
|
|
assert("atlas" in j, "atlas key not in json");
|
|
|
|
FontAtlas atlas = {
|
|
type: (j["atlas"]["type"].str == "softmask" ? AtlasType.SoftMask : AtlasType.None),
|
|
size: j["atlas"]["size"].floating,
|
|
width: cast(u32)j["atlas"]["width"].integer,
|
|
height: cast(u32)j["atlas"]["height"].integer,
|
|
y_origin: (j["atlas"]["yOrigin"].str == "bottom" ? YOrigin.Bottom : YOrigin.None),
|
|
em_size: cast(f32)j["metrics"]["emSize"].integer,
|
|
line_height: j["metrics"]["lineHeight"].floating,
|
|
ascender: j["metrics"]["ascender"].floating,
|
|
descender: j["metrics"]["descender"].floating,
|
|
underline_y: j["metrics"]["underlineY"].floating,
|
|
underline_thickness: j["metrics"]["underlineThickness"].floating,
|
|
};
|
|
|
|
foreach(val; j["glyphs"].array)
|
|
{
|
|
Glyph glyph = {
|
|
ch: cast(dchar)val["unicode"].integer,
|
|
advance: val["advance"].floating,
|
|
};
|
|
|
|
if ("planeBounds" in val)
|
|
{
|
|
glyph.plane_left = val["planeBounds"]["left"].floating;
|
|
glyph.plane_bottom = val["planeBounds"]["bottom"].floating;
|
|
glyph.plane_right = val["planeBounds"]["right"].floating;
|
|
glyph.plane_top = val["planeBounds"]["top"].floating;
|
|
|
|
glyph.atlas_left = val["atlasBounds"]["left"].floating;
|
|
glyph.atlas_bottom = val["atlasBounds"]["bottom"].floating;
|
|
glyph.atlas_right = val["atlasBounds"]["right"].floating;
|
|
glyph.atlas_top = val["atlasBounds"]["top"].floating;
|
|
}
|
|
|
|
atlas.glyphs ~= glyph;
|
|
}
|
|
|
|
|
|
f.writeln("import util;\n");
|
|
f.writeln("static immutable FontAtlas FONT_ATLAS = {");
|
|
|
|
f.writefln("\ttype: AtlasType.%s,", atlas.type);
|
|
f.writefln("\tsize: %f,", atlas.size);
|
|
f.writefln("\twidth: %d,", atlas.width);
|
|
f.writefln("\theight: %d,", atlas.height);
|
|
f.writefln("\ty_origin: YOrigin.%s,", atlas.y_origin);
|
|
f.writefln("\tem_size: %f,", atlas.em_size);
|
|
f.writefln("\tline_height: %f,", atlas.line_height);
|
|
f.writefln("\tascender: %f,", atlas.ascender);
|
|
f.writefln("\tdescender: %f,", atlas.descender);
|
|
f.writefln("\tunderline_y: %f,", atlas.underline_y);
|
|
f.writefln("\tunderline_thickness: %f,", atlas.underline_thickness);
|
|
|
|
f.writeln("\tglyphs: [");
|
|
|
|
foreach(g; atlas.glyphs)
|
|
{
|
|
f.writeln("\t\t{");
|
|
|
|
f.writefln("\t\t\tch: '%s',", g.ch);
|
|
f.writefln("\t\t\tadvance: %f,", g.advance);
|
|
|
|
if (g.plane_left > 0.0 || g.plane_right > 0.0)
|
|
{
|
|
f.writefln("\t\t\tplane_left: %f,", g.plane_left);
|
|
f.writefln("\t\t\tplane_bottom: %f,", g.plane_bottom);
|
|
f.writefln("\t\t\tplane_right: %f,", g.plane_right);
|
|
f.writefln("\t\t\tplane_top: %f,", g.plane_top);
|
|
|
|
f.writefln("\t\t\tatlas_left: %f,", g.atlas_left);
|
|
f.writefln("\t\t\tatlas_bottom: %f,", atlas.height - g.atlas_bottom);
|
|
f.writefln("\t\t\tatlas_right: %f,", g.atlas_right);
|
|
f.writefln("\t\t\tatlas_top: %f,", atlas.height - g.atlas_top);
|
|
}
|
|
|
|
f.writeln("\t\t},");
|
|
}
|
|
|
|
f.writeln("\t],");
|
|
|
|
f.writeln("};");
|
|
}
|
|
|
|
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;
|
|
|
|
FILE_NAMES ~= file;
|
|
ASSET_COUNT += 1;
|
|
}
|
|
|
|
FileHeader h = InitHeader(ASSET_COUNT);
|
|
ap.rawWrite([h]);
|
|
|
|
u64 offset = FileHeader.sizeof + (AssetInfo.sizeof * ASSET_COUNT);
|
|
AssetInfo[] asset_info;
|
|
foreach(file; 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");
|
|
scope(exit) f.close();
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
ModelMeta
|
|
GetModelMeta(u8[] data)
|
|
{
|
|
m3d_t* model = m3d_load(data.ptr, null, null, null);
|
|
assert(model != null, "m3d_load failure: model is null");
|
|
|
|
u64 index_count = cast(u64)(model.numface * 3);
|
|
|
|
m3d_free(model);
|
|
|
|
return ModelMeta(index_count: index_count);
|
|
}
|
|
|
|
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(ASSET_COUNT);
|
|
assert(file_header == test_header, "TestFile failure: Header is incorrect");
|
|
|
|
AssetInfo[] file_info = ap.rawRead(new AssetInfo[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; 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;
|
|
}
|
|
|
|
ModelData
|
|
ConvertModel(u8[] data)
|
|
{
|
|
assert(data.length > 4, "Model data too small for a magic number");
|
|
|
|
u32 magic = *cast(u32*)(data.ptr);
|
|
|
|
ModelData model;
|
|
switch (magic)
|
|
{
|
|
case MagicValue("3DMO"):
|
|
{
|
|
model = ConvertM3D(data);
|
|
} break;
|
|
case MagicValue("glTF"):
|
|
{
|
|
model = ConvertGLTF(data);
|
|
} break;
|
|
default:
|
|
{
|
|
assert(false, "Unsupported model type");
|
|
} break;
|
|
}
|
|
|
|
return model;
|
|
}
|
|
|
|
ModelData
|
|
ConvertGLTF(u8[] data)
|
|
{
|
|
ModelData model;
|
|
|
|
assert(false, "Not yet supported");
|
|
|
|
return model;
|
|
}
|
|
|
|
ModelData
|
|
ConvertM3D(u8[] data)
|
|
{
|
|
ModelData model;
|
|
|
|
return model;
|
|
}
|
|
|
|
|