sandbox
Loading...
Searching...
No Matches
window.hpp
1#ifndef LIBSBX_DEVICES_WINDOW_HPP_
2#define LIBSBX_DEVICES_WINDOW_HPP_
3
4#include <GLFW/glfw3.h>
5
6#include <stdexcept>
7#include <functional>
8#include <filesystem>
9#include <unordered_set>
10#include <cmath>
11
12#include <libsbx/core/concepts.hpp>
14
15#include <libsbx/math/vector2.hpp>
16
17#include <libsbx/signals/signal.hpp>
18
19#include <libsbx/devices/events.hpp>
20#include <libsbx/devices/input.hpp>
21
22namespace sbx::devices {
23
25 std::string title{};
26 std::uint32_t width{};
27 std::uint32_t height{};
28}; // struct window_create_info
29
30class window {
31
32public:
33
34 window(const window_create_info& create_info)
35 : _last_mouse_position{-1.0f, -1.0f} {
36 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
37 // [NOTE] KAJ 2023-08-15 : Currently there seems to be a bug in the Vukan SDK version 1.3.250.1 that causes the validation layers to crash when resizing the window.
38 // glfwWindowHint(GLFW_RESIZABLE, false);
39 glfwWindowHint(GLFW_VISIBLE, false);
40 // glfwWindowHint(GLFW_DECORATED, false);
41
42 _title = create_info.title;
43 _width = create_info.width;
44 _height = create_info.height;
45
46 auto* monitor = glfwGetPrimaryMonitor();
47
48 if (!monitor) {
49 throw std::runtime_error{"Could not get primary monitor"};
50 }
51
52 const auto* video_mode = glfwGetVideoMode(monitor);
53
54 _width = static_cast<std::uint32_t>(video_mode->width);
55 _height = static_cast<std::uint32_t>(video_mode->height);
56
57 _handle = glfwCreateWindow(static_cast<std::int32_t>(_width), static_cast<std::int32_t>(_height), _title.c_str(), nullptr, nullptr);
58
59 if (!_handle) {
60 throw std::runtime_error{"Could not create glfw window"};
61 }
62
63 glfwSetWindowUserPointer(_handle, this);
64
65 glfwFocusWindow(_handle);
66
67 if (glfwRawMouseMotionSupported()) {
68 glfwSetInputMode(_handle, GLFW_RAW_MOUSE_MOTION, true);
69 }
70
71 // glfwSetInputMode(_handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
72
73 glfwSetInputMode(_handle, GLFW_STICKY_KEYS, true);
74
75 glfwSetInputMode(_handle, GLFW_LOCK_KEY_MODS, true);
76
77 _set_callbacks();
78 }
79
80 ~window() {
81 glfwDestroyWindow(_handle);
82 }
83
84 auto handle() -> GLFWwindow* {
85 return _handle;
86 }
87
88 operator GLFWwindow*() {
89 return _handle;
90 }
91
92 auto title() const -> const std::string& {
93 return _title;
94 }
95
96 auto set_title(const std::string& title) -> void {
97 _title = title;
98 glfwSetWindowTitle(_handle, _title.c_str());
99 }
100
101 auto width() const -> std::uint32_t {
102 return _width;
103 }
104
105 auto height() const -> std::uint32_t {
106 return _height;
107 }
108
109 auto aspect_ratio() const -> std::float_t {
110 return static_cast<std::float_t>(_width) / static_cast<std::float_t>(_height);
111 }
112
117 auto should_close() -> bool {
118 return glfwWindowShouldClose(_handle);
119 }
120
124 auto show() -> void {
125 glfwShowWindow(_handle);
126 }
127
131 auto hide() -> void {
132 glfwHideWindow(_handle);
133 }
134
135 auto is_iconified() const noexcept -> bool {
136 return glfwGetWindowAttrib(_handle, GLFW_ICONIFIED);
137 }
138
139 auto is_focused() const noexcept -> bool {
140 return glfwGetWindowAttrib(_handle, GLFW_FOCUSED);
141 }
142
143 auto is_visible() const noexcept -> bool {
144 return glfwGetWindowAttrib(_handle, GLFW_VISIBLE);
145 }
146
147 auto on_window_closed_signal() -> signals::signal<const window_closed_event&>& {
148 return _on_window_closed_signal;
149 }
150
151 auto on_window_moved_signal() -> signals::signal<const window_moved_event&>& {
152 return _on_window_moved_signal;
153 }
154
155 auto on_window_resized_signal() -> signals::signal<const window_resized_event&>& {
156 return _on_window_resized_signal;
157 }
158
159 auto on_framebuffer_resized() -> signals::signal<const framebuffer_resized_event&>& {
160 return _on_framebuffer_resized;
161 }
162
163 auto on_key_pressed() -> signals::signal<const key_pressed_event&>& {
164 return _on_key_pressed;
165 }
166
167 auto on_key_released() -> signals::signal<const key_released_event&>& {
168 return _on_key_released;
169 }
170
171 auto on_mouse_moved() -> signals::signal<const mouse_moved_event&>& {
172 return _on_mouse_moved;
173 }
174
175private:
176
177 void _set_callbacks() {
178 glfwSetWindowUserPointer(_handle, this);
179
180 glfwSetWindowCloseCallback(_handle, [](GLFWwindow* window){
181 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
182
183 self._on_window_closed_signal(window_closed_event{});
184 });
185
186 glfwSetWindowPosCallback(_handle, [](GLFWwindow* window, std::int32_t x, std::int32_t y){
187 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
188
189 self._on_window_moved_signal(window_moved_event{x, y});
190 });
191
192 glfwSetWindowSizeCallback(_handle, [](GLFWwindow* window, std::int32_t width, std::int32_t height){
193 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
194
195 self._on_window_resized_signal(window_resized_event{width, height});
196 });
197
198 glfwSetFramebufferSizeCallback(_handle, [](GLFWwindow* window, std::int32_t width, std::int32_t height){
199 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
200
201 self._on_framebuffer_resized(framebuffer_resized_event{width, height});
202
203 self._width = static_cast<std::uint32_t>(width);
204 self._height = static_cast<std::uint32_t>(height);
205 });
206
207 glfwSetKeyCallback(_handle, [](GLFWwindow* window, std::int32_t key, [[maybe_unused]] std::int32_t scancode, std::int32_t action, std::int32_t mods){
208 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
209
210 if (action == GLFW_PRESS) {
211 input::_update_key_state(static_cast<devices::key>(key), input_action::press);
212 self._on_key_pressed(key_pressed_event{static_cast<devices::key>(key), static_cast<devices::input_mod>(mods)});
213 } else if (action == GLFW_RELEASE) {
214 input::_update_key_state(static_cast<devices::key>(key), input_action::release);
215 self._on_key_released(key_released_event{static_cast<devices::key>(key), static_cast<devices::input_mod>(mods)});
216 }
217 });
218
219 glfwSetCursorPosCallback(_handle, [](auto* window, auto x, auto y){
220 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
221
222 auto mouse_position = math::vector2{static_cast<std::float_t>(x), static_cast<std::float_t>(y)};
223
224 if (self._last_mouse_position.x() < 0.0f || self._last_mouse_position.y() < 0.0f) {
225 self._on_mouse_moved(mouse_moved_event{mouse_position.x(), mouse_position.y()});
226 } else {
227 self._on_mouse_moved(mouse_moved_event{mouse_position.x() - self._last_mouse_position.x(), mouse_position.y() - self._last_mouse_position.y()});
228 self._last_mouse_position = mouse_position;
229 }
230
231 input::_update_mouse_position(mouse_position);
232 });
233
234 glfwSetMouseButtonCallback(_handle, [](auto* window, auto button, auto action, auto mods){
235 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
236
237 if (action == GLFW_PRESS) {
238 input::_update_mouse_button_state(static_cast<devices::mouse_button>(button), input_action::press);
239 self._on_mouse_button_pressed(mouse_button_pressed_event{static_cast<devices::mouse_button>(button), static_cast<devices::input_mod>(mods)});
240 } else if (action == GLFW_RELEASE) {
241 input::_update_mouse_button_state(static_cast<devices::mouse_button>(button), input_action::release);
242 self._on_mouse_button_released(mouse_button_released_event{static_cast<devices::mouse_button>(button), static_cast<devices::input_mod>(mods)});
243 }
244 });
245
246 glfwSetScrollCallback(_handle, [](auto* window, auto x, auto y){
247 auto& self = *static_cast<devices::window*>(glfwGetWindowUserPointer(window));
248
249 self._on_mouse_scrolled(mouse_scrolled_event{static_cast<std::float_t>(x), static_cast<std::float_t>(y)});
250
251 input::_update_scroll_delta(math::vector2{static_cast<std::float_t>(x), static_cast<std::float_t>(y)});
252 });
253 }
254
255 std::string _title{};
256 std::uint32_t _width{};
257 std::uint32_t _height{};
258
259 GLFWwindow* _handle{};
260
261 math::vector2 _last_mouse_position;
262
263 signals::signal<const window_closed_event&> _on_window_closed_signal;
264 signals::signal<const window_moved_event&> _on_window_moved_signal;
265 signals::signal<const window_resized_event&> _on_window_resized_signal;
266 signals::signal<const framebuffer_resized_event&> _on_framebuffer_resized;
267 signals::signal<const key_pressed_event&> _on_key_pressed;
268 signals::signal<const key_released_event&> _on_key_released;
269 signals::signal<const mouse_moved_event&> _on_mouse_moved;
270 signals::signal<const mouse_button_pressed_event&> _on_mouse_button_pressed;
271 signals::signal<const mouse_button_released_event&> _on_mouse_button_released;
272 signals::signal<const mouse_scrolled_event&> _on_mouse_scrolled;
273
274}; // class window
275
276} // namespace sbx::devices
277
278#endif // LIBSBX_DEVICES_WINDOW_HPP_
Definition: window.hpp:30
auto show() -> void
Makes the window visible.
Definition: window.hpp:124
auto should_close() -> bool
Determins if the window should be closed.
Definition: window.hpp:117
auto hide() -> void
Hides the window.
Definition: window.hpp:131
Definition: window.hpp:24