diff --git a/src/world.zig b/src/world.zig index 35eecf6..6a79088 100644 --- a/src/world.zig +++ b/src/world.zig @@ -27,17 +27,25 @@ pub var max_order: Order = undefined; const Object = struct { transform: Graphics.Transform = .{}, + target_transform: Graphics.Transform = .{}, scale: Graphics.Transform.Scale, mesh: Graphics.Mesh, texture: Assets.Texture, order: Order, id: Id, + index: u32, parent: enum { none, hand, } = .none, hand_index: u32 = 0, - parent_infl: f32 = 0, + influence: f32 = 0, + + pub fn drawingTransform(self: @This()) Graphics.Transform { + var transform = self.transform; + transform.position += @as(@Vector(3, f32), @splat(self.influence)) * World.hand_transform.position; + return transform; + } }; const World = @This(); @@ -54,6 +62,7 @@ pub fn initDebug() void { .texture = Assets.load(.texture, "data/yakuza.png"), .order = @intCast(i), .id = @intCast(i), + .index = @intCast(i), }; World.object_map.put(Game.alloc, @intCast(i), i) catch err.oom(); } @@ -88,12 +97,13 @@ pub fn deinit() void { } pub fn update(delta: f32) void { + World.updateOrder(); const hand_target = Graphics.camera.raycast(.{ Game.mouse.x_norm, Game.mouse.y_norm }, .{ 0, 0, 1, 0 }); World.hand_transform.position = math.lerpTimeLn( World.hand_transform.position, - hand_target + @Vector(3, f32){ World.hand_transform.scale[0] * 0.5, -World.hand_transform.scale[1] * 0.5, 0.25 }, + hand_target + @Vector(3, f32){ World.hand_transform.scale[0] * 0.5, -World.hand_transform.scale[1] * 0.5, 0.2 }, delta, - -16, + -24, ); World.hover = null; World.hand_objects = 0; @@ -103,21 +113,53 @@ pub fn update(delta: f32) void { for (World.objects.items) |*object| { updateObject(object, delta); } - if (Game.mouse.buttons.is_just_pressed(sdl.BUTTON_LEFT)) { - World.panning = !World.tryPick(); - } - if (Game.mouse.buttons.is_just_pressed(sdl.BUTTON_RIGHT)) { - _ = World.tryRelease(); - } + World.updateControls(); World.updateCamera(delta); } +pub fn updateControls() void { + if (Game.keyboard.keys.is_pressed(sdl.SDL_SCANCODE_LSHIFT)) { + if (Game.mouse.buttons.is_just_pressed(sdl.BUTTON_LEFT)) World.panning = true; + if (Game.mouse.wheel > 0 and World.hand_objects > 0) { + var left_to_scroll = @rem(Game.mouse.wheel, @as(i32, @intCast(World.hand_objects))); + var i = World.objects.items.len - 1; + while (left_to_scroll > 0) : (i -= 1) { + const object = &World.objects.items[i]; + if (object.parent != .hand) continue; + + World.bringToBottom(object); + left_to_scroll -= 1; + } + } + if (Game.mouse.wheel < 0 and World.hand_objects > 0) { + var left_to_scroll = @rem(-Game.mouse.wheel, @as(i32, @intCast(World.hand_objects))); + var i: usize = 0; + while (left_to_scroll > 0) : (i += 1) { + const object = &World.objects.items[i]; + if (object.parent != .hand) continue; + + World.bringToTop(object); + left_to_scroll -= 1; + } + } + } else { + if (Game.mouse.buttons.is_just_pressed(sdl.BUTTON_LEFT)) { + World.panning = !World.tryPick(); + } + if (Game.mouse.buttons.is_just_pressed(sdl.BUTTON_RIGHT)) { + _ = World.tryRelease(); + } + World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8); + } +} + pub fn tryPick() bool { - if (World.hover) |hover_id| { - World.panning = false; - World.getObject(hover_id).?.parent = .hand; - return true; - } else return false; + const hover_id = World.hover orelse return false; + const object = World.getObject(hover_id) orelse return false; + World.panning = false; + object.parent = .hand; + World.bringToTop(object); + return true; } pub fn tryRelease() bool { var last: ?*Object = null; @@ -126,6 +168,13 @@ pub fn tryRelease() bool { last = object; } if (last) |object| { + object.transform = object.drawingTransform(); + object.target_transform.position = World.hand_transform.position + @Vector(3, f32){ + -World.hand_transform.scale[0] * 0.5, + World.hand_transform.scale[1] * 0.5, + 0, + }; + object.influence = 0; object.parent = .none; return true; } @@ -138,8 +187,8 @@ pub fn updateHover(object: *Object) void { World.hand_objects += 1; return; } - if (Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.transform)) { - if (World.hover == null or World.getObject(World.hover.?).?.transform.position[2] < object.transform.position[2]) { + if (Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.target_transform)) { + if (World.hover == null or World.getObject(World.hover.?).?.index < object.index) { World.hover = object.id; } } @@ -148,23 +197,13 @@ pub fn updateHover(object: *Object) void { pub fn updateObject(object: *Object, delta: f32) void { switch (object.parent) { .none => { - object.transform.position[2] = math.lerpTimeLn( - object.transform.position[2], - if (World.hover == object.id) @as(f32, 0.125) else @as(f32, 0.0625), - delta, - -8, - ); - object.transform.scale = math.lerpTimeLn( - object.transform.scale, - if (World.hover == object.id) object.scale * @as(@Vector(3, f32), @splat(1.25)) else object.scale, - delta, - -4, - ); + object.target_transform.position[2] = if (World.hover == object.id) @as(f32, 0.1) else @as(f32, 0.001) * @as(f32, @floatFromInt(object.index + 1)); + object.target_transform.scale = object.scale; }, .hand => { - var target_position = World.hand_transform.position; + var target_position = @as(@Vector(3, f32), @splat(0)); var target_scale = object.scale; - target_position[2] *= 0.5; + target_position[2] -= 0.001; const hand_order = hand_objects - object.hand_index - 1; switch (hand_order) { 0 => { @@ -172,38 +211,47 @@ pub fn updateObject(object: *Object, delta: f32) void { target_position[1] += World.hand_transform.scale[1] * 0.5; }, else => |i| { - target_position[0] += World.hand_transform.scale[0] * if ((i - 1) & 1 == 0) @as(f32, 0.5) else @as(f32, 1); + target_position[0] += World.hand_transform.scale[0] * if (i & 2 == 0) @as(f32, 0.5) else @as(f32, 1); target_position[1] += World.hand_transform.scale[1] * if ((i - 1) & 2 == 0) @as(f32, 0.25) else @as(f32, -0.25); - target_position[2] -= @as(f32, @floatFromInt((hand_order - 1) / 4)) * 0.01; + target_position[2] -= @as(f32, @floatFromInt((hand_order - 1) / 4)) * 0.001; target_scale = math.limit(target_scale, World.hand_transform.scale[1] * 0.5); }, } - object.transform.position = math.lerpTimeLn( - object.transform.position, - target_position, - delta, - -16, - ); - object.transform.scale = math.lerpTimeLn( - object.transform.scale, - target_scale, - delta, - -4, - ); + object.target_transform.position = target_position; + object.target_transform.scale = target_scale; }, } + if (object.parent == .hand) { + object.influence = math.lerpTimeLn( + object.influence, + 1.0, + delta, + -8, + ); + } + object.transform.position = math.lerpTimeLn( + object.transform.position, + object.target_transform.position, + delta, + -8, + ); + object.transform.scale = math.lerpTimeLn( + object.transform.scale, + object.target_transform.scale, + delta, + -8, + ); } pub fn draw() void { Graphics.drawMesh(World.table_mesh, World.texture, Graphics.Transform.matrix(.{ .scale = @splat(8) })); for (World.objects.items) |*object| { - Graphics.drawMesh(object.mesh, object.texture, object.transform.matrix()); + Graphics.drawMesh(object.mesh, object.texture, object.drawingTransform().matrix()); } Graphics.drawMesh(World.plane_mesh, World.hand_texture, World.hand_transform.matrix()); } pub fn updateCamera(delta: f32) void { - World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8); const zoom_factor = std.math.exp(@as(f32, @floatFromInt(zoom)) * @log(2.0) * -0.5); if (Game.mouse.buttons.is_pressed(sdl.BUTTON_LEFT)) { @@ -258,48 +306,72 @@ fn bringToBottom(object: *Object) void { object.order = World.min_order; } -const CUBE_MESH_DATA = [_]f32{ - -0.5, 0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, -0.5, 0.0, 0.0, - -0.5, -0.5, -0.5, 0.0, 0.0, - 0.5, -0.5, -0.5, 0.0, 0.0, - -0.5, -0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, -0.5, 0.0, 0.0, +var even: bool = false; +fn updateOrder() void { + var i: usize = undefined; + if (even) i = 0 else i = 1; + even = !even; - 0.5, 0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, 0.5, 0.0, 0.0, - 0.5, -0.5, -0.5, 0.0, 0.0, - 0.5, -0.5, 0.5, 0.0, 0.0, - 0.5, -0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, 0.5, 0.0, 0.0, + while (i + 1 < World.objects.items.len) : (i += 2) { + const left = &World.objects.items[i]; + const right = &World.objects.items[i + 1]; + + if (left.order <= right.order) continue; + std.mem.swap(u32, &left.index, &right.index); + + World.object_map.putAssumeCapacity(left.id, left.index); + World.object_map.putAssumeCapacity(right.id, right.index); + + std.mem.swap(Object, left, right); + } +} + +const CUBEMAP_MESH_DATA = CUBE_MESH_DATA; + +const T1 = 1.0 / 3.0; +const T2 = 2.0 / 3.0; +const CUBE_MESH_DATA = [_]f32{ + -0.5, 0.5, -0.5, T2, 0, + -0.5, -0.5, -0.5, T2, 0.5, + 0.5, 0.5, -0.5, 1, 0, + 0.5, -0.5, -0.5, 1, 0.5, + 0.5, 0.5, -0.5, 1, 0, + -0.5, -0.5, -0.5, T2, 0.5, + + 0.5, 0.5, -0.5, 0, 1, + 0.5, -0.5, -0.5, T1, 1, + 0.5, 0.5, 0.5, 0, 0.5, + 0.5, -0.5, 0.5, T1, 0.5, + 0.5, 0.5, 0.5, 0, 0.5, + 0.5, -0.5, -0.5, T1, 1, 0.5, 0.5, 0.5, 1.0, 0.0, - -0.5, 0.5, 0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, -0.5, 0.5, 0.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 1.0, - -0.5, 0.5, 0.5, 0.0, 0.0, - -0.5, 0.5, 0.5, 0.0, 0.0, - -0.5, 0.5, -0.5, 0.0, 0.0, - -0.5, -0.5, 0.5, 0.0, 0.0, - -0.5, -0.5, -0.5, 0.0, 0.0, - -0.5, -0.5, 0.5, 0.0, 0.0, - -0.5, 0.5, -0.5, 0.0, 0.0, + -0.5, 0.5, 0.5, T1, 0, + -0.5, -0.5, 0.5, 0, 0, + -0.5, 0.5, -0.5, T1, 0.5, + -0.5, -0.5, -0.5, 0, 0.5, + -0.5, 0.5, -0.5, T1, 0.5, + -0.5, -0.5, 0.5, 0, 0, - -0.5, 0.5, 0.5, 0.0, 0.0, - 0.5, 0.5, 0.5, 0.0, 0.0, - -0.5, 0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, -0.5, 0.0, 0.0, - -0.5, 0.5, -0.5, 0.0, 0.0, - 0.5, 0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, 0.5, T1, 0.5, + -0.5, 0.5, -0.5, T1, 1, + 0.5, 0.5, 0.5, T2, 0.5, + 0.5, 0.5, -0.5, T2, 1, + 0.5, 0.5, 0.5, T2, 0.5, + -0.5, 0.5, -0.5, T1, 1, - -0.5, -0.5, -0.5, 0.0, 0.0, - 0.5, -0.5, -0.5, 0.0, 0.0, - -0.5, -0.5, 0.5, 0.0, 0.0, - 0.5, -0.5, 0.5, 0.0, 0.0, - -0.5, -0.5, 0.5, 0.0, 0.0, - 0.5, -0.5, -0.5, 0.0, 0.0, + -0.5, -0.5, -0.5, T2, 0.5, + -0.5, -0.5, 0.5, T2, 0, + 0.5, -0.5, -0.5, T1, 0.5, + 0.5, -0.5, 0.5, T1, 0, + 0.5, -0.5, -0.5, T1, 0.5, + -0.5, -0.5, 0.5, T2, 0, }; const PLANE_MESH_DATA = [_]f32{ -0.5, -0.5, 0, 0.0, 1.0,