304 lines
9.8 KiB
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(©)),
|
|
);
|
|
}
|
|
|
|
//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();
|
|
}
|
|
};
|