781 lines
20 KiB
D
781 lines
20 KiB
D
module dlib.assets;
|
|
|
|
import includes;
|
|
import dlib.aliases;
|
|
import dlib.util;
|
|
import dlib.alloc;
|
|
import dlib.math;
|
|
|
|
import std.file;
|
|
import std.path;
|
|
import std.format;
|
|
import std.stdio;
|
|
import std.exception;
|
|
|
|
__gshared ImageData DEFAULT_IMAGE = GenerateDefaultTexture(32, 32);
|
|
__gshared Material DEFAULT_MATERIAL = GenerateDefaultMaterial();
|
|
|
|
// TODO:
|
|
// Alignment?
|
|
|
|
/*************************
|
|
****** FILE PACKER ******
|
|
*************************/
|
|
|
|
/*************************
|
|
****** FILE PACKER ******
|
|
*************************/
|
|
|
|
/************************
|
|
*** ASSET STRUCTURES ***
|
|
************************/
|
|
|
|
struct ImageData
|
|
{
|
|
u8[] data;
|
|
u32 w;
|
|
u32 h;
|
|
u32 ch;
|
|
}
|
|
|
|
struct ModelData
|
|
{
|
|
Model model;
|
|
ImageData[] tex;
|
|
}
|
|
|
|
/************************
|
|
*** ASSET STRUCTURES ***
|
|
************************/
|
|
|
|
/**************************
|
|
***** GFX STRUCTURES *****
|
|
**************************/
|
|
|
|
enum MaterialMapIndex
|
|
{
|
|
Albedo,
|
|
Normal,
|
|
Metallic,
|
|
Roughness,
|
|
Occlusion,
|
|
Emission,
|
|
Height,
|
|
Cubemap,
|
|
Irradiance,
|
|
Prefilter,
|
|
BRDF,
|
|
|
|
Max,
|
|
}
|
|
|
|
alias MMI = MaterialMapIndex;
|
|
|
|
struct MaterialMap
|
|
{
|
|
Vec4 col;
|
|
u32 tex_id;
|
|
f32 value;
|
|
}
|
|
|
|
struct Material
|
|
{
|
|
u32 pipeline_id;
|
|
MaterialMap[MMI.max] maps;
|
|
}
|
|
|
|
struct Vertex
|
|
{
|
|
Vec4 color;
|
|
Vec4 tangent;
|
|
Vec3 pos;
|
|
Vec3 normal;
|
|
Vec2[2] uv;
|
|
}
|
|
|
|
struct Mesh
|
|
{
|
|
Vertex[] vtx;
|
|
u32[] idx;
|
|
u64 start;
|
|
u64 length;
|
|
u32 mat_id;
|
|
}
|
|
|
|
struct Model
|
|
{
|
|
Mat4 transform;
|
|
|
|
Vertex[] vtx_buf;
|
|
u32[] idx_buf;
|
|
|
|
Mesh[] meshes;
|
|
Material[] mats;
|
|
|
|
// TODO: bones/animations
|
|
}
|
|
|
|
/**************************
|
|
***** GFX STRUCTURES *****
|
|
**************************/
|
|
|
|
__gshared string g_BASE_ASSETS_DIR;
|
|
|
|
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));
|
|
}
|
|
|
|
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[]
|
|
OpenFile(string file_name)
|
|
{
|
|
File f;
|
|
u8[] data;
|
|
|
|
try
|
|
{
|
|
f = File(file_name, "rb");
|
|
data = Alloc!(u8)(f.size());
|
|
f.rawRead(data);
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
data = null;
|
|
}
|
|
|
|
f.close();
|
|
|
|
return data;
|
|
}
|
|
|
|
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 = 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);
|
|
}
|
|
|
|
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
|
|
{
|
|
char[512] buf;
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
if(type == mime_type)
|
|
{
|
|
accepted = true;
|
|
goto PostTypeCheck;
|
|
}
|
|
}
|
|
|
|
PostTypeCheck:
|
|
u8[] image_data;
|
|
if(accepted)
|
|
{
|
|
image = LoadImage(data.ptr, cast(i32)data.length);
|
|
}
|
|
else
|
|
{
|
|
Logf("Unknown image type [%s], unable to load", mime_type);
|
|
}
|
|
|
|
Free(data);
|
|
}
|
|
}
|
|
|
|
if(image.data == null)
|
|
{
|
|
Logf("Failed to load GLTF image data/file");
|
|
image = DEFAULT_IMAGE;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
ModelData
|
|
LoadGLTF(Arena* arena, string file_name)
|
|
{
|
|
ModelData m_data;
|
|
Model* model = &m_data.model;
|
|
|
|
u8[] file_data = OpenFile(file_name);
|
|
assert(file_data != null);
|
|
|
|
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;
|
|
u64 vtx_count;
|
|
u64 idx_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;
|
|
|
|
if(node.mesh.primitives[j].indices != null && node.mesh.primitives[j].indices.buffer_view != null)
|
|
{
|
|
idx_count += node.mesh.primitives[j].indices.count;
|
|
}
|
|
|
|
for(u64 k = 0; k < node.mesh.primitives[j].attributes_count; k += 1)
|
|
{
|
|
if(node.mesh.primitives[j].attributes[k].type == cgltf_attribute_type_position)
|
|
{
|
|
vtx_count += node.mesh.primitives[j].attributes[k].data.count;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
model.idx_buf = Alloc!(u32)(idx_count);
|
|
model.vtx_buf = Alloc!(Vertex)(vtx_count);
|
|
model.meshes = Alloc!(Mesh)(primitive_count);
|
|
model.mats = Alloc!(Material)(data.materials_count+1);
|
|
m_data.tex = Alloc!(ImageData)(data.textures_count+1);
|
|
|
|
model.mats[0] = DEFAULT_MATERIAL;
|
|
|
|
u32 tex_idx;
|
|
string file_path = GetFilePath(file_name);
|
|
for(u64 i = 0; i < data.materials_count; i += 1)
|
|
{
|
|
u64 mat_idx = i+1;
|
|
|
|
model.mats[mat_idx] = DEFAULT_MATERIAL;
|
|
|
|
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.a = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
u64 mesh_index, idx_index;
|
|
vtx_count = 0;
|
|
for(u64 i = 0; i < data.nodes_count; i += 1)
|
|
{
|
|
cgltf_node* node = &data.nodes[i];
|
|
cgltf_mesh* mesh = node.mesh;
|
|
|
|
if(mesh == null) continue;
|
|
|
|
cgltf_float[16] world_transform;
|
|
cgltf_node_transform_world(node, world_transform.ptr);
|
|
|
|
Mat4 world_matrix = Mat4(world_transform);
|
|
|
|
for(u64 p = 0; p < mesh.primitives_count; p += 1)
|
|
{
|
|
if(mesh.primitives[p].type != cgltf_primitive_type_triangles)
|
|
{
|
|
Logf("Unable to process primitive type [%s]", mesh.primitives[p].type);
|
|
continue;
|
|
}
|
|
|
|
auto prim = mesh.primitives + p;
|
|
for(u64 j = 0; j < prim.attributes_count; j += 1)
|
|
{
|
|
switch(prim.attributes[j].type)
|
|
{
|
|
case cgltf_attribute_type_position:
|
|
{
|
|
cgltf_accessor* attr = prim.attributes[j].data;
|
|
|
|
if(attr.type == cgltf_type_vec3 && attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
AddMeshVertices(attr, model, mesh_index, &vtx_count);
|
|
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].pos = Vec3(buffer[3*k+0], buffer[3*k+1], buffer[3*k+2]);
|
|
Transform(&model.meshes[mesh_index].vtx[k].pos, &world_matrix, 1.0);
|
|
}
|
|
}
|
|
else Logf("Format needs to be Vec3 f32, skipping.");
|
|
} break;
|
|
case cgltf_attribute_type_normal:
|
|
{
|
|
cgltf_accessor* attr = prim.attributes[j].data;
|
|
|
|
if(attr.type == cgltf_type_vec3 && attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
AddMeshVertices(attr, model, mesh_index, &vtx_count);
|
|
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].normal = Vec3(buffer[3*k+0], buffer[3*k+1], buffer[3*k+2]);
|
|
Transform(&model.meshes[mesh_index].vtx[k].normal, &world_matrix, 1.0);
|
|
}
|
|
}
|
|
else Logf("Format needs to be Vec3 f32, skipping.");
|
|
} break;
|
|
case cgltf_attribute_type_tangent:
|
|
{
|
|
cgltf_accessor* attr = prim.attributes[j].data;
|
|
|
|
if(attr.type == cgltf_type_vec4 && attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
AddMeshVertices(attr, model, mesh_index, &vtx_count);
|
|
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].tangent = world_matrix * Vec4(buffer[4*k+0], buffer[4*k+1], buffer[4*k+2], buffer[4*k+3]);
|
|
}
|
|
}
|
|
else Logf("Format needs to be Vec4 f32, skipping.");
|
|
} break;
|
|
case cgltf_attribute_type_texcoord:
|
|
{
|
|
cgltf_accessor* attr = prim.attributes[j].data;
|
|
|
|
if(attr.type == cgltf_type_vec2)
|
|
{
|
|
AddMeshVertices(attr, model, mesh_index, &vtx_count);
|
|
|
|
u32 uv_idx = prim.attributes[j].index;
|
|
if(uv_idx >= 2)
|
|
{
|
|
Logf("Unable to use more than two uvs, skipping");
|
|
continue;
|
|
}
|
|
|
|
if(attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].uv[uv_idx] = Vec2(buffer[2*k+0], buffer[2*k+1]);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_8u)
|
|
{
|
|
u8* buffer = GetGLTFBuffer!(u8)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].uv[uv_idx] = Vec2(cast(f32)(buffer[2*k+0])/255.0, cast(f32)(buffer[2*k+1])/255.0);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_16u)
|
|
{
|
|
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].uv[uv_idx] = Vec2(cast(f32)(buffer[2*k+0])/65535.0, cast(f32)(buffer[2*k+1])/65535.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Logf("Unsupported format [%s] for uv, skipping", attr.component_type);
|
|
}
|
|
}
|
|
} break;
|
|
case cgltf_attribute_type_color:
|
|
{
|
|
cgltf_accessor* attr = prim.attributes[j].data;
|
|
|
|
if(attr.type == cgltf_type_vec3 || attr.type == cgltf_type_vec4)
|
|
{
|
|
AddMeshVertices(attr, model, mesh_index, &vtx_count);
|
|
|
|
if(attr.type == cgltf_type_vec3)
|
|
{
|
|
if(attr.component_type == cgltf_component_type_r_8u)
|
|
{
|
|
u8* buffer = GetGLTFBuffer!(u8)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
|
cast(f32)(buffer[k*3+0])/255.0,
|
|
cast(f32)(buffer[k*3+1])/255.0,
|
|
cast(f32)(buffer[k*3+2])/255.0,
|
|
1.0
|
|
);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_16u)
|
|
{
|
|
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
|
cast(f32)(buffer[k*3+0])/65535.0,
|
|
cast(f32)(buffer[k*3+1])/65535.0,
|
|
cast(f32)(buffer[k*3+2])/65535.0,
|
|
1.0
|
|
);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(buffer[k*3+0], buffer[k*3+1], buffer[k*3+2], 1.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Logf("Color component type [%s] not supported", attr.component_type);
|
|
}
|
|
}
|
|
else if(attr.type == cgltf_type_vec4)
|
|
{
|
|
if(attr.component_type == cgltf_component_type_r_8u)
|
|
{
|
|
u8* buffer = GetGLTFBuffer!(u8)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
|
cast(f32)(buffer[k*4+0])/255.0,
|
|
cast(f32)(buffer[k*4+1])/255.0,
|
|
cast(f32)(buffer[k*4+2])/255.0,
|
|
cast(f32)(buffer[k*4+3])/255.0
|
|
);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_16u)
|
|
{
|
|
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(
|
|
cast(f32)(buffer[k*4+0])/65535.0,
|
|
cast(f32)(buffer[k*4+1])/65535.0,
|
|
cast(f32)(buffer[k*4+2])/65535.0,
|
|
cast(f32)(buffer[k*4+3])/65535.0
|
|
);
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_32f)
|
|
{
|
|
f32* buffer = GetGLTFBuffer!(f32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].vtx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].vtx[k].color = Vec4(buffer[k*4+0], buffer[k*4+1], buffer[k*4+2], buffer[k*4+3]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Logf("Color component type [%s] not supported", attr.component_type);
|
|
}
|
|
|
|
}
|
|
}
|
|
} break;
|
|
default: break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if(prim.indices != null && prim.indices.buffer_view != null)
|
|
{
|
|
cgltf_accessor* attr = prim.indices;
|
|
|
|
model.meshes[mesh_index].idx = model.idx_buf[idx_index .. idx_index+attr.count];
|
|
idx_index += attr.count;
|
|
|
|
if(attr.component_type == cgltf_component_type_r_16u)
|
|
{
|
|
u16* buffer = GetGLTFBuffer!(u16)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].idx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].idx[k] = cast(u32)buffer[k];
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_8u)
|
|
{
|
|
u8* buffer = GetGLTFBuffer!(u8)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].idx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].idx[k] = cast(u32)buffer[k];
|
|
}
|
|
}
|
|
else if(attr.component_type == cgltf_component_type_r_32u)
|
|
{
|
|
u32* buffer = GetGLTFBuffer!(u32)(attr);
|
|
for(u64 k = 0; k < model.meshes[mesh_index].idx.length; k += 1)
|
|
{
|
|
model.meshes[mesh_index].idx[k] = buffer[k];
|
|
}
|
|
}
|
|
else Logf("Unsupported index type [%s]", attr.component_type);
|
|
}
|
|
else // unindexed mesh (may implement later)
|
|
{
|
|
Logf("Unindexed mesh encountered");
|
|
}
|
|
|
|
for(u32 k = 0; k < data.materials_count; k += 1)
|
|
{
|
|
if(data.materials + k == prim.material)
|
|
{
|
|
model.meshes[mesh_index].mat_id = k+1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mesh_index += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_data;
|
|
}
|
|
|
|
void
|
|
AddMeshVertices(cgltf_accessor* accessor, Model* model, u64 mesh_index, u64* vtx_count)
|
|
{
|
|
if(model.meshes[mesh_index].vtx == null)
|
|
{
|
|
model.meshes[mesh_index].vtx = model.vtx_buf[*vtx_count .. *vtx_count+accessor.count];
|
|
model.meshes[mesh_index].start = *vtx_count;
|
|
model.meshes[mesh_index].length = accessor.count;
|
|
*vtx_count += accessor.count;
|
|
}
|
|
}
|
|
|
|
T*
|
|
GetGLTFBuffer(T)(cgltf_accessor* accessor)
|
|
{
|
|
return cast(T*)(accessor.buffer_view.buffer.data + accessor.buffer_view.offset/T.sizeof + accessor.offset/T.sizeof);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|