Implemented keyboard input
This commit is contained in:
parent
4eed1778a6
commit
b6d50a781d
11 changed files with 179 additions and 59 deletions
|
|
@ -77,9 +77,11 @@ pub fn build(b: *std.Build) void {
|
|||
if (wayland) {
|
||||
exe.root_module.addIncludePath(b.path("ext"));
|
||||
exe.linkSystemLibrary("wayland-client");
|
||||
exe.linkSystemLibrary("xkbcommon");
|
||||
exe.root_module.addCSourceFile(.{ .file = b.path("ext/xdg-shell.c") });
|
||||
} else {
|
||||
exe.linkSystemLibrary("xcb");
|
||||
exe.linkSystemLibrary("xcb-keysyms");
|
||||
exe.linkSystemLibrary("xcb-icccm");
|
||||
}
|
||||
b.installArtifact(exe);
|
||||
|
|
|
|||
|
|
@ -22,32 +22,32 @@ pub const KeyCode = enum(u32) {
|
|||
@"9" = 57,
|
||||
semicolon = 59,
|
||||
equal = 61,
|
||||
a = 65,
|
||||
b = 66,
|
||||
c = 67,
|
||||
d = 68,
|
||||
e = 69,
|
||||
f = 70,
|
||||
g = 71,
|
||||
h = 72,
|
||||
i = 73,
|
||||
j = 74,
|
||||
k = 75,
|
||||
l = 76,
|
||||
m = 77,
|
||||
n = 78,
|
||||
o = 79,
|
||||
p = 80,
|
||||
q = 81,
|
||||
r = 82,
|
||||
s = 83,
|
||||
t = 84,
|
||||
u = 85,
|
||||
v = 86,
|
||||
w = 87,
|
||||
x = 88,
|
||||
y = 89,
|
||||
z = 90,
|
||||
a = 97,
|
||||
b = 98,
|
||||
c = 99,
|
||||
d = 100,
|
||||
e = 101,
|
||||
f = 102,
|
||||
g = 103,
|
||||
h = 104,
|
||||
i = 105,
|
||||
j = 106,
|
||||
k = 107,
|
||||
l = 108,
|
||||
m = 109,
|
||||
n = 110,
|
||||
o = 111,
|
||||
p = 112,
|
||||
q = 113,
|
||||
r = 114,
|
||||
s = 115,
|
||||
t = 116,
|
||||
u = 117,
|
||||
v = 118,
|
||||
w = 119,
|
||||
x = 120,
|
||||
y = 121,
|
||||
z = 122,
|
||||
left_bracket = 91,
|
||||
backslash = 92,
|
||||
right_bracket = 93,
|
||||
|
|
@ -124,6 +124,7 @@ pub const KeyCode = enum(u32) {
|
|||
right_alt = 346,
|
||||
right_super = 347,
|
||||
menu = 348,
|
||||
_,
|
||||
};
|
||||
|
||||
key_pressed: [@intFromEnum(KeyCode.menu)]bool = .{false} ** @intFromEnum(Input.KeyCode.menu),
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ pub const SystemGroup = []const System;
|
|||
pub const SyncGroup = []const System;
|
||||
|
||||
pub const Resources = struct {
|
||||
camera: Camera,
|
||||
camera: *Camera,
|
||||
renderer: *Renderer,
|
||||
input: Input,
|
||||
delta_time: f64 = 0.0,
|
||||
input: *Input,
|
||||
delta_time: f32 = 0.0,
|
||||
};
|
||||
|
||||
pub const Human = struct {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ pub const Matrix = extern struct {
|
|||
|
||||
pub fn lookAt(eye: [3]f32, target: [3]f32, arbitrary_up: [3]f32) Matrix {
|
||||
const t: @Vector(3, f32) = target;
|
||||
var e: @Vector(3, f32) = eye;
|
||||
e = -e;
|
||||
const e: @Vector(3, f32) = eye;
|
||||
const u: @Vector(3, f32) = arbitrary_up;
|
||||
const forward = normalize(t - e);
|
||||
const right = normalize(cross(forward, u));
|
||||
|
|
|
|||
|
|
@ -12,32 +12,39 @@ pub const Uniform = struct {
|
|||
};
|
||||
|
||||
position: @Vector(3, f32),
|
||||
target: @Vector(3, f32) = .{ 0.0, 0.0, 0.0 },
|
||||
front: @Vector(3, f32) = .{ 0.0, 0.0, 1.0 },
|
||||
target: @Vector(3, f32) = .{ 0.0, 0.0, -1.0 },
|
||||
up: @Vector(3, f32) = .{ 0.0, 1.0, 0.0 },
|
||||
speed: f32 = 2.5,
|
||||
speed: f32 = 5,
|
||||
|
||||
pub fn getProjection(width: usize, height: usize) math.Matrix {
|
||||
return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 100.0);
|
||||
}
|
||||
|
||||
pub fn getView(self: Camera) math.Matrix {
|
||||
return math.Matrix.lookAt(self.position, self.target, self.up);
|
||||
pub fn getView(self: *Camera) math.Matrix {
|
||||
return math.Matrix.lookAt(self.position, self.position + self.target, self.up);
|
||||
}
|
||||
|
||||
pub fn moveCamera(pool: *ecs.Pool) void {
|
||||
pub fn moveCamera(pool: *ecs.Pool) !void {
|
||||
const input = pool.resources.input;
|
||||
const camera = pool.resources.camera;
|
||||
var camera = pool.resources.camera;
|
||||
const mul = @as(@Vector(3, f32), @splat(camera.speed * pool.resources.delta_time));
|
||||
|
||||
if (input.isKeyDown(.w)) {
|
||||
camera.position += (camera.front * (camera.speed * pool.resources.delta_time));
|
||||
camera.position += camera.target * mul;
|
||||
}
|
||||
if (input.isKeyDown(.s)) {
|
||||
camera.position -= (camera.front * (camera.speed * pool.resources.delta_time));
|
||||
camera.position -= camera.target * mul;
|
||||
}
|
||||
if (input.isKeyDown(.a)) {
|
||||
camera.position -= math.normalize(math.cross(camera.front, camera.up)) * (camera.speed * pool.resources.delta_time);
|
||||
camera.position -= math.normalize(math.cross(camera.target, camera.up)) * mul;
|
||||
}
|
||||
if (input.isKeyDown(.d)) {
|
||||
camera.position += math.normalize(math.cross(camera.front, camera.up)) * (camera.speed * pool.resources.delta_time);
|
||||
camera.position += math.normalize(math.cross(camera.target, camera.up)) * mul;
|
||||
}
|
||||
if (input.isKeyDown(.space)) {
|
||||
camera.position += camera.up * mul;
|
||||
}
|
||||
if (input.isKeyDown(.left_shift)) {
|
||||
camera.position -= camera.up * mul;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ pub fn create_device(self: *PhysicalDevice, surface: vk.Surface, allocator: Allo
|
|||
samples = 2;
|
||||
}
|
||||
|
||||
|
||||
std.debug.print("Using {} samples for MSAA\n", .{samples});
|
||||
|
||||
return .{
|
||||
|
|
|
|||
|
|
@ -109,10 +109,12 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
|
|||
|
||||
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);
|
||||
pool.resources.delta_time = delta_time;
|
||||
renderer.previous_time = now;
|
||||
|
||||
const view = camera.getView();
|
||||
const view_memory = renderer.graphics_pipeline.view_memory;
|
||||
@memcpy(view_memory[0..@sizeOf(math.Matrix)], std.mem.asBytes(&camera.getView()));
|
||||
@memcpy(view_memory[0..@sizeOf(math.Matrix)], std.mem.asBytes(&view));
|
||||
|
||||
const view_pos_memory = renderer.graphics_pipeline.view_pos_memory;
|
||||
const view_pos: [*]f32 = @alignCast(@ptrCast(view_pos_memory));
|
||||
|
|
@ -120,8 +122,6 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
|
|||
view_pos[1] = camera.position[1];
|
||||
view_pos[2] = camera.position[2];
|
||||
|
||||
_ = delta_time;
|
||||
|
||||
const transform_memory = renderer.graphics_pipeline.transform_buffer.mapped_memory;
|
||||
|
||||
try renderer.device.waitFence(renderer.current_frame);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|||
const allocator = gpa.allocator();
|
||||
var pool: ecs.Pool = undefined;
|
||||
var renderer: Renderer = undefined;
|
||||
var camera: rendering.Camera = .{
|
||||
.position = .{ 0.0, 0.0, 5.0 },
|
||||
};
|
||||
var input: ecs.Input = .{ .key_pressed = .{false} ** @intFromEnum(ecs.Input.KeyCode.menu) };
|
||||
var resources: ecs.Resources = undefined;
|
||||
|
||||
fn init_mods() void {
|
||||
|
|
@ -47,18 +51,15 @@ fn init_mods() void {
|
|||
|
||||
export fn sideros_init(init: api.GameInit) callconv(.c) void {
|
||||
resources = .{
|
||||
.camera = .{
|
||||
.position = .{ 0.0, 5.0, -5.0 },
|
||||
.target = .{ 0.0, 0.0, 0.0 },
|
||||
},
|
||||
.camera = &camera,
|
||||
.renderer = undefined,
|
||||
.input = .{ .key_pressed = .{false} ** @intFromEnum(ecs.Input.KeyCode.menu) },
|
||||
.input = &input,
|
||||
};
|
||||
|
||||
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");
|
||||
pool.addSystemGroup(&[_]ecs.System{Renderer.render, rendering.Camera.moveCamera}, true) catch @panic("TODO: Gracefuly handle error");
|
||||
pool.resources.renderer = &renderer;
|
||||
pool.tick();
|
||||
init_mods();
|
||||
|
|
@ -74,3 +75,13 @@ export fn sideros_cleanup() callconv(.c) void {
|
|||
pool.deinit();
|
||||
if (gpa.deinit() != .ok) @panic("Memory leaked");
|
||||
}
|
||||
|
||||
export fn sideros_key_callback(key: u32, release: bool) callconv(.c) void {
|
||||
if (key <= @intFromEnum(ecs.Input.KeyCode.menu) and key >= @intFromEnum(ecs.Input.KeyCode.space)) {
|
||||
if (release) {
|
||||
input.key_pressed[key] = false;
|
||||
} else {
|
||||
input.key_pressed[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
#include "vulkan/vulkan.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
VkInstance instance;
|
||||
VkSurfaceKHR surface;
|
||||
VkInstance instance;
|
||||
VkSurfaceKHR surface;
|
||||
} GameInit;
|
||||
|
||||
typedef struct {
|
||||
double dt;
|
||||
double dt;
|
||||
} GameUpdate;
|
||||
|
||||
void sideros_init(GameInit init);
|
||||
void sideros_update(GameUpdate state);
|
||||
void sideros_key_callback(unsigned int key, bool release);
|
||||
void sideros_cleanup(void);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
|||
const c = @cImport({
|
||||
@cInclude("wayland-client.h");
|
||||
@cInclude("xdg-shell.h");
|
||||
@cInclude("xkbcommon/xkbcommon.h");
|
||||
@cInclude("vulkan/vulkan.h");
|
||||
@cInclude("vulkan/vulkan_wayland.h");
|
||||
});
|
||||
|
|
@ -16,11 +17,22 @@ var quit = false;
|
|||
var new_width: u32 = 0;
|
||||
var new_height: u32 = 0;
|
||||
|
||||
fn mapKeysym(keysym: u32) u32 {
|
||||
return switch (keysym) {
|
||||
0xffe1 => 340,
|
||||
else => keysym,
|
||||
};
|
||||
}
|
||||
|
||||
const State = struct {
|
||||
compositor: ?*c.wl_compositor = null,
|
||||
shell: ?*c.xdg_wm_base = null,
|
||||
surface: ?*c.wl_surface = null,
|
||||
seat: ?*c.wl_seat = null,
|
||||
configured: bool = false,
|
||||
xkb_context: ?*c.xkb_context = null,
|
||||
xkb_state: ?*c.xkb_state = null,
|
||||
allocator: std.mem.Allocator,
|
||||
};
|
||||
|
||||
const validation_layers: []const [*c]const u8 = if (!debug) &[0][*c]const u8{} else &[_][*c]const u8{
|
||||
|
|
@ -156,6 +168,8 @@ fn registryHandleGlobal(data: ?*anyopaque, registry: ?*c.wl_registry, name: u32,
|
|||
} else if (std.mem.eql(u8, @as([:0]const u8, std.mem.span(interface)), std.mem.span(c.xdg_wm_base_interface.name))) {
|
||||
state.shell = @ptrCast(c.wl_registry_bind(registry.?, name, &c.xdg_wm_base_interface, 4));
|
||||
_ = c.xdg_wm_base_add_listener(state.shell, &shell_listener, null);
|
||||
} else if (std.mem.eql(u8, @as([:0]const u8, std.mem.span(interface)), std.mem.span(c.wl_seat_interface.name))) {
|
||||
state.seat = @ptrCast(c.wl_registry_bind(registry.?, name, &c.wl_seat_interface, 4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +230,62 @@ fn frameHandleDone(data: ?*anyopaque, callback: ?*c.wl_callback, time: u32) call
|
|||
_ = c.wl_surface_commit(state.surface);
|
||||
}
|
||||
|
||||
fn keyboardHandleKeymap(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, format: u32, fd: i32, size: u32) callconv(.c) void {
|
||||
_ = keyboard;
|
||||
_ = format;
|
||||
|
||||
const state: *State = @alignCast(@ptrCast(data));
|
||||
|
||||
const addr = std.posix.mmap(null, size, std.posix.PROT.READ, std.os.linux.MAP { .TYPE = .PRIVATE }, fd, 0) catch @panic("Can't mmap keymap data");
|
||||
const mapped: []u8 = @as([*]u8, @ptrCast(addr))[0..size];
|
||||
|
||||
const keymap = c.xkb_keymap_new_from_string(state.xkb_context, @ptrCast(mapped), c.XKB_KEYMAP_FORMAT_TEXT_V1, c.XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
state.xkb_state = c.xkb_state_new(keymap);
|
||||
}
|
||||
|
||||
fn keyboardHandleEnter(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, surface: ?*c.wl_surface, keys: ?*c.wl_array) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = surface;
|
||||
_ = keys;
|
||||
}
|
||||
|
||||
fn keyboardHandleLeave(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, surface: ?*c.wl_surface) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = surface;
|
||||
}
|
||||
|
||||
fn keyboardHandleKey(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, serial: u32, time: u32, key: u32, s: u32) callconv(.c) void {
|
||||
_ = keyboard;
|
||||
_ = serial;
|
||||
_ = time;
|
||||
|
||||
const state: *State = @alignCast(@ptrCast(data));
|
||||
|
||||
const keysym = c.xkb_state_key_get_one_sym(state.xkb_state, key+8);
|
||||
sideros.sideros_key_callback(mapKeysym(keysym), s == 0);
|
||||
}
|
||||
|
||||
fn keyboardHandleModifiers(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 keyboardHandleRepeatInfo(data: ?*anyopaque, keyboard: ?*c.wl_keyboard, rate: i32, delay: i32) callconv(.c) void {
|
||||
_ = data;
|
||||
_ = keyboard;
|
||||
_ = rate;
|
||||
_ = delay;
|
||||
}
|
||||
|
||||
const frame_listener: c.wl_callback_listener = .{
|
||||
.done = frameHandleDone,
|
||||
};
|
||||
|
|
@ -239,8 +309,22 @@ const registry_listener: c.wl_registry_listener = .{
|
|||
.global_remove = registryHandleGlobalRemove,
|
||||
};
|
||||
|
||||
const keyboard_listener: c.wl_keyboard_listener = .{
|
||||
.keymap = keyboardHandleKeymap,
|
||||
.enter = keyboardHandleEnter,
|
||||
.leave = keyboardHandleLeave,
|
||||
.key = keyboardHandleKey,
|
||||
.modifiers = keyboardHandleModifiers,
|
||||
.repeat_info = keyboardHandleRepeatInfo,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var state: State = .{};
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
defer if (gpa.deinit() != .ok) @panic("Platform memory leaked");
|
||||
|
||||
var state: State = .{ .allocator = allocator };
|
||||
state.xkb_context = c.xkb_context_new(c.XKB_CONTEXT_NO_FLAGS);
|
||||
const display = c.wl_display_connect(null);
|
||||
defer c.wl_display_disconnect(display);
|
||||
if (display == null) {
|
||||
|
|
@ -251,6 +335,9 @@ pub fn main() !void {
|
|||
_ = c.wl_registry_add_listener(registry, ®istry_listener, @ptrCast(&state));
|
||||
_ = c.wl_display_roundtrip(display);
|
||||
|
||||
const keyboard = c.wl_seat_get_keyboard(state.seat);
|
||||
_ = c.wl_keyboard_add_listener(keyboard, &keyboard_listener, @ptrCast(&state));
|
||||
|
||||
const surface = c.wl_compositor_create_surface(state.compositor);
|
||||
const xdg_surface = c.xdg_wm_base_get_xdg_surface(state.shell, surface);
|
||||
_ = c.xdg_surface_add_listener(xdg_surface, &surface_listener, @ptrCast(&state));
|
||||
|
|
@ -272,9 +359,6 @@ pub fn main() !void {
|
|||
}
|
||||
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
defer if (gpa.deinit() != .ok) @panic("Platform memory leaked");
|
||||
|
||||
const gameInit = try vulkan_init(allocator, display, surface);
|
||||
defer vulkan_cleanup(gameInit);
|
||||
|
|
|
|||
15
src/xorg.zig
15
src/xorg.zig
|
|
@ -4,6 +4,7 @@ const sideros = @cImport({
|
|||
});
|
||||
const c = @cImport({
|
||||
@cInclude("xcb/xcb.h");
|
||||
@cInclude("xcb/xcb_keysyms.h");
|
||||
@cInclude("vulkan/vulkan.h");
|
||||
@cInclude("vulkan/vulkan_xcb.h");
|
||||
@cInclude("xcb/xcb_icccm.h");
|
||||
|
|
@ -138,13 +139,15 @@ fn vulkan_cleanup(gameInit: sideros.GameInit) void {
|
|||
pub fn main() !void {
|
||||
const connection = c.xcb_connect(null, null);
|
||||
defer c.xcb_disconnect(connection);
|
||||
const keysyms = c.xcb_key_symbols_alloc(connection);
|
||||
defer c.xcb_key_symbols_free(keysyms);
|
||||
|
||||
const setup = c.xcb_get_setup(connection);
|
||||
const iter = c.xcb_setup_roots_iterator(setup);
|
||||
const screen = iter.data;
|
||||
|
||||
const mask = c.XCB_CW_EVENT_MASK;
|
||||
const value = c.XCB_EVENT_MASK_EXPOSURE;
|
||||
const value = c.XCB_EVENT_MASK_EXPOSURE | c.XCB_EVENT_MASK_KEY_PRESS | c.XCB_EVENT_MASK_KEY_RELEASE;
|
||||
|
||||
const window = c.xcb_generate_id(connection);
|
||||
_ = c.xcb_create_window(connection, c.XCB_COPY_FROM_PARENT, window, screen.*.root, 0, 0, 800, 600, 10, c.XCB_WINDOW_CLASS_INPUT_OUTPUT, screen.*.root_visual, mask, &value);
|
||||
|
|
@ -170,6 +173,16 @@ pub fn main() !void {
|
|||
while (true) {
|
||||
if (c.xcb_poll_for_event(connection)) |e| {
|
||||
switch (e.*.response_type & ~@as(u32, 0x80)) {
|
||||
c.XCB_KEY_PRESS => {
|
||||
const ev: *c.xcb_key_press_event_t = @ptrCast(e);
|
||||
const key = c.xcb_key_symbols_get_keysym(keysyms, ev.detail, 0);
|
||||
sideros.sideros_key_callback(key, false);
|
||||
},
|
||||
c.XCB_KEY_RELEASE => {
|
||||
const ev: *c.xcb_key_release_event_t = @ptrCast(e);
|
||||
const key = c.xcb_key_symbols_get_keysym(keysyms, ev.detail, 0);
|
||||
sideros.sideros_key_callback(key, false);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
std.c.free(e);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue