Backlog/engine/_archive/graphics/src/mesh.zig

304 lines
9.8 KiB
Zig

const std = @import("std");
const core = @import("core");
const vk_renderer = @import("vk_renderer.zig");
const vma = @import("vma");
const vk = @import("vulkan");
const obj_loader = @import("objLoader");
const constants = @import("vk_constants.zig");
const vk_utils = @import("vk_utils.zig");
const vk_dynamic_mesh = @import("vk_dynamic_mesh.zig");
const NeonVkUploader = vk_utils.NeonVkUploader;
const NeonVkBuffer = vk_renderer.NeonVkBuffer;
const ObjMesh = obj_loader.ObjMesh;
const ArrayList = std.ArrayList;
const Vectorf = core.Vectorf;
const Vector2f = core.Vector2f;
const Color = core.colors.Color;
const NeonVkContext = vk_renderer.NeonVkContext;
const debug_struct = core.debug_struct;
pub const DynamicMesh = vk_dynamic_mesh.DynamicMesh;
pub const DynamicMeshManager = vk_dynamic_mesh.DynamicMeshManager;
pub const MeshVertex = extern struct {
position: Vectorf = .{},
normal: Vectorf = .{},
color: Color = .{},
uv: Vector2f = .{},
bones: [4]u8 = .{ 0, 0, 0, 0 },
weights: [4]u8 = .{ 0, 0, 0, 0 },
};
pub const IndexBuffer = struct {
buffer: NeonVkBuffer,
indices: []const u32,
allocator: std.mem.Allocator,
pub fn uploadIndexBuffer(gc: *NeonVkContext, indices: []const u32, allocator: std.mem.Allocator) !@This() {
var self = @This(){
.buffer = undefined,
.indices = indices,
.allocator = allocator,
};
self.indices = try allocator.dupe(u32, indices);
const bufferSize = indices.len * @sizeOf(u32);
const bci = vk.BufferCreateInfo{
.flags = .{},
.size = bufferSize,
.usage = .{ .transfer_src_bit = true },
.sharing_mode = .exclusive,
.queue_family_index_count = 0,
.p_queue_family_indices = undefined,
};
const vmaCreateInfo = vma.AllocationCreateInfo{
.flags = .{},
.usage = .cpuOnly,
};
var stagingBuffer = try gc.vkAllocator.createBuffer(bci, vmaCreateInfo, @src().fn_name ++ " - upload buffer");
defer stagingBuffer.deinit(gc.vkAllocator);
{
const data = try gc.vkAllocator.vmaAllocator.mapMemory(stagingBuffer.allocation, u8);
var dataSlice: []u8 = undefined;
dataSlice.ptr = data;
dataSlice.len = bufferSize;
var iSlice: []const u8 = undefined;
iSlice.ptr = @as([*]const u8, @ptrCast(indices.ptr));
iSlice.len = bufferSize;
@memcpy(dataSlice, iSlice);
gc.vkAllocator.vmaAllocator.unmapMemory(stagingBuffer.allocation);
}
// GPU sided buffer
const gpuBci = vk.BufferCreateInfo{
.flags = .{},
.size = bufferSize,
.usage = .{ .transfer_dst_bit = true, .index_buffer_bit = true },
.sharing_mode = .exclusive,
.queue_family_index_count = 0,
.p_queue_family_indices = undefined,
};
const gpuVmaCreateInfo = vma.AllocationCreateInfo{
.flags = .{},
.usage = .gpuOnly,
};
self.buffer = try gc.vkAllocator.createBuffer(gpuBci, gpuVmaCreateInfo, @src().fn_name ++ " - gpu buffer");
//try gc.start_upload_context(&gc.uploadContext);
try gc.uploader.startUploadContext();
{
var copy = vk.BufferCopy{
.dst_offset = 0,
.src_offset = 0,
.size = bufferSize,
};
const cmd = gc.uploader.commandBuffer;
// core.graphics_log("Starting command copy buffer", .{});
gc.vkd.cmdCopyBuffer(
cmd,
stagingBuffer.buffer,
self.buffer.buffer,
1,
@as([*]const vk.BufferCopy, @ptrCast(&copy)),
);
}
//try gc.finish_upload_context(&gc.uploadContext);
try gc.uploader.finishUploadContext();
return self;
}
pub fn deinit(self: *@This(), gc: *NeonVkContext) void {
self.buffer.deinit(gc.vkAllocator);
self.allocator.free(self.indices);
}
};
pub fn loadObjMeshVertices(vertices: *ArrayList(MeshVertex), mesh: ObjMesh) !void {
try mesh.validate_mesh();
try vertices.ensureTotalCapacity(mesh.v_faces.items.len * 3);
for (mesh.v_faces.items) |face| {
if (face.count == 3) {
var i: u32 = 0;
while (i < 3) : (i += 1) {
const v = vertexFromFaceOffset(mesh, face, i);
try vertices.append(v);
}
} else if (face.count == 4) {
const vx = [_]MeshVertex{
vertexFromFaceOffset(mesh, face, 0),
vertexFromFaceOffset(mesh, face, 1),
vertexFromFaceOffset(mesh, face, 2),
vertexFromFaceOffset(mesh, face, 2),
vertexFromFaceOffset(mesh, face, 3),
vertexFromFaceOffset(mesh, face, 0),
};
try vertices.appendSlice(vx[0..]);
}
}
}
fn vertexFromFaceOffset(mesh: ObjMesh, face: obj_loader.ObjFace, offset: u32) MeshVertex {
const p = mesh.v_positions.items[face.vertex[offset] - 1];
const n = mesh.v_normals.items[face.normal[offset] - 1];
const u = mesh.v_uvs.items[face.texture[offset] - 1];
const v = MeshVertex{
.position = .{ .x = p.x, .y = p.y, .z = p.z },
.normal = .{ .x = n.x, .y = n.y, .z = n.z },
.color = .{ .r = n.x, .g = n.y, .b = n.z, .a = 1.0 },
.uv = .{ .x = u.x, .y = 1 - u.y },
};
return v;
}
// legacy, don't use
pub const Mesh = struct {
vertices: ArrayList(MeshVertex),
buffer: NeonVkBuffer,
allocator: std.mem.Allocator,
pub fn init(context: *NeonVkContext, allocator: std.mem.Allocator) Mesh {
const self = Mesh{
.vertices = ArrayList(MeshVertex).init(allocator),
.buffer = undefined,
.allocator = allocator,
};
_ = context;
return self;
}
pub fn upload(self: *Mesh, ctx: *NeonVkContext) !void {
try ctx.stage_and_push_mesh(self);
}
pub fn loadFromObjFileCooked(self: *Mesh, fileName: []const u8) !void {
const mapping = try core.fs().loadFile(fileName);
defer core.fs().unmap(mapping);
const s = @sizeOf(MeshVertex);
var i: usize = 0;
var vertexOffset: usize = 0;
try self.vertices.resize(1 + mapping.bytes.len / s);
while (i < mapping.bytes.len) : (i += s) {
self.vertices.items[vertexOffset] = @as(*const MeshVertex, @ptrCast(@alignCast(mapping.bytes.ptr + i))).*;
vertexOffset += 1;
}
}
pub fn load_from_obj_file(self: *Mesh, fileName: []const u8) !void {
const mapping = try core.fs().loadFile(fileName);
defer core.fs().unmap(mapping);
var fileObjs = try obj_loader.loadObjBytes(mapping.bytes, self.allocator);
defer fileObjs.deinit();
if (fileObjs.meshes.items.len > 0) {
// default grabbing shape zero
core.graphics_log("loading mesh: {s}", .{fileName});
// fileObjs.meshes.items[0].print_stats();
// try self.load_from_obj_mesh(fileObjs.meshes.items[0]);
try loadObjMeshVertices(&self.vertices, fileObjs.meshes.items[0]);
}
core.graphics_log("mesh loaded with {d} vertices size {d}", .{ self.vertices.items.len, self.vertices.items.len * @sizeOf(MeshVertex) });
}
pub fn deinit(self: *Mesh, ctx: *NeonVkContext) void {
self.buffer.deinit(ctx.vkAllocator);
self.vertices.deinit();
}
};
pub const VertexInputDescription = struct {
bindings: ArrayList(vk.VertexInputBindingDescription),
attributes: ArrayList(vk.VertexInputAttributeDescription),
flags: vk.PipelineVertexInputStateCreateFlags = .{},
pub fn init(allocator: std.mem.Allocator) !VertexInputDescription {
var self = VertexInputDescription{
.bindings = ArrayList(vk.VertexInputBindingDescription).init(allocator),
.attributes = ArrayList(vk.VertexInputAttributeDescription).init(allocator),
};
try self.bindings.append(.{
.binding = 0,
.stride = @sizeOf(MeshVertex),
.input_rate = .vertex,
});
//debug_struct("bindings 0", self.bindings.items[0]);
// position
try self.attributes.append(.{
.binding = 0,
.location = 0,
.format = .r32g32b32_sfloat,
.offset = @offsetOf(MeshVertex, "position"),
});
//debug_struct("attributes 0", self.attributes.items[0]);
// normal
try self.attributes.append(.{
.binding = 0,
.location = 1,
.format = .r32g32b32_sfloat,
.offset = @offsetOf(MeshVertex, "normal"),
});
//debug_struct("attributes 0", self.attributes.items[1]);
// color
try self.attributes.append(.{
.binding = 0,
.location = 2,
.format = .r32g32b32a32_sfloat,
.offset = @offsetOf(MeshVertex, "color"),
});
//debug_struct("attributes 0", self.attributes.items[2]);
try self.attributes.append(.{
.binding = 0,
.location = 3,
.format = .r32g32_sfloat,
.offset = @offsetOf(MeshVertex, "uv"),
});
try self.attributes.append(.{
.binding = 0,
.location = 4,
.format = .a8b8g8r8_uint_pack32,
.offset = @offsetOf(MeshVertex, "bones"),
});
try self.attributes.append(.{
.binding = 0,
.location = 5,
.format = .a8b8g8r8_uint_pack32,
.offset = @offsetOf(MeshVertex, "weights"),
});
return self;
}
pub fn deinit(self: *@This()) void {
self.bindings.deinit();
self.attributes.deinit();
}
};