diff --git a/build.zig b/build.zig index 22b1948..46a8ede 100644 --- a/build.zig +++ b/build.zig @@ -18,12 +18,6 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); - const ecs = b.createModule(.{ - .root_source_file = b.path("src/ecs/ecs.zig"), - .target = target, - .optimize = optimize, - }); - const rendering = b.createModule(.{ .root_source_file = b.path("src/rendering/rendering.zig"), .target = target, @@ -33,7 +27,12 @@ pub fn build(b: *std.Build) void { rendering.addIncludePath(b.path("ext")); rendering.addCSourceFile(.{ .file = b.path("ext/stb_image.c") }); rendering.addImport("math", math); - rendering.addImport("ecs", ecs); + + const ecs = b.createModule(.{ + .root_source_file = b.path("src/ecs/ecs.zig"), + .target = target, + .optimize = optimize, + }); ecs.addImport("rendering", rendering); compileAllShaders(b, rendering); @@ -52,6 +51,7 @@ pub fn build(b: *std.Build) void { sideros.root_module.addImport("mods", mods); sideros.root_module.addImport("ecs", ecs); sideros.root_module.addImport("rendering", rendering); + sideros.root_module.addImport("math", math); b.installArtifact(sideros); diff --git a/src/rendering/Camera.zig b/src/rendering/Camera.zig index de5dced..4cd4e38 100644 --- a/src/rendering/Camera.zig +++ b/src/rendering/Camera.zig @@ -24,27 +24,4 @@ pub fn getView(self: *Camera) math.Matrix { return math.Matrix.lookAt(self.position, self.position + self.target, self.up); } -pub fn moveCamera(pool: *ecs.Pool) !void { - const input = pool.resources.input; - var camera = pool.resources.camera; - const mul = @as(@Vector(3, f32), @splat(camera.speed * pool.resources.delta_time)); - if (input.isKeyDown(.w)) { - camera.position += camera.target * mul; - } - if (input.isKeyDown(.s)) { - camera.position -= camera.target * mul; - } - if (input.isKeyDown(.a)) { - camera.position -= math.normalize(math.cross(camera.target, camera.up)) * mul; - } - if (input.isKeyDown(.d)) { - camera.position += math.normalize(math.cross(camera.target, camera.up)) * mul; - } - if (input.isKeyDown(.space)) { - camera.position += camera.up * mul; - } - if (input.isKeyDown(.left_shift)) { - camera.position -= camera.up * mul; - } -} diff --git a/src/rendering/Renderer.zig b/src/rendering/Renderer.zig index 9b5f9ad..ad6da5b 100644 --- a/src/rendering/Renderer.zig +++ b/src/rendering/Renderer.zig @@ -1,5 +1,4 @@ const math = @import("math"); -const ecs = @import("ecs"); const std = @import("std"); const vk = @import("vulkan.zig"); const c = vk.c; @@ -8,7 +7,7 @@ const Texture = vk.Texture; const Camera = @import("Camera.zig"); const Allocator = std.mem.Allocator; -const Renderer = @This(); +const Self = @This(); instance: vk.Instance, surface: vk.Surface, @@ -21,8 +20,9 @@ current_frame: u32, mesh: Mesh, transforms: std.ArrayList(math.Transform), previous_time: std.time.Instant, +current_image: usize, -pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Renderer { +pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Self { const instance: vk.Instance = .{ .handle = instance_handle }; const surface: vk.Surface = .{ .handle = surface_handle }; var physical_device = try vk.PhysicalDevice.pick(allocator, instance); @@ -79,7 +79,7 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand try transforms.append(math.Transform.init(.{0.0, 0.0, -1.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0})); try transforms.append(math.Transform.init(.{0.0, 0.0, 0.0}, .{0.5, 0.5, 0.5}, .{0.0, 0.0, 0.0})); - return Renderer{ + return .{ .instance = instance, .surface = surface, .physical_device = physical_device, @@ -91,10 +91,11 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand .transforms = transforms, .previous_time = try std.time.Instant.now(), .mesh = mesh, + .current_image = undefined, }; } -pub fn deinit(self: Renderer) void { +pub fn deinit(self: Self) void { self.device.waitIdle(); self.graphics_pipeline.deinit(self.device); self.swapchain.deinit(self.device); @@ -102,54 +103,48 @@ pub fn deinit(self: Renderer) void { self.device.deinit(); } -// TODO: render is maybe a bad name? something like present() or submit() is better? -pub fn render(pool: *ecs.Pool) anyerror!void { - var renderer = pool.resources.renderer; - var camera = pool.resources.camera; - - const now = try std.time.Instant.now(); - const delta_time: f32 = @as(f32, @floatFromInt(now.since(renderer.previous_time))) / @as(f32, 1_000_000_000.0); - pool.resources.delta_time = delta_time; - renderer.previous_time = now; - +pub fn setCamera(self: *Self, camera: *Camera) void { const view = camera.getView(); - const view_memory = renderer.graphics_pipeline.view_memory; + const view_memory = self.graphics_pipeline.view_memory; @memcpy(view_memory[0..@sizeOf(math.Matrix)], std.mem.asBytes(&view)); - const view_pos_memory = renderer.graphics_pipeline.view_pos_memory; + const view_pos_memory = self.graphics_pipeline.view_pos_memory; const view_pos: [*]f32 = @alignCast(@ptrCast(view_pos_memory)); view_pos[0] = camera.position[0]; view_pos[1] = camera.position[1]; view_pos[2] = camera.position[2]; - - const transform_memory = renderer.graphics_pipeline.transform_buffer.mapped_memory; - - try renderer.device.waitFence(renderer.current_frame); - const image = try renderer.swapchain.nextImage(renderer.device, renderer.current_frame); - try renderer.device.resetCommand(renderer.current_frame); - try renderer.device.beginCommand(renderer.current_frame); - renderer.render_pass.begin(renderer.swapchain, renderer.device, image, renderer.current_frame); - renderer.graphics_pipeline.bind(renderer.device, renderer.current_frame); - renderer.device.bindVertexBuffer(renderer.graphics_pipeline.vertex_buffer, renderer.current_frame); - renderer.device.bindIndexBuffer(renderer.graphics_pipeline.index_buffer, renderer.current_frame); - renderer.device.bindDescriptorSets(renderer.graphics_pipeline, renderer.current_frame, 0); - var lights: u32 = 2; - - for (renderer.transforms.items, 0..) |transform, i| { - transform_memory[i] = transform; - var index = i; - - renderer.device.pushConstant(renderer.graphics_pipeline, c.VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, @ptrCast(&lights), renderer.current_frame); - renderer.device.pushConstant(renderer.graphics_pipeline, c.VK_SHADER_STAGE_VERTEX_BIT, 4, 4, @ptrCast(&index), renderer.current_frame); - renderer.device.draw(renderer.mesh.index_count, renderer.current_frame, renderer.mesh); - } - - renderer.render_pass.end(renderer.device, renderer.current_frame); - try renderer.device.endCommand(renderer.current_frame); - - try renderer.device.submit(renderer.swapchain, image, renderer.current_frame); - - renderer.current_frame = (renderer.current_frame + 1) % 2; - - renderer.device.waitIdle(); } + +pub fn begin(self: *Self) !void { + try self.device.waitFence(self.current_frame); + const image = try self.swapchain.nextImage(self.device, self.current_frame); + try self.device.resetCommand(self.current_frame); + try self.device.beginCommand(self.current_frame); + self.render_pass.begin(self.swapchain, self.device, image, self.current_frame); + self.graphics_pipeline.bind(self.device, self.current_frame); + self.device.bindVertexBuffer(self.graphics_pipeline.vertex_buffer, self.current_frame); + self.device.bindIndexBuffer(self.graphics_pipeline.index_buffer, self.current_frame); + self.device.bindDescriptorSets(self.graphics_pipeline, self.current_frame, 0); + self.current_image = image; +} + +pub fn setLightCount(self: *Self, count: u32) void { + self.device.pushConstant(self.graphics_pipeline, c.VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, @constCast(@ptrCast(&count)), self.current_frame); +} + +pub fn setTransform(self: *Self, transform: u32) void { + self.device.pushConstant(self.graphics_pipeline, c.VK_SHADER_STAGE_VERTEX_BIT, 4, 4, @constCast(@ptrCast(&transform)), self.current_frame); +} + +pub fn end(self: *Self) !void { + self.render_pass.end(self.device, self.current_frame); + try self.device.endCommand(self.current_frame); + + try self.device.submit(self.swapchain, self.current_image, self.current_frame); + + self.current_frame = (self.current_frame + 1) % 2; + + self.device.waitIdle(); +} + + diff --git a/src/rendering/dynamic_buffer.zig b/src/rendering/dynamic_buffer.zig index e44e13e..930da14 100644 --- a/src/rendering/dynamic_buffer.zig +++ b/src/rendering/dynamic_buffer.zig @@ -86,7 +86,7 @@ pub fn DynamicBuffer(comptime T: type) type { var free_indices = std.ArrayList(usize).init(allocator); for (0..10) |i| { - free_indices.append(i); + try free_indices.append(i); } return .{ diff --git a/src/sideros.zig b/src/sideros.zig index b7738a2..2e5a5fc 100644 --- a/src/sideros.zig +++ b/src/sideros.zig @@ -10,6 +10,8 @@ const api = @cImport({ const std = @import("std"); +const systems = @import("systems.zig"); + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); var pool: ecs.Pool = undefined; @@ -59,7 +61,7 @@ export fn sideros_init(init: api.GameInit) callconv(.c) void { pool = ecs.Pool.init(allocator, &resources) catch @panic("TODO: Gracefully handle error"); // TODO(ernesto): I think this @ptrCast are unavoidable but maybe not? renderer = Renderer.init(allocator, @ptrCast(init.instance), @ptrCast(init.surface)) catch @panic("TODO: Gracefully handle error"); - pool.addSystemGroup(&[_]ecs.System{Renderer.render, rendering.Camera.moveCamera}, true) catch @panic("TODO: Gracefuly handle error"); + pool.addSystemGroup(&[_]ecs.System{systems.render, systems.moveCamera}, true) catch @panic("TODO: Gracefuly handle error"); pool.resources.renderer = &renderer; pool.tick(); init_mods(); diff --git a/src/systems.zig b/src/systems.zig new file mode 100644 index 0000000..966db83 --- /dev/null +++ b/src/systems.zig @@ -0,0 +1,54 @@ +const ecs = @import("ecs"); +const math = @import("math"); +const std = @import("std"); + +pub fn render(pool: *ecs.Pool) anyerror!void { + var renderer = pool.resources.renderer; + const camera = pool.resources.camera; + + const now = try std.time.Instant.now(); + const delta_time: f32 = @as(f32, @floatFromInt(now.since(renderer.previous_time))) / @as(f32, 1_000_000_000.0); + pool.resources.delta_time = delta_time; + renderer.previous_time = now; + + renderer.setCamera(camera); + + const transform_memory = renderer.graphics_pipeline.transform_buffer.mapped_memory; + + try renderer.begin(); + + renderer.setLightCount(2); + + for (renderer.transforms.items, 0..) |transform, i| { + transform_memory[i] = transform; + renderer.setTransform(@intCast(i)); + renderer.device.draw(renderer.mesh.index_count, renderer.current_frame, renderer.mesh); + } + + try renderer.end(); +} + +pub fn moveCamera(pool: *ecs.Pool) !void { + const input = pool.resources.input; + var camera = pool.resources.camera; + const mul = @as(@Vector(3, f32), @splat(camera.speed * pool.resources.delta_time)); + + if (input.isKeyDown(.w)) { + camera.position += camera.target * mul; + } + if (input.isKeyDown(.s)) { + camera.position -= camera.target * mul; + } + if (input.isKeyDown(.a)) { + camera.position -= math.normalize(math.cross(camera.target, camera.up)) * mul; + } + if (input.isKeyDown(.d)) { + camera.position += math.normalize(math.cross(camera.target, camera.up)) * mul; + } + if (input.isKeyDown(.space)) { + camera.position += camera.up * mul; + } + if (input.isKeyDown(.left_shift)) { + camera.position -= camera.up * mul; + } +}