dlib/assets.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;
}