GUI image implementation, player hotbar

This commit is contained in:
2026-09-20 22:31:46 +02:00
parent ff72311979
commit c3fa7115c8
6 changed files with 423 additions and 136 deletions

View File

@@ -2,6 +2,7 @@ const Player = @This();
const std = @import("std");
const c = @import("const.zig");
const ctx = @import("AppContext.zig");
const glfw = @import("zglfw");
const math = @import("math.zig");
const vm = @import("vecmath");
@@ -231,7 +232,6 @@ pub fn onKeyDown(self: *Player, key: glfw.Key) void {
const key_code = @intFromEnum(key);
if (key_code >= @intFromEnum(glfw.Key.one) and key_code <= @intFromEnum(glfw.Key.nine)) {
self.block_index = @intCast(key_code - @intFromEnum(glfw.Key.one));
std.log.info("Picked block {s}", .{blocks[self.block_index]});
}
}
@@ -281,7 +281,11 @@ pub fn onMouseDown(self: *Player, button: glfw.MouseButton, game: *Game) void {
}
}
pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
pub fn update(self: *Player, dt: f32, game: *Game) void {
const swapchain = ctx.swapchain;
const materials = ctx.materials;
const gui = ctx.gui;
defer self.resetAllButtons();
const raycast_origin_sv = self.position_sv
@@ -294,7 +298,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
))
.round()
.asInt();
self.maybe_raycast_hit = chunks.raycast(raycast_origin_sv, raycast_ray_sv);
self.maybe_raycast_hit = game.chunks.raycast(raycast_origin_sv, raycast_ray_sv);
// --- GATHER INPUTS -------------------------------------------------------
@@ -343,7 +347,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
var max_sv = position_sv.add(.init(collision_half_width_sv, collision_half_width_sv, collision_height_sv));
if (vertical_displacement_sv > 0) {
if (chunks.sweepCastUp(min_sv, max_sv, vertical_displacement_sv)) |hit| {
if (game.chunks.sweepCastUp(min_sv, max_sv, vertical_displacement_sv)) |hit| {
vertical_displacement_sv -= hit.projected_distance_sv;
}
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
@@ -353,7 +357,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
var i: usize = 0;
while (i < 2) : (i += 1) {
if (chunks.sweepCastHorizontal(min_sv, max_sv, horizontal_displacement_sv)) |hit| {
if (game.chunks.sweepCastHorizontal(min_sv, max_sv, horizontal_displacement_sv)) |hit| {
const adjustment = math.mulFrac2(hit.normal_frac.dropZ(), hit.projected_distance_sv);
horizontal_displacement_sv = .add(
horizontal_displacement_sv,
@@ -368,7 +372,7 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
if (vertical_displacement_sv < 0.0) {
min_sv = .add(min_sv, horizontal_displacement_sv.withZ(0));
max_sv = .add(max_sv, horizontal_displacement_sv.withZ(0));
if (chunks.sweepCastDown(min_sv, max_sv, -vertical_displacement_sv)) |hit| {
if (game.chunks.sweepCastDown(min_sv, max_sv, -vertical_displacement_sv)) |hit| {
vertical_displacement_sv += hit.projected_distance_sv;
}
position_sv = .add(position_sv, .init(0, 0, vertical_displacement_sv));
@@ -377,6 +381,131 @@ pub fn update(self: *Player, dt: f32, chunks: *const Chunks) void {
self.position_sv = position_sv;
},
}
// --- GUI -----------------------------------------------------------------
const extent = swapchain.extent;
const framebuffer_size = vm.Vector2.init(
@floatFromInt(extent.width),
@floatFromInt(extent.height),
);
// --- CROSSHAIR ---
{
const crosshair_half_extent_px = 8;
const crosshair_half_width_px = 1;
gui.pushBox(.{
.background_color = .init(1, 1, 1, 0.5),
.border_color = .init(0, 0, 0, 1),
.position_sspx = framebuffer_size.mulScalar(0.5).add(.init(-crosshair_half_extent_px, -crosshair_half_width_px)),
.size_px = .init(2.0 * crosshair_half_extent_px, 2.0 * crosshair_half_width_px),
.border_width_px = 0,
.border_radius_px = 0,
});
gui.pushBox(.{
.background_color = .init(1, 1, 1, 0.5),
.border_color = .init(0, 0, 0, 1),
.position_sspx = framebuffer_size.mulScalar(0.5).add(.init(-crosshair_half_width_px, -crosshair_half_extent_px)),
.size_px = .init(2.0 * crosshair_half_width_px, 2.0 * crosshair_half_extent_px),
.border_width_px = 0,
.border_radius_px = 0,
});
}
// --- COORDINATES ---
{
const margin: f16 = 8;
const font_size: f32 = 16;
gui.pushBox(.{
.background_color = .init(0, 0, 0, 0.75),
.border_color = .init(0, 0, 0, 1),
.position_sspx = .init(0, 0),
.size_px = .init(157, 4 * margin + 3 * font_size),
.border_width_px = 0,
.border_radius_px = 0,
});
gui.printLine("X {X:0>8}", .{@as(u32, @bitCast(self.position_sv.x))}, .{
.position_sspx = .init(margin, margin + font_size),
.font_id = @enumFromInt(0),
.cap_height_px = font_size,
.color = .init(1, 1, 1, 1),
});
gui.printLine("Y {X:0>8}", .{@as(u32, @bitCast(self.position_sv.y))}, .{
.position_sspx = .init(margin, 2 * (margin + font_size)),
.font_id = @enumFromInt(0),
.cap_height_px = font_size,
.color = .init(1, 1, 1, 1),
});
gui.printLine("Z {X:0>8}", .{@as(u32, @bitCast(self.position_sv.z))}, .{
.position_sspx = .init(margin, 3 * (margin + font_size)),
.font_id = @enumFromInt(0),
.cap_height_px = font_size,
.color = .init(1, 1, 1, 1),
});
}
// --- HOTBAR ---
{
const block_selection_outline_width_px: f32 = 4;
const block_image_size_px: f32 = 48;
const block_image_gap_px: f32 = 8;
const block_image_margin_px: f32 = 8;
const hotbar_width_px: f32 = @as(f32, @floatFromInt(blocks.len)) * block_image_size_px + @as(f32, @floatFromInt(blocks.len - 1)) * block_image_gap_px;
const hotbar_left_px: f32 = 0.5 * (framebuffer_size.x - hotbar_width_px);
const hotbar_top_px: f32 = framebuffer_size.y - block_image_margin_px - block_image_size_px;
gui.pushBox(.{
.background_color = .init(0, 0, 0, 0.75),
.border_color = .init(0, 0, 0, 1),
.position_sspx = .init(hotbar_left_px - block_image_margin_px, hotbar_top_px - block_image_margin_px),
.size_px = .init(hotbar_width_px + 2 * block_image_margin_px, block_image_size_px + 2 * block_image_margin_px),
.border_width_px = 4,
.border_radius_px = 0,
});
var cx: f32 = hotbar_left_px;
for (blocks, 0..) |filename, i| {
defer cx += block_image_size_px + block_image_gap_px;
const id = game.blocks.getOrLoad(filename) catch |err| {
std.log.err("Error while rendering hotbar block {s}: {}", .{ filename, err });
continue;
};
const definition = &game.blocks.array.items[@intFromEnum(id)];
const material_id = definition.walls.positive_z.material;
const material = &materials.array.items[@intFromEnum(material_id)];
if (i == self.block_index) {
gui.pushBox(.{
.background_color = .initScalar(0),
.border_color = .init(1, 1, 1, 1),
.position_sspx = vm.Vector2.init(cx, hotbar_top_px).sub(.initScalar(block_selection_outline_width_px)),
.size_px = .initScalar(block_image_size_px + 2 * block_selection_outline_width_px),
.border_width_px = block_selection_outline_width_px,
.border_radius_px = block_selection_outline_width_px,
});
}
const texture_id = material.base_color_texture;
gui.pushImage(.{
.position_sspx = .init(cx, hotbar_top_px),
.size_px = .initScalar(block_image_size_px),
.texture_id = texture_id,
});
}
}
}
fn resetAllButtons(self: *Player) void {