commit dd09b4131dced5f702ba7c26bbe413a1f6316fb3
parent dd54785a418716cb14026d20e4089d4da1690a8a
Author: Christian Ermann <christianermann@gmail.com>
Date: Fri, 6 Dec 2024 21:35:49 -0800
Rename 'MeshBuffer' to 'RenderData' and move to separate file
Diffstat:
4 files changed, 345 insertions(+), 368 deletions(-)
diff --git a/src/line_render_pipeline.zig b/src/line_render_pipeline.zig
@@ -2,7 +2,7 @@ const std = @import("std");
const gpu = @import("mach_gpu");
const App = @import("main.zig").App;
-const MeshBuffer = @import("main.zig").MeshBuffer;
+const RenderData = @import("render_data.zig");
const UniformData = @import("main.zig").UniformData;
const f32x4 = @import("main.zig").f32x4;
const mat4 = @import("main.zig").mat4;
@@ -10,14 +10,13 @@ const CubeMap = @import("cubemap.zig");
const Textures = @import("textures.zig");
const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
const Buffer = @import("main.zig").Buffer;
-const InstanceData = @import("main.zig").MeshInstanceData;
const Self = @This();
pub const Buffers = struct {
positions: *const Buffer(f32x4),
indices: *const Buffer(u32),
- instances: *const Buffer(InstanceData),
+ object_data: *const Buffer(RenderData.ObjectData),
indirect: *const Buffer([5]u32),
};
@@ -66,7 +65,7 @@ pub fn init(
const bind_group_descriptor = gpu.BindGroup.Descriptor.init(.{
.layout = bind_group_layout,
.entries = &.{
- gpu.BindGroup.Entry.buffer(0, buffers.instances.data, 0, buffers.instances.size),
+ gpu.BindGroup.Entry.buffer(0, buffers.object_data.data, 0, buffers.object_data.size),
gpu.BindGroup.Entry.buffer(1, uniform_buffer, 0, @sizeOf(UniformData)),
},
});
diff --git a/src/main.zig b/src/main.zig
@@ -13,6 +13,7 @@ const CubeMap = @import("cubemap.zig");
const Textures = @import("textures.zig");
const Material = @import("material.zig");
const Mesh = @import("mesh.zig");
+const RenderData = @import("render_data.zig");
const Camera = @import("camera.zig");
const input = @import("input.zig");
@@ -289,15 +290,6 @@ pub const f32x3 = @Vector(3, f32);
pub const f32x4 = @Vector(4, f32);
pub const mat4 = [4]@Vector(4, f32);
-pub const ClusterInstanceData = struct {
- mesh_id: u32,
-};
-
-pub const MeshInstanceData = struct {
- model_matrix: mat4,
- material: Material,
-};
-
pub const UniformData = struct {
pw_camera: f32x3,
view_matrix: mat4,
@@ -374,313 +366,6 @@ pub fn Buffer(comptime T: type) type {
};
}
-pub const MeshBufferOptions = struct {
- device: *gpu.Device,
- queue: *gpu.Queue,
- n_meshes: u32,
- n_vertices: u32,
- n_indices: u32,
- allocator: std.mem.Allocator,
-};
-
-pub const MeshOptions = struct {
- transform: *Transform,
- data: *const Mesh,
-};
-
-pub const MeshBuffer = struct {
- device: *gpu.Device,
- queue: *gpu.Queue,
-
- positions: Buffer(f32x4),
- normals: Buffer(f32x4),
- tex_coords: Buffer(f32x4),
- tangents: Buffer(f32x4),
- bitangents: Buffer(f32x4),
- indices: Buffer(u32),
-
- cluster_instances: Buffer(ClusterInstanceData),
- mesh_instances: Buffer(MeshInstanceData),
- indirect: Buffer([5]u32),
-
- meshes: std.ArrayList(RenderMesh),
-
- lines: std.ArrayList(RenderLines),
- lines_instances: Buffer(MeshInstanceData),
- lines_indirect: Buffer([5]u32),
-
- pub fn init(options: MeshBufferOptions) MeshBuffer {
- const device = options.device;
- const n_vertices = options.n_vertices;
- const n_indices = options.n_indices;
-
- return .{
- .device = options.device,
- .queue = options.queue,
- .positions = Buffer(f32x4).init(
- n_vertices,
- device,
- .{ .vertex = true, .copy_dst = true },
- false,
- ),
- .normals = Buffer(f32x4).init(
- n_vertices,
- device,
- .{ .vertex = true, .copy_dst = true },
- false,
- ),
- .tex_coords = Buffer(f32x4).init(
- n_vertices,
- device,
- .{ .vertex = true, .copy_dst = true },
- false,
- ),
- .tangents = Buffer(f32x4).init(
- n_vertices,
- device,
- .{ .vertex = true, .copy_dst = true },
- false,
- ),
- .bitangents = Buffer(f32x4).init(
- n_vertices,
- device,
- .{ .vertex = true, .copy_dst = true },
- false,
- ),
- .indices = Buffer(u32).init(
- n_indices,
- device,
- .{ .index = true, .copy_dst = true },
- false,
- ),
- .cluster_instances = Buffer(ClusterInstanceData).init(
- 2000,
- device,
- .{ .storage = true, .copy_dst = true },
- false,
- ),
- .mesh_instances = Buffer(MeshInstanceData).init(
- options.n_meshes,
- device,
- .{ .storage = true, .copy_dst = true },
- false,
- ),
- .indirect = Buffer([5]u32).init(
- options.n_meshes,
- device,
- .{ .indirect = true, .copy_dst = true },
- false,
- ),
- .lines_indirect = Buffer([5]u32).init(
- options.n_meshes,
- device,
- .{ .indirect = true, .copy_dst = true },
- false,
- ),
- .lines_instances = Buffer(MeshInstanceData).init(
- options.n_meshes,
- device,
- .{ .storage = true, .copy_dst = true },
- false,
- ),
- .meshes = std.ArrayList(RenderMesh).init(options.allocator),
- .lines = std.ArrayList(RenderLines).init(options.allocator),
- };
- }
-
- pub fn initLines(
- self: *MeshBuffer,
- positions: []const f32x4,
- indices: []const u32,
- transform: *Transform,
- ) !*RenderLines {
- const num_vertices = positions.len;
- const num_indices = indices.len;
-
- const offset_p = try self.positions.allocWrite(positions, self.queue);
- const offset_i = try self.indices.allocWrite(indices, self.queue);
-
- const instance_id = self.lines_indirect.count();
- const indirect_args = [_][5]u32{.{
- @intCast(num_indices),
- 1,
- offset_i,
- offset_p,
- instance_id,
- }};
- _ = try self.lines_indirect.allocWrite(&indirect_args, self.queue);
-
- const lines = RenderLines{
- .num_vertices = num_vertices,
- .num_indices = num_indices,
- .transform = transform,
- };
-
- const instances = [_]MeshInstanceData{
- lines.instanceData(),
- };
- _ = try self.lines_instances.allocWrite(&instances, self.queue);
-
- try self.lines.append(lines);
- return &self.lines.items[0];
- }
-
- pub fn initMesh(
- self: *MeshBuffer,
- options: *const MeshOptions,
- allocator: std.mem.Allocator,
- ) !*RenderMesh {
- const mesh_data = options.data;
- const num_vertices = mesh_data.positions.len;
- const num_indices = mesh_data.indices.len;
- std.log.info(
- "init mesh with {} vertices, {} indices",
- .{ num_vertices, num_indices },
- );
-
- const offset_p = try self.positions.allocWrite(mesh_data.positions, self.queue);
- _ = try self.normals.allocWrite(mesh_data.normals, self.queue);
- _ = try self.tex_coords.allocWrite(mesh_data.tex_coords, self.queue);
- _ = try self.tangents.allocWrite(mesh_data.tangents, self.queue);
- _ = try self.bitangents.allocWrite(mesh_data.bitangents, self.queue);
-
- const offset_i = try self.indices.allocWrite(mesh_data.indices, self.queue);
-
- const mesh = RenderMesh{
- .num_vertices = num_vertices,
- .num_indices = num_indices,
- .transform = options.transform,
- };
-
- const instances = [_]MeshInstanceData{
- mesh.instanceData(),
- };
- _ = try self.mesh_instances.allocWrite(&instances, self.queue);
-
- if (mesh_data.descriptors != null) {
- const descriptors = mesh_data.descriptors.?;
- const num_clusters = descriptors.len;
- const indirect_args = try allocator.alloc([5]u32, num_clusters);
- defer allocator.free(indirect_args);
-
- const cluster_instances = try allocator.alloc(
- ClusterInstanceData,
- num_clusters,
- );
- defer allocator.free(cluster_instances);
-
- var instance_id = self.indirect.count();
- for (descriptors, 0..) |descriptor, i| {
- indirect_args[i] = .{
- @intCast(descriptor.num_triangles * 3),
- 1,
- offset_i + descriptor.offset,
- offset_p,
- instance_id,
- };
- cluster_instances[i] = .{ .mesh_id = @intCast(self.meshes.items.len) };
- instance_id += 1;
- }
- _ = try self.cluster_instances.allocWrite(cluster_instances, self.queue);
- _ = try self.indirect.allocWrite(indirect_args, self.queue);
- } else {
- const cluster_instances = [_]ClusterInstanceData{
- .{ .mesh_id = @intCast(self.meshes.items.len) },
- };
-
- const instance_id = self.indirect.count();
- const indirect_args = [_][5]u32{.{
- @intCast(num_indices),
- 1,
- offset_i,
- offset_p,
- instance_id,
- }};
- _ = try self.cluster_instances.allocWrite(&cluster_instances, self.queue);
- _ = try self.indirect.allocWrite(&indirect_args, self.queue);
- }
-
- try self.meshes.append(mesh);
- return &self.meshes.items[0];
- }
-
- pub fn updateMeshes(self: *MeshBuffer) void {
- for (self.meshes.items, 0..) |*mesh, i| {
- if (!mesh.dirty) {
- continue;
- }
- const instances = [_]MeshInstanceData{mesh.instanceData()};
- self.mesh_instances.write(&instances, self.queue, @intCast(i));
- mesh.dirty = false;
- }
- }
-
- pub fn updateLines(self: *MeshBuffer) void {
- for (self.lines.items, 0..) |*line, i| {
- if (!line.dirty) {
- continue;
- }
- const instances = [_]MeshInstanceData{line.instanceData()};
- self.lines_instances.write(&instances, self.queue, @intCast(i));
- line.dirty = false;
- }
- }
-};
-
-pub const RenderLines = struct {
- num_vertices: usize,
- num_indices: usize,
- transform: *Transform,
- dirty: bool = false,
-
- pub fn instanceData(self: *const RenderLines) MeshInstanceData {
- return MeshInstanceData{
- .model_matrix = self.transform.matrix(),
- .material = undefined,
- };
- }
-
- pub fn setScale(self: *RenderMesh, scale: f32) void {
- self.transform.scale = .{ scale, scale, scale };
- self.dirty = true;
- }
-
- pub fn setOffset(self: *RenderMesh, offset: f32x3) void {
- self.transform.offset = offset;
- self.dirty = true;
- }
-};
-
-pub const RenderMesh = struct {
- num_vertices: usize,
- num_indices: usize,
- transform: *Transform,
- material: Material = undefined,
- dirty: bool = false,
-
- pub fn instanceData(self: *const RenderMesh) MeshInstanceData {
- return MeshInstanceData{
- .model_matrix = self.transform.matrix(),
- .material = self.material,
- };
- }
-
- pub fn setScale(self: *RenderMesh, scale: f32) void {
- self.transform.scale = .{ scale, scale, scale };
- self.dirty = true;
- }
-
- pub fn setOffset(self: *RenderMesh, offset: f32x3) void {
- self.transform.offset = offset;
- self.dirty = true;
- }
-
- pub fn setMaterial(self: *RenderMesh, material: *const Material) void {
- self.material = material.*;
- self.dirty = true;
- }
-};
-
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
@@ -712,14 +397,17 @@ pub fn main() !void {
var camera = Camera{};
camera.logParams();
- var mesh_buffer = MeshBuffer.init(.{
- .device = app.device,
- .queue = app.queue,
- .n_meshes = 500,
- .n_vertices = 60000,
- .n_indices = 60000,
- .allocator = allocator,
- });
+ var render_data = RenderData.init(
+ .{
+ .device = app.device,
+ .queue = app.queue,
+ .n_instances = 2000,
+ .n_objects = 500,
+ .n_vertices = 60000,
+ .n_indices = 60000,
+ },
+ allocator,
+ );
var mesh = try load_obj.loadFile(.{
.allocator = allocator,
@@ -740,36 +428,53 @@ pub fn main() !void {
const cbunny_mesh = try buildClusters(allocator, &bunny_mesh, 64, 126);
std.log.info("num clusters: {}", .{cluster_mesh.descriptors.?.len});
+ var rp = try MeshRenderPipeline.init(
+ &app,
+ .{
+ .positions = &render_data.positions,
+ .normals = &render_data.normals,
+ .tex_coords = &render_data.tex_coords,
+ .tangents = &render_data.tangents,
+ .bitangents = &render_data.bitangents,
+ .indices = &render_data.indices,
+ .instance_data = &render_data.instance_data,
+ .object_data = &render_data.object_data,
+ .indirect = &render_data.indirect_mesh,
+ },
+ &textures,
+ "shaders/mesh_clusters.wgsl",
+ );
+
+ var lrp = try LineRenderPipeline.init(
+ &app,
+ .{
+ .positions = &render_data.positions,
+ .indices = &render_data.indices,
+ .object_data = &render_data.object_data,
+ .indirect = &render_data.indirect_line,
+ },
+ "shaders/lines.wgsl",
+ );
+
var transform_1 = Transform{};
var transform_2 = Transform{};
- var render_mesh = try mesh_buffer.initMesh(&.{
- .data = &cluster_mesh,
- .transform = &transform_1,
- }, allocator);
+ var render_mesh = try render_data.addMesh(
+ &transform_1,
+ &cluster_mesh,
+ allocator,
+ );
- _ = try mesh_buffer.initMesh(&.{
- .data = &cbunny_mesh,
- .transform = &transform_2,
- }, allocator);
+ _ = try render_data.addMesh(
+ &transform_2,
+ &cbunny_mesh,
+ allocator,
+ );
const corners = mesh.bboxVertices();
const bbox_indices = Mesh.bboxIndices();
- var lines = try mesh_buffer.initLines(&corners, &bbox_indices, &transform_1);
-
- var rp = try MeshRenderPipeline.init(&app, &mesh_buffer, &textures, "shaders/mesh_clusters.wgsl");
-
- var lrp = try LineRenderPipeline.init(
- &app,
- .{
- .positions = &mesh_buffer.positions,
- .indices = &mesh_buffer.indices,
- .instances = &mesh_buffer.lines_instances,
- .indirect = &mesh_buffer.lines_indirect,
- },
- "shaders/lines.wgsl",
- );
+ var lines = try render_data.addLines(&corners, &bbox_indices, &transform_1);
const material = try Material.init(
&textures,
@@ -781,7 +486,7 @@ pub fn main() !void {
);
render_mesh.setMaterial(&material);
- mesh_buffer.updateMeshes();
+ render_data.updateObjects();
var skybox = SkyBoxRenderPipeline.init(&app, cube_map);
@@ -823,8 +528,7 @@ pub fn main() !void {
render_mesh.dirty = true;
lines.dirty = true;
- mesh_buffer.updateMeshes();
- mesh_buffer.updateLines();
+ render_data.updateObjects();
try app.frame(&passes);
}
diff --git a/src/mesh_render_pipeline.zig b/src/mesh_render_pipeline.zig
@@ -2,7 +2,8 @@ const std = @import("std");
const gpu = @import("mach_gpu");
const App = @import("main.zig").App;
-const MeshBuffer = @import("main.zig").MeshBuffer;
+const Buffer = @import("main.zig").Buffer;
+const RenderData = @import("render_data.zig");
const UniformData = @import("main.zig").UniformData;
const f32x4 = @import("main.zig").f32x4;
const mat4 = @import("main.zig").mat4;
@@ -12,14 +13,26 @@ const RenderPipeline = @import("render_pipeline.zig").RenderPipeline;
const MeshRenderPipeline = @This();
+pub const Buffers = struct {
+ positions: *const Buffer(f32x4),
+ normals: *const Buffer(f32x4),
+ tex_coords: *const Buffer(f32x4),
+ tangents: *const Buffer(f32x4),
+ bitangents: *const Buffer(f32x4),
+ indices: *const Buffer(u32),
+ instance_data: *const Buffer(RenderData.InstanceData),
+ object_data: *const Buffer(RenderData.ObjectData),
+ indirect: *const Buffer([5]u32),
+};
+
gpu_pipeline: *gpu.RenderPipeline,
-mesh_buffer: *const MeshBuffer,
+buffers: Buffers,
bind_group: *gpu.BindGroup,
uniform_buffer: *gpu.Buffer,
pub fn init(
app: *App,
- mesh_buffer: *const MeshBuffer,
+ buffers: Buffers,
textures: *const Textures,
comptime shader_path: []const u8,
) !MeshRenderPipeline {
@@ -58,11 +71,11 @@ pub fn init(
const bind_group_descriptor = gpu.BindGroup.Descriptor.init(.{
.layout = bind_group_layout,
.entries = &.{
- gpu.BindGroup.Entry.buffer(0, mesh_buffer.mesh_instances.data, 0, mesh_buffer.mesh_instances.size),
+ gpu.BindGroup.Entry.buffer(0, buffers.object_data.data, 0, buffers.object_data.size),
gpu.BindGroup.Entry.buffer(1, uniform_buffer, 0, @sizeOf(UniformData)),
gpu.BindGroup.Entry.sampler(2, textures.sampler),
gpu.BindGroup.Entry.textureView(3, textures.view),
- gpu.BindGroup.Entry.buffer(4, mesh_buffer.cluster_instances.data, 0, mesh_buffer.cluster_instances.size),
+ gpu.BindGroup.Entry.buffer(4, buffers.instance_data.data, 0, buffers.instance_data.size),
},
});
const bind_group = app.device.createBindGroup(&bind_group_descriptor);
@@ -93,7 +106,7 @@ pub fn init(
return .{
.gpu_pipeline = app.device.createRenderPipeline(&pipeline_descriptor),
- .mesh_buffer = mesh_buffer,
+ .buffers = buffers,
.bind_group = bind_group,
.uniform_buffer = uniform_buffer,
};
@@ -170,18 +183,18 @@ pub fn frame(ptr: *anyopaque, pass: *gpu.RenderPassEncoder) void {
const self: *MeshRenderPipeline = @ptrCast(@alignCast(ptr));
pass.setPipeline(self.gpu_pipeline);
- pass.setVertexBuffer(0, self.mesh_buffer.positions.data, 0, self.mesh_buffer.positions.size);
- pass.setVertexBuffer(1, self.mesh_buffer.normals.data, 0, self.mesh_buffer.normals.size);
- pass.setVertexBuffer(2, self.mesh_buffer.tex_coords.data, 0, self.mesh_buffer.tex_coords.size);
- pass.setVertexBuffer(3, self.mesh_buffer.tangents.data, 0, self.mesh_buffer.tangents.size);
- pass.setVertexBuffer(4, self.mesh_buffer.bitangents.data, 0, self.mesh_buffer.bitangents.size);
+ pass.setVertexBuffer(0, self.buffers.positions.data, 0, self.buffers.positions.size);
+ pass.setVertexBuffer(1, self.buffers.normals.data, 0, self.buffers.normals.size);
+ pass.setVertexBuffer(2, self.buffers.tex_coords.data, 0, self.buffers.tex_coords.size);
+ pass.setVertexBuffer(3, self.buffers.tangents.data, 0, self.buffers.tangents.size);
+ pass.setVertexBuffer(4, self.buffers.bitangents.data, 0, self.buffers.bitangents.size);
pass.setBindGroup(0, self.bind_group, null);
- pass.setIndexBuffer(self.mesh_buffer.indices.data, .uint32, 0, self.mesh_buffer.indices.size);
+ pass.setIndexBuffer(self.buffers.indices.data, .uint32, 0, self.buffers.indices.size);
- const num_indirect = self.mesh_buffer.indirect.count();
+ const num_indirect = self.buffers.indirect.count();
for (0..num_indirect) |idx| {
- const offset = idx * self.mesh_buffer.indirect.attrib_size;
- pass.drawIndexedIndirect(self.mesh_buffer.indirect.data, offset);
+ const offset = idx * self.buffers.indirect.attrib_size;
+ pass.drawIndexedIndirect(self.buffers.indirect.data, offset);
}
}
diff --git a/src/render_data.zig b/src/render_data.zig
@@ -0,0 +1,261 @@
+const std = @import("std");
+const gpu = @import("mach_gpu");
+
+const Buffer = @import("main.zig").Buffer;
+const Material = @import("material.zig");
+const Mesh = @import("mesh.zig");
+const Transform = @import("transform.zig");
+
+const RenderData = @This();
+
+pub const f32x3 = @Vector(3, f32);
+pub const f32x4 = @Vector(4, f32);
+pub const mat4 = [4]@Vector(4, f32);
+
+pub const InstanceData = struct {
+ object_id: u32,
+};
+
+pub const ObjectData = struct {
+ model_matrix: mat4,
+ material: Material,
+};
+
+pub const RenderObject = struct {
+ num_vertices: usize,
+ num_indices: usize,
+ transform: *Transform,
+ material: Material = undefined,
+ dirty: bool = false,
+
+ pub fn instanceData(self: *const RenderObject) ObjectData {
+ return .{
+ .model_matrix = self.transform.matrix(),
+ .material = self.material,
+ };
+ }
+
+ pub fn setScale(self: *RenderObject, scale: f32) void {
+ self.transform.scale = .{ scale, scale, scale };
+ self.dirty = true;
+ }
+
+ pub fn setOffset(self: *RenderObject, offset: f32x3) void {
+ self.transform.offset = offset;
+ self.dirty = true;
+ }
+
+ pub fn setMaterial(self: *RenderObject, material: *const Material) void {
+ self.material = material.*;
+ self.dirty = true;
+ }
+};
+
+device: *gpu.Device,
+queue: *gpu.Queue,
+
+positions: Buffer(f32x4),
+normals: Buffer(f32x4),
+tex_coords: Buffer(f32x4),
+tangents: Buffer(f32x4),
+bitangents: Buffer(f32x4),
+indices: Buffer(u32),
+
+// TODO: indirect buffers should be generated by pipelines
+indirect_mesh: Buffer([5]u32),
+indirect_line: Buffer([5]u32),
+
+instance_data: Buffer(InstanceData),
+object_data: Buffer(ObjectData),
+
+objects: std.ArrayList(RenderObject),
+
+pub const Options = struct {
+ device: *gpu.Device,
+ queue: *gpu.Queue,
+ n_instances: u32,
+ n_objects: u32,
+ n_vertices: u32,
+ n_indices: u32,
+};
+
+pub fn init(options: Options, allocator: std.mem.Allocator) RenderData {
+ return .{
+ .device = options.device,
+ .queue = options.queue,
+ .positions = Buffer(f32x4).init(
+ options.n_vertices,
+ options.device,
+ .{ .vertex = true, .copy_dst = true },
+ false,
+ ),
+ .normals = Buffer(f32x4).init(
+ options.n_vertices,
+ options.device,
+ .{ .vertex = true, .copy_dst = true },
+ false,
+ ),
+ .tex_coords = Buffer(f32x4).init(
+ options.n_vertices,
+ options.device,
+ .{ .vertex = true, .copy_dst = true },
+ false,
+ ),
+ .tangents = Buffer(f32x4).init(
+ options.n_vertices,
+ options.device,
+ .{ .vertex = true, .copy_dst = true },
+ false,
+ ),
+ .bitangents = Buffer(f32x4).init(
+ options.n_vertices,
+ options.device,
+ .{ .vertex = true, .copy_dst = true },
+ false,
+ ),
+ .indices = Buffer(u32).init(
+ options.n_indices,
+ options.device,
+ .{ .index = true, .copy_dst = true },
+ false,
+ ),
+ .instance_data = Buffer(InstanceData).init(
+ options.n_instances,
+ options.device,
+ .{ .storage = true, .copy_dst = true },
+ false,
+ ),
+ .object_data = Buffer(ObjectData).init(
+ options.n_objects,
+ options.device,
+ .{ .storage = true, .copy_dst = true },
+ false,
+ ),
+ .indirect_mesh = Buffer([5]u32).init(
+ options.n_instances,
+ options.device,
+ .{ .indirect = true, .copy_dst = true },
+ false,
+ ),
+ .indirect_line = Buffer([5]u32).init(
+ options.n_instances,
+ options.device,
+ .{ .indirect = true, .copy_dst = true },
+ false,
+ ),
+ .objects = std.ArrayList(RenderObject).init(allocator),
+ };
+}
+
+pub fn addLines(
+ self: *RenderData,
+ positions: []const f32x4,
+ indices: []const u32,
+ transform: *Transform,
+) !*RenderObject {
+ const offset_p = try self.positions.allocWrite(positions, self.queue);
+ const n: u32 = @intCast(positions.len);
+ _ = try self.normals.alloc(n);
+ _ = try self.tex_coords.alloc(n);
+ _ = try self.tangents.alloc(n);
+ _ = try self.bitangents.alloc(n);
+ const offset_i = try self.indices.allocWrite(indices, self.queue);
+
+ const object = RenderObject{
+ .num_vertices = positions.len,
+ .num_indices = indices.len,
+ .transform = transform,
+ };
+ const object_data = [_]ObjectData{object.instanceData()};
+ _ = try self.object_data.allocWrite(&object_data, self.queue);
+
+ const instance_data = [_]InstanceData{
+ .{ .object_id = @intCast(self.objects.items.len) },
+ };
+ const indirect_args = [_][5]u32{.{
+ @intCast(indices.len),
+ 1,
+ offset_i,
+ offset_p,
+ // lines are always one "piece", so we don't need to map from an
+ // instance id to an object
+ @intCast(self.objects.items.len),
+ }};
+ _ = try self.instance_data.allocWrite(&instance_data, self.queue);
+ _ = try self.indirect_line.allocWrite(&indirect_args, self.queue);
+
+ try self.objects.append(object);
+ return &self.objects.items[self.objects.items.len - 1];
+}
+
+pub fn addMesh(
+ self: *RenderData,
+ transform: *Transform,
+ mesh: *const Mesh,
+ allocator: std.mem.Allocator,
+) !*RenderObject {
+ const offset_p = try self.positions.allocWrite(mesh.positions, self.queue);
+ _ = try self.normals.allocWrite(mesh.normals, self.queue);
+ _ = try self.tex_coords.allocWrite(mesh.tex_coords, self.queue);
+ _ = try self.tangents.allocWrite(mesh.tangents, self.queue);
+ _ = try self.bitangents.allocWrite(mesh.bitangents, self.queue);
+ const offset_i = try self.indices.allocWrite(mesh.indices, self.queue);
+
+ const object = RenderObject{
+ .num_vertices = mesh.positions.len,
+ .num_indices = mesh.indices.len,
+ .transform = transform,
+ };
+ const object_data = [_]ObjectData{object.instanceData()};
+ _ = try self.object_data.allocWrite(&object_data, self.queue);
+
+ if (mesh.descriptors != null) {
+ const descriptors = mesh.descriptors.?;
+ const instance_data = try allocator.alloc(InstanceData, descriptors.len);
+ defer allocator.free(instance_data);
+ const indirect_args = try allocator.alloc([5]u32, descriptors.len);
+ defer allocator.free(indirect_args);
+
+ var instance_id = self.indirect_mesh.count();
+ for (descriptors, 0..) |descriptor, i| {
+ instance_data[i] = .{ .object_id = @intCast(self.objects.items.len) };
+ indirect_args[i] = .{
+ @intCast(descriptor.num_triangles * 3),
+ 1,
+ offset_i + descriptor.offset,
+ offset_p,
+ instance_id,
+ };
+ instance_id += 1;
+ }
+ _ = try self.instance_data.allocWrite(instance_data, self.queue);
+ _ = try self.indirect_mesh.allocWrite(indirect_args, self.queue);
+ } else {
+ const instance_data = [_]InstanceData{
+ .{ .object_id = @intCast(self.objects.items.len) },
+ };
+ const indirect_args = [_][5]u32{.{
+ @intCast(mesh.indices.len),
+ 1,
+ offset_i,
+ offset_p,
+ self.indirect_mesh.count(),
+ }};
+ _ = try self.instance_data.allocWrite(&instance_data, self.queue);
+ _ = try self.indirect_mesh.allocWrite(&indirect_args, self.queue);
+ }
+
+ try self.objects.append(object);
+ return &self.objects.items[self.objects.items.len - 1];
+}
+
+pub fn updateObjects(self: *RenderData) void {
+ for (self.objects.items, 0..) |*object, i| {
+ if (!object.dirty) {
+ continue;
+ }
+ const object_data = [_]ObjectData{object.instanceData()};
+ self.object_data.write(&object_data, self.queue, @intCast(i));
+ object.dirty = false;
+ }
+}