rework mesh/materials and start gltf loading

This commit is contained in:
Matthew 2025-11-11 07:59:43 +11:00
parent 50b9ce9ee8
commit 9bc34ca4b9
6 changed files with 7367 additions and 55 deletions

View File

@ -88,6 +88,12 @@ struct AssetInfo
AssetType type; AssetType type;
} }
struct Mesh
{
Vertex[] vtx;
u32[] idx;
}
struct MeshPart struct MeshPart
{ {
u64 start; u64 start;
@ -97,15 +103,28 @@ struct MeshPart
struct ModelData struct ModelData
{ {
string name; string name;
Vertex[] vtx; Mesh[] meshes;
u32[] idx;
MaterialData[] mats; MaterialData[] mats;
MeshPart[] parts; }
struct MaterialMap
{
u32 texture_id;
Vec4 color;
f32 value;
}
struct Material
{
u32 shader_id;
MaterialMap[] maps;
Vec4 params;
} }
struct MaterialData struct MaterialData
{ {
string name; string name;
Vec3[MatColor.max] colors; Vec3[MatColor.max] colors;
string[MatMap.max] maps; string[MatMap.max] maps;
f32[MatFloat.max] props = 0.0; f32[MatFloat.max] props = 0.0;
@ -133,6 +152,7 @@ struct Vertex
Vec3 pos; Vec3 pos;
Vec3 normal; Vec3 normal;
Vec2 uv; Vec2 uv;
Vec2 uv2;
} }
enum IllumModel : u32 enum IllumModel : u32

7228
external/cgltf/cgltf.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,3 +24,6 @@
#define CGLM_FORCE_DEPTH_ZERO_TO_ONE #define CGLM_FORCE_DEPTH_ZERO_TO_ONE
#include "external/cglm/cglm.h" #include "external/cglm/cglm.h"
#define CGLTF_IMPLEMENTATION
#include "external/cgltf/cgltf.h"

145
packer.d
View File

@ -5,6 +5,7 @@ import dlib.util;
import dlib.aliases; import dlib.aliases;
import dlib.assets; import dlib.assets;
import dlib.platform; import dlib.platform;
import dlib.alloc;
import std.stdio; import std.stdio;
import std.string; import std.string;
@ -79,9 +80,9 @@ union MeshIdx
{ {
struct struct
{ {
u32 v, uv, n; u32 v, uv, n, t;
}; };
u32[3] arr; u32[4] arr;
} }
struct Model struct Model
@ -451,9 +452,20 @@ TokenizeLines(u8[] data)
u8[] u8[]
OpenFile(string file_name) OpenFile(string file_name)
{ {
File f = File(file_name, "rb"); File f;
u8[] data = new u8[f.size()]; u8[] data;
try
{
f = File(file_name, "rb");
data = new u8[f.size()];
f.rawRead(data); f.rawRead(data);
}
catch(Exception e)
{
data = null;
}
f.close(); f.close();
return data; return data;
@ -494,14 +506,14 @@ ConvertObj(string file_name)
Vec3[] positions = new Vec3[vcount]; Vec3[] positions = new Vec3[vcount];
Vec3[] normals = new Vec3[ncount]; Vec3[] normals = new Vec3[ncount];
Vec2[] uvs = new Vec2[uvcount]; Vec2[] uvs = new Vec2[uvcount];
MeshIdx[][] idx = []; MeshIdx[3][][] idx = [];
MaterialData[] mtls = []; MaterialData[] mtls = [];
vcount = 0; vcount = 0;
ncount = 0; ncount = 0;
uvcount = 0; uvcount = 0;
MeshIdx[] part_idx = []; MeshIdx[3][] part_idx = [];
for(u64 i = 0; i < tokens.length; i += 1) for(u64 i = 0; i < tokens.length; i += 1)
{ {
if(tokens[i][0] == "#") continue; if(tokens[i][0] == "#") continue;
@ -536,17 +548,18 @@ ConvertObj(string file_name)
if(tokens[i].length == 4) if(tokens[i].length == 4)
{ {
MeshIdx[3] face;
for(u64 j = 1; j < tokens[i].length; j += 1) for(u64 j = 1; j < tokens[i].length; j += 1)
{ {
string[] parts = tokens[i][j].split('/'); string[] parts = tokens[i][j].split('/');
if(sep_count == 0) if(sep_count == 0)
{ {
part_idx ~= MeshIdx(v: to!u32(parts[0])); face[j-1] = MeshIdx(v: to!u32(parts[0]));
} }
if(sep_count == 1) if(sep_count == 1)
{ {
part_idx ~= MeshIdx(v: to!u32(parts[0]), uv: to!u32(parts[1])); face[j-1] = MeshIdx(v: to!u32(parts[0]), uv: to!u32(parts[1]));
} }
if(sep_count == 2) if(sep_count == 2)
{ {
@ -557,9 +570,11 @@ ConvertObj(string file_name)
mesh_idx.arr[ipart] = to!u32(part); mesh_idx.arr[ipart] = to!u32(part);
} }
part_idx ~= mesh_idx; face[j-1] = mesh_idx;
} }
} }
part_idx ~= face;
} }
else assert(false, "Only triangles or quads supported for mesh face"); else assert(false, "Only triangles or quads supported for mesh face");
@ -569,7 +584,6 @@ ConvertObj(string file_name)
if(tokens[i][0] == "g" && part_idx.length > 0) if(tokens[i][0] == "g" && part_idx.length > 0)
{ {
idx ~= part_idx; idx ~= part_idx;
Logf("%s %s", idx.length, part_idx.length);
part_idx = []; part_idx = [];
continue; continue;
} }
@ -645,69 +659,110 @@ ConvertObj(string file_name)
face_count += part.length; face_count += part.length;
} }
positions = Deduplicate(positions, idx, 0);
uvs = Deduplicate(uvs, idx, 1);
normals = Deduplicate(normals, idx, 2);
ModelData md = { ModelData md = {
name: baseName(file_name, ".obj"), name: baseName(file_name, ".obj"),
vtx: new Vertex[face_count*3], 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; u64 vtx_count = 0;
foreach(part; idx) foreach(part; idx)
{ {
for(u64 i = 0; i < part.length; i += 1) for(u64 i = 0; i < part.length; i += 1)
{ {
MeshIdx* mi = part.ptr + i; 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];
}
if(mi.v ) md.vtx[vtx_count].pos = positions[mi.v-1]; vtx_count += 3;
if(mi.n ) md.vtx[vtx_count].normal = normals[mi.n-1];
if(mi.uv) md.vtx[vtx_count].uv = uvs[mi.uv-1];
vtx_count += 1;
} }
} }
return model; return model;
} }
T[] extern (C) cgltf_result
Deduplicate(T)(T[] values, MeshIdx[][] indices, u32 arr_idx) GLTFLoadCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, const(char)* path, cgltf_size* size, void** data)
{ {
u64 dup_count; u8[] file_data = OpenFile(ConvToStr(path[0 .. strlen(path)]));
for(u64 i = 0; i < values.length; i += 1)
{
for(u64 j = i+1; j < values.length; j += 1)
{
if(values[i] == values[j])
{
dup_count += 1;
Logf("before"); if(file_data == null) return cgltf_result_io_error;
values[j .. $] = values[j+1 .. values.length-1];
Logf("after");
foreach(ref part; indices) *size = cast(cgltf_size)file_data.length;
{ *data = Alloc!(u8)(file_data).ptr;
for(u64 k = 0; k < part.length; k += 1)
{ return cgltf_result_success;
if(part[k].arr[arr_idx] > j+1)
{
part[k].arr[arr_idx] -= 1;
} }
if(part[k].arr[arr_idx] == j+1) extern (C) void
GLTFFreeCallback(cgltf_memory_options* memory_opts, cgltf_file_options* file_opts, void* data, cgltf_size size)
{ {
part[k].arr[arr_idx] = cast(u32)(i+1); Free(data[0 .. size]);
}
} }
ModelData
LoadGLTF(string file_name)
{
ModelData 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 < mesh.primitives_count; j += 1)
{
if(mesh.primitives[j].type == cgltf_primtive_type_triangles)
{
primitive_count += 1;
} }
} }
} }
return values[0 .. values.length-dup_count]; model.meshes = new Mesh[primitive_count];
model.mats = new MaterialData[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)
{
}
}
}
} }
string string

View File

@ -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 --of=$name 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
rm $name.o rm $name.o
./$name ./$name

10
util.d
View File

@ -66,11 +66,17 @@ CastArr(T, U)(U[] input_array)
} }
void void
Logf(Args...)(string fmt, Args args) Debugf(Args...)(string fmt, Args args)
{
debug Logf(fmt, args, "[DEBUG]: ");
}
void
Logf(Args...)(string fmt, Args args, string prefix = "[INFO]: ")
{ {
try try
{ {
write("[INFO]: "); write(prefix);
writefln(fmt, args); writefln(fmt, args);
} }
catch (Exception e) catch (Exception e)