MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
GlfwWindow.cpp
Go to the documentation of this file.
1#include "GlfwWindow.hpp"
2
3#include "GlfwSingleton.hpp"
5
6#ifdef GLFW_BACKEND
7
8#define GLFW_EXPOSE_NATIVE_COCOA
9#include <GLFW/glfw3native.h>
10
11namespace MayaFlux::Core {
12
13GlfwWindow::GlfwWindow(const WindowCreateInfo& create_info,
14 const GraphicsSurfaceInfo& surface_info, GlobalGraphicsConfig::GraphicsApi api, GlfwPreInitConfig pre_init_config)
15 : m_create_info(create_info)
16{
17 GLFWSingleton::configure(pre_init_config);
18
19 if (!GLFWSingleton::initialize()) {
20 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
21 "Failed to initialize GLFW for window creation");
22 }
23
24 configure_window_hints(surface_info, api);
25
26 GLFWmonitor* monitor = nullptr;
27 if (create_info.fullscreen) {
28 if (create_info.monitor_id >= 0) {
29 int count {};
30 std::span<GLFWmonitor*> monitors(glfwGetMonitors(&count), count);
31 if (create_info.monitor_id < count) {
32 monitor = monitors[create_info.monitor_id];
33 }
34 } else {
35 monitor = glfwGetPrimaryMonitor();
36 }
37 }
38
39 m_window = glfwCreateWindow(
40 (int32_t)create_info.width,
41 (int32_t)create_info.height,
42 create_info.title.c_str(),
43 monitor,
44 nullptr);
45
46 if (!m_window) {
47 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
48 "Failed to create GLFW window: {}", create_info.title);
49 }
50
51 glfwSetWindowUserPointer(m_window, this);
52 setup_callbacks();
53
54 int w {}, h {};
55 glfwGetWindowSize(m_window, &w, &h);
56 m_state.current_width = w;
57 m_state.current_height = h;
58 m_state.is_visible = false;
59
60 GLFWSingleton::mark_window_created();
61
62 MF_INFO(Journal::Component::Core, Journal::Context::WindowingSubsystem,
63 "Created window '{}' ({}x{})", create_info.title, w, h);
64}
65
66GlfwWindow::~GlfwWindow()
67{
68 destroy();
69}
70
71void GlfwWindow::destroy()
72{
73 if (m_window) {
74 glfwDestroyWindow(m_window);
75 GLFWSingleton::mark_window_destroyed();
76 m_window = nullptr;
77 }
78}
79
80GlfwWindow::GlfwWindow(GlfwWindow&& other) noexcept
81 : m_window(other.m_window)
82 , m_create_info(std::move(other.m_create_info))
83 , m_state(other.m_state)
84 , m_input_config(other.m_input_config)
85 , m_event_callback(std::move(other.m_event_callback))
86{
87 other.m_window = nullptr;
88 if (m_window) {
89 glfwSetWindowUserPointer(m_window, this);
90 }
91}
92
93GlfwWindow& GlfwWindow::operator=(GlfwWindow&& other) noexcept
94{
95 if (this != &other) {
96 if (m_window) {
97 glfwDestroyWindow(m_window);
98 GLFWSingleton::mark_window_destroyed();
99 }
100
101 m_window = other.m_window;
102 m_create_info = std::move(other.m_create_info);
103 m_state = other.m_state;
104 m_input_config = other.m_input_config;
105 m_event_callback = std::move(other.m_event_callback);
106
107 other.m_window = nullptr;
108 if (m_window) {
109 glfwSetWindowUserPointer(m_window, this);
110 }
111 }
112 return *this;
113}
114
115void GlfwWindow::set_title(const std::string& title)
116{
117 if (m_window) {
118 glfwSetWindowTitle(m_window, title.c_str());
119 m_create_info.title = title;
120 }
121}
122
123void GlfwWindow::configure_window_hints(const GraphicsSurfaceInfo& /*surface_info*/, GlobalGraphicsConfig::GraphicsApi api) const
124{
125 glfwDefaultWindowHints();
126
127#ifdef MAYAFLUX_PLATFORM_MACOS
128 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
129#else
130 glfwWindowHint(GLFW_RESIZABLE, m_create_info.resizable ? GLFW_TRUE : GLFW_FALSE);
131#endif // MAYAFLUX_PLATFORM_MACOS
132
133 glfwWindowHint(GLFW_DECORATED, m_create_info.decorated ? GLFW_TRUE : GLFW_FALSE);
134 glfwWindowHint(GLFW_FLOATING, m_create_info.floating ? GLFW_TRUE : GLFW_FALSE);
135 glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, m_create_info.transparent ? GLFW_TRUE : GLFW_FALSE);
136 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
137
138 if (api == GlobalGraphicsConfig::GraphicsApi::VULKAN) {
139 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
140 } else if (api == GlobalGraphicsConfig::GraphicsApi::OPENGL) {
141 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
142 }
143}
144
145void GlfwWindow::setup_callbacks()
146{
147 glfwSetWindowSizeCallback(m_window, glfw_window_size_callback);
148 glfwSetWindowCloseCallback(m_window, glfw_window_close_callback);
149 glfwSetWindowFocusCallback(m_window, glfw_window_focus_callback);
150 glfwSetFramebufferSizeCallback(m_window, glfw_framebuffer_size_callback);
151 glfwSetKeyCallback(m_window, glfw_key_callback);
152 glfwSetCursorPosCallback(m_window, glfw_cursor_pos_callback);
153 glfwSetMouseButtonCallback(m_window, glfw_mouse_button_callback);
154 glfwSetScrollCallback(m_window, glfw_scroll_callback);
155}
156
157void GlfwWindow::show()
158{
159 if (m_window) {
160 glfwShowWindow(m_window);
161 m_state.is_visible = true;
162 }
163}
164
165void GlfwWindow::hide()
166{
167 if (m_window) {
168 glfwHideWindow(m_window);
169 m_state.is_visible = false;
170 }
171}
172
173bool GlfwWindow::should_close() const
174{
175 return m_window ? glfwWindowShouldClose(m_window) : true;
176}
177
178void GlfwWindow::set_event_callback(WindowEventCallback callback)
179{
180 m_event_callback = std::move(callback);
181}
182
183void* GlfwWindow::get_native_handle() const
184{
185 if (!m_window)
186 return nullptr;
187
188 return glfwGetCocoaWindow(m_window);
189}
190
191void GlfwWindow::glfw_window_size_callback(GLFWwindow* window, int width, int height)
192{
193 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
194 if (win && win->m_event_callback) {
195 win->m_state.current_width = width;
196 win->m_state.current_height = height;
197
198 if (win->m_event_callback) {
199 WindowEvent event;
200 event.type = WindowEventType::WINDOW_RESIZED;
201 event.timestamp = glfwGetTime();
202 event.data = WindowEvent::ResizeData {
203 .width = static_cast<uint32_t>(width),
204 .height = static_cast<uint32_t>(height)
205 };
206 win->m_event_callback(event);
207 }
208 }
209}
210
211void GlfwWindow::set_size(uint32_t width, uint32_t height)
212{
213 if (m_window) {
214 glfwSetWindowSize(m_window, static_cast<int>(width), static_cast<int>(height));
215 }
216
217 m_create_info.width = width;
218 m_create_info.height = height;
219}
220
221void GlfwWindow::set_position(uint32_t x, uint32_t y)
222{
223 if (m_window) {
224 glfwSetWindowPos(m_window, static_cast<int>(x), static_cast<int>(y));
225 }
226}
227
228void GlfwWindow::set_color(const std::array<float, 4>& color)
229{
230 m_create_info.clear_color = color;
231}
232
233void GlfwWindow::glfw_window_close_callback(GLFWwindow* window)
234{
235 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
236 if (!win)
237 return;
238
239 WindowEvent event;
240 event.type = WindowEventType::WINDOW_CLOSED;
241 event.timestamp = glfwGetTime();
242
243 win->m_event_source.signal(event);
244
245 if (win->m_event_callback) {
246 win->m_event_callback(event);
247 }
248}
249
250void GlfwWindow::glfw_window_focus_callback(GLFWwindow* window, int focused)
251{
252 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
253 if (!win)
254 return;
255
256 win->m_state.is_focused = (focused == GLFW_TRUE);
257
258 WindowEvent event;
259 event.type = focused ? WindowEventType::WINDOW_FOCUS_GAINED
260 : WindowEventType::WINDOW_FOCUS_LOST;
261 event.timestamp = glfwGetTime();
262
263 win->m_event_source.signal(event);
264
265 if (win->m_event_callback) {
266 win->m_event_callback(event);
267 }
268}
269
270void GlfwWindow::glfw_framebuffer_size_callback(GLFWwindow* window, int width, int height)
271{
272 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
273 if (!win)
274 return;
275
276 WindowEvent event;
277 event.type = WindowEventType::FRAMEBUFFER_RESIZED;
278 event.timestamp = glfwGetTime();
279 event.data = WindowEvent::ResizeData {
280 .width = static_cast<uint32_t>(width),
281 .height = static_cast<uint32_t>(height)
282 };
283
284 win->m_event_source.signal(event);
285
286 if (win->m_event_callback) {
287 win->m_event_callback(event);
288 }
289}
290
291void GlfwWindow::glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
292{
293 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
294 if (!win)
295 return;
296
297 WindowEventType type {};
298 switch (action) {
299 case GLFW_PRESS:
300 type = WindowEventType::KEY_PRESSED;
301 break;
302 case GLFW_RELEASE:
303 type = WindowEventType::KEY_RELEASED;
304 break;
305 case GLFW_REPEAT:
306 type = WindowEventType::KEY_REPEAT;
307 break;
308 default:
309 return;
310 }
311
312 WindowEvent event;
313 event.type = type;
314 event.timestamp = glfwGetTime();
315 event.data = WindowEvent::KeyData {
316 .key = static_cast<int16_t>(key),
317 .scancode = scancode,
318 .mods = mods
319 };
320
321 win->m_event_source.signal(event);
322
323 if (win->m_event_callback) {
324 win->m_event_callback(event);
325 }
326}
327
328void GlfwWindow::glfw_cursor_pos_callback(GLFWwindow* window, double xpos, double ypos)
329{
330 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
331 if (!win)
332 return;
333
334 WindowEvent event;
335 event.type = WindowEventType::MOUSE_MOTION;
336 event.timestamp = glfwGetTime();
337
338 event.data = WindowEvent::MousePosData {
339 .x = xpos,
340 .y = ypos
341 };
342
343 win->m_event_source.signal(event);
344
345 if (win->m_event_callback) {
346 win->m_event_callback(event);
347 }
348}
349
350void GlfwWindow::glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
351{
352 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
353 if (!win)
354 return;
355
356 WindowEvent event;
357 event.type = (action == GLFW_PRESS) ? WindowEventType::MOUSE_BUTTON_PRESSED
359 event.timestamp = glfwGetTime();
360
361 event.data = WindowEvent::MouseButtonData {
362 .button = static_cast<int8_t>(button),
363 .mods = mods
364 };
365
366 win->m_event_source.signal(event);
367
368 if (win->m_event_callback) {
369 win->m_event_callback(event);
370 }
371}
372
373void GlfwWindow::glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
374{
375 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
376 if (!win)
377 return;
378
379 WindowEvent event;
380 event.type = WindowEventType::MOUSE_SCROLLED;
381 event.timestamp = glfwGetTime();
382 event.data = WindowEvent::ScrollData {
383 .x_offset = xoffset,
384 .y_offset = yoffset
385 };
386
387 win->m_event_source.signal(event);
388
389 if (win->m_event_callback) {
390 win->m_event_callback(event);
391 }
392}
393
394void GlfwWindow::set_graphics_registered(bool registered)
395{
396 m_graphics_registered.store(registered, std::memory_order_release);
397}
398
399void GlfwWindow::register_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
400{
401 for (const auto& weak_buf : m_rendering_buffers) {
402 if (auto buf = weak_buf.lock()) {
403 if (buf == buffer) {
404 return;
405 }
406 }
407 }
408
409 std::lock_guard lock(m_render_tracking_mutex);
410 m_rendering_buffers.push_back(buffer);
411
412 MF_RT_DEBUG(Journal::Component::Core, Journal::Context::GraphicsCallback,
413 "Window '{}': registered VKBuffer for rendering (total: {})",
414 m_create_info.title, m_rendering_buffers.size());
415}
416
417void GlfwWindow::unregister_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
418{
419 auto it = std::ranges::find_if(m_rendering_buffers,
420 [&buffer](const std::weak_ptr<Buffers::VKBuffer>& weak_buf) {
421 auto buf = weak_buf.lock();
422 return buf == buffer;
423 });
424
425 if (it != m_rendering_buffers.end()) {
426 std::lock_guard lock(m_render_tracking_mutex);
427 m_rendering_buffers.erase(it);
428 }
429}
430
431void GlfwWindow::track_frame_command(uint64_t cmd_id)
432{
433 std::lock_guard lock(m_render_tracking_mutex);
434 m_frame_commands.push_back(cmd_id);
435
436 MF_RT_TRACE(Journal::Component::Core, Journal::Context::GraphicsCallback,
437 "Window '{}': tracked command buffer {} (total this frame: {})",
438 m_create_info.title, cmd_id, m_frame_commands.size());
439}
440
441const std::vector<uint64_t>& GlfwWindow::get_frame_commands() const
442{
443 return m_frame_commands;
444}
445
446void GlfwWindow::clear_frame_commands()
447{
448 std::lock_guard lock(m_render_tracking_mutex);
449 m_frame_commands.clear();
450}
451
452std::vector<std::shared_ptr<Buffers::VKBuffer>> GlfwWindow::get_rendering_buffers() const
453{
454 std::lock_guard lock(m_render_tracking_mutex);
455
456 std::vector<std::shared_ptr<Buffers::VKBuffer>> buffers;
457 for (const auto& weak_buf : m_rendering_buffers) {
458 if (auto buf = weak_buf.lock()) {
459 buffers.push_back(buf);
460 }
461 }
462 return buffers;
463}
464
465}
466
467#endif // GLFW_BACKEND
#define MF_INFO(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
uint32_t width
Definition Decoder.cpp:59
uint32_t h
Definition InkPress.cpp:28
size_t count
WindowEventType
Types of window and input events.