Renderer code
This commit is contained in:
53
src/StorageBuffer.zig
Normal file
53
src/StorageBuffer.zig
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
const zgpu = @import("zgpu");
|
||||||
|
|
||||||
|
const main = @import("main.zig");
|
||||||
|
|
||||||
|
pub fn StorageBuffer(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
storage_buffer_handle: zgpu.BufferHandle,
|
||||||
|
|
||||||
|
pub fn init(desired_capacity: usize) @This() {
|
||||||
|
// NOTE For some reason, the method function call syntax doesn't compile
|
||||||
|
const storage_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{
|
||||||
|
.usage = .{ .copy_dst = true, .storage = true },
|
||||||
|
.size = desired_capacity * @sizeOf(T),
|
||||||
|
});
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.storage_buffer_handle = storage_buffer_handle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *@This()) void {
|
||||||
|
main.gctx.releaseResource(self.storage_buffer_handle);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capacity(self: @This()) usize {
|
||||||
|
return @divExact(self.info().size, @sizeOf(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(self: @This(), offset: usize, data: []const T) void {
|
||||||
|
main.gctx.queue.writeBuffer(self.obj(), offset, T, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ensureCapacityDiscard(self: *@This(), desired_capacity: usize) void {
|
||||||
|
if (self.capacity() < desired_capacity) {
|
||||||
|
main.gctx.releaseResource(self.storage_buffer_handle);
|
||||||
|
// NOTE For some reason, the method function call syntax doesn't compile
|
||||||
|
self.storage_buffer_handle = zgpu.GraphicsContext.createBuffer(main.gctx, .{
|
||||||
|
.usage = .{ .copy_dst = true, .storage = true },
|
||||||
|
.size = desired_capacity * @sizeOf(T),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info(self: @This()) zgpu.BufferInfo {
|
||||||
|
return main.gctx.lookupResourceInfo(self.vertex_buffer_handle).?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn obj(self: @This()) zgpu.wgpu.Buffer {
|
||||||
|
return main.gctx.lookupResource(self.vertex_buffer_handle).?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
372
src/game.zig
372
src/game.zig
@@ -2,38 +2,239 @@ const std = @import("std");
|
|||||||
|
|
||||||
const zglfw = @import("zglfw");
|
const zglfw = @import("zglfw");
|
||||||
const zgui = @import("zgui");
|
const zgui = @import("zgui");
|
||||||
|
const zgpu = @import("zgpu");
|
||||||
|
|
||||||
const main = @import("main.zig");
|
const main = @import("main.zig");
|
||||||
|
const IndexBuffer = @import("IndexBuffer.zig");
|
||||||
var show_console: bool = false;
|
const Samplers = @import("Samplers.zig");
|
||||||
var show_demo_window: bool = false;
|
const StorageBuffer = @import("StorageBuffer.zig").StorageBuffer;
|
||||||
|
const Texture = @import("Texture.zig");
|
||||||
|
const VertexBuffer = @import("VertexBuffer.zig").VertexBuffer;
|
||||||
|
|
||||||
const Vertex = extern struct {
|
const Vertex = extern struct {
|
||||||
position: [3]f32,
|
position_os: [3]f32,
|
||||||
tex_coord: [2]f32,
|
tex_coord: [2]f32,
|
||||||
normal: [3]f32,
|
normal_os: [3]f32,
|
||||||
tangent: [4]f32,
|
tangent_os: [4]f32,
|
||||||
|
|
||||||
pub fn init(x: f32, y: f32, z: f32, u: f32, v: f32, nx: f32, ny: f32, nz: f32, tx: f32, ty: f32, tz: f32, tw: f32) Vertex {
|
pub fn init(x: f32, y: f32, z: f32, u: f32, v: f32, nx: f32, ny: f32, nz: f32, tx: f32, ty: f32, tz: f32, tw: f32) Vertex {
|
||||||
return .{
|
return .{
|
||||||
.position = .{ x, y, z },
|
.position_os = .{ x, y, z },
|
||||||
.tex_coord = .{ u, v },
|
.tex_coord = .{ u, v },
|
||||||
.normal = .{ nx, ny, nz },
|
.normal_os = .{ nx, ny, nz },
|
||||||
.tangent = .{ tx, ty, tw, tz },
|
.tangent_os = .{ tx, ty, tw, tz },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const vertex_buffer = [_]Vertex{
|
const PointLight = extern struct {
|
||||||
Vertex.init(-0.5, -0.5, 0, 0, 1, 0, 0, 1, 1, 0, 0, -1),
|
position_ws: [3]f32,
|
||||||
Vertex.init(0.5, -0.5, 0, 1, 1, 0, 0, 1, 1, 0, 0, -1),
|
color: [3]f32,
|
||||||
Vertex.init(-0.5, 0.5, 0, 0, 0, 0, 0, 1, 1, 0, 0, -1),
|
|
||||||
Vertex.init(0.5, 0.5, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const index_buffer = [_]u16{ 0, 1, 2, 2, 1, 3 };
|
const DirectionalLight = extern struct {
|
||||||
|
direction_ws: [3]f32,
|
||||||
|
color: [3]f32,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn init() void {}
|
const GlobalUniforms = extern struct {
|
||||||
|
matrix_ws_to_vs: [16]f32,
|
||||||
|
matrix_vs_to_cs: [16]f32,
|
||||||
|
ambient_light: [3]f32,
|
||||||
|
point_light_count: u32,
|
||||||
|
directional_light_count: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ObjectUniforms = extern struct {
|
||||||
|
matrix_os_to_ws: [16]f32,
|
||||||
|
matrix_os_to_ws_normal: [16]f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
var show_console: bool = false;
|
||||||
|
var show_demo_window: bool = false;
|
||||||
|
|
||||||
|
var global_bind_group_layout: zgpu.BindGroupLayoutHandle = undefined;
|
||||||
|
var per_material_bind_group_layout: zgpu.BindGroupLayoutHandle = undefined;
|
||||||
|
var per_object_bind_group_layout: zgpu.BindGroupLayoutHandle = undefined;
|
||||||
|
|
||||||
|
var vertex_buffer: VertexBuffer(Vertex) = undefined;
|
||||||
|
var index_buffer: IndexBuffer = undefined;
|
||||||
|
|
||||||
|
var block_pipeline: zgpu.RenderPipelineHandle = undefined;
|
||||||
|
|
||||||
|
var point_light_buffer: StorageBuffer(PointLight) = undefined;
|
||||||
|
var directional_light_buffer: StorageBuffer(DirectionalLight) = undefined;
|
||||||
|
var sampler: zgpu.SamplerHandle = undefined;
|
||||||
|
var base_color_texture: Texture = undefined;
|
||||||
|
var occlusion_roughness_metallic_texture: Texture = undefined;
|
||||||
|
var normal_texture: Texture = undefined;
|
||||||
|
|
||||||
|
var global_bind_group: zgpu.BindGroupHandle = undefined;
|
||||||
|
var per_material_bind_group: zgpu.BindGroupHandle = undefined;
|
||||||
|
var per_object_bind_group: zgpu.BindGroupHandle = undefined;
|
||||||
|
|
||||||
|
pub fn init() !void {
|
||||||
|
global_bind_group_layout = main.gctx.createBindGroupLayout(&.{
|
||||||
|
zgpu.bufferEntry(0, .{ .vertex = true, .fragment = true }, .uniform, true, 0),
|
||||||
|
zgpu.bufferEntry(1, .{ .fragment = true }, .read_only_storage, false, 0),
|
||||||
|
zgpu.bufferEntry(2, .{ .fragment = true }, .read_only_storage, false, 0),
|
||||||
|
zgpu.samplerEntry(3, .{ .fragment = true }, .filtering),
|
||||||
|
zgpu.textureEntry(4, .{ .fragment = true }, .float, .tvdim_2d_array, false),
|
||||||
|
zgpu.textureEntry(5, .{ .fragment = true }, .float, .tvdim_2d_array, false),
|
||||||
|
zgpu.textureEntry(6, .{ .fragment = true }, .float, .tvdim_2d_array, false),
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(global_bind_group_layout);
|
||||||
|
|
||||||
|
per_material_bind_group_layout = main.gctx.createBindGroupLayout(&.{
|
||||||
|
zgpu.bufferEntry(0, .{ .fragment = true }, .uniform, true, 0),
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(per_material_bind_group_layout);
|
||||||
|
|
||||||
|
per_object_bind_group_layout = main.gctx.createBindGroupLayout(&.{
|
||||||
|
zgpu.bufferEntry(0, .{ .fragment = true }, .uniform, true, 0),
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(per_object_bind_group_layout);
|
||||||
|
|
||||||
|
vertex_buffer = VertexBuffer(Vertex).init(4);
|
||||||
|
vertex_buffer.write(0, &[_]Vertex{
|
||||||
|
Vertex.init(-0.5, -0.5, 0, 0, 1, 0, 0, 1, 1, 0, 0, -1),
|
||||||
|
Vertex.init(0.5, -0.5, 0, 1, 1, 0, 0, 1, 1, 0, 0, -1),
|
||||||
|
Vertex.init(-0.5, 0.5, 0, 0, 0, 0, 0, 1, 1, 0, 0, -1),
|
||||||
|
Vertex.init(0.5, 0.5, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1),
|
||||||
|
});
|
||||||
|
errdefer vertex_buffer.deinit();
|
||||||
|
|
||||||
|
index_buffer = IndexBuffer.init(6);
|
||||||
|
index_buffer.write(0, &[_]u16{ 0, 1, 2, 2, 1, 3 });
|
||||||
|
errdefer index_buffer.deinit();
|
||||||
|
|
||||||
|
block_pipeline = block_pipeline: {
|
||||||
|
const pipeline_layout = main.gctx.createPipelineLayout(&.{
|
||||||
|
global_bind_group_layout,
|
||||||
|
per_material_bind_group_layout,
|
||||||
|
per_object_bind_group_layout,
|
||||||
|
});
|
||||||
|
defer main.gctx.releaseResource(pipeline_layout);
|
||||||
|
|
||||||
|
const module = zgpu.createWgslShaderModule(main.gctx.device, @embedFile("../shaders/block.wgsl"), null);
|
||||||
|
defer module.release();
|
||||||
|
|
||||||
|
const vertex_buffers = [_]zgpu.wgpu.VertexBufferLayout{
|
||||||
|
vertexBufferLayoutFromStruct(Vertex),
|
||||||
|
};
|
||||||
|
|
||||||
|
const targets = [_]zgpu.wgpu.ColorTargetState{.{
|
||||||
|
.format = zgpu.GraphicsContext.swapchain_format,
|
||||||
|
.blend = &.{
|
||||||
|
.color = .{
|
||||||
|
.operation = .add,
|
||||||
|
.src_factor = .one,
|
||||||
|
.dst_factor = .one_minus_src_alpha,
|
||||||
|
},
|
||||||
|
.alpha = .{
|
||||||
|
.operation = .add,
|
||||||
|
.src_factor = .one,
|
||||||
|
.dst_factor = .one_minus_src_alpha,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}};
|
||||||
|
|
||||||
|
const pipeline_descriptor = zgpu.wgpu.RenderPipelineDescriptor{
|
||||||
|
.vertex = .{
|
||||||
|
.module = module,
|
||||||
|
.entry_point = "vert",
|
||||||
|
.buffer_count = vertex_buffers.len,
|
||||||
|
.buffers = &vertex_buffers,
|
||||||
|
},
|
||||||
|
.fragment = .{
|
||||||
|
.module = module,
|
||||||
|
.entry_point = "frag",
|
||||||
|
.target_count = targets.len,
|
||||||
|
.targets = &targets,
|
||||||
|
},
|
||||||
|
.primitive = .{
|
||||||
|
.cull_mode = .back,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
break :block_pipeline main.gctx.createRenderPipeline(pipeline_layout, pipeline_descriptor);
|
||||||
|
};
|
||||||
|
errdefer main.gctx.releaseResource(block_pipeline);
|
||||||
|
|
||||||
|
point_light_buffer = StorageBuffer(PointLight).init(4);
|
||||||
|
errdefer point_light_buffer.deinit();
|
||||||
|
|
||||||
|
directional_light_buffer = StorageBuffer(DirectionalLight).init(4);
|
||||||
|
errdefer directional_light_buffer.deinit();
|
||||||
|
|
||||||
|
sampler = main.gctx.createSampler(.{
|
||||||
|
.address_mode_u = .repeat,
|
||||||
|
.address_mode_v = .repeat,
|
||||||
|
.address_mode_w = .repeat,
|
||||||
|
.mag_filter = .linear,
|
||||||
|
.min_filter = .linear,
|
||||||
|
.mipmap_filter = .linear,
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(sampler);
|
||||||
|
|
||||||
|
const tile_count = 16;
|
||||||
|
|
||||||
|
const base_color_texture_data = @embedFile("../library/textures/BaseColor");
|
||||||
|
const base_color_tile_size = std.math.sqrt(@divExact(base_color_texture_data.len, 4 * tile_count));
|
||||||
|
base_color_texture = Texture.init2DArray(base_color_tile_size, base_color_tile_size, tile_count);
|
||||||
|
errdefer base_color_texture.deinit();
|
||||||
|
main.gctx.queue.writeTexture(
|
||||||
|
.{ .texture = base_color_texture.texObj() },
|
||||||
|
.{ .bytes_per_row = 4 * base_color_tile_size, .rows_per_image = base_color_tile_size },
|
||||||
|
.{ .width = base_color_tile_size, .height = base_color_tile_size, .depth_or_array_layers = tile_count },
|
||||||
|
u8,
|
||||||
|
base_color_texture_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
const occlusion_roughness_metallic_texture_data = @embedFile("../library/textures/OcclusionRoughnessMetallic");
|
||||||
|
const occlusion_roughness_metallic_tile_size = std.math.sqrt(@divExact(occlusion_roughness_metallic_texture_data.len, 4 * tile_count));
|
||||||
|
occlusion_roughness_metallic_texture = Texture.init2DArray(occlusion_roughness_metallic_tile_size, occlusion_roughness_metallic_tile_size, tile_count);
|
||||||
|
errdefer occlusion_roughness_metallic_texture.deinit();
|
||||||
|
main.gctx.queue.writeTexture(
|
||||||
|
.{ .texture = occlusion_roughness_metallic_texture.texObj() },
|
||||||
|
.{ .bytes_per_row = 4 * occlusion_roughness_metallic_tile_size, .rows_per_image = occlusion_roughness_metallic_tile_size },
|
||||||
|
.{ .width = occlusion_roughness_metallic_tile_size, .height = occlusion_roughness_metallic_tile_size, .depth_or_array_layers = tile_count },
|
||||||
|
u8,
|
||||||
|
occlusion_roughness_metallic_texture_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
const normal_texture_data = @embedFile("../library/textures/Normal");
|
||||||
|
const normal_tile_size = std.math.sqrt(@divExact(normal_texture_data.len, 4 * tile_count));
|
||||||
|
normal_texture = Texture.init2DArray(normal_tile_size, normal_tile_size, tile_count);
|
||||||
|
errdefer normal_texture.deinit();
|
||||||
|
main.gctx.queue.writeTexture(
|
||||||
|
.{ .texture = normal_texture.texObj() },
|
||||||
|
.{ .bytes_per_row = 4 * normal_tile_size, .rows_per_image = normal_tile_size },
|
||||||
|
.{ .width = normal_tile_size, .height = normal_tile_size, .depth_or_array_layers = tile_count },
|
||||||
|
u8,
|
||||||
|
normal_texture_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
global_bind_group = main.gctx.createBindGroup(global_bind_group_layout, &.{
|
||||||
|
.{ .binding = 0, .buffer_handle = main.gctx.uniforms.buffer, .size = @sizeOf(GlobalUniforms) },
|
||||||
|
.{ .binding = 1, .buffer_handle = point_light_buffer.storage_buffer_handle, .size = point_light_buffer.info().size },
|
||||||
|
.{ .binding = 2, .buffer_handle = directional_light_buffer.storage_buffer_handle, .size = directional_light_buffer.info().size },
|
||||||
|
.{ .binding = 3, .sampler_handle = sampler },
|
||||||
|
.{ .binding = 4, .texture_view_handle = base_color_texture.texture_view_handle },
|
||||||
|
.{ .binding = 5, .texture_view_handle = occlusion_roughness_metallic_texture.texture_view_handle },
|
||||||
|
.{ .binding = 6, .texture_view_handle = normal_texture.texture_view_handle },
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(global_bind_group);
|
||||||
|
|
||||||
|
per_material_bind_group = main.gctx.createBindGroup(per_material_bind_group, &.{
|
||||||
|
.{ .binding = 0, .buffer_handle = main.gctx.uniforms.buffer, .size = @sizeOf(u32) },
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(per_material_bind_group);
|
||||||
|
|
||||||
|
per_object_bind_group = main.gctx.createBindGroup(per_object_bind_group, &.{
|
||||||
|
.{ .binding = 0, .buffer_handle = main.gctx.uniforms.buffer, .size = @sizeOf(ObjectUniforms) },
|
||||||
|
});
|
||||||
|
errdefer main.gctx.releaseResource(per_object_bind_group);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(dt: f32) void {
|
pub fn update(dt: f32) void {
|
||||||
_ = dt;
|
_ = dt;
|
||||||
@@ -45,6 +246,68 @@ pub fn update(dt: f32) void {
|
|||||||
if (show_demo_window) {
|
if (show_demo_window) {
|
||||||
zgui.showDemoWindow(&show_demo_window);
|
zgui.showDemoWindow(&show_demo_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const back_buffer_view = main.gctx.swapchain.getCurrentTextureView();
|
||||||
|
defer back_buffer_view.release();
|
||||||
|
|
||||||
|
const commands = commands: {
|
||||||
|
const encoder = main.gctx.device.createCommandEncoder(null);
|
||||||
|
defer encoder.release();
|
||||||
|
|
||||||
|
{
|
||||||
|
const color_attachments = [_]zgpu.wgpu.RenderPassColorAttachment{.{
|
||||||
|
.view = back_buffer_view,
|
||||||
|
.load_op = .clear,
|
||||||
|
.store_op = .store,
|
||||||
|
.clear_value = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
|
}};
|
||||||
|
const pass = encoder.beginRenderPass(.{
|
||||||
|
.color_attachment_count = color_attachments.len,
|
||||||
|
.color_attachments = &color_attachments,
|
||||||
|
});
|
||||||
|
defer {
|
||||||
|
pass.end();
|
||||||
|
pass.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
const block_pipeline_obj = main.gctx.lookupResource(block_pipeline).?;
|
||||||
|
const global_bind_group_obj = main.gctx.lookupResource(global_bind_group).?;
|
||||||
|
const per_material_bind_group_obj = main.gctx.lookupResource(per_material_bind_group).?;
|
||||||
|
const per_object_bind_group_obj = main.gctx.lookupResource(per_object_bind_group).?;
|
||||||
|
|
||||||
|
pass.setPipeline(block_pipeline_obj);
|
||||||
|
|
||||||
|
const vb = vertex_buffer.info();
|
||||||
|
const ib = index_buffer.info();
|
||||||
|
|
||||||
|
pass.setVertexBuffer(0, vb.gpuobj.?, 0, vb.size);
|
||||||
|
pass.setIndexBuffer(ib.gpuobj.?, .uint16, 0, ib.size);
|
||||||
|
|
||||||
|
const global_uniforms_offsets = allocateUniform(GlobalUniforms{
|
||||||
|
.matrix_ws_to_vs = .{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||||
|
.matrix_vs_to_cs = .{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||||
|
.ambient_light = .{ 0, 0, 0 },
|
||||||
|
.point_light_count = 0,
|
||||||
|
.directional_light_count = 0,
|
||||||
|
});
|
||||||
|
pass.setBindGroup(0, global_bind_group_obj, &global_uniforms_offsets);
|
||||||
|
|
||||||
|
const per_material_offsets = allocateUniform(@as(u32, 0));
|
||||||
|
pass.setBindGroup(1, per_material_bind_group_obj, &per_material_offsets);
|
||||||
|
|
||||||
|
const per_object_offsets = allocateUniform(ObjectUniforms{
|
||||||
|
.matrix_os_to_ws = .{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||||
|
.matrix_os_to_ws_normal = .{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||||
|
});
|
||||||
|
pass.setBindGroup(2, per_object_bind_group_obj, &per_object_offsets);
|
||||||
|
|
||||||
|
pass.drawIndexed(@intCast(@divExact(ib.size, @sizeOf(u16))), 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
break :commands encoder.finish(null);
|
||||||
|
};
|
||||||
|
defer commands.release();
|
||||||
|
|
||||||
|
main.gctx.submit(&.{commands});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn charCallback(
|
pub fn charCallback(
|
||||||
@@ -103,7 +366,9 @@ pub fn scrollCallback(
|
|||||||
_ = yoffset;
|
_ = yoffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {}
|
pub fn deinit() void {
|
||||||
|
Samplers.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
fn showConsole() void {
|
fn showConsole() void {
|
||||||
const display_size = zgui.io.getDisplaySize();
|
const display_size = zgui.io.getDisplaySize();
|
||||||
@@ -133,3 +398,76 @@ fn showConsole() void {
|
|||||||
}
|
}
|
||||||
zgui.end();
|
zgui.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn allocateUniform(value: anytype) [1]u32 {
|
||||||
|
const mem = main.gctx.uniformsAllocate(@TypeOf(value), 1);
|
||||||
|
mem.slice[0] = value;
|
||||||
|
return [1]u32{mem.offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vertexAttributesFromStruct(comptime T: type) [structFieldCount(T)]zgpu.wgpu.VertexAttribute {
|
||||||
|
const struct_info = @typeInfo(T).Struct;
|
||||||
|
if (struct_info.layout != .Extern) {
|
||||||
|
@compileError("Vertex struct " ++ @typeName(T) ++ " does not have extern layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime var ret: [structFieldCount(T)]zgpu.wgpu.VertexAttribute = undefined;
|
||||||
|
inline for (struct_info.fields, 0..) |struct_field, i| {
|
||||||
|
const vertex_format: zgpu.wgpu.VertexFormat = switch (struct_field.type) {
|
||||||
|
[2]u8 => .uint8x2,
|
||||||
|
[4]u8 => .uint8x4,
|
||||||
|
|
||||||
|
[2]i8 => .sint8x2,
|
||||||
|
[4]i8 => .sint8x4,
|
||||||
|
|
||||||
|
[2]u16 => .uint16x2,
|
||||||
|
[4]u16 => .uint16x4,
|
||||||
|
|
||||||
|
[2]i16 => .sint16x2,
|
||||||
|
[4]i16 => .sint16x4,
|
||||||
|
|
||||||
|
[2]f16 => .float16x2,
|
||||||
|
[4]f16 => .float16x4,
|
||||||
|
|
||||||
|
f32 => .float32,
|
||||||
|
[1]f32 => .float32,
|
||||||
|
[2]f32 => .float32x2,
|
||||||
|
[3]f32 => .float32x3,
|
||||||
|
[4]f32 => .float32x4,
|
||||||
|
|
||||||
|
u32 => .uint32,
|
||||||
|
[1]u32 => .uint32,
|
||||||
|
[2]u32 => .uint32x2,
|
||||||
|
[3]u32 => .uint32x3,
|
||||||
|
[4]u32 => .uint32x4,
|
||||||
|
|
||||||
|
i32 => .sint32,
|
||||||
|
[1]i32 => .sint32,
|
||||||
|
[2]i32 => .sint32x2,
|
||||||
|
[3]i32 => .sint32x3,
|
||||||
|
[4]i32 => .sint32x4,
|
||||||
|
else => @compileError("Vertex attribute of type " ++ @typeName(struct_field.type) ++ " not supported"),
|
||||||
|
};
|
||||||
|
|
||||||
|
ret[i] = .{
|
||||||
|
.format = vertex_format,
|
||||||
|
.offset = @offsetOf(T, struct_field.name),
|
||||||
|
.shader_location = i,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vertexBufferLayoutFromStruct(comptime T: type) zgpu.wgpu.VertexBufferLayout {
|
||||||
|
return .{
|
||||||
|
.array_stride = @sizeOf(T),
|
||||||
|
.step_mode = .vertex,
|
||||||
|
.attribute_count = structFieldCount(T),
|
||||||
|
.attributes = comptime &vertexAttributesFromStruct(T),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn structFieldCount(comptime T: type) comptime_int {
|
||||||
|
return @typeInfo(T).Struct.fields.len;
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const zone_init_game = ztracy.ZoneN(@src(), "Init game");
|
const zone_init_game = ztracy.ZoneN(@src(), "Init game");
|
||||||
|
|
||||||
game.init();
|
try game.init();
|
||||||
defer game.deinit();
|
defer game.deinit();
|
||||||
|
|
||||||
zone_init_game.End();
|
zone_init_game.End();
|
||||||
|
|||||||
Reference in New Issue
Block a user