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