285 lines
12 KiB
Zig
285 lines
12 KiB
Zig
pub fn loadIndexedMeshForPoolingGltf(allocator: std.mem.Allocator, meshName: core.Name, skeletonName: ?core.Name, path: []const u8) !MeshUpdate {
|
|
const file = try core.fs().loadFile(path);
|
|
defer core.fs().unmap(file);
|
|
|
|
const gcAllocator = allocator;
|
|
|
|
// const allocator = gMeshPoolBuffer.allocator;
|
|
|
|
var parser = zgltf.init(allocator);
|
|
defer parser.deinit();
|
|
|
|
const ext = core.getFileExtension(path);
|
|
if (std.mem.eql(u8, ".gltf", ext)) {
|
|
try parser.parse(@alignCast(file.bytes[0 .. file.bytes.len - 1]));
|
|
} else {
|
|
try parser.parse(@alignCast(file.bytes));
|
|
}
|
|
|
|
// std.debug.print("\n", .{});
|
|
// parser.debugPrint();
|
|
|
|
if (parser.data.meshes.items.len > 1) {
|
|
return error.OnlyOneMeshPerGltfImplemented;
|
|
}
|
|
|
|
if (parser.data.skins.items.len > 1) {
|
|
return error.TooManySkins;
|
|
}
|
|
|
|
var binaryFile: ?core.packer.PackerBytesMapping = null;
|
|
var binaryBytes: []const u8 = undefined;
|
|
|
|
if (std.mem.eql(u8, ext, ".glb")) {
|
|
binaryBytes = parser.glb_binary.?;
|
|
} else {
|
|
const binaryPath = try std.fmt.allocPrint(allocator, "{s}bin", .{path[0 .. path.len - 4]});
|
|
defer allocator.free(binaryPath);
|
|
core.engine_log("{s}", .{binaryPath});
|
|
binaryFile = try core.fs().loadFile(binaryPath);
|
|
binaryBytes = binaryFile.?.bytes;
|
|
}
|
|
|
|
defer if (binaryFile) |f| core.fs().unmap(f);
|
|
|
|
const m = parser.data.meshes.items[0];
|
|
core.engine_log("mesh name {s} number of primitives = {d}", .{ m.name, m.primitives.items.len });
|
|
|
|
var positions = std.ArrayList(f32).init(allocator);
|
|
defer positions.deinit();
|
|
|
|
var texcoords = std.ArrayList(f32).init(allocator);
|
|
defer texcoords.deinit();
|
|
|
|
var normals = std.ArrayList(f32).init(allocator);
|
|
defer normals.deinit();
|
|
|
|
var joints = std.ArrayList(u16).init(allocator);
|
|
defer joints.deinit();
|
|
// add a different joint format one, todo- i need to fix up zgltf
|
|
|
|
var useJoints8: bool = false;
|
|
var joints8 = std.ArrayList(u8).init(allocator);
|
|
defer joints8.deinit();
|
|
|
|
var weights = std.ArrayList(f32).init(allocator);
|
|
defer weights.deinit();
|
|
|
|
var weightCount: usize = 4;
|
|
|
|
if (m.primitives.items.len > 1) {
|
|
@panic("sorry, havent implemented support for multiple primitives yet, would require more work on the way i handle materials");
|
|
}
|
|
|
|
var indexList = std.ArrayList(u32).init(allocator);
|
|
for (m.primitives.items) |primitive| {
|
|
if (primitive.indices) |indices| {
|
|
const accessor = parser.data.accessors.items[indices];
|
|
// core.engine_log("index accessor info: {any}", .{accessor});
|
|
|
|
if (accessor.component_type == .unsigned_short) {
|
|
var temp = std.ArrayList(u16).init(allocator);
|
|
defer temp.deinit();
|
|
parser.getDataFromBufferView(u16, &temp, accessor, @alignCast(binaryBytes));
|
|
for (temp.items) |t| {
|
|
try indexList.append(@intCast(t));
|
|
}
|
|
} else if (accessor.component_type == .unsigned_integer) {
|
|
parser.getDataFromBufferView(u32, &indexList, accessor, @alignCast(binaryBytes));
|
|
}
|
|
}
|
|
|
|
for (primitive.attributes.items) |attribute| {
|
|
// core.engine_log("attribute: {any}", .{attribute});
|
|
|
|
switch (attribute) {
|
|
.position => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
// core.engine_log("accessor info: {any}", .{accessor});
|
|
|
|
parser.getDataFromBufferView(f32, &positions, accessor, @alignCast(binaryBytes));
|
|
// core.engine_log("positions loaded: {d}", .{positions.items.len});
|
|
},
|
|
.normal => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
// core.engine_log("accessor info: {any}", .{accessor});
|
|
|
|
parser.getDataFromBufferView(f32, &normals, accessor, @alignCast(binaryBytes));
|
|
// core.engine_log("normals loaded: {d}", .{normals.items.len});
|
|
},
|
|
.texcoord => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
// core.engine_log("accessor info: {any}", .{accessor});
|
|
|
|
parser.getDataFromBufferView(f32, &texcoords, accessor, @alignCast(binaryBytes));
|
|
// core.engine_log("texcoords loaded: {d}", .{texcoords.items.len});
|
|
},
|
|
.joints => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
// core.engine_log("accessor info: {any} acecssor index {d}", .{ accessor, x });
|
|
|
|
if (accessor.component_type == .unsigned_byte) {
|
|
useJoints8 = true;
|
|
parser.getDataFromBufferView(u8, &joints8, accessor, @alignCast(binaryBytes));
|
|
// core.engine_log("joints8 loaded: {d} - {d} {d} {d} {d}", .{ joints8.items.len, joints8.items[0], joints8.items[1], joints8.items[2], joints8.items[3] });
|
|
} else {
|
|
parser.getDataFromBufferView(u16, &joints, accessor, @alignCast(binaryBytes));
|
|
// core.engine_log("joints loaded: {d} - {d} {d} {d} {d}", .{ joints.items.len, joints.items[0], joints.items[1], joints.items[2], joints.items[3] });
|
|
}
|
|
},
|
|
.weights => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
// core.engine_log("accessor info: {any}", .{accessor});
|
|
|
|
parser.getDataFromBufferView(f32, &weights, accessor, @alignCast(binaryBytes));
|
|
|
|
if (accessor.type == .vec3) {
|
|
weightCount = 3;
|
|
}
|
|
|
|
// core.engine_log("weights loaded: {d} - {d} {d} {d} {d}", .{ weights.items.len, weights.items[0], weights.items[1], weights.items[2], weights.items[3] });
|
|
},
|
|
.tangent => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
core.engine_log("accessor info: {any} NOT PARSED", .{accessor});
|
|
},
|
|
.color => |x| {
|
|
const accessor = parser.data.accessors.items[x];
|
|
core.engine_log("accessor info: {any} NOT PARSED", .{accessor});
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parser.data.skins.items.len > 1) {
|
|
@panic("too many skins, not supported");
|
|
}
|
|
|
|
var jointNameList: std.ArrayList(JointNameEntry) = std.ArrayList(JointNameEntry).init(allocator);
|
|
|
|
if (weights.items.len > 0) {
|
|
core.engine_log("skin found, building joint map", .{});
|
|
if (parser.data.skins.items[0].skeleton) |skeletonIndex| {
|
|
for (parser.data.nodes.items[skeletonIndex..], 0..) |node, i| {
|
|
// core.engine_log("gltf: {s} -> {d} (skeleton index)", .{ node.name, i });
|
|
// const gcAllocator = graphics.getContext().allocator;
|
|
try jointNameList.append(.{ .index = @intCast(i), .name = try gcAllocator.dupe(u8, node.name) });
|
|
}
|
|
} else {
|
|
if (parser.data.skins.items[0].joints.items.len > 0) {
|
|
for (parser.data.skins.items[0].joints.items, 0..) |i, j| {
|
|
const node = parser.data.nodes.items[i];
|
|
// core.engine_log("gltf: {s} -> {d} (joints map)", .{ node.name, j });
|
|
// const gcAllocator = graphics.getContext().allocator;
|
|
try jointNameList.append(.{ .index = @intCast(j), .name = try gcAllocator.dupe(u8, node.name) });
|
|
}
|
|
} else {
|
|
for (parser.data.nodes.items, 0..) |node, i| {
|
|
// core.engine_log("gltf: {s} -> {d} (fallback)", .{ node.name, i });
|
|
// const gcAllocator = graphics.getContext().allocator;
|
|
try jointNameList.append(.{ .index = @intCast(i), .name = try gcAllocator.dupe(u8, node.name) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var vertexList = std.ArrayList(MeshVertex).init(allocator);
|
|
|
|
var i: usize = 0;
|
|
const vertexCount = positions.items.len / 3;
|
|
while (i < vertexCount) : (i += 1) {
|
|
const normalIndex = i * 3;
|
|
const positionIndex = i * 3;
|
|
const uvIndex = i * 2;
|
|
|
|
const uv: core.Vector2f = if (uvIndex < texcoords.items.len) .{
|
|
.x = texcoords.items[uvIndex],
|
|
.y = texcoords.items[uvIndex + 1],
|
|
} else core.Vector2f{};
|
|
|
|
const normal = if (normalIndex < normals.items.len) core.Vectorf{
|
|
.x = normals.items[i],
|
|
.y = normals.items[i + 1],
|
|
.z = normals.items[i + 2],
|
|
} else core.Vectorf{};
|
|
|
|
try vertexList.append(.{
|
|
.position = .{
|
|
.x = positions.items[positionIndex],
|
|
.y = positions.items[positionIndex + 1],
|
|
.z = positions.items[positionIndex + 2],
|
|
},
|
|
.normal = normal,
|
|
.color = .{},
|
|
.uv = uv,
|
|
});
|
|
|
|
const jointsIndex = weightCount * i;
|
|
if (weightCount == 4) {
|
|
if (useJoints8) {
|
|
if (jointsIndex < joints8.items.len) {
|
|
vertexList.items[vertexList.items.len - 1].bones = .{
|
|
@intCast(joints8.items[jointsIndex + 0]),
|
|
@intCast(joints8.items[jointsIndex + 1]),
|
|
@intCast(joints8.items[jointsIndex + 2]),
|
|
@intCast(joints8.items[jointsIndex + 3]),
|
|
};
|
|
vertexList.items[vertexList.items.len - 1].weights = .{
|
|
@intFromFloat(weights.items[jointsIndex + 0] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 1] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 2] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 3] * 255),
|
|
};
|
|
}
|
|
} else {
|
|
if (jointsIndex < joints.items.len) {
|
|
vertexList.items[vertexList.items.len - 1].bones = .{
|
|
@intCast(joints.items[jointsIndex + 0]),
|
|
@intCast(joints.items[jointsIndex + 1]),
|
|
@intCast(joints.items[jointsIndex + 2]),
|
|
@intCast(joints.items[jointsIndex + 3]),
|
|
};
|
|
vertexList.items[vertexList.items.len - 1].weights = .{
|
|
@intFromFloat(weights.items[jointsIndex + 0] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 1] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 2] * 255),
|
|
@intFromFloat(weights.items[jointsIndex + 3] * 255),
|
|
};
|
|
}
|
|
}
|
|
} else {
|
|
return error.NotImplementedYet;
|
|
}
|
|
}
|
|
|
|
if (indexList.items.len == 0) {
|
|
for (0..vertexList.items.len) |x| {
|
|
try indexList.append(@intCast(x));
|
|
}
|
|
}
|
|
|
|
const rv: MeshUpdate = .{
|
|
.new = .{
|
|
.vertices = try vertexList.toOwnedSlice(),
|
|
.indices = try indexList.toOwnedSlice(),
|
|
.jointNames = try jointNameList.toOwnedSlice(),
|
|
.skeletonName = skeletonName,
|
|
.name = meshName,
|
|
},
|
|
};
|
|
|
|
core.graphics_log("[{s}] gltf loaded vertex count vertices={d} indices={d}", .{ path, rv.new.vertices.len, rv.new.indices.len });
|
|
|
|
// try gMeshPoolBuffer.updateRequests.pushLocked(rv);
|
|
return rv;
|
|
}
|
|
|
|
const meshes = @import("meshes.zig");
|
|
const MeshUpdate = meshes.MeshUpdate;
|
|
const JointNameEntry = meshes.JointNameEntry;
|
|
const MeshVertex = meshes.MeshVertex;
|
|
|
|
const core = @import("core");
|
|
const std = @import("std");
|
|
const zgltf = @import("zgltf");
|