diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/assets.d b/assets.d index 13dadfa..af9ad5c 100644 --- a/assets.d +++ b/assets.d @@ -4,6 +4,7 @@ import includes; import dlib.aliases; import dlib.util; import dlib.alloc; +import dlib.math; import std.file; import std.path; @@ -86,18 +87,17 @@ struct Material struct Vertex { - Vec4 color; - Vec4 tangent; - Vec3 pos; - Vec3 normal; - Vec2 uv; - Vec2 uv2; + Vec4 color; + Vec4 tangent; + Vec3 pos; + Vec3 normal; + Vec2[2] uv; } struct Mesh { Vertex[] vtx; - u32 idx; + u32[] idx; u32 mat_id; } @@ -105,6 +105,9 @@ struct Model { Mat4 transform; + Vertex[] vtx_buf; + u32[] idx_buf; + Mesh[] meshes; Material[] mats; @@ -345,6 +348,8 @@ LoadGLTF(Arena* arena, string file_name) } u64 primitive_count; + u64 vtx_count; + u64 idx_count; for(u64 i = 0; i < data.nodes_count; i += 1) { @@ -357,13 +362,30 @@ LoadGLTF(Arena* arena, string file_name) 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.meshes = Alloc!(Mesh)(primitive_count); - model.mats = Alloc!(Material)(data.materials_count+1); - m_data.tex = Alloc!(ImageData)(data.textures_count+1); + 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; @@ -420,12 +442,297 @@ LoadGLTF(Arena* arena, string file_name) } } + 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]; + *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) diff --git a/build.sh b/build.sh index 7deeb39..9481fcd 100755 --- a/build.sh +++ b/build.sh @@ -36,16 +36,16 @@ if ! [ -f "${build}/libstb.a" ]; then fi # M3D -src="${script_dir}/external/m3d/m3d.c" -flags="-std=c99 -Wno-everything -Iexternal/m3d -c -static" -obj="${build}/m3d.o" -lib="${build}/libm3d.a" - -if ! [ -f "${build}/libm3d.a" ]; then - $c_compiler $flags $src $out $obj - ar rcs $lib $obj - rm $obj -fi +#src="${script_dir}/external/m3d/m3d.c" +#flags="-std=c99 -Wno-everything -Iexternal/m3d -c -static" +#obj="${build}/m3d.o" +#lib="${build}/libm3d.a" +# +#if ! [ -f "${build}/libm3d.a" ]; then +# $c_compiler $flags $src $out $obj +# ar rcs $lib $obj +# rm $obj +#fi # CGLM src="${script_dir}/external/cglm/cglm.c" diff --git a/math.d b/math.d index 78cc76c..1b860ba 100644 --- a/math.d +++ b/math.d @@ -435,6 +435,11 @@ align(16) struct Matrix(T, int D) } } + this(U)(U x) if(is(U: typeof(this.v))) + { + this.v = x; + } + @property inout(T)* ptr() inout { return v.ptr; @@ -924,6 +929,14 @@ Inverse(Mat4 mat) return res; } +void +Transform(Vec3* vec, Mat4* mat, f32 last = 1.0) +{ + Vec4 tvec = Vec4(*vec, last); + tvec = *mat * tvec; + *vec = tvec.xyz; +} + pragma(inline) f32 Lerp(f32 x, f32 y, f32 a) { @@ -1129,10 +1142,27 @@ unittest assert(vec == Vec4(1.0, 2.0, 3.0, 4.0)); Mat2 mat = Mat2(1.0, 0.0, 0.0, 1.0); - Mat4 mat4; + + f32[16] floats = 22.0; + Mat4 mat4 = Mat4(floats); + assert(mat4.v == floats); Quat quat = Quat(1.0, 1.0, 1.0, 1.0); Quat quat2; } + + { + Vec3 vec = Vec3(1.0, 2.0, 3.0); + Mat4 mat = Mat4( + 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, + 3.0, 3.0, 3.0, 3.0, + 4.0, 4.0, 4.0, 4.0 + ); + + Transform(&vec, &mat, 1.0); + + assert(vec == Vec3(18.0)); + } } diff --git a/test.sh b/test.sh index ddcc007..36bbaa8 100755 --- a/test.sh +++ b/test.sh @@ -2,7 +2,9 @@ name="Test_Runner" -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 +/bin/bash ./build.sh build + +ldc2 platform.d aliases.d math.d util.d alloc.d assets.d external/xxhash/xxhash.d build/libcglm.a -Xcc=-mno-sse -P-I/usr/include/freetype2 -L-lfreetype --main --unittest -g --of=$name rm $name.o ./$name