469 lines
7.5 KiB
D
469 lines
7.5 KiB
D
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;
|
|
|
|
__gshared u8[] DEFAULT_TEXTURE = GenerateDefaultTexture(32, 32);
|
|
|
|
const u32 FILE_VERSION = 3;
|
|
const u32 MODEL_VERSION = 2;
|
|
|
|
// TODO:
|
|
// Alignment?
|
|
|
|
/*************************
|
|
****** 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 ******
|
|
*************************/
|
|
|
|
/************************
|
|
*** ASSET STRUCTURES ***
|
|
************************/
|
|
|
|
alias StringID = u64;
|
|
|
|
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;
|
|
}
|
|
|
|
/************************
|
|
*** ASSET STRUCTURES ***
|
|
************************/
|
|
|
|
/**************************
|
|
***** GFX STRUCTURES *****
|
|
**************************/
|
|
|
|
struct Vertex
|
|
{
|
|
Vec4 color;
|
|
Vec4 tangent;
|
|
Vec3 pos;
|
|
Vec3 normal;
|
|
Vec2 uv;
|
|
Vec2 uv2;
|
|
}
|
|
|
|
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,
|
|
}
|
|
|
|
/**************************
|
|
***** GFX STRUCTURES *****
|
|
**************************/
|
|
|
|
bool Asset_Pack_Opened = false;
|
|
|
|
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);
|
|
}
|
|
|
|
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 = 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]);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
Model model;
|
|
|
|
u8[] file_data; // = OpenFile(file_name);
|
|
|
|
cgltf_options opts;
|
|
cgltf_data* data;
|
|
|
|
opts.file.read = &GLTFLoadCallback;
|
|
opts.file.release = &GLTFFreeCallback;
|
|
|
|
cgltf_result result = cgltf_parse(&opts, file_data.ptr, file_data.length, &data);
|
|
|
|
if(result == cgltf_result_success)
|
|
{
|
|
result = cgltf_load_buffers(&opts, data, file_name.ptr);
|
|
if(result != cgltf_result_success)
|
|
{
|
|
Logf("%s Failure: Unable to load buffers", __FUNCTION__);
|
|
}
|
|
|
|
u64 primitive_count;
|
|
|
|
for(u64 i = 0; i < data.nodes_count; i += 1)
|
|
{
|
|
cgltf_node* node = &data.nodes[i];
|
|
|
|
if(node.mesh == null) continue;
|
|
|
|
for(u64 j = 0; j < node.mesh.primitives_count; j += 1)
|
|
{
|
|
if(node.mesh.primitives[j].type == cgltf_primitive_type_triangles)
|
|
{
|
|
primitive_count += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
model.meshes = Alloc!(Mesh)(arena, primitive_count);
|
|
model.mats = Alloc!(Material)(arena, data.materials_count+1);
|
|
|
|
// Make and load default material into model.mats[0]
|
|
|
|
string file_path = GetFilePath(file_name);
|
|
for(u64 i = 0; i < data.materials_count; i += 1)
|
|
{
|
|
// model.mats[i+1] = default_material;
|
|
|
|
if(data.materials[i].has_pbr_metallic_roughness)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return model;
|
|
}
|
|
|