diff --git a/assets/shaders/shader.vert b/assets/shaders/shader.vert index 90028ae..a35795b 100644 --- a/assets/shaders/shader.vert +++ b/assets/shaders/shader.vert @@ -15,6 +15,7 @@ layout (binding = 1) uniform ViewUniform { layout (binding = 4) uniform TransformUniform { mat4 translation; mat4 scale; + mat4 rotation; } transform; layout(location = 2) out vec3 Normal; @@ -22,7 +23,7 @@ layout(location = 3) out vec3 FragPos; layout(location = 4) out vec2 TexCoords; void main() { - mat4 transformation = transform.translation * transform.scale; + mat4 transformation = transform.translation * transform.scale * transform.rotation; vec4 out_vec = proj.proj * view.view * transformation * vec4(vertPos, 1.0); FragPos = vec3(vec4(vertPos, 1.0)); Normal = normal; diff --git a/src/ecs/entities.zig b/src/ecs/entities.zig index df28ae3..a848108 100644 --- a/src/ecs/entities.zig +++ b/src/ecs/entities.zig @@ -26,7 +26,7 @@ pub const Human = struct { // TODO(ernesto): Move pool to its own file pub const Pool = struct { humans: std.MultiArrayList(Human), - resources: Resources, + resources: *Resources, allocator: Allocator, system_groups: std.ArrayList(SystemGroup), sync_groups: std.ArrayList(SyncGroup), @@ -34,7 +34,7 @@ pub const Pool = struct { wait_group: std.Thread.WaitGroup, mutex: std.Thread.Mutex, - pub fn init(allocator: Allocator, resources: Resources) !@This() { + pub fn init(allocator: Allocator, resources: *Resources) !@This() { var pool = @This(){ .humans = .{}, .resources = resources, diff --git a/src/math.zig b/src/math.zig index 03f34c4..09c8e99 100644 --- a/src/math.zig +++ b/src/math.zig @@ -11,18 +11,21 @@ pub const Axis = struct { pub const z: [3]f32 = .{0.0, 0.0, 1.0}; }; -pub const Transform = struct { +pub const Transform = extern struct { translation: Matrix, scale: Matrix, + rotation_matrix: Matrix, rotation: Quaternion, pub fn init(position: [3]f32, scale: [3]f32, rotation: [3]f32) Transform { var translation = Matrix.identity(); translation.translate(position); + const quaternion = Quaternion.fromEulerAngles(rotation); return .{ .translation = translation, - .rotation = Quaternion.fromEulerAngles(rotation), + .rotation = quaternion, + .rotation_matrix = quaternion.matrix(), .scale = Matrix.scale(scale), }; } @@ -35,10 +38,11 @@ pub const Transform = struct { const delta = Quaternion.fromAxisAngle(axis, angle); self.rotation = self.rotation.mul(delta); self.rotation = self.rotation.normalize(); + self.rotation_matrix = self.rotation.matrix(); } }; -pub const Matrix = struct { +pub const Matrix = extern struct { rows: [4][4]f32, pub fn lookAt(eye: [3]f32, target: [3]f32, arbitrary_up: [3]f32) Matrix { @@ -134,7 +138,7 @@ pub const Matrix = struct { } }; -const Quaternion = struct { +pub const Quaternion = extern struct { w: f32, x: f32, y: f32, @@ -150,7 +154,7 @@ const Quaternion = struct { .w = cos(half_angle), .x = axis[0] * s, .y = axis[1] * s, - .z = axis[3] * s, + .z = axis[2] * s, }; } diff --git a/src/renderer/Renderer.zig b/src/renderer/Renderer.zig index 12ce2e1..68c5291 100644 --- a/src/renderer/Renderer.zig +++ b/src/renderer/Renderer.zig @@ -20,6 +20,7 @@ current_frame: u32, vertex_buffer: vk.Buffer, index_buffer: vk.Buffer, transform: math.Transform, +previous_time: std.time.Instant, pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Renderer { const instance: vk.Instance = .{ .handle = instance_handle }; @@ -68,7 +69,8 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand // TODO: Why are we storing the buffer and not the Mesh? .vertex_buffer = triangle.vertex_buffer, .index_buffer = triangle.index_buffer, - .transform = math.Transform.init(.{0.0, 0.0, 0.0}, .{1.0, 1.0, 1.0}, .{0.0, 0.0, 0.0}), + .transform = math.Transform.init(.{0.0, 0.0, 0.0}, .{1.0, 1.0, 1.0}, .{0.0, math.rad(45.0), 0.0}), + .previous_time = try std.time.Instant.now(), }; } @@ -87,6 +89,10 @@ 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); + renderer.previous_time = now; + const view_memory = renderer.graphics_pipeline.view_memory; @memcpy(view_memory[0..@sizeOf(math.Matrix)], std.mem.asBytes(&camera.getView())); @@ -96,8 +102,10 @@ pub fn render(pool: *ecs.Pool) anyerror!void { view_pos[1] = camera.position[1]; view_pos[2] = camera.position[2]; + renderer.transform.rotate(math.rad(10) * delta_time, .{0.0, 1.0, 0.0}); + const transform_memory = renderer.graphics_pipeline.transform_memory; - @memcpy(transform_memory[0..@sizeOf(math.Transform)], std.mem.asBytes(&renderer.transform)); + @memcpy(transform_memory[0..(@sizeOf(math.Transform)-@sizeOf(math.Quaternion))], std.mem.asBytes(&renderer.transform)[0..(@sizeOf(math.Transform)-@sizeOf(math.Quaternion))]); try renderer.device.waitFence(renderer.current_frame); const image = try renderer.swapchain.nextImage(renderer.device, renderer.current_frame); diff --git a/src/renderer/vulkan.zig b/src/renderer/vulkan.zig index 8836b13..1fc5985 100644 --- a/src/renderer/vulkan.zig +++ b/src/renderer/vulkan.zig @@ -548,7 +548,7 @@ pub fn GraphicsPipeline(comptime n: usize) type { c.vkUpdateDescriptorSets(device.handle, 1, &write_view_descriptor_set, 0, null); - const transform_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf(math.Transform)); + const transform_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf(math.Transform) - @sizeOf(math.Quaternion)); var transform_data: [*c]u8 = undefined; diff --git a/src/sideros.zig b/src/sideros.zig index e28de8c..94d1a93 100644 --- a/src/sideros.zig +++ b/src/sideros.zig @@ -12,6 +12,7 @@ var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); var pool: ecs.Pool = undefined; var renderer: Renderer = undefined; +var resources: ecs.Resources = undefined; fn init_mods() void { var global_runtime = mods.GlobalRuntime.init(allocator); @@ -43,14 +44,16 @@ fn init_mods() void { } export fn sideros_init(init: api.GameInit) callconv(.c) void { - pool = ecs.Pool.init(allocator, .{ + resources = .{ .camera = .{ .position = .{ 5.0, 5.0, 5.0 }, .target = .{ 0.0, 0.0, 0.0 }, }, .renderer = undefined, .input = .{ .key_pressed = .{false} ** @intFromEnum(ecs.Input.KeyCode.menu) }, - }) catch @panic("TODO: Gracefully handle error"); + }; + + 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}, true) catch @panic("TODO: Gracefuly handle error");