Keyboard and rotation!
This commit is contained in:
@@ -8,6 +8,7 @@ pub fn build(b: *std.Build) void {
|
||||
// of this build script using `b.option()`. All defined flags (including
|
||||
// target and optimize options) will be listed when running `zig build --help`
|
||||
// in this directory.
|
||||
const llvm = b.option(bool, "llvm", "Build with llvm");
|
||||
|
||||
const mod = b.addModule("puzzle", .{
|
||||
.root_source_file = b.path("src/root.zig"),
|
||||
@@ -16,6 +17,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "wl-main",
|
||||
.use_llvm = llvm,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
@@ -27,6 +29,7 @@ pub fn build(b: *std.Build) void {
|
||||
});
|
||||
exe.root_module.link_libc = true;
|
||||
exe.root_module.linkSystemLibrary("wayland-client", .{});
|
||||
exe.root_module.linkSystemLibrary("xkbcommon", .{});
|
||||
|
||||
exe.root_module.addIncludePath(b.path("src"));
|
||||
exe.root_module.addCSourceFiles(.{
|
||||
|
||||
@@ -4,9 +4,12 @@ mkShell {
|
||||
zig
|
||||
zls
|
||||
wayland-scanner
|
||||
gdb
|
||||
lldb
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
wayland
|
||||
libxkbcommon
|
||||
];
|
||||
}
|
||||
|
||||
+128
-6
@@ -1,4 +1,5 @@
|
||||
const std = @import("std");
|
||||
const linux = std.os.linux;
|
||||
|
||||
const puzzle = @import("puzzle");
|
||||
|
||||
@@ -7,6 +8,7 @@ const c = @cImport({
|
||||
@cInclude("wayland-client-core.h");
|
||||
@cInclude("xdg-shell.h");
|
||||
@cInclude("linux/input-event-codes.h");
|
||||
@cInclude("xkbcommon/xkbcommon.h");
|
||||
});
|
||||
|
||||
const WlPointerEventMask = packed struct(u16) {
|
||||
@@ -45,6 +47,10 @@ const WaylandState = struct {
|
||||
shared_memory: ?*c.wl_shm,
|
||||
xdg_wm_base: ?*c.xdg_wm_base,
|
||||
|
||||
xkb_context: ?*c.xkb_context,
|
||||
xkb_keymap: ?*c.xkb_keymap,
|
||||
xkb_state: ?*c.xkb_state,
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
resize: bool,
|
||||
@@ -88,8 +94,8 @@ fn createSharedMemoryPool(wl_state: WaylandState) !MemoryPool {
|
||||
|
||||
const fd: c_int = try createShmFile(pool_size);
|
||||
|
||||
const prot = std.os.linux.PROT.READ | std.os.linux.PROT.WRITE;
|
||||
const flags: std.os.linux.MAP = .{ .TYPE = .SHARED };
|
||||
const prot = linux.PROT.READ | std.os.linux.PROT.WRITE;
|
||||
const flags: linux.MAP = .{ .TYPE = .SHARED };
|
||||
const ret = try std.posix.mmap(null, pool_size, prot, flags, fd, 0);
|
||||
|
||||
const pool = c.wl_shm_create_pool(wl_state.shared_memory, fd, @intCast(pool_size));
|
||||
@@ -585,14 +591,124 @@ const wl_pointer_listener: c.struct_wl_pointer_listener = .{
|
||||
.frame = wlPointerHandleFrame,
|
||||
};
|
||||
|
||||
fn wlKeyboardHandleKeymap(
|
||||
data: ?*anyopaque,
|
||||
wl_keyboard: ?*c.struct_wl_keyboard,
|
||||
format: u32,
|
||||
fd: i32,
|
||||
size: u32,
|
||||
) callconv(.c) void {
|
||||
_ = wl_keyboard;
|
||||
std.debug.assert(format == c.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
|
||||
const wl_state: *WaylandState = @ptrCast(@alignCast(data));
|
||||
|
||||
const map_shm: []align(4096) const u8 = std.posix.mmap(null, size, linux.PROT.READ, .{ .TYPE = .SHARED }, fd, 0) catch {
|
||||
std.debug.panic("[Wayland] Keyboard keymap handler failed mmap", .{});
|
||||
};
|
||||
|
||||
const keymap: ?*c.struct_xkb_keymap = c.xkb_keymap_new_from_string(wl_state.xkb_context, @ptrCast(map_shm), c.XKB_KEYMAP_FORMAT_TEXT_V1, c.XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
|
||||
std.posix.munmap(map_shm);
|
||||
std.posix.close(fd);
|
||||
|
||||
const xkb_state: ?*c.struct_xkb_state = c.xkb_state_new(keymap);
|
||||
|
||||
// NOTE: Unmap existing ones
|
||||
if (wl_state.xkb_keymap != null) c.xkb_keymap_unref(wl_state.xkb_keymap);
|
||||
if (wl_state.xkb_state != null) c.xkb_state_unref(wl_state.xkb_state);
|
||||
|
||||
wl_state.xkb_keymap = keymap;
|
||||
wl_state.xkb_state = xkb_state;
|
||||
}
|
||||
|
||||
fn wlKeyboardHandleEnter(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, surface: ?*c.wl_surface, keys: [*c]c.wl_array) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = surface;
|
||||
_ = keys;
|
||||
}
|
||||
|
||||
fn wlKeyboardHandleLeave(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, surface: ?*c.wl_surface) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = surface;
|
||||
}
|
||||
|
||||
fn wlKeyboardHandleKey(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, time: u32, key: u32, state: u32) callconv(.c) void {
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = time;
|
||||
|
||||
const wl_state: *WaylandState = @ptrCast(@alignCast(data));
|
||||
var buf: [32:0]u8 = undefined;
|
||||
const keycode: u32 = key + 8;
|
||||
|
||||
const sym: c.xkb_keysym_t = c.xkb_state_key_get_one_sym(wl_state.xkb_state, keycode);
|
||||
_ = c.xkb_keysym_get_name(sym, &buf, buf.len);
|
||||
|
||||
const pressed = state == c.WL_KEYBOARD_KEY_STATE_PRESSED or state == c.WL_KEYBOARD_KEY_STATE_REPEATED;
|
||||
|
||||
std.debug.print("{s} {any}\n", .{buf, pressed});
|
||||
|
||||
switch (sym) {
|
||||
c.XKB_KEY_Escape => {
|
||||
wl_state.running = false;
|
||||
},
|
||||
c.XKB_KEY_space => {
|
||||
wl_state.app_input.key.space.down = pressed;
|
||||
},
|
||||
c.XKB_KEY_r => {
|
||||
wl_state.app_input.key.r.down = pressed;
|
||||
},
|
||||
c.XKB_KEY_q => {
|
||||
wl_state.app_input.key.q.down = pressed;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn wlKeyboardHandleModifiers(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, mods_depressed: u32, mods_latched: u32, mods_locked: u32, group: u32) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = mods_depressed;
|
||||
_ = mods_latched;
|
||||
_ = mods_locked;
|
||||
_ = group;
|
||||
}
|
||||
|
||||
fn wlKeyboardHandleRepeatInfo(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, rate: i32, delay: i32) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = rate;
|
||||
_ = delay;
|
||||
}
|
||||
|
||||
const wl_keyboard_listener: c.wl_keyboard_listener = .{
|
||||
.keymap = wlKeyboardHandleKeymap,
|
||||
.enter = wlKeyboardHandleEnter,
|
||||
.leave = wlKeyboardHandleLeave,
|
||||
.key = wlKeyboardHandleKey,
|
||||
.modifiers = wlKeyboardHandleModifiers,
|
||||
.repeat_info = wlKeyboardHandleRepeatInfo,
|
||||
};
|
||||
|
||||
fn wlSeatHandleCapabilities(data: ?*anyopaque, wl_seat: ?*c.struct_wl_seat, capabilities: u32) callconv(.c) void {
|
||||
const wl_state: *WaylandState = @ptrCast(@alignCast(data));
|
||||
|
||||
if (capabilities & c.WL_SEAT_CAPABILITY_POINTER == 1) {
|
||||
if (capabilities & c.WL_SEAT_CAPABILITY_POINTER == c.WL_SEAT_CAPABILITY_POINTER) {
|
||||
std.debug.print("[Wayland] wl_seat: got pointer capability\n", .{});
|
||||
const pointer: ?*c.struct_wl_pointer = c.wl_seat_get_pointer(wl_seat);
|
||||
_ = c.wl_pointer_add_listener(pointer, &wl_pointer_listener, wl_state);
|
||||
}
|
||||
|
||||
if (capabilities & c.WL_SEAT_CAPABILITY_KEYBOARD == c.WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
std.debug.print("[Wayland] wl_seat: got keyboard capability\n", .{});
|
||||
const keyboard = c.wl_seat_get_keyboard(wl_seat);
|
||||
_ = c.wl_keyboard_add_listener(keyboard, &wl_keyboard_listener, wl_state);
|
||||
}
|
||||
}
|
||||
|
||||
fn wlSeatHandleName(data: ?*anyopaque, wl_seat: ?*c.struct_wl_seat, name: [*c]const u8) callconv(.c) void {
|
||||
@@ -647,6 +763,9 @@ pub fn main() u8 {
|
||||
std.debug.print("[Wayland] Connection established.\n", .{});
|
||||
|
||||
var wl_state: WaylandState = undefined;
|
||||
wl_state.xkb_context = null;
|
||||
wl_state.xkb_state = null;
|
||||
wl_state.xkb_keymap = null;
|
||||
|
||||
const registry = c.wl_display_get_registry(display);
|
||||
if (registry == null) {
|
||||
@@ -656,6 +775,8 @@ pub fn main() u8 {
|
||||
|
||||
_ = c.wl_registry_add_listener(registry, ®istry_listener, &wl_state);
|
||||
|
||||
wl_state.xkb_context = c.xkb_context_new(c.XKB_CONTEXT_NO_FLAGS);
|
||||
|
||||
_ = c.wl_display_roundtrip(display);
|
||||
if (wl_state.compositor == null or wl_state.shared_memory == null or wl_state.seat == null) {
|
||||
std.debug.print("ERROR: Wayland compositor, seat, or shm not bound.\n", .{});
|
||||
@@ -835,13 +956,14 @@ pub fn main() u8 {
|
||||
|
||||
_ = c.wl_display_roundtrip(display);
|
||||
|
||||
std.posix.nanosleep(0, std.time.ns_per_ms * 32);
|
||||
// std.posix.nanosleep(0, std.time.ns_per_ms * 32);
|
||||
|
||||
const current = timer.lap();
|
||||
const current_ms = current / std.time.ns_per_ms;
|
||||
const sleep_time_ms: f64 = @as(f64, @floatFromInt(sleep_time)) / @as(f64, @floatFromInt(std.time.ns_per_ms));
|
||||
std.debug.print(
|
||||
"Render: {d}ms, Sleeping: {d}ms, Frame: {d}ms.\n",
|
||||
.{ render_time_ms, sleep_time_ms, current / std.time.ns_per_ms },
|
||||
"Render: {d:.3}ms, Sleeping: {d:.3}ms, Frame: {d}ms.\n",
|
||||
.{ render_time_ms, sleep_time_ms, current_ms },
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,16 @@ pub fn megaBytes(bytes: usize) usize {
|
||||
return kiloBytes(bytes) * 1024;
|
||||
}
|
||||
|
||||
const Key = struct {
|
||||
down: bool,
|
||||
};
|
||||
|
||||
const Keyboard = struct {
|
||||
r: Key,
|
||||
q: Key,
|
||||
space: Key,
|
||||
};
|
||||
|
||||
pub const AppInput = struct {
|
||||
mouse_present: bool = false,
|
||||
mouse_left_down: bool = false,
|
||||
@@ -15,6 +25,8 @@ pub const AppInput = struct {
|
||||
mouse_y: f64,
|
||||
|
||||
scroll_y: f64,
|
||||
|
||||
key: Keyboard,
|
||||
};
|
||||
|
||||
/// Buffer the platform creates and hands off to the app
|
||||
|
||||
+99
-47
@@ -30,8 +30,28 @@ const Camera = struct {
|
||||
};
|
||||
|
||||
const Brick = struct {
|
||||
rotating: bool,
|
||||
pos: V2,
|
||||
color: u32,
|
||||
tiles: [4][4]u32,
|
||||
|
||||
fn rotate(self: Brick) [4][4]u32 {
|
||||
var result = [4][4]u32{
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
for (0..self.tiles.len) |i| {
|
||||
const row = self.tiles[i];
|
||||
for (0..row.len) |j| {
|
||||
result[j][row.len - i - 1] = self.tiles[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
const State = struct {
|
||||
@@ -74,8 +94,8 @@ fn fillRect(
|
||||
if (buffer.width < end_x) end_x = buffer.width;
|
||||
if (buffer.height < end_y) end_y = buffer.height;
|
||||
|
||||
for (@intCast(start_y) .. @intCast(end_y)) |y| {
|
||||
for (@intCast(start_x) .. @intCast(end_x)) |x| {
|
||||
for (@intCast(start_y)..@intCast(end_y)) |y| {
|
||||
for (@intCast(start_x)..@intCast(end_x)) |x| {
|
||||
const idx: usize = y * @as(usize, @intCast(buffer.width)) + x;
|
||||
|
||||
pixels[idx] = color;
|
||||
@@ -96,91 +116,109 @@ fn fillSquare(
|
||||
pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBuffer, input: platform.AppInput) void {
|
||||
var state: *State = @ptrCast(@alignCast(memory.permanent_storage));
|
||||
|
||||
const mid = V2{ .x = @floatFromInt(@divTrunc(buffer.width, 2)), .y = @floatFromInt(@divTrunc(buffer.height, 2)), };
|
||||
const mid = V2{
|
||||
.x = @floatFromInt(@divTrunc(buffer.width, 2)),
|
||||
.y = @floatFromInt(@divTrunc(buffer.height, 2)),
|
||||
};
|
||||
if (!memory.initialized) {
|
||||
state.camera.offset = mid;
|
||||
|
||||
state.bricks[0] = Brick{
|
||||
.pos = V2{ .x = 0, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 0, .y = 50 },
|
||||
.color = 0xFFFF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{1, 1, 1, 1},
|
||||
.{1, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 1, 1, 1, 1 },
|
||||
.{ 1, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[1] = Brick{
|
||||
.pos = V2{ .x = 32, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 32, .y = 50 },
|
||||
.color = 0xFFEF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{2, 2, 2, 0},
|
||||
.{2, 2, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 2, 2, 2, 0 },
|
||||
.{ 2, 2, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[2] = Brick{
|
||||
.pos = V2{ .x = 64, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 64, .y = 50 },
|
||||
.color = 0xFFDF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{3, 3, 3, 0},
|
||||
.{0, 0, 3, 3},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 3, 3, 3, 0 },
|
||||
.{ 0, 0, 3, 3 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[3] = Brick{
|
||||
.pos = V2{ .x = 96, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 96, .y = 50 },
|
||||
.color = 0xFFCF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{4, 0, 0, 0},
|
||||
.{4, 4, 4, 0},
|
||||
.{0, 0, 4, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 4, 0, 0, 0 },
|
||||
.{ 4, 4, 4, 0 },
|
||||
.{ 0, 0, 4, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[4] = Brick{
|
||||
.pos = V2{ .x = 128, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 128, .y = 150 },
|
||||
.color = 0xFFBF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{5, 5, 5, 5},
|
||||
.{0, 5, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 5, 5, 5, 5 },
|
||||
.{ 0, 5, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[5] = Brick{
|
||||
.pos = V2{ .x = 160, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 160, .y = 250 },
|
||||
.color = 0xFFAF0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{6, 6, 6, 0},
|
||||
.{6, 0, 0, 0},
|
||||
.{6, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 6, 6, 6, 0 },
|
||||
.{ 6, 0, 0, 0 },
|
||||
.{ 6, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[6] = Brick{
|
||||
.pos = V2{ .x = 192, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 192, .y = 350 },
|
||||
.color = 0xFF9F0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{7, 7, 7, 0},
|
||||
.{7, 7, 7, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 7, 7, 7, 0 },
|
||||
.{ 7, 7, 7, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
state.bricks[7] = Brick{
|
||||
.pos = V2{ .x = 224, .y = 50},
|
||||
.rotating = false,
|
||||
.pos = V2{ .x = 224, .y = 450 },
|
||||
.color = 0xFF8F0000,
|
||||
.tiles = [4][4]u32{
|
||||
.{8, 8, 8, 0},
|
||||
.{8, 0, 8, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{0, 0, 0, 0},
|
||||
.{ 8, 8, 8, 0 },
|
||||
.{ 8, 0, 8, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
.{ 0, 0, 0, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
memory.initialized = true;
|
||||
}
|
||||
|
||||
@@ -194,6 +232,8 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
||||
|
||||
var mouse_on_brick = false;
|
||||
for (&state.bricks) |*brick| {
|
||||
brick.rotating = false;
|
||||
|
||||
for (brick.tiles, 0..) |row, i| {
|
||||
for (row, 0..) |tile, j| {
|
||||
if (tile > 0) {
|
||||
@@ -208,6 +248,14 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
||||
if (input.mouse_left_down) {
|
||||
const diff = mouse_pos.sub(state.mouse_pos);
|
||||
brick.pos = brick.pos.add(diff);
|
||||
|
||||
if (input.key.space.down and !brick.rotating) {
|
||||
// TODO: Rotate
|
||||
brick.rotating = true;
|
||||
const rotated = brick.rotate();
|
||||
brick.tiles = rotated;
|
||||
}
|
||||
|
||||
mouse_on_brick = true;
|
||||
}
|
||||
}
|
||||
@@ -221,7 +269,6 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
||||
state.camera.pos = state.camera.pos.add(diff);
|
||||
}
|
||||
|
||||
|
||||
state.mouse_pos = mouse_pos;
|
||||
|
||||
// Render
|
||||
@@ -255,7 +302,13 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
||||
.y = @floatFromInt(i * TILE_SIZE),
|
||||
};
|
||||
const camera_pos = brick.pos.add(pos).add(state.camera.pos);
|
||||
fillSquare(buffer, @intFromFloat(camera_pos.x), @intFromFloat(camera_pos.y), 30, 0xFFFF0000);
|
||||
fillSquare(
|
||||
buffer,
|
||||
@intFromFloat(camera_pos.x),
|
||||
@intFromFloat(camera_pos.y),
|
||||
30,
|
||||
if (brick.rotating) 0xFF00FF00 else brick.color ,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,4 +316,3 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
||||
|
||||
state.frame_count += 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user