MayaFlux 0.2.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 MAYAFLUX_PLATFORM_WINDOWS
7#define GLFW_EXPOSE_NATIVE_WIN32
8#include <GLFW/glfw3native.h>
9#elif MAYAFLUX_PLATFORM_LINUX
10#include <GLFW/glfw3native.h>
11#elif MAYAFLUX_PLATFORM_MACOS
12#define GLFW_EXPOSE_NATIVE_COCOA
13#include <GLFW/glfw3native.h>
14#endif
15
16namespace MayaFlux::Core {
17
19 const GraphicsSurfaceInfo& surface_info, GlobalGraphicsConfig::GraphicsApi api, GlfwPreInitConfig pre_init_config)
20 : m_create_info(create_info)
21{
22 GLFWSingleton::configure(pre_init_config);
23
25 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
26 "Failed to initialize GLFW for window creation");
27 }
28
29 configure_window_hints(surface_info, api);
30
31 GLFWmonitor* monitor = nullptr;
32 if (create_info.fullscreen) {
33 if (create_info.monitor_id >= 0) {
34 int count {};
35 std::span<GLFWmonitor*> monitors(glfwGetMonitors(&count), count);
36 if (create_info.monitor_id < count) {
37 monitor = monitors[create_info.monitor_id];
38 }
39 } else {
40 monitor = glfwGetPrimaryMonitor();
41 }
42 }
43
44 m_window = glfwCreateWindow(
45 create_info.width,
46 create_info.height,
47 create_info.title.c_str(),
48 monitor,
49 nullptr);
50
51 if (!m_window) {
52 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
53 "Failed to create GLFW window: {}", create_info.title);
54 }
55
56 glfwSetWindowUserPointer(m_window, this);
58
59 int w {}, h {};
60 glfwGetWindowSize(m_window, &w, &h);
63 m_state.is_visible = false;
64
66
68 "Created window '{}' ({}x{})", create_info.title, w, h);
69}
70
75
77{
78 if (m_window) {
79 glfwDestroyWindow(m_window);
81 m_window = nullptr;
82 }
83}
84
86 : m_window(other.m_window)
87 , m_create_info(std::move(other.m_create_info))
88 , m_state(other.m_state)
89 , m_input_config(other.m_input_config)
90 , m_event_callback(std::move(other.m_event_callback))
91{
92 other.m_window = nullptr;
93 if (m_window) {
94 glfwSetWindowUserPointer(m_window, this);
95 }
96}
97
99{
100 if (this != &other) {
101 if (m_window) {
102 glfwDestroyWindow(m_window);
104 }
105
106 m_window = other.m_window;
107 m_create_info = std::move(other.m_create_info);
108 m_state = other.m_state;
109 m_input_config = other.m_input_config;
110 m_event_callback = std::move(other.m_event_callback);
111
112 other.m_window = nullptr;
113 if (m_window) {
114 glfwSetWindowUserPointer(m_window, this);
115 }
116 }
117 return *this;
118}
119
120void GlfwWindow::set_title(const std::string& title)
121{
122 if (m_window) {
123 glfwSetWindowTitle(m_window, title.c_str());
124 m_create_info.title = title;
125 }
126}
127
129{
130 glfwDefaultWindowHints();
131
132#ifdef MAYAFLUX_PLATFORM_MACOS
133 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
134#else
135 glfwWindowHint(GLFW_RESIZABLE, m_create_info.resizable ? GLFW_TRUE : GLFW_FALSE);
136#endif // MAYAFLUX_PLATFORM_MACOS
137
138 glfwWindowHint(GLFW_DECORATED, m_create_info.decorated ? GLFW_TRUE : GLFW_FALSE);
139 glfwWindowHint(GLFW_FLOATING, m_create_info.floating ? GLFW_TRUE : GLFW_FALSE);
140 glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, m_create_info.transparent ? GLFW_TRUE : GLFW_FALSE);
141 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
142
144 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
146 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
147 }
148}
149
151{
152 glfwSetWindowSizeCallback(m_window, glfw_window_size_callback);
153 glfwSetWindowCloseCallback(m_window, glfw_window_close_callback);
154 glfwSetWindowFocusCallback(m_window, glfw_window_focus_callback);
155 glfwSetFramebufferSizeCallback(m_window, glfw_framebuffer_size_callback);
156 glfwSetKeyCallback(m_window, glfw_key_callback);
157 glfwSetCursorPosCallback(m_window, glfw_cursor_pos_callback);
158 glfwSetMouseButtonCallback(m_window, glfw_mouse_button_callback);
159 glfwSetScrollCallback(m_window, glfw_scroll_callback);
160}
161
163{
164 if (m_window) {
165 glfwShowWindow(m_window);
166 m_state.is_visible = true;
167 }
168}
169
171{
172 if (m_window) {
173 glfwHideWindow(m_window);
174 m_state.is_visible = false;
175 }
176}
177
179{
180 return m_window ? glfwWindowShouldClose(m_window) : true;
181}
182
184{
185 m_event_callback = std::move(callback);
186}
187
189{
190 if (!m_window)
191 return nullptr;
192
193#ifdef MAYAFLUX_PLATFORM_WINDOWS
194 return glfwGetWin32Window(m_window);
195#elif MAYAFLUX_PLATFORM_LINUX
196#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
197 if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
198 return glfwGetWaylandWindow(m_window);
199 }
200#endif
201#if defined(GLFW_EXPOSE_NATIVE_X11)
202 if (glfwGetPlatform() == GLFW_PLATFORM_X11) {
203 return reinterpret_cast<void*>(glfwGetX11Window(m_window));
204 }
205#endif
206 return nullptr;
207#elif MAYAFLUX_PLATFORM_MACOS
208 return glfwGetCocoaWindow(m_window);
209#else
210 return m_window;
211#endif
212}
213
215{
216#ifdef MAYAFLUX_PLATFORM_LINUX
217#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
218 if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
219 return glfwGetWaylandDisplay();
220 }
221#endif
222#if defined(GLFW_EXPOSE_NATIVE_X11)
223 if (glfwGetPlatform() == GLFW_PLATFORM_X11) {
224 return glfwGetX11Display();
225 }
226#endif
227#endif
228 return nullptr;
229}
230
231void GlfwWindow::glfw_window_size_callback(GLFWwindow* window, int width, int height)
232{
233 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
234 if (win && win->m_event_callback) {
235 win->m_state.current_width = width;
236 win->m_state.current_height = height;
237
238 if (win->m_event_callback) {
239 WindowEvent event;
241 event.timestamp = glfwGetTime();
242 event.data = WindowEvent::ResizeData {
243 .width = static_cast<uint32_t>(width),
244 .height = static_cast<uint32_t>(height)
245 };
246 win->m_event_callback(event);
247 }
248 }
249}
250
251void GlfwWindow::set_size(uint32_t width, uint32_t height)
252{
253 if (m_window) {
254 glfwSetWindowSize(m_window, static_cast<int>(width), static_cast<int>(height));
255 }
256
257 m_create_info.width = width;
258 m_create_info.height = height;
259}
260
261void GlfwWindow::set_position(uint32_t x, uint32_t y)
262{
263 if (m_window) {
264 glfwSetWindowPos(m_window, static_cast<int>(x), static_cast<int>(y));
265 }
266}
267
269{
270 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
271 if (!win)
272 return;
273
274 WindowEvent event;
276 event.timestamp = glfwGetTime();
277
278 win->m_event_source.signal(event);
279
280 if (win->m_event_callback) {
281 win->m_event_callback(event);
282 }
283}
284
285void GlfwWindow::glfw_window_focus_callback(GLFWwindow* window, int focused)
286{
287 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
288 if (!win)
289 return;
290
291 win->m_state.is_focused = (focused == GLFW_TRUE);
292
293 WindowEvent event;
296 event.timestamp = glfwGetTime();
297
298 win->m_event_source.signal(event);
299
300 if (win->m_event_callback) {
301 win->m_event_callback(event);
302 }
303}
304
305void GlfwWindow::glfw_framebuffer_size_callback(GLFWwindow* window, int width, int height)
306{
307 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
308 if (!win)
309 return;
310
311 WindowEvent event;
313 event.timestamp = glfwGetTime();
314 event.data = WindowEvent::ResizeData {
315 .width = static_cast<uint32_t>(width),
316 .height = static_cast<uint32_t>(height)
317 };
318
319 win->m_event_source.signal(event);
320
321 if (win->m_event_callback) {
322 win->m_event_callback(event);
323 }
324}
325
326void GlfwWindow::glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
327{
328 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
329 if (!win)
330 return;
331
332 WindowEventType type {};
333 switch (action) {
334 case GLFW_PRESS:
336 break;
337 case GLFW_RELEASE:
339 break;
340 case GLFW_REPEAT:
342 break;
343 default:
344 return;
345 }
346
347 WindowEvent event;
348 event.type = type;
349 event.timestamp = glfwGetTime();
350 event.data = WindowEvent::KeyData {
351 .key = key,
352 .scancode = scancode,
353 .mods = mods
354 };
355
356 win->m_event_source.signal(event);
357
358 if (win->m_event_callback) {
359 win->m_event_callback(event);
360 }
361}
362
363void GlfwWindow::glfw_cursor_pos_callback(GLFWwindow* window, double xpos, double ypos)
364{
365 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
366 if (!win)
367 return;
368
369 WindowEvent event;
371 event.timestamp = glfwGetTime();
372
373 event.data = WindowEvent::MousePosData {
374 .x = xpos,
375 .y = ypos
376 };
377
378 win->m_event_source.signal(event);
379
380 if (win->m_event_callback) {
381 win->m_event_callback(event);
382 }
383}
384
385void GlfwWindow::glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
386{
387 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
388 if (!win)
389 return;
390
391 WindowEvent event;
392 event.type = (action == GLFW_PRESS) ? WindowEventType::MOUSE_BUTTON_PRESSED
394 event.timestamp = glfwGetTime();
395
396 event.data = WindowEvent::MouseButtonData {
397 .button = button,
398 .mods = mods
399 };
400
401 win->m_event_source.signal(event);
402
403 if (win->m_event_callback) {
404 win->m_event_callback(event);
405 }
406}
407
408void GlfwWindow::glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
409{
410 auto* win = static_cast<GlfwWindow*>(glfwGetWindowUserPointer(window));
411 if (!win)
412 return;
413
414 WindowEvent event;
416 event.timestamp = glfwGetTime();
417 event.data = WindowEvent::ScrollData {
418 .x_offset = xoffset,
419 .y_offset = yoffset
420 };
421
422 win->m_event_source.signal(event);
423
424 if (win->m_event_callback) {
425 win->m_event_callback(event);
426 }
427}
428
430{
431 m_graphics_registered.store(registered, std::memory_order_release);
432}
433
434void GlfwWindow::register_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
435{
436 for (const auto& weak_buf : m_rendering_buffers) {
437 if (auto buf = weak_buf.lock()) {
438 if (buf == buffer) {
439 return;
440 }
441 }
442 }
443
444 std::lock_guard lock(m_render_tracking_mutex);
445 m_rendering_buffers.push_back(buffer);
446
448 "Window '{}': registered VKBuffer for rendering (total: {})",
450}
451
452void GlfwWindow::unregister_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
453{
454 auto it = std::ranges::find_if(m_rendering_buffers,
455 [&buffer](const std::weak_ptr<Buffers::VKBuffer>& weak_buf) {
456 auto buf = weak_buf.lock();
457 return buf == buffer;
458 });
459
460 if (it != m_rendering_buffers.end()) {
461 std::lock_guard lock(m_render_tracking_mutex);
462 m_rendering_buffers.erase(it);
463 }
464}
465
467{
468 std::lock_guard lock(m_render_tracking_mutex);
469 m_frame_commands.push_back(cmd_id);
470
472 "Window '{}': tracked command buffer {} (total this frame: {})",
473 m_create_info.title, cmd_id, m_frame_commands.size());
474}
475
476const std::vector<uint64_t>& GlfwWindow::get_frame_commands() const
477{
478 return m_frame_commands;
479}
480
482{
483 std::lock_guard lock(m_render_tracking_mutex);
484 m_frame_commands.clear();
485}
486
487std::vector<std::shared_ptr<Buffers::VKBuffer>> GlfwWindow::get_rendering_buffers() const
488{
489 std::lock_guard lock(m_render_tracking_mutex);
490
491 std::vector<std::shared_ptr<Buffers::VKBuffer>> buffers;
492 for (const auto& weak_buf : m_rendering_buffers) {
493 if (auto buf = weak_buf.lock()) {
494 buffers.push_back(buf);
495 }
496 }
497 return buffers;
498}
499
500}
#define MF_INFO(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
static void mark_window_created()
Increments the count of active GLFW windows.
static void mark_window_destroyed()
Decrements the count of active GLFW windows.
static bool initialize()
Initializes the GLFW library if not already initialized.
static void configure(const GlfwPreInitConfig &config)
Configures GLFW with pre-initialization hints.
void clear_frame_commands() override
Clear tracked commands for this frame.
void register_rendering_buffer(std::shared_ptr< Buffers::VKBuffer > buffer) override
Register a VKBuffer as rendering to this window.
std::vector< std::weak_ptr< Buffers::VKBuffer > > m_rendering_buffers
bool should_close() const override
Poll for window events (non-blocking)
void * get_native_display() const override
Get native display handle (platform-specific)
static void glfw_scroll_callback(GLFWwindow *window, double xoffset, double yoffset)
void set_graphics_registered(bool registered) override
Mark window as registered/unregistered with graphics Called by GraphicsSubsystem during register/unre...
static void glfw_key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
WindowCreateInfo m_create_info
static void glfw_cursor_pos_callback(GLFWwindow *window, double xpos, double ypos)
void * get_native_handle() const override
Get native window handle (platform-specific)
void show() override
Show the window.
void set_title(const std::string &title) override
Set window title, size, or position.
static void glfw_window_size_callback(GLFWwindow *window, int width, int height)
const std::vector< uint64_t > & get_frame_commands() const override
Get all command buffers recorded for this frame.
void set_position(uint32_t x, uint32_t y) override
Move the window to a new position.
void set_event_callback(WindowEventCallback callback) override
Set the callback function for window events.
void destroy() override
Destroy the window and release resources.
std::atomic< bool > m_graphics_registered
static void glfw_window_focus_callback(GLFWwindow *window, int focused)
void unregister_rendering_buffer(std::shared_ptr< Buffers::VKBuffer > buffer) override
Unregister a VKBuffer from this window.
GlfwWindow & operator=(const GlfwWindow &)=delete
static void glfw_mouse_button_callback(GLFWwindow *window, int button, int action, int mods)
void track_frame_command(uint64_t cmd_id) override
Track a secondary command buffer for this frame.
void hide() override
Hide the window.
void configure_window_hints(const GraphicsSurfaceInfo &surface_info, GlobalGraphicsConfig::GraphicsApi api) const
std::vector< std::shared_ptr< Buffers::VKBuffer > > get_rendering_buffers() const override
Get all VKBuffers currently rendering to this window.
static void glfw_window_close_callback(GLFWwindow *window)
void set_size(uint32_t width, uint32_t height) override
Resize the window.
std::vector< uint64_t > m_frame_commands
static void glfw_framebuffer_size_callback(GLFWwindow *window, int width, int height)
WindowEventCallback m_event_callback
GlfwWindow(const WindowCreateInfo &create_info, const GraphicsSurfaceInfo &surface_info, GlobalGraphicsConfig::GraphicsApi api, GlfwPreInitConfig pre_init_config={})
Creates a window with the given configuration.
Platform-agnostic window wrapper.
WindowEventType
Types of window and input events.
std::function< void(const WindowEvent &)> WindowEventCallback
@ WindowingSubsystem
Windowing system operations (GLFW, SDL)
@ GraphicsCallback
Graphics/visual rendering callback - frame-rate real-time.
@ Core
Core engine, backend, subsystems.
Configuration hints for GLFW initialization.
System-wide configuration for visual stream processing.
bool transparent
Transparent framebuffer (compositing)
std::string title
Window title/identifier.
bool fullscreen
Start in fullscreen mode.
bool resizable
Window can be resized by user.
uint32_t width
Initial window dimensions.
int32_t monitor_id
Target monitor ID (-1 = primary monitor)
bool decorated
Show OS window decorations (title bar, borders)
Configuration for creating a single window instance.
Event data for window and input events.