add window and user input
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
build
|
||||
.cache
|
||||
run
|
||||
|
||||
14
external/CMakeLists.txt
vendored
14
external/CMakeLists.txt
vendored
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
134
source/ui/display.cpp
Normal 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
57
source/ui/display.hpp
Normal 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
35
source/ui/user_input.cpp
Normal 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
170
source/ui/user_input.hpp
Normal 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
|
||||
Reference in New Issue
Block a user