delete stuff, start on gltf loading (again)
This commit is contained in:
parent
70e3c135cf
commit
f89bd36b18
616
assets.d
616
assets.d
@ -6,21 +6,13 @@ import dlib.util;
|
|||||||
import dlib.alloc;
|
import dlib.alloc;
|
||||||
|
|
||||||
import std.file;
|
import std.file;
|
||||||
|
import std.path;
|
||||||
|
import std.format;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.exception;
|
import std.exception;
|
||||||
|
|
||||||
File Asset_File;
|
__gshared ImageData DEFAULT_IMAGE = GenerateDefaultTexture(32, 32);
|
||||||
|
__gshared Material DEFAULT_MATERIAL = GenerateDefaultMaterial();
|
||||||
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;
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Alignment?
|
// Alignment?
|
||||||
@ -29,23 +21,6 @@ const u32 MODEL_VERSION = 2;
|
|||||||
****** FILE PACKER ******
|
****** 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 ******
|
****** FILE PACKER ******
|
||||||
*************************/
|
*************************/
|
||||||
@ -54,69 +29,18 @@ struct DirHeader
|
|||||||
*** ASSET STRUCTURES ***
|
*** ASSET STRUCTURES ***
|
||||||
************************/
|
************************/
|
||||||
|
|
||||||
alias StringID = u64;
|
struct ImageData
|
||||||
|
|
||||||
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 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;
|
u8[] data;
|
||||||
|
u32 w;
|
||||||
|
u32 h;
|
||||||
|
u32 ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModelData
|
||||||
|
{
|
||||||
|
Model model;
|
||||||
|
ImageData[] tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
@ -127,6 +51,39 @@ struct AssetData
|
|||||||
***** GFX STRUCTURES *****
|
***** 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
|
struct Vertex
|
||||||
{
|
{
|
||||||
Vec4 color;
|
Vec4 color;
|
||||||
@ -137,96 +94,85 @@ struct Vertex
|
|||||||
Vec2 uv2;
|
Vec2 uv2;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IllumModel : u32
|
struct Mesh
|
||||||
{
|
{
|
||||||
Color = 0,
|
Vertex[] vtx;
|
||||||
ColorAmbient,
|
u32 idx;
|
||||||
Highlight,
|
u32 mat_id;
|
||||||
ReflectionRayTrace,
|
|
||||||
GlassRayTrace,
|
|
||||||
FresnelRayTrace,
|
|
||||||
RefractionRayTrace,
|
|
||||||
RefractionFresnelRayTrace,
|
|
||||||
Reflection,
|
|
||||||
Glass,
|
|
||||||
ShadowsInvis,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MatColor : u32
|
struct Model
|
||||||
{
|
{
|
||||||
Ambient,
|
Mat4 transform;
|
||||||
Albedo,
|
|
||||||
Specular,
|
|
||||||
Transmission,
|
|
||||||
Emissive,
|
|
||||||
|
|
||||||
Max,
|
Mesh[] meshes;
|
||||||
}
|
Material[] mats;
|
||||||
|
|
||||||
enum MatFloat : u32
|
// TODO: bones/animations
|
||||||
{
|
|
||||||
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 *****
|
***** GFX STRUCTURES *****
|
||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
bool Asset_Pack_Opened = false;
|
__gshared string g_BASE_ASSETS_DIR;
|
||||||
|
|
||||||
debug
|
static u32
|
||||||
|
MagicValue(string str)
|
||||||
{
|
{
|
||||||
void
|
assert(str.length == 4, "Magic value must 4 characters");
|
||||||
SetAssetsDir(string dir)
|
return cast(u32)(cast(u32)(str[0] << 24) | cast(u32)(str[1] << 16) | cast(u32)(str[2] << 8) | cast(u32)(str[3] << 0));
|
||||||
{
|
|
||||||
assert(ChDir(dir));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetBaseAssetsDir(string dir)
|
||||||
|
{
|
||||||
|
if(!isDir(dir))
|
||||||
|
{
|
||||||
|
assert(false, "Unable to find assets directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_BASE_ASSETS_DIR = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
U32ColToVec4(u32 col, Vec4* vec)
|
||||||
|
{
|
||||||
|
if(!col)
|
||||||
|
{
|
||||||
|
vec.rgb = 0.0;
|
||||||
|
vec.a = 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make better
|
||||||
u8[]
|
u8[]
|
||||||
LoadAssetData(Arena* arena, string name)
|
OpenFile(string file_name)
|
||||||
{
|
{
|
||||||
File f;
|
File f;
|
||||||
|
u8[] data;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
f = File(name, "rb");
|
f = File(file_name, "rb");
|
||||||
|
data = Alloc!(u8)(f.size());
|
||||||
|
f.rawRead(data);
|
||||||
}
|
}
|
||||||
catch (ErrnoException e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
assert(false, "Unable to open file");
|
data = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8[] mem = Alloc!(u8)(arena, f.size());
|
f.close();
|
||||||
return f.rawRead(mem);
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern (C) cgltf_result
|
extern (C) cgltf_result
|
||||||
@ -237,7 +183,7 @@ debug
|
|||||||
if(file_data == null) return cgltf_result_io_error;
|
if(file_data == null) return cgltf_result_io_error;
|
||||||
|
|
||||||
*size = cast(cgltf_size)file_data.length;
|
*size = cast(cgltf_size)file_data.length;
|
||||||
*data = Alloc!(u8)(file_data).ptr;
|
*data = file_data.ptr;
|
||||||
|
|
||||||
return cgltf_result_success;
|
return cgltf_result_success;
|
||||||
}
|
}
|
||||||
@ -245,173 +191,142 @@ debug
|
|||||||
extern (C) void
|
extern (C) void
|
||||||
GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, void* data, cgltf_size size)
|
GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, void* data, cgltf_size size)
|
||||||
{
|
{
|
||||||
Free(data[0 .. 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(asset_image.uri != null)
|
||||||
|
{
|
||||||
|
if(strlen(asset_image.uri) > 5 && ConvToStr(asset_image.uri[0 .. 5]) == "data:")
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
for(; asset_image.uri[i] != ',' && asset_image.uri[i] != 0; i += 1) {}
|
||||||
|
|
||||||
|
if(asset_image.uri[i] == 0)
|
||||||
|
{
|
||||||
|
Logf("gltf data URI for is not a valid image");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
void
|
char[512] buf;
|
||||||
OpenAssetPack(string file_path)
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(asset_image.buffer_view != null && asset_image.buffer_view.buffer.data != null)
|
||||||
{
|
{
|
||||||
if(!Asset_Pack_Opened)
|
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)
|
||||||
{
|
{
|
||||||
bool success = true;
|
if(type == mime_type)
|
||||||
|
|
||||||
// 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");
|
accepted = true;
|
||||||
|
goto PostTypeCheck;
|
||||||
}
|
}
|
||||||
catch (ErrnoException e)
|
}
|
||||||
|
|
||||||
|
PostTypeCheck:
|
||||||
|
u8[] image_data;
|
||||||
|
if(accepted)
|
||||||
{
|
{
|
||||||
Logf("OpenAssetPack failure: Unable to open file %s", file_path);
|
image = LoadImage(data.ptr, cast(i32)data.length);
|
||||||
assert(false, "Unable to open asset pack file");
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
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);
|
Logf("Unknown image type [%s], unable to load", mime_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetInfo
|
Free(data);
|
||||||
GetAssetInfo(string name)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(image.data == null)
|
||||||
{
|
{
|
||||||
CheckAssetPack();
|
Logf("Failed to load GLTF image data/file");
|
||||||
|
image = DEFAULT_IMAGE;
|
||||||
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 image;
|
||||||
|
|
||||||
return asset_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8[]
|
ModelData
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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 placeholder_tex;
|
|
||||||
}
|
|
||||||
|
|
||||||
Model
|
|
||||||
LoadGLTF(Arena* arena, string file_name)
|
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_options opts;
|
||||||
cgltf_data* data;
|
cgltf_data* data;
|
||||||
@ -446,23 +361,110 @@ LoadGLTF(Arena* arena, string file_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
model.meshes = Alloc!(Mesh)(arena, primitive_count);
|
model.meshes = Alloc!(Mesh)(primitive_count);
|
||||||
model.mats = Alloc!(Material)(arena, data.materials_count+1);
|
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);
|
string file_path = GetFilePath(file_name);
|
||||||
for(u64 i = 0; i < data.materials_count; i += 1)
|
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)
|
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 model;
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 .. $];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
751
packer.d
751
packer.d
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
test.sh
2
test.sh
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
name="Test_Runner"
|
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
|
rm $name.o
|
||||||
./$name
|
./$name
|
||||||
|
|||||||
7
util.d
7
util.d
@ -6,7 +6,7 @@ import dlib.alloc;
|
|||||||
import xxhash3;
|
import xxhash3;
|
||||||
import includes;
|
import includes;
|
||||||
|
|
||||||
import std.stdio : write, writeln, writefln, stderr;
|
import std.stdio : write, writeln, writef, writefln, stderr;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import std.string;
|
import std.string;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
@ -72,11 +72,12 @@ Debugf(Args...)(string fmt, Args args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Logf(Args...)(string fmt, Args args, string prefix = "[INFO]: ")
|
Logf(Args...)(string fmt, Args args, string prefix = "INFO", string func = __FUNCTION__)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
write(prefix);
|
debug writef("[%s] FUNC: [%s]: ", prefix, func);
|
||||||
|
else write("[%s]: ", prefix);
|
||||||
writefln(fmt, args);
|
writefln(fmt, args);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user