Better scrolling, cubemap, yakuza setup

This commit is contained in:
duck
2025-08-31 08:03:52 +05:00
parent 39db8ed3a1
commit d317694056
3 changed files with 132 additions and 59 deletions

BIN
data/cubemap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 B

View File

@@ -84,7 +84,7 @@ pub fn load(path: []const u8, alloc: std.mem.Allocator) Assets.LoadError!@This()
}, false); }, false);
} }
rows_uploaded += rows_to_upload; rows_uploaded += rows_to_upload;
if (rows_uploaded == height) { if (rows_uploaded == height and mip_level > 1) {
sdl.GenerateMipmapsForGPUTexture(command_buffer, texture); sdl.GenerateMipmapsForGPUTexture(command_buffer, texture);
} }
const fence = sdl.SubmitGPUCommandBufferAndAcquireFence(command_buffer) orelse return error.SdlError; const fence = sdl.SubmitGPUCommandBufferAndAcquireFence(command_buffer) orelse return error.SdlError;

View File

@@ -15,8 +15,10 @@ pub var objects: std.ArrayListUnmanaged(Object) = .{};
pub var hand_mesh: Graphics.Mesh = undefined; pub var hand_mesh: Graphics.Mesh = undefined;
pub var cube_mesh: Graphics.Mesh = undefined; pub var cube_mesh: Graphics.Mesh = undefined;
pub var table_mesh: Graphics.Mesh = undefined; pub var table_mesh: Graphics.Mesh = undefined;
pub var cubemap_mesh: Graphics.Mesh = undefined;
pub var table_texture: Assets.Texture = undefined; pub var table_texture: Assets.Texture = undefined;
pub var hand_texture: Assets.Texture = undefined; pub var hand_texture: Assets.Texture = undefined;
pub var cubemap_texture: Assets.Texture = undefined;
pub var camera_position: @Vector(2, f32) = @splat(0); pub var camera_position: @Vector(2, f32) = @splat(0);
pub var hand_transform: Graphics.Transform = .{}; pub var hand_transform: Graphics.Transform = .{};
@@ -92,16 +94,16 @@ const Object = struct {
const World = @This(); const World = @This();
pub fn initDebug() void { pub fn initDebug() void {
for (0..10) |i| { for (0..70) |i| {
World.objects.append(Game.alloc, .{ World.objects.append(Game.alloc, .{
.type = .card, .type = .card,
.width = 0.5, .width = 0.5,
.height = 0.5, .height = 0.5,
.mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane( .mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(
15.0 / 16.0, @as(f32, @floatFromInt(9 + i / 10)) / 16.0,
@as(f32, @floatFromInt(i)) / 16.0, @as(f32, @floatFromInt(0 + i % 10)) / 16.0,
16.0 / 16.0, @as(f32, @floatFromInt(10 + i / 10)) / 16.0,
@as(f32, @floatFromInt(i + 1)) / 16.0, @as(f32, @floatFromInt(1 + i % 10)) / 16.0,
0.5, 0.5,
0.5, 0.5,
))), ))),
@@ -109,11 +111,12 @@ pub fn initDebug() void {
.order = @intCast(i), .order = @intCast(i),
.id = @intCast(i), .id = @intCast(i),
.index = @intCast(i), .index = @intCast(i),
.parent = .{ .deck = 10 }, .parent = .{ .deck = if (i < 60) @as(Id, 70) else @as(Id, 71) },
}) catch err.oom(); }) catch err.oom();
World.object_map.put(Game.alloc, @intCast(i), i) catch err.oom(); World.object_map.put(Game.alloc, @intCast(i), i) catch err.oom();
} }
World.objects.append(Game.alloc, .{ World.objects.append(Game.alloc, .{
.target_transform = .{ .position = .{ -3, 0, 0 } },
.type = .deck, .type = .deck,
.width = 1, .width = 1,
.height = 1, .height = 1,
@@ -126,16 +129,37 @@ pub fn initDebug() void {
1, 1,
))), ))),
.texture = Assets.load(.texture, "data/yakuza.png"), .texture = Assets.load(.texture, "data/yakuza.png"),
.order = 10, .order = 70,
.id = 10, .id = 70,
.index = 10, .index = 70,
}) catch err.oom(); }) catch err.oom();
World.object_map.put(Game.alloc, 10, 10) catch err.oom(); World.object_map.put(Game.alloc, 60, 60) catch err.oom();
World.objects.append(Game.alloc, .{
.target_transform = .{ .position = .{ 3, 0, 0 } },
.type = .deck,
.width = 1,
.height = 1,
.mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(
0.0 / 8.0,
4.0 / 8.0,
1.0 / 8.0,
5.0 / 8.0,
1,
1,
))),
.texture = Assets.load(.texture, "data/yakuza.png"),
.order = 71,
.id = 71,
.index = 71,
}) catch err.oom();
World.object_map.put(Game.alloc, 71, 71) catch err.oom();
World.table_mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(0, 0, 0.5, 0.5, 8, 8))); World.table_mesh = Graphics.loadMesh(@ptrCast(&Graphics.generatePlane(0, 0, 0.5, 0.5, 8, 8)));
World.hand_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA)); World.hand_mesh = Graphics.loadMesh(@ptrCast(&PLANE_MESH_DATA));
World.cubemap_mesh = Graphics.loadMesh(@ptrCast(&CUBEMAP_MESH_DATA));
World.table_texture = Assets.load(.texture, "data/yakuza.png"); World.table_texture = Assets.load(.texture, "data/yakuza.png");
World.hand_texture = Assets.load(.texture, "data/hand.png"); World.hand_texture = Assets.load(.texture, "data/hand.png");
World.cubemap_texture = Assets.load(.texture, "data/cubemap.png");
World.camera_position = @splat(0); World.camera_position = @splat(0);
World.hand_transform = .{}; World.hand_transform = .{};
@@ -149,14 +173,16 @@ pub fn initDebug() void {
World.panning = false; World.panning = false;
World.dock_focused = false; World.dock_focused = false;
World.min_order = 0; World.min_order = 0;
World.max_order = 10; World.max_order = 71;
} }
pub fn deinit() void { pub fn deinit() void {
Graphics.unloadMesh(World.table_mesh); Graphics.unloadMesh(World.table_mesh);
Graphics.unloadMesh(World.hand_mesh); Graphics.unloadMesh(World.hand_mesh);
Graphics.unloadMesh(World.cubemap_mesh);
Assets.free(World.table_texture); Assets.free(World.table_texture);
Assets.free(World.hand_texture); Assets.free(World.hand_texture);
Assets.free(World.cubemap_texture);
for (World.objects.items) |*object| { for (World.objects.items) |*object| {
Assets.free(object.texture); Assets.free(object.texture);
Graphics.unloadMesh(object.mesh); Graphics.unloadMesh(object.mesh);
@@ -205,28 +231,7 @@ pub fn update(delta: f32) void {
pub fn updateControls() void { pub fn updateControls() void {
if (Game.keyboard.keys.is_pressed(sdl.SDL_SCANCODE_LSHIFT)) { if (Game.keyboard.keys.is_pressed(sdl.SDL_SCANCODE_LSHIFT)) {
if (Game.mouse.wheel > 0 and World.hand_objects > 0) { World.scroll(Game.mouse.wheel);
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 { } else {
World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8); World.zoom = std.math.clamp(World.zoom + Game.mouse.wheel, -4, 8);
} }
@@ -244,9 +249,74 @@ pub fn updateControls() void {
} }
} }
pub fn scroll(delta: i32) void {
if (World.getHover()) |hover_object| {
if (hover_object.type == .deck) {
if (delta > 0) {
var left_to_put = delta;
var i = World.objects.items.len - 1;
while (left_to_put > 0) {
const object = &World.objects.items[i];
if (object.parent != .hand) {
if (i == 0) break;
i -= 1;
continue;
}
World.bringToTop(object);
object.reparent(.{ .deck = hover_object.id });
if (i == 0) break;
i -= 1;
left_to_put -= 1;
}
}
if (delta < 0) {
var left_to_take = -delta;
var i = World.objects.items.len - 1;
while (left_to_take > 0) {
const object = &World.objects.items[i];
if (object.parent != .deck or object.parent.deck != hover_object.id) {
if (i == 0) break;
i -= 1;
continue;
}
World.bringToTop(object);
object.reparent(.hand);
if (i == 0) break;
i -= 1;
left_to_take -= 1;
}
}
return;
}
}
if (delta > 0 and World.hand_objects > 0) {
var left_to_scroll = @rem(delta, @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 (delta < 0 and World.hand_objects > 0) {
var left_to_scroll = @rem(-delta, @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;
}
}
}
pub fn tryPick() bool { pub fn tryPick() bool {
const hover_id = World.hover orelse return false; var object = World.getHover() orelse return false;
var object = World.getObject(hover_id) orelse return false;
switch (object.type) { switch (object.type) {
.card => {}, .card => {},
.deck => { .deck => {
@@ -281,12 +351,10 @@ pub fn tryRelease() bool {
object.target_transform.position = World.hand_transform.position; object.target_transform.position = World.hand_transform.position;
World.bringToTop(object); World.bringToTop(object);
if (!Game.keyboard.keys.is_pressed(sdl.SDL_SCANCODE_LSHIFT)) { if (!Game.keyboard.keys.is_pressed(sdl.SDL_SCANCODE_LSHIFT)) {
if (World.hover) |hover_id| { if (World.getHover()) |hover_object| {
if (World.getObject(hover_id)) |hover_object| { if (hover_object.type == .deck) {
if (hover_object.type == .deck) { object.reparent(.{ .deck = hover_object.id });
object.reparent(.{ .deck = hover_id }); return true;
return true;
}
} }
} }
} }
@@ -308,7 +376,7 @@ pub fn updateHover(object: *Object) void {
}, },
.none => { .none => {
if (!World.dock_focused and Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.drawingTransform(), object.width, object.height)) { if (!World.dock_focused and Graphics.camera.mouse_in_quad(.{ Game.mouse.x_norm, Game.mouse.y_norm }, object.drawingTransform(), object.width, object.height)) {
if (World.hover == null or World.getObject(World.hover.?).?.z < object.z) { if (World.hover == null or World.getHover().?.z < object.z) {
World.hover = object.id; World.hover = object.id;
} }
} }
@@ -426,6 +494,10 @@ pub fn draw() void {
), ),
); );
Graphics.drawMesh(World.cubemap_mesh, &World.cubemap_texture, .{
.scale = Graphics.camera.far,
.position = Graphics.camera.transform.position,
});
Graphics.clearDepth(); Graphics.clearDepth();
for (World.objects.items) |*object| { for (World.objects.items) |*object| {
if (object.parent == .dock) if (object.parent == .dock)
@@ -473,6 +545,13 @@ pub fn updateCamera(delta: f32) void {
)); ));
} }
fn getHover() ?*Object {
if (World.hover) |id| {
return World.getObject(id);
}
return null;
}
fn getObject(id: Id) ?*Object { fn getObject(id: Id) ?*Object {
const index = World.object_map.get(id) orelse return null; const index = World.object_map.get(id) orelse return null;
if (index >= World.objects.items.len) return null; if (index >= World.objects.items.len) return null;
@@ -488,26 +567,20 @@ fn bringToBottom(object: *Object) void {
object.order = World.min_order; object.order = World.min_order;
} }
var even: bool = false;
fn updateOrder() void { fn updateOrder() void {
var i: usize = undefined; std.sort.block(Object, World.objects.items, {}, objectOrderLessThan);
if (even) i = 0 else i = 1; World.object_map.clearRetainingCapacity();
even = !even; for (0.., World.objects.items) |i, *object| {
object.index = @intCast(i);
while (i + 1 < World.objects.items.len) : (i += 2) { World.object_map.putAssumeCapacityNoClobber(object.id, i);
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);
} }
} }
fn objectOrderLessThan(ctx: void, lhs: Object, rhs: Object) bool {
_ = ctx;
return lhs.order < rhs.order;
}
const T1 = 1.0 / 3.0; const T1 = 1.0 / 3.0;
const T2 = 2.0 / 3.0; const T2 = 2.0 / 3.0;
const CUBEMAP_MESH_DATA = [_]f32{ const CUBEMAP_MESH_DATA = [_]f32{