Meshes, mesh drawing and debug scene
This commit is contained in:
91
src/debug_scene.zig
Normal file
91
src/debug_scene.zig
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const sdl = @import("sdl");
|
||||||
|
const Controller = @import("graph/controller.zig");
|
||||||
|
const Graphics = @import("graphics.zig");
|
||||||
|
const Game = @import("game.zig");
|
||||||
|
|
||||||
|
const CUBE_MESH_DATA = [_]f32{
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
-1, -1, -1,
|
||||||
|
1, -1, -1,
|
||||||
|
-1, -1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, -1, -1,
|
||||||
|
1, -1, 1,
|
||||||
|
1, -1, -1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
-1, -1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
-1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, -1, -1,
|
||||||
|
1, -1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const OFFSETS = [_]@Vector(3, f32){
|
||||||
|
.{ -3, 3, 0 },
|
||||||
|
.{ 0, 3, 0 },
|
||||||
|
.{ 3, 3, 0 },
|
||||||
|
.{ -3, 0, 0 },
|
||||||
|
.{ 0, 0, 0 },
|
||||||
|
.{ 3, 0, 0 },
|
||||||
|
.{ -3, -3, 0 },
|
||||||
|
.{ 0, -3, 0 },
|
||||||
|
.{ 3, -3, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Cube = struct {
|
||||||
|
mesh: Graphics.Mesh,
|
||||||
|
transform: Graphics.Transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(controller: *Controller, graphics: *Graphics) !void {
|
||||||
|
controller.addResource(Cube{
|
||||||
|
.mesh = try graphics.loadMesh(@ptrCast(&CUBE_MESH_DATA)),
|
||||||
|
.transform = Graphics.Transform{},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit() void {}
|
||||||
|
|
||||||
|
pub fn update(cube: *Cube, mouse: *Game.Mouse, graphics: *Graphics) void {
|
||||||
|
if (@abs(mouse.dx) < 0.01 and @abs(mouse.dy) < 0.01) return;
|
||||||
|
|
||||||
|
const delta, const length = Graphics.Transform.extractNormal(.{ -mouse.dy, -mouse.dx, 0.0 });
|
||||||
|
const rot = Graphics.Transform.rotationByAxis(
|
||||||
|
delta,
|
||||||
|
length * std.math.pi / @as(f32, @floatFromInt(graphics.window_size[1])) * 2.0,
|
||||||
|
);
|
||||||
|
cube.transform.rotate(rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(cube: *Cube, graphics: *Graphics) !void {
|
||||||
|
for (OFFSETS) |offset| {
|
||||||
|
try graphics.drawMesh(cube.mesh, Graphics.Transform{
|
||||||
|
.position = cube.transform.position + offset,
|
||||||
|
.rotation = cube.transform.rotation,
|
||||||
|
.scale = cube.transform.scale,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
51
src/game.zig
51
src/game.zig
@@ -1,6 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const sdl = @import("sdl");
|
const sdl = @import("sdl");
|
||||||
|
|
||||||
|
const debug_scene = @import("debug_scene.zig");
|
||||||
const Graph = @import("graph.zig");
|
const Graph = @import("graph.zig");
|
||||||
const Graphics = @import("graphics.zig");
|
const Graphics = @import("graphics.zig");
|
||||||
|
|
||||||
@@ -8,6 +10,7 @@ const Graphics = @import("graphics.zig");
|
|||||||
// - Do something about deallocating `Resource`s when `Graph` fails
|
// - Do something about deallocating `Resource`s when `Graph` fails
|
||||||
|
|
||||||
const RunInfo = struct { running: bool };
|
const RunInfo = struct { running: bool };
|
||||||
|
pub const Mouse = struct { x: f32, y: f32, dx: f32, dy: f32 };
|
||||||
|
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
@@ -21,8 +24,18 @@ pub fn init(alloc: std.mem.Allocator) GameError!Self {
|
|||||||
|
|
||||||
var controller = try graph.getController();
|
var controller = try graph.getController();
|
||||||
controller.addResource(graphics);
|
controller.addResource(graphics);
|
||||||
|
controller.addResource(Mouse{
|
||||||
|
.x = 0.0,
|
||||||
|
.y = 0.0,
|
||||||
|
.dx = 0.0,
|
||||||
|
.dy = 0.0,
|
||||||
|
});
|
||||||
|
controller.queue(debug_scene.init);
|
||||||
try graph.freeController(controller);
|
try graph.freeController(controller);
|
||||||
|
|
||||||
|
defer graph.reset();
|
||||||
|
try graph.runAllSystems();
|
||||||
|
|
||||||
return Self{
|
return Self{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.graph = graph,
|
.graph = graph,
|
||||||
@@ -44,7 +57,9 @@ pub fn run(self: *Self) GameError!void {
|
|||||||
var controller = try self.graph.getController();
|
var controller = try self.graph.getController();
|
||||||
controller.queue(.{
|
controller.queue(.{
|
||||||
.events = processEvents,
|
.events = processEvents,
|
||||||
.draw = draw,
|
.update = debug_scene.update,
|
||||||
|
.begin_draw = beginDraw,
|
||||||
|
.end_draw = endDraw,
|
||||||
.ordered = true,
|
.ordered = true,
|
||||||
});
|
});
|
||||||
try self.graph.freeController(controller);
|
try self.graph.freeController(controller);
|
||||||
@@ -54,12 +69,13 @@ pub fn run(self: *Self) GameError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(graphics: *Graphics) GameError!void {
|
fn beginDraw(graphics: *Graphics, controller: *Graph.Controller) GameError!void {
|
||||||
try graphics.beginDraw();
|
if (try graphics.beginDraw()) {
|
||||||
{
|
controller.queue(debug_scene.draw);
|
||||||
errdefer graphics.endDraw() catch {};
|
|
||||||
try graphics.drawDebug();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endDraw(graphics: *Graphics) GameError!void {
|
||||||
try graphics.endDraw();
|
try graphics.endDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +84,10 @@ fn clean(graphics: *Graphics) !void {
|
|||||||
// TODO: Also remove the resource
|
// TODO: Also remove the resource
|
||||||
}
|
}
|
||||||
|
|
||||||
fn processEvents(graphics: *Graphics, run_info: *RunInfo) GameError!void {
|
fn processEvents(graphics: *Graphics, run_info: *RunInfo, mouse: *Mouse) GameError!void {
|
||||||
|
mouse.dx = 0.0;
|
||||||
|
mouse.dy = 0.0;
|
||||||
|
|
||||||
sdl.PumpEvents();
|
sdl.PumpEvents();
|
||||||
while (true) {
|
while (true) {
|
||||||
var buffer: [16]sdl.Event = undefined;
|
var buffer: [16]sdl.Event = undefined;
|
||||||
@@ -85,14 +104,10 @@ fn processEvents(graphics: *Graphics, run_info: *RunInfo) GameError!void {
|
|||||||
},
|
},
|
||||||
sdl.EVENT_MOUSE_MOTION => {
|
sdl.EVENT_MOUSE_MOTION => {
|
||||||
if (event.motion.windowID != sdl.GetWindowID(graphics.window)) continue;
|
if (event.motion.windowID != sdl.GetWindowID(graphics.window)) continue;
|
||||||
if (@abs(event.motion.xrel) < 0.01 and @abs(event.motion.yrel) < 0.01) continue;
|
mouse.x = event.motion.x;
|
||||||
const Transform = @import("graphics/transform.zig");
|
mouse.y = event.motion.y;
|
||||||
const delta, const length = Transform.extractNormal(.{ -event.motion.yrel, -event.motion.xrel, 0.0 });
|
mouse.dx += event.motion.xrel;
|
||||||
const rot = Transform.rotationByAxis(
|
mouse.dy += event.motion.yrel;
|
||||||
delta,
|
|
||||||
length * std.math.pi / @as(f32, @floatFromInt(graphics.window_size[1])) * 2.0,
|
|
||||||
);
|
|
||||||
graphics.mesh_transform.rotate(rot);
|
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@@ -106,7 +121,11 @@ fn processEvents(graphics: *Graphics, run_info: *RunInfo) GameError!void {
|
|||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
var controller = self.graph.getController() catch unreachable;
|
var controller = self.graph.getController() catch unreachable;
|
||||||
controller.queue(clean);
|
controller.queue(.{
|
||||||
|
.deinit = debug_scene.deinit,
|
||||||
|
.clean = clean,
|
||||||
|
.ordered = true,
|
||||||
|
});
|
||||||
self.graph.freeController(controller) catch unreachable;
|
self.graph.freeController(controller) catch unreachable;
|
||||||
self.graph.runAllSystems() catch unreachable;
|
self.graph.runAllSystems() catch unreachable;
|
||||||
|
|
||||||
|
@@ -149,7 +149,10 @@ pub fn runAllSystems(self: *Self) GraphError!void {
|
|||||||
const next_system = self.system_queue.pop().?;
|
const next_system = self.system_queue.pop().?;
|
||||||
|
|
||||||
defer next_system.deinit(self.alloc);
|
defer next_system.deinit(self.alloc);
|
||||||
try self.runSystem(next_system);
|
self.runSystem(next_system) catch |err| {
|
||||||
|
std.debug.print("System run error: {} while running {s}\n", .{ err, next_system.label });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ function_runner: *const fn ([]const *anyopaque) void,
|
|||||||
requested_types: []const Request,
|
requested_types: []const Request,
|
||||||
requires_dud: ?Dud.Id,
|
requires_dud: ?Dud.Id,
|
||||||
submit_dud: ?Dud.Id,
|
submit_dud: ?Dud.Id,
|
||||||
|
label: []const u8,
|
||||||
|
|
||||||
pub const Dud = struct {
|
pub const Dud = struct {
|
||||||
pub const Id = usize;
|
pub const Id = usize;
|
||||||
@@ -37,6 +38,7 @@ pub fn fromFunction(comptime function: anytype, alloc: std.mem.Allocator) !Self
|
|||||||
.function_runner = utils.generateRunner(function),
|
.function_runner = utils.generateRunner(function),
|
||||||
.requires_dud = null,
|
.requires_dud = null,
|
||||||
.submit_dud = null,
|
.submit_dud = null,
|
||||||
|
.label = @typeName(@TypeOf(function)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
237
src/graphics.zig
237
src/graphics.zig
@@ -1,20 +1,33 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const sdl = @import("sdl");
|
const sdl = @import("sdl");
|
||||||
const presets = @import("graphics/presets.zig");
|
const presets = @import("graphics/presets.zig");
|
||||||
const Transform = @import("graphics/transform.zig");
|
|
||||||
const Camera = @import("graphics/camera.zig");
|
|
||||||
const GameError = @import("game.zig").GameError;
|
const GameError = @import("game.zig").GameError;
|
||||||
|
|
||||||
|
pub const Transform = @import("graphics/transform.zig");
|
||||||
|
pub const Camera = @import("graphics/camera.zig");
|
||||||
|
|
||||||
|
pub const Mesh = struct {
|
||||||
|
vertex_start: usize,
|
||||||
|
vertex_count: usize,
|
||||||
|
};
|
||||||
|
|
||||||
window: *sdl.Window,
|
window: *sdl.Window,
|
||||||
renderer: *sdl.Renderer,
|
renderer: *sdl.Renderer,
|
||||||
device: *sdl.GPUDevice,
|
device: *sdl.GPUDevice,
|
||||||
/// Only available while drawing
|
/// Only available while drawing
|
||||||
command_buffer: ?*sdl.GPUCommandBuffer,
|
command_buffer: ?*sdl.GPUCommandBuffer,
|
||||||
|
render_pass: ?*sdl.GPURenderPass,
|
||||||
|
|
||||||
shader_vert: *sdl.GPUShader,
|
shader_vert: *sdl.GPUShader,
|
||||||
shader_frag: *sdl.GPUShader,
|
shader_frag: *sdl.GPUShader,
|
||||||
|
|
||||||
vertex_buffer: *sdl.GPUBuffer,
|
vertex_buffer: *sdl.GPUBuffer,
|
||||||
|
vertex_buffer_capacity: usize,
|
||||||
|
vertex_buffer_used: usize,
|
||||||
|
|
||||||
|
transfer_buffer: *sdl.GPUTransferBuffer,
|
||||||
|
transfer_buffer_capacity: usize,
|
||||||
|
|
||||||
depth_texture: *sdl.GPUTexture,
|
depth_texture: *sdl.GPUTexture,
|
||||||
msaa_resolve: *sdl.GPUTexture,
|
msaa_resolve: *sdl.GPUTexture,
|
||||||
pipeline: *sdl.GPUGraphicsPipeline,
|
pipeline: *sdl.GPUGraphicsPipeline,
|
||||||
@@ -22,50 +35,13 @@ pipeline: *sdl.GPUGraphicsPipeline,
|
|||||||
window_size: [2]u32,
|
window_size: [2]u32,
|
||||||
|
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
mesh_transform: Transform,
|
|
||||||
|
|
||||||
to_resize: ?[2]u32 = null,
|
to_resize: ?[2]u32 = null,
|
||||||
|
|
||||||
const MESH_BYTES = MESH.len * 4;
|
const VERTEX_BUFFER_DEFAULT_CAPACITY = 1024;
|
||||||
const MESH_VERTS = @divExact(MESH.len, 3);
|
const VERTEX_BUFFER_GROWTH_MULTIPLIER = 2;
|
||||||
const MESH = [_]f32{
|
const TRANSFER_BUFFER_DEFAULT_CAPACITY = 1024;
|
||||||
-1, 1, -1,
|
const BYTES_PER_VERTEX = 3 * 4;
|
||||||
1, 1, -1,
|
|
||||||
-1, -1, -1,
|
|
||||||
1, -1, -1,
|
|
||||||
-1, -1, -1,
|
|
||||||
1, 1, -1,
|
|
||||||
1, 1, -1,
|
|
||||||
1, 1, 1,
|
|
||||||
1, -1, -1,
|
|
||||||
1, -1, 1,
|
|
||||||
1, -1, -1,
|
|
||||||
1, 1, 1,
|
|
||||||
1, 1, 1,
|
|
||||||
-1, 1, 1,
|
|
||||||
1, -1, 1,
|
|
||||||
-1, -1, 1,
|
|
||||||
1, -1, 1,
|
|
||||||
-1, 1, 1,
|
|
||||||
-1, 1, 1,
|
|
||||||
-1, 1, -1,
|
|
||||||
-1, -1, 1,
|
|
||||||
-1, -1, -1,
|
|
||||||
-1, -1, 1,
|
|
||||||
-1, 1, -1,
|
|
||||||
-1, 1, 1,
|
|
||||||
1, 1, 1,
|
|
||||||
-1, 1, -1,
|
|
||||||
1, 1, -1,
|
|
||||||
-1, 1, -1,
|
|
||||||
1, 1, 1,
|
|
||||||
-1, -1, -1,
|
|
||||||
1, -1, -1,
|
|
||||||
-1, -1, 1,
|
|
||||||
1, -1, 1,
|
|
||||||
-1, -1, 1,
|
|
||||||
1, -1, -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
pub fn create() GameError!Self {
|
pub fn create() GameError!Self {
|
||||||
@@ -126,35 +102,15 @@ pub fn create() GameError!Self {
|
|||||||
|
|
||||||
const vertex_buffer = sdl.CreateGPUBuffer(device, &.{
|
const vertex_buffer = sdl.CreateGPUBuffer(device, &.{
|
||||||
.usage = sdl.GPU_BUFFERUSAGE_VERTEX,
|
.usage = sdl.GPU_BUFFERUSAGE_VERTEX,
|
||||||
// Vertices * 3 Coordinates * 4 Bytes
|
.size = VERTEX_BUFFER_DEFAULT_CAPACITY,
|
||||||
.size = MESH_BYTES,
|
|
||||||
}) orelse return GameError.SdlError;
|
}) orelse return GameError.SdlError;
|
||||||
errdefer sdl.ReleaseGPUBuffer(device, vertex_buffer);
|
errdefer sdl.ReleaseGPUBuffer(device, vertex_buffer);
|
||||||
|
|
||||||
const transfer_buffer = sdl.CreateGPUTransferBuffer(device, &.{
|
const transfer_buffer = sdl.CreateGPUTransferBuffer(device, &.{
|
||||||
.size = MESH_BYTES,
|
.size = TRANSFER_BUFFER_DEFAULT_CAPACITY,
|
||||||
.usage = sdl.GPU_TRANSFERBUFFERUSAGE_UPLOAD,
|
.usage = sdl.GPU_TRANSFERBUFFERUSAGE_UPLOAD | sdl.GPU_TRANSFERBUFFERUSAGE_DOWNLOAD,
|
||||||
}) orelse return GameError.SdlError;
|
}) orelse return GameError.SdlError;
|
||||||
defer sdl.ReleaseGPUTransferBuffer(device, transfer_buffer);
|
errdefer sdl.ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||||
|
|
||||||
{ // Filling up transfer buffer
|
|
||||||
const mapped_buffer: [*c]f32 = @alignCast(@ptrCast(sdl.MapGPUTransferBuffer(device, transfer_buffer, false) orelse return GameError.SdlError));
|
|
||||||
defer sdl.UnmapGPUTransferBuffer(device, transfer_buffer);
|
|
||||||
std.mem.copyForwards(f32, mapped_buffer[0..MESH.len], &MESH);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Copying data over from transfer buffer to vertex buffer
|
|
||||||
const command_buffer = sdl.AcquireGPUCommandBuffer(device) orelse return GameError.SdlError;
|
|
||||||
const copy_pass = sdl.BeginGPUCopyPass(command_buffer) orelse return GameError.SdlError;
|
|
||||||
|
|
||||||
sdl.UploadToGPUBuffer(copy_pass, &.{ .transfer_buffer = transfer_buffer }, &.{
|
|
||||||
.size = MESH_BYTES,
|
|
||||||
.buffer = vertex_buffer,
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
sdl.EndGPUCopyPass(copy_pass);
|
|
||||||
if (!sdl.SubmitGPUCommandBuffer(command_buffer)) return GameError.SdlError;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target_format = sdl.GetGPUSwapchainTextureFormat(device, window);
|
const target_format = sdl.GetGPUSwapchainTextureFormat(device, window);
|
||||||
if (target_format == sdl.GPU_TEXTUREFORMAT_INVALID) return GameError.SdlError;
|
if (target_format == sdl.GPU_TEXTUREFORMAT_INVALID) return GameError.SdlError;
|
||||||
@@ -211,24 +167,33 @@ pub fn create() GameError!Self {
|
|||||||
.window = window.?,
|
.window = window.?,
|
||||||
.renderer = renderer.?,
|
.renderer = renderer.?,
|
||||||
.device = device,
|
.device = device,
|
||||||
|
|
||||||
.command_buffer = null,
|
.command_buffer = null,
|
||||||
|
.render_pass = null,
|
||||||
|
|
||||||
.shader_vert = shader_vert,
|
.shader_vert = shader_vert,
|
||||||
.shader_frag = shader_frag,
|
.shader_frag = shader_frag,
|
||||||
|
|
||||||
.vertex_buffer = vertex_buffer,
|
.vertex_buffer = vertex_buffer,
|
||||||
|
.vertex_buffer_capacity = VERTEX_BUFFER_DEFAULT_CAPACITY,
|
||||||
|
.vertex_buffer_used = 0,
|
||||||
|
|
||||||
|
.transfer_buffer = transfer_buffer,
|
||||||
|
.transfer_buffer_capacity = TRANSFER_BUFFER_DEFAULT_CAPACITY,
|
||||||
|
|
||||||
.depth_texture = depth_texture,
|
.depth_texture = depth_texture,
|
||||||
.msaa_resolve = msaa_resolve,
|
.msaa_resolve = msaa_resolve,
|
||||||
.pipeline = pipeline,
|
.pipeline = pipeline,
|
||||||
|
|
||||||
.window_size = .{ 1600, 900 },
|
.window_size = .{ 1600, 900 },
|
||||||
|
|
||||||
.camera = Camera{
|
.camera = Camera{
|
||||||
.transform = Transform{
|
.transform = Transform{
|
||||||
.position = .{ 0.0, 0.0, -6.0 },
|
.position = .{ 0.0, 0.0, -4.0 },
|
||||||
},
|
},
|
||||||
.near = 1.0,
|
.near = 1.0,
|
||||||
.far = 1024.0,
|
.far = 1024.0,
|
||||||
.lens = .{ 0.5 * 16.0 / 9.0, 0.5 },
|
.lens = .{ 1.5 * 16.0 / 9.0, 1.5 },
|
||||||
},
|
|
||||||
.mesh_transform = Transform{
|
|
||||||
.scale = .{ 1.0, 1.5, 2.0 },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -242,6 +207,7 @@ pub fn destroy(self: *Self) void {
|
|||||||
sdl.ReleaseGPUTexture(self.device, self.msaa_resolve);
|
sdl.ReleaseGPUTexture(self.device, self.msaa_resolve);
|
||||||
sdl.ReleaseGPUTexture(self.device, self.depth_texture);
|
sdl.ReleaseGPUTexture(self.device, self.depth_texture);
|
||||||
sdl.ReleaseGPUBuffer(self.device, self.vertex_buffer);
|
sdl.ReleaseGPUBuffer(self.device, self.vertex_buffer);
|
||||||
|
sdl.ReleaseGPUTransferBuffer(self.device, self.transfer_buffer);
|
||||||
|
|
||||||
sdl.ReleaseGPUShader(self.device, self.shader_vert);
|
sdl.ReleaseGPUShader(self.device, self.shader_vert);
|
||||||
sdl.ReleaseGPUShader(self.device, self.shader_frag);
|
sdl.ReleaseGPUShader(self.device, self.shader_frag);
|
||||||
@@ -253,7 +219,107 @@ pub fn destroy(self: *Self) void {
|
|||||||
sdl.DestroyGPUDevice(self.device);
|
sdl.DestroyGPUDevice(self.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beginDraw(self: *Self) GameError!void {
|
pub fn loadMesh(self: *Self, mesh_bytes: []const u8) GameError!Mesh {
|
||||||
|
std.debug.assert(mesh_bytes.len < self.transfer_buffer_capacity);
|
||||||
|
|
||||||
|
var size_mult: usize = 1;
|
||||||
|
while (self.vertex_buffer_used + mesh_bytes.len > self.vertex_buffer_capacity) {
|
||||||
|
size_mult *= VERTEX_BUFFER_GROWTH_MULTIPLIER;
|
||||||
|
}
|
||||||
|
if (size_mult > 1) {
|
||||||
|
try self.growVertexBuffer(self.vertex_buffer_capacity * size_mult);
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = sdl.MapGPUTransferBuffer(self.device, self.transfer_buffer, false) orelse return GameError.SdlError;
|
||||||
|
@memcpy(@as([*]u8, @ptrCast(map)), mesh_bytes);
|
||||||
|
sdl.UnmapGPUTransferBuffer(self.device, self.transfer_buffer);
|
||||||
|
|
||||||
|
const command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
||||||
|
const fence = blk: {
|
||||||
|
errdefer _ = sdl.CancelGPUCommandBuffer(command_buffer);
|
||||||
|
|
||||||
|
const copy_pass = sdl.BeginGPUCopyPass(command_buffer) orelse return GameError.SdlError;
|
||||||
|
sdl.UploadToGPUBuffer(copy_pass, &.{
|
||||||
|
.transfer_buffer = self.transfer_buffer,
|
||||||
|
.offset = 0,
|
||||||
|
}, &.{
|
||||||
|
.buffer = self.vertex_buffer,
|
||||||
|
.offset = @intCast(self.vertex_buffer_used),
|
||||||
|
.size = @intCast(mesh_bytes.len),
|
||||||
|
}, false);
|
||||||
|
sdl.EndGPUCopyPass(copy_pass);
|
||||||
|
|
||||||
|
break :blk sdl.SubmitGPUCommandBufferAndAcquireFence(command_buffer) orelse return GameError.SdlError;
|
||||||
|
};
|
||||||
|
defer sdl.ReleaseGPUFence(self.device, fence);
|
||||||
|
|
||||||
|
if (!sdl.WaitForGPUFences(self.device, true, &fence, 1)) return GameError.SdlError;
|
||||||
|
|
||||||
|
const vertex_start = self.vertex_buffer_used;
|
||||||
|
self.vertex_buffer_used += mesh_bytes.len;
|
||||||
|
|
||||||
|
return Mesh{
|
||||||
|
.vertex_start = vertex_start / BYTES_PER_VERTEX,
|
||||||
|
.vertex_count = mesh_bytes.len / BYTES_PER_VERTEX,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unloadMesh(self: *Self, mesh: Mesh) void {
|
||||||
|
// TODO: free some memory
|
||||||
|
_ = self;
|
||||||
|
_ = &mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn growVertexBuffer(self: *Self, new_size: usize) GameError!void {
|
||||||
|
const new_buffer = sdl.CreateGPUBuffer(self.device, &.{
|
||||||
|
.size = @intCast(new_size),
|
||||||
|
.usage = sdl.GPU_BUFFERUSAGE_VERTEX,
|
||||||
|
}) orelse return GameError.SdlError;
|
||||||
|
errdefer sdl.ReleaseGPUBuffer(self.device, new_buffer);
|
||||||
|
|
||||||
|
const command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
||||||
|
|
||||||
|
const fence = blk: {
|
||||||
|
errdefer _ = sdl.CancelGPUCommandBuffer(command_buffer);
|
||||||
|
|
||||||
|
const copy_pass = sdl.BeginGPUCopyPass(command_buffer);
|
||||||
|
var copied: usize = 0;
|
||||||
|
while (copied < self.vertex_buffer_used) {
|
||||||
|
const to_transer = @min(self.vertex_buffer_used - copied, self.transfer_buffer_capacity);
|
||||||
|
sdl.DownloadFromGPUBuffer(copy_pass, &.{
|
||||||
|
.buffer = self.vertex_buffer,
|
||||||
|
.offset = @intCast(copied),
|
||||||
|
.size = @intCast(to_transer),
|
||||||
|
}, &.{
|
||||||
|
.transfer_buffer = self.transfer_buffer,
|
||||||
|
.offset = 0,
|
||||||
|
});
|
||||||
|
sdl.UploadToGPUBuffer(copy_pass, &.{
|
||||||
|
.transfer_buffer = self.transfer_buffer,
|
||||||
|
.offset = 0,
|
||||||
|
}, &.{
|
||||||
|
.buffer = new_buffer,
|
||||||
|
.offset = @intCast(copied),
|
||||||
|
.size = @intCast(to_transer),
|
||||||
|
}, false);
|
||||||
|
copied += to_transer;
|
||||||
|
}
|
||||||
|
sdl.EndGPUCopyPass(copy_pass);
|
||||||
|
|
||||||
|
break :blk sdl.SubmitGPUCommandBufferAndAcquireFence(command_buffer) orelse return GameError.SdlError;
|
||||||
|
};
|
||||||
|
defer sdl.ReleaseGPUFence(self.device, fence);
|
||||||
|
|
||||||
|
if (!sdl.WaitForGPUFences(self.device, true, &fence, 1)) return GameError.SdlError;
|
||||||
|
|
||||||
|
sdl.ReleaseGPUBuffer(self.device, self.vertex_buffer);
|
||||||
|
self.vertex_buffer = new_buffer;
|
||||||
|
self.vertex_buffer_capacity = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If window is minimized returns `false`, `render_pass` remains null
|
||||||
|
/// Otherwise `command_buffer` and `render_pass` are both set
|
||||||
|
pub fn beginDraw(self: *Self) GameError!bool {
|
||||||
self.command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
self.command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
||||||
if (self.to_resize) |new_size| {
|
if (self.to_resize) |new_size| {
|
||||||
try self.resetTextures(new_size[0], new_size[1]);
|
try self.resetTextures(new_size[0], new_size[1]);
|
||||||
@@ -261,17 +327,15 @@ pub fn beginDraw(self: *Self) GameError!void {
|
|||||||
self.window_size = new_size;
|
self.window_size = new_size;
|
||||||
self.to_resize = null;
|
self.to_resize = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drawDebug(self: *Self) GameError!void {
|
|
||||||
var render_target: ?*sdl.GPUTexture = null;
|
var render_target: ?*sdl.GPUTexture = null;
|
||||||
var width: u32 = 0;
|
var width: u32 = 0;
|
||||||
var height: u32 = 0;
|
var height: u32 = 0;
|
||||||
if (!sdl.WaitAndAcquireGPUSwapchainTexture(self.command_buffer, self.window, &render_target, &width, &height)) return GameError.SdlError;
|
if (!sdl.WaitAndAcquireGPUSwapchainTexture(self.command_buffer, self.window, &render_target, &width, &height)) return GameError.SdlError;
|
||||||
// Hidden
|
// Hidden
|
||||||
if (render_target == null) return;
|
if (render_target == null) return false;
|
||||||
|
|
||||||
const render_pass = sdl.BeginGPURenderPass(self.command_buffer, &.{
|
self.render_pass = sdl.BeginGPURenderPass(self.command_buffer, &.{
|
||||||
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
.cycle = false,
|
.cycle = false,
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
@@ -289,17 +353,26 @@ pub fn drawDebug(self: *Self) GameError!void {
|
|||||||
.texture = self.depth_texture,
|
.texture = self.depth_texture,
|
||||||
}) orelse return GameError.SdlError;
|
}) orelse return GameError.SdlError;
|
||||||
|
|
||||||
sdl.BindGPUGraphicsPipeline(render_pass, self.pipeline);
|
sdl.BindGPUGraphicsPipeline(self.render_pass, self.pipeline);
|
||||||
sdl.BindGPUVertexBuffers(render_pass, 0, &.{ .offset = 0, .buffer = self.vertex_buffer }, 1);
|
sdl.BindGPUVertexBuffers(self.render_pass, 0, &.{ .offset = 0, .buffer = self.vertex_buffer }, 1);
|
||||||
sdl.PushGPUVertexUniformData(self.command_buffer, 0, &self.camera.matrix(), 16 * 4);
|
sdl.PushGPUVertexUniformData(self.command_buffer, 0, &self.camera.matrix(), 16 * 4);
|
||||||
sdl.PushGPUVertexUniformData(self.command_buffer, 1, &self.mesh_transform.matrix(), 16 * 4);
|
|
||||||
sdl.DrawGPUPrimitives(render_pass, MESH_VERTS, 1, 0, 0);
|
|
||||||
|
|
||||||
sdl.EndGPURenderPass(render_pass);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drawMesh(self: *Self, mesh: Mesh, transform: Transform) GameError!void {
|
||||||
|
if (self.render_pass == null) return;
|
||||||
|
|
||||||
|
sdl.PushGPUVertexUniformData(self.command_buffer, 1, &transform.matrix(), 16 * 4);
|
||||||
|
sdl.DrawGPUPrimitives(self.render_pass, @intCast(mesh.vertex_count), 1, @intCast(mesh.vertex_start), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn endDraw(self: *Self) GameError!void {
|
pub fn endDraw(self: *Self) GameError!void {
|
||||||
defer self.command_buffer = null;
|
defer self.command_buffer = null;
|
||||||
|
defer self.render_pass = null;
|
||||||
|
if (self.render_pass) |render_pass| {
|
||||||
|
sdl.EndGPURenderPass(render_pass);
|
||||||
|
}
|
||||||
if (!sdl.SubmitGPUCommandBuffer(self.command_buffer)) return GameError.SdlError;
|
if (!sdl.SubmitGPUCommandBuffer(self.command_buffer)) return GameError.SdlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user