add window and user input

This commit is contained in:
2026-04-16 23:49:06 -03:00
parent 47f8b8598d
commit b3d64b40b1
8 changed files with 419 additions and 7 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
build
.cache
run

View File

@@ -8,12 +8,12 @@ FetchContent_Declare(
GIT_TAG 06fac4b
)
#set(GLFW_BUILD_WAYLAND OFF CACHE BOOL "WAYLAND GLFW" FORCE)
#FetchContent_Declare(
# glfw_fetch
# GIT_REPOSITORY https://github.com/glfw/glfw.git
# GIT_TAG 3.4
#)
set(GLFW_BUILD_WAYLAND OFF CACHE BOOL "WAYLAND GLFW" FORCE)
FetchContent_Declare(
glfw_fetch
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.4
)
FetchContent_Declare(
glm_fetch
@@ -63,4 +63,4 @@ FetchContent_Declare(
GIT_TAG 35368f913b79acc112c05d67291681e7badea68b
)
FetchContent_MakeAvailable(vuk_fetch glm_fetch entt_fetch slang_fetch fastgltf_fetch)
FetchContent_MakeAvailable(vuk_fetch glfw_fetch glm_fetch entt_fetch slang_fetch fastgltf_fetch)

View File

@@ -1,6 +1,10 @@
add_library(rogue-lib STATIC
cli/args.cpp
cli/args.hpp
ui/display.cpp
ui/display.hpp
ui/user_input.cpp
ui/user_input.hpp
)
target_include_directories(rogue-lib PUBLIC source .)
target_compile_definitions(rogue-lib PUBLIC -DGLFW_INCLUDE_VULKAN -DGLM_ENABLE_EXPERIMENTAL)
@@ -10,6 +14,7 @@ target_link_libraries(rogue-lib PUBLIC
vk-bootstrap
slang
fastgltf
glfw
)
add_executable(rogue

View File

@@ -1,5 +1,6 @@
#include <cli/args.hpp>
#include <print>
#include <ui/display.hpp>
#include <util/logger.hpp>
auto main(int argc, char **argv) -> int {
@@ -23,6 +24,15 @@ auto main(int argc, char **argv) -> int {
std::println("{} does not exist", args.scene_path.generic_string());
return 2;
}
auto user_input = rog::ui::user_input();
glfwInit();
auto display = rog::ui::display(&user_input, {1920, 1080}, "Rogue PT");
while (!display.should_close()) {
display.poll_events();
}
glfwTerminate();
} catch (const std::exception &ex) {
log.error("{}", ex.what());
}

134
source/ui/display.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include "display.hpp"
#include <stdexcept>
#include <utility>
namespace rog::ui {
GLFWwindow *display::create_window(glm::uvec2 extent, std::string_view title,
void *user_data) {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
const auto window =
glfwCreateWindow(extent.x, extent.y, title.data(), nullptr, nullptr);
if (window == nullptr) {
auto description = static_cast<const char *>(nullptr);
glfwGetError(&description);
throw std::runtime_error(description);
}
glfwSetWindowUserPointer(window, user_data);
return window;
}
display::display(user_input *input, glm::uvec2 extent, std::string_view title)
: handle(create_window(extent, title, this)), title(title), input(input) {
glfwSetWindowSizeCallback(
handle, [](GLFWwindow *window, int width, int height) {
auto self = static_cast<display *>(glfwGetWindowUserPointer(window));
for (const auto &cb : self->resize_callbacks) {
cb(glm::uvec2(width, height));
}
});
glfwSetKeyCallback(handle, [](GLFWwindow *window, int key,
[[maybe_unused]] int scancode, int action,
[[maybe_unused]] int mods) {
auto self = static_cast<display *>(glfwGetWindowUserPointer(window));
if (action == GLFW_RELEASE) {
self->input->set_key_state(static_cast<key_code>(key),
key_state::released);
} else if (action == GLFW_REPEAT) {
self->input->set_key_state(static_cast<key_code>(key), key_state::repeat);
} else if (action == GLFW_PRESS) {
self->input->set_key_state(static_cast<key_code>(key),
key_state::pressed);
}
});
glfwSetCursorPosCallback(handle, [](GLFWwindow *window, double x, double y) {
static_cast<display *>(glfwGetWindowUserPointer(window))
->input->set_mouse_pos(glm::vec2{x, y});
});
glfwSetMouseButtonCallback(
handle, [](GLFWwindow *window, int button, int action, int mods) {
auto self = static_cast<display *>(glfwGetWindowUserPointer(window));
auto mouse_button = ui::mouse_button::left;
switch (button) {
case GLFW_MOUSE_BUTTON_LEFT:
mouse_button = ui::mouse_button::left;
break;
case GLFW_MOUSE_BUTTON_RIGHT:
mouse_button = ui::mouse_button::right;
break;
case GLFW_MOUSE_BUTTON_MIDDLE:
mouse_button = ui::mouse_button::middle;
break;
default:;
}
auto mouse_action = ui::button_state::down;
switch (action) {
case GLFW_PRESS:
mouse_action = ui::button_state::down;
break;
case GLFW_RELEASE:
mouse_action = ui::button_state::up;
break;
default:;
}
self->input->set_mouse_button(mouse_button, mouse_action);
});
}
display::~display() { glfwDestroyWindow(handle); }
display::display(const display &rhs)
: handle(create_window(rhs.extent(), rhs.title, this)), title(rhs.title) {
glfwSetWindowSizeCallback(
handle, [](GLFWwindow *window, int width, int height) {
auto self = static_cast<display *>(glfwGetWindowUserPointer(window));
for (const auto &cb : self->resize_callbacks) {
cb(glm::uvec2(width, height));
}
});
}
display::display(display &&rhs) noexcept
: handle(std::exchange(rhs.handle, nullptr)), title(rhs.title) {}
display &display::operator=(const display &rhs) { return *this = display(rhs); }
display &display::operator=(display &&rhs) noexcept {
std::swap(handle, rhs.handle);
std::swap(title, rhs.title);
return *this;
}
bool display::should_close() const noexcept {
return glfwWindowShouldClose(handle);
}
glm::uvec2 display::extent() const noexcept {
auto extent = glm::ivec2();
glfwGetFramebufferSize(handle, &extent.x, &extent.y);
return extent;
}
void display::poll_events() { glfwPollEvents(); }
vk::raii::SurfaceKHR
display::create_surface(const vk::raii::Instance &instance) {
auto c_surface = VkSurfaceKHR();
glfwCreateWindowSurface(*instance, handle, nullptr, &c_surface);
return vk::raii::SurfaceKHR(instance, c_surface);
}
void display::resize_callback(std::function<void(glm::uvec2 extent)> callback) {
resize_callbacks.push_back(callback);
}
GLFWwindow *display::raw() const noexcept { return handle; }
void display::request_close() noexcept {
glfwSetWindowShouldClose(handle, true);
}
} // namespace rog::ui

57
source/ui/display.hpp Normal file
View File

@@ -0,0 +1,57 @@
#ifndef DISPLAY_HPP
#define DISPLAY_HPP
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vulkan/vulkan_raii.hpp>
#include "user_input.hpp"
#include <functional>
#include <string_view>
namespace rog::ui {
class display {
private:
GLFWwindow *handle;
std::string_view title;
user_input *input;
[[nodiscard]] static GLFWwindow *
create_window(glm::uvec2 extent, std::string_view title, void *user_data);
std::vector<std::function<void(glm::uvec2 extent)>> resize_callbacks = {};
public:
display(user_input *input, glm::uvec2 extent, std::string_view title);
~display();
display(const display &rhs);
display(display &&rhs) noexcept;
display &operator=(const display &rhs);
display &operator=(display &&rhs) noexcept;
[[nodiscard]] bool should_close() const noexcept;
[[nodiscard]] glm::uvec2 extent() const noexcept;
void poll_events();
[[nodiscard]] vk::raii::SurfaceKHR
create_surface(const vk::raii::Instance &instance);
void resize_callback(std::function<void(glm::uvec2 extent)> callback);
[[nodiscard]] GLFWwindow *raw() const noexcept;
void request_close() noexcept;
};
} // namespace rog::ui
#endif

35
source/ui/user_input.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "user_input.hpp"
namespace rog::ui {
void user_input::set_key_state(key_code key, key_state state) {
const auto key_index = static_cast<int>(key);
if (key_index < this->state.keys.size()) {
this->state.keys[key_index] = state;
}
}
void user_input::set_mouse_pos(glm::vec2 pos) { state.mouse_pos = pos; }
void user_input::set_mouse_button(mouse_button button, button_state state) {
this->state.mouse_buttons[static_cast<int>(button)] = state;
}
bool user_input::is_key_down(key_code code) const noexcept {
const auto idx = static_cast<int>(code);
return state.keys[idx] == key_state::pressed ||
state.keys[idx] == key_state::repeat ||
state.keys[idx] == key_state::held;
}
bool user_input::is_key_pressed(key_code code) const noexcept {
return state.keys[static_cast<int>(code)] == key_state::pressed;
}
glm::vec2 user_input::get_mouse_position() const noexcept {
return state.mouse_pos;
}
input_state user_input::current_state() const noexcept { return state; }
} // namespace rog::ui

170
source/ui/user_input.hpp Normal file
View File

@@ -0,0 +1,170 @@
#ifndef USER_INPUT_HPP
#define USER_INPUT_HPP
#include <glm/glm.hpp>
namespace rog::ui {
enum class key_code {
space = 32, // I can't wait to write all of these out
apostrophe = 39,
comma = 44,
minus = 45,
period = 46,
slash = 47,
key_0 = 48,
key_1 = 49,
key_2 = 50,
key_3 = 51,
key_4 = 52,
key_5 = 53,
key_6 = 54,
key_7 = 55,
key_8 = 56,
key_9 = 57, // This is starting to get really annoying
semicolon = 59,
equal = 61,
key_a = 65,
key_b = 66,
key_c = 67,
key_d = 68,
key_e = 69,
key_f = 70,
key_g = 71,
key_h = 72,
key_i = 73,
key_j = 74,
key_k = 75,
key_l = 76,
key_m = 77,
key_n = 78,
key_o = 79,
key_p = 80,
key_q = 81,
key_r = 82,
key_s = 83,
key_t = 84,
key_u = 85,
key_v = 86,
key_w = 87,
key_x = 88,
key_y = 89,
key_z = 90,
key_left_bracket = 91, /* [ */
key_backslash = 92, /* \ */
key_right_bracket = 93, /* ] */
key_grave_accent = 96, /* ` */
key_world_1 = 161, /* non-US #1 */
key_world_2 = 162, /* non-US #2 */
key_escape = 256,
key_enter = 257,
key_tab = 258,
key_backspace = 259,
key_insert = 260,
key_delete = 261,
key_right = 262,
key_left = 263,
key_down = 264,
key_up = 265,
key_page_up = 266,
key_page_down = 267,
key_home = 268,
key_end = 269,
key_caps_lock = 280,
key_scroll_lock = 281,
key_num_lock = 282,
key_print_screen = 283,
key_pause = 284,
key_f1 = 290,
key_f2 = 291,
key_f3 = 292,
key_f4 = 293,
key_f5 = 294,
key_f6 = 295,
key_f7 = 296,
key_f8 = 297,
key_f9 = 298,
key_f10 = 299,
key_f11 = 300,
key_f12 = 301,
key_f13 = 302,
key_f14 = 303,
key_f15 = 304,
key_f16 = 305,
key_f17 = 306,
key_f18 = 307,
key_f19 = 308,
key_f20 = 309,
key_f21 = 310,
key_f22 = 311,
key_f23 = 312,
key_f24 = 313,
key_f25 = 314,
key_kp_0 = 320,
key_kp_1 = 321,
key_kp_2 = 322,
key_kp_3 = 323,
key_kp_4 = 324,
key_kp_5 = 325,
key_kp_6 = 326,
key_kp_7 = 327,
key_kp_8 = 328,
key_kp_9 = 329,
key_kp_decimal = 330,
key_kp_divide = 331,
key_kp_multiply = 332,
key_kp_subtract = 333,
key_kp_add = 334,
key_kp_enter = 335,
key_kp_equal = 336,
key_left_shift = 340,
key_left_control = 341,
key_left_alt = 342,
key_left_super = 343,
key_right_shift = 344,
key_right_control = 345,
key_right_alt = 346,
key_right_super = 347,
key_menu = 348,
max_key = 1024,
};
enum class key_state { none, pressed, held, repeat, released };
enum class button_state { down, up };
enum class mouse_button {
left,
right,
middle,
};
struct input_state {
std::array<key_state, static_cast<int>(key_code::max_key)> keys = {};
std::array<button_state, 3> mouse_buttons = {};
glm::vec2 mouse_pos = {};
};
class user_input {
public:
void set_key_state(key_code key, key_state state);
void set_mouse_pos(glm::vec2 pos);
void set_mouse_button(mouse_button button, button_state state);
[[nodiscard]] bool is_key_down(key_code code) const noexcept;
[[nodiscard]] bool is_key_pressed(key_code code) const noexcept;
[[nodiscard]] glm::vec2 get_mouse_position() const noexcept;
[[nodiscard]] input_state current_state() const noexcept;
private:
input_state state;
};
} // namespace rog::ui
#endif