diff options
| author | 2025-06-07 09:51:24 -0400 | |
|---|---|---|
| committer | 2025-06-07 09:51:24 -0400 | |
| commit | 658e476c3d43718a2c9eb2884f16ac37cc3f1da2 (patch) | |
| tree | d8851ea63b0cd666db050eb093d299d4a469f89f | |
| parent | a2e04b98512e9db93d5457ecc52ac385b9a9e0aa (diff) | |
| download | stela-658e476c3d43718a2c9eb2884f16ac37cc3f1da2.tar.gz stela-658e476c3d43718a2c9eb2884f16ac37cc3f1da2.tar.bz2 stela-658e476c3d43718a2c9eb2884f16ac37cc3f1da2.zip | |
Window events refactor, slight GL cleanup
- Support orientation and touch events from GLFM.
Signed-off-by: Andrew Opalach <andrew@akon.city>
| -rw-r--r-- | meson.build | 10 | ||||
| -rw-r--r-- | src/egl_common.c | 10 | ||||
| -rw-r--r-- | src/gl_common.h | 28 | ||||
| -rw-r--r-- | src/window.c | 194 | ||||
| -rw-r--r-- | src/window.h | 57 | ||||
| -rw-r--r-- | src/window_glfm.c | 70 | ||||
| -rw-r--r-- | src/window_glfm.h | 1 | ||||
| -rw-r--r-- | src/window_glfw.c | 101 | ||||
| -rw-r--r-- | src/window_kms.c | 1 | ||||
| -rw-r--r-- | src/window_wayland.c | 47 | ||||
| -rw-r--r-- | src/window_win32.c | 40 | ||||
| -rw-r--r-- | src/window_win32.h | 1 | ||||
| -rw-r--r-- | src/window_x11.c | 7 | ||||
| -rw-r--r-- | subprojects/libalabaster.wrap | 2 | ||||
| -rw-r--r-- | subprojects/libnaunet.wrap | 2 |
15 files changed, 340 insertions, 231 deletions
diff --git a/meson.build b/meson.build index 95e7991..dbe46b6 100644 --- a/meson.build +++ b/meson.build @@ -74,18 +74,22 @@ elif get_option('api') in ['gl', 'gles'] egl = dependency('egl') stela_deps += [egl] stela_src += ['src/egl_common.c'] - elif get_option('window') == 'win32' - stela_deps += [compiler.find_library('opengl32')] endif if use_glad glad_opts = use_gles ? 'use_gles=true' : 'use_gles=false' stela_deps += [subproject('glad', default_options: glad_opts).get_variable('glad')] stela_args += ['-DSTELA_USE_GLAD'] - elif not is_android and not is_windows + elif is_windows + stela_deps += [compiler.find_library('opengl32')] + elif not is_android stela_deps += [dependency('gl')] endif if use_gles stela_args += ['-DSTELA_USE_GLES'] + else + if compiler.has_header('GL/glext.h') + stela_args += ['-DSTELA_HAS_GLEXT'] + endif endif stela_src += ['src/gl_common.c'] stela_args += ['-DSTELA_API_OPENGL'] diff --git a/src/egl_common.c b/src/egl_common.c index ad2bea3..7ed6a62 100644 --- a/src/egl_common.c +++ b/src/egl_common.c @@ -2,6 +2,7 @@ #include <al/log.h> #include <al/macros.h> +#ifdef STELA_API_OPENGL #include "egl_common.h" #define STELA_GL_API EGL_OPENGL_API @@ -16,6 +17,7 @@ #include "gl_versions.h" PASTE_GL_VERSIONS() +#endif bool stl_maybe_load_egl(void) { @@ -185,7 +187,6 @@ bool stl_egl_make_current(struct stl_egl *egl) void stl_egl_release_current(struct stl_egl *egl) { - al_assert(egl->context == egl->current); // https://gitlab.freedesktop.org/mesa/mesa/-/issues/6547 // libplacebo calls release_current() after swapping buffers. That locks in the // current backbuffer size. So, if all that happens for the next frame is: @@ -196,9 +197,12 @@ void stl_egl_release_current(struct stl_egl *egl) // 5. swap buffers // The frame that is presented will still have the dimensions of the previous backbuffer. // We only support 1 context at a time, so this shouldn't be an issue. + al_assert(egl->context == egl->current); #if 0 - eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - egl->current = EGL_NO_CONTEXT; + if (egl->current != EGL_NO_CONTEXT) { + eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + egl->current = EGL_NO_CONTEXT; + } #endif } diff --git a/src/gl_common.h b/src/gl_common.h index ae49215..9173aa4 100644 --- a/src/gl_common.h +++ b/src/gl_common.h @@ -4,9 +4,6 @@ #include <nnwt/windows.h> #endif -#ifdef STELA_WINDOW_GLFM -#include <glfm.h> -#else #ifdef STELA_USE_GLAD #ifdef STELA_USE_GLES #include <glad/gles2.h> @@ -16,29 +13,24 @@ #else #ifdef STELA_USE_GLES #include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES2/gl2platform.h> +/* +#include <GLES3/gl3.h> +#include <GLES3/gl31.h> +#include <GLES3/gl32.h> +#include <GLES3/gl3ext.h> +#include <GLES3/gl3platform.h> +*/ #else #define GL_GLEXT_PROTOTYPES #include <GL/gl.h> -#ifndef NAUNET_ON_WINDOWS +#ifdef STELA_HAS_GLEXT #include <GL/glext.h> #include <GL/glcorearb.h> #endif #endif #endif -#endif - -#ifdef NAUNET_ON_WINDOWS -// https://registry.khronos.org/OpenGL/api/GL/wgl.h -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif bool stl_gl_check_error(); bool stl_gl_loader_load(void (*(*get_proc_address)(const char *))(void)); diff --git a/src/window.c b/src/window.c index 6f57c80..08dc625 100644 --- a/src/window.c +++ b/src/window.c @@ -3,10 +3,55 @@ #include "window.h" +static bool nop_pointer_pos_callback(void *userdata, f64 x, f64 y) +{ + (void)userdata; + (void)x; + (void)y; + return false; +} + +static bool nop_touch_callback(void *userdata, s32 index, u8 phase, f64 x, f64 y) +{ + (void)userdata; + (void)index; + (void)phase; + (void)x; + (void)y; + return false; +} + +static bool nop_scroll_callback(void *userdata, f64 y) +{ + (void)userdata; + (void)y; + return false; +} + +static bool nop_mouse_button_callback(void *userdata, u8 state, u8 button) +{ + (void)userdata; + (void)state; + (void)button; + return false; +} + +static bool nop_key_callback(void *userdata, u8 state, u16 button) +{ + (void)userdata; + (void)state; + (void)button; + return false; +} + void stl_window_init(struct stl_window *window) { + window->pointer_pos_callback = nop_pointer_pos_callback; + window->touch_callback = nop_touch_callback; + window->scroll_callback = nop_scroll_callback; + window->mouse_button_callback = nop_mouse_button_callback; + window->key_callback = nop_key_callback; #ifdef STELA_EVENT_BUFFER - window->data = al_malloc(STELA_EVENTS_SIZE); al_ring_buffer_init(&window->events, window->data, STELA_EVENTS_SIZE); #endif #ifdef STELA_PAUSE @@ -21,9 +66,16 @@ void stl_window_created(struct stl_window *window, u32 width, u32 height, u32 fl window->flags = flags; } +void stl_window_send_render_event(struct stl_window *window) +{ + if (window->render_callback) { + window->render_callback(window->userdata); + } +} + #ifdef STELA_EVENT_BUFFER #define GET_EVENT_CHUNK(op) \ - size_t size; \ + ptrdiff_t size; \ u8 *ptr = al_ring_buffer_write_chunk(&window->events, &size); \ if (size < STELA_EVENT_SIZE) { \ log_warn("Buffer full, discarding event."); \ @@ -35,6 +87,22 @@ void stl_window_created(struct stl_window *window, u32 width, u32 height, u32 fl #define APPEND_EVENT_CHUNK() \ al_ring_buffer_append(&window->events, ptr, STELA_EVENT_SIZE) +void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height) +{ + al_assert(width == window->width && height == window->height); +#ifdef STELA_EVENT_BUFFER + window->pending_resize = true; +#else + window->resize_internal(window, width, height); + if (window->resize_callback) { + window->resize_callback(window->userdata, width, height); + } +#ifdef STELA_PAUSE + window->pending_refresh = true; +#endif +#endif +} + void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y) { #ifdef STELA_EVENT_BUFFER @@ -43,13 +111,27 @@ void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y) ((f64 *)(&ptr[9]))[0] = y; APPEND_EVENT_CHUNK(); #else - if (window->pointer_pos_callback) { - if (window->pointer_pos_callback(window->userdata, x, y)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->pointer_pos_callback(window->userdata, x, y); +#endif +} + +void stl_window_send_touch_event(struct stl_window *window, s32 index, u8 phase, f64 x, f64 y) +{ +#ifdef STELA_EVENT_BUFFER + GET_EVENT_CHUNK(STELA_EVENT_TOUCH); + ((s32 *)(&ptr[1]))[0] = index; + ptr[5] = phase; + ((f64 *)(&ptr[6]))[0] = x; + ((f64 *)(&ptr[14]))[0] = y; + APPEND_EVENT_CHUNK(); +#else +#ifdef STELA_PAUSE + window->pending_refresh |= +#endif + window->touch_callback(window->userdata, index, phase, x, y); #endif } @@ -60,13 +142,10 @@ void stl_window_send_scroll_event(struct stl_window *window, f64 y) ((f64 *)(&ptr[1]))[0] = y; APPEND_EVENT_CHUNK(); #else - if (window->scroll_callback) { - if (window->scroll_callback(window->userdata, y)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->scroll_callback(window->userdata, y); #endif } @@ -78,13 +157,10 @@ void stl_window_send_mouse_button_event(struct stl_window *window, u8 state, u8 ptr[2] = button; APPEND_EVENT_CHUNK(); #else - if (window->mouse_button_callback) { - if (window->mouse_button_callback(window->userdata, state, button)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->mouse_button_callback(window->userdata, state, button); #endif } @@ -96,52 +172,20 @@ void stl_window_send_key_event(struct stl_window *window, u8 state, u16 button) ((u16 *)(&ptr[2]))[0] = button; APPEND_EVENT_CHUNK(); #else - if (window->key_callback) { - if (window->key_callback(window->userdata, state, button)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->key_callback(window->userdata, state, button); #endif } -void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height) +void stl_window_send_key_immediate_event(struct stl_window *window, u8 state, u16 button) { -#ifdef STELA_EVENT_BUFFER - (void)width; - (void)height; - window->pending_resize = true; -#else - window->resize_internal(window, width, height); - if (window->resize_callback) { - window->resize_callback(window->userdata, width, height); + if (window->key_immediate_callback) { + window->key_immediate_callback(window->userdata, state, button); } -#ifdef STELA_PAUSE - window->pending_refresh = true; -#endif -#endif } -void stl_window_send_render_event(struct stl_window *window) -{ - if (window->render_callback) { - window->render_callback(window->userdata); - } -} - -#ifdef STELA_POLL_INLINE -void stl_window_send_refresh_event(struct stl_window *window) -{ - if (window->refresh_callback) { - window->refresh_callback(window->userdata); - } -#ifdef STELA_PAUSE - window->pending_refresh = true; -#endif -} -#endif - void stl_window_send_should_close_event(struct stl_window *window) { #ifdef STELA_EVENT_BUFFER @@ -160,70 +204,56 @@ bool stl_window_read_events(struct stl_window *window) u8 op = STELA_EVENT_NONE; if (window->pending_resize) { - u32 width = window->width; - u32 height = window->height; - window->resize_internal(window, width, height); + op = STELA_EVENT_RESIZE; + window->resize_internal(window, window->width, window->height); if (window->resize_callback) { - window->resize_callback(window->userdata, width, height); + window->resize_callback(window->userdata, window->width, window->height); } #ifdef STELA_PAUSE window->pending_refresh = true; #endif window->pending_resize = false; - op = STELA_EVENT_RESIZE; } - size_t size; + ptrdiff_t size; u8 *ptr = al_ring_buffer_read_chunk(&window->events, &size); u8 *bc = ptr; - while ((size_t)(bc - ptr) < size) { + while (bc - ptr < size) { op = *bc; switch (op) { case STELA_EVENT_POINTER_POS: { f64 x = ((f64 *)(&bc[1]))[0]; f64 y = ((f64 *)(&bc[9]))[0]; - if (window->pointer_pos_callback) { - if (window->pointer_pos_callback(window->userdata, x, y)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->pointer_pos_callback(window->userdata, x, y); break; } case STELA_EVENT_SCROLL: { f64 y = ((f64 *)(&bc[1]))[0]; - if (window->scroll_callback) { - if (window->scroll_callback(window->userdata, y)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->scroll_callback(window->userdata, y); break; } case STELA_EVENT_MOUSE_BUTTON: { u8 state = bc[1]; u8 button = bc[2]; - if (window->mouse_button_callback) { - if (window->mouse_button_callback(window->userdata, state, button)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->mouse_button_callback(window->userdata, state, button); break; } case STELA_EVENT_KEY: { u8 state = bc[1]; u16 button = ((u16 *)(&bc[2]))[0]; - if (window->key_callback) { - if (window->key_callback(window->userdata, state, button)) { #ifdef STELA_PAUSE - window->pending_refresh = true; + window->pending_refresh |= #endif - } - } + window->key_callback(window->userdata, state, button); break; } case STELA_EVENT_SHOULD_CLOSE: { @@ -237,7 +267,7 @@ bool stl_window_read_events(struct stl_window *window) } bc += STELA_EVENT_SIZE; } - al_assert((size_t)(bc - ptr) == size); + al_assert(bc - ptr == size); al_ring_buffer_consume(&window->events, ptr, size); return op != STELA_EVENT_NONE; diff --git a/src/window.h b/src/window.h index d22b13d..cd4e81f 100644 --- a/src/window.h +++ b/src/window.h @@ -33,11 +33,11 @@ #endif #ifndef STELA_MIN_WIDTH -#define STELA_MIN_WIDTH 16 +#define STELA_MIN_WIDTH 16u #endif #ifndef STELA_MIN_HEIGHT -#define STELA_MIN_HEIGHT 16 +#define STELA_MIN_HEIGHT 16u #endif enum { @@ -55,21 +55,17 @@ struct stl_monitor { char name[STELA_MAX_MONITOR_NAME]; }; +#define STELA_EVENT_SIZE 24u +#ifndef STELA_EVENTS_SIZE +#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 64u) +#endif + struct stl_window { u32 width; u32 height; u32 scale; bool fullscreen; u32 flags; -#ifdef STELA_EVENT_BUFFER - u8 *data; - // Render thread events. - struct al_ring_buffer events; - bool pending_resize; -#endif -#ifdef STELA_PAUSE - bool pending_refresh; -#endif // Methods. bool (*create_window)(struct stl_window *, u32, u32, const char *, const char *, u32); void (*resize_internal)(struct stl_window *, u32, u32); @@ -108,24 +104,34 @@ struct stl_window { // Callbacks. void (*output_discovered_callback)(void *, struct stl_monitor *); void (*render_callback)(void *); - void (*refresh_callback)(void *); + void (*resize_callback)(void *, u32, u32); bool (*pointer_pos_callback)(void *, f64, f64); + bool (*touch_callback)(void *, s32, u8, f64, f64); bool (*scroll_callback)(void *, f64); bool (*mouse_button_callback)(void *, u8, u8); bool (*key_callback)(void *, u8, u16); - // Always runs on the thread that's processing events. + // Always runs on the thread that received the key event. void (*key_immediate_callback)(void *, u8, u16); - void (*resize_callback)(void *, u32, u32); void (*should_close_callback)(void *); void *userdata; +#ifdef STELA_PAUSE + bool pending_refresh; +#endif +#ifdef STELA_EVENT_BUFFER + bool pending_resize; + // Render thread events. + struct al_ring_buffer events; + u8 data[STELA_EVENTS_SIZE]; +#endif }; enum { - STELA_EVENT_POINTER_POS = 0, + STELA_EVENT_RESIZE = 0, + STELA_EVENT_POINTER_POS, + STELA_EVENT_TOUCH, STELA_EVENT_SCROLL, STELA_EVENT_MOUSE_BUTTON, STELA_EVENT_KEY, - STELA_EVENT_RESIZE, STELA_EVENT_SHOULD_CLOSE, STELA_EVENT_NONE = 255 }; @@ -141,10 +147,13 @@ enum { STELA_MOUSE3 = 1 << 2 }; -#define STELA_EVENT_SIZE 32 -#ifndef STELA_EVENTS_SIZE -#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 128) -#endif +enum { + STELA_TOUCH_HOVER = 0, + STELA_TOUCH_BEGAN, + STELA_TOUCH_MOVED, + STELA_TOUCH_ENDED, + STELA_TOUCH_CANCELLED +}; extern s32 stl_platform_main(u32 argc, str *argv); @@ -157,14 +166,14 @@ s32 stl_swallow_main(u32 argc, str *argv, s32 (*main)(u32, str *, void *), void void stl_global_close(void); struct stl_window *stl_window_create(void); +void stl_window_send_render_event(struct stl_window *window); +void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height); void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y); +void stl_window_send_touch_event(struct stl_window *window, s32 index, u8 phase, f64 x, f64 y); void stl_window_send_scroll_event(struct stl_window *window, f64 y); void stl_window_send_mouse_button_event(struct stl_window *window, u8 state, u8 button); void stl_window_send_key_event(struct stl_window *window, u8 state, u16 button); -void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height); -#ifdef STELA_POLL_INLINE -void stl_window_send_refresh_event(struct stl_window *window); -#endif +void stl_window_send_key_immediate_event(struct stl_window *window, u8 state, u16 button); void stl_window_send_should_close_event(struct stl_window *window); #ifdef STELA_EVENT_BUFFER bool stl_window_read_events(struct stl_window *window); diff --git a/src/window_glfm.c b/src/window_glfm.c index b230f48..39de449 100644 --- a/src/window_glfm.c +++ b/src/window_glfm.c @@ -36,46 +36,92 @@ void stl_global_close(void) static void onSurfaceCreated(GLFMDisplay *display, s32 width, s32 height) { - GLFMRenderingAPI api = glfmGetRenderingAPI(display); (void)width; (void)height; - log_info("Created GLES context of version %s.", - api == GLFMRenderingAPIOpenGLES32 ? "3.2" : - api == GLFMRenderingAPIOpenGLES31 ? "3.1" : - api == GLFMRenderingAPIOpenGLES3 ? "3.0" : "2.0"); if (!global.did_main) { stl_platform_main(0, NULL); global.did_main = true; } + GLFMRenderingAPI api = glfmGetRenderingAPI(display); + log_info("Created GLES context of version %s.", + api == GLFMRenderingAPIOpenGLES32 ? "3.2" : + api == GLFMRenderingAPIOpenGLES31 ? "3.1" : + api == GLFMRenderingAPIOpenGLES3 ? "3.0" : "2.0"); +} + +static void onDraw(GLFMDisplay *display) +{ + struct stl_window_glfm *glfm = (struct stl_window_glfm *)glfmGetUserData(display); + stl_window_send_render_event(&glfm->w); } static void onSurfaceDestroyed(GLFMDisplay *display) { - (void)display; + struct stl_window_glfm *glfm = (struct stl_window_glfm *)glfmGetUserData(display); + stl_window_send_should_close_event(&glfm->w); } -static void onDraw(GLFMDisplay *display) +static void swap_dimensions_and_send_resize(struct stl_window_glfm *glfm) +{ + SWAP(glfm->w.width, glfm->w.height); + stl_window_send_resize_event(&glfm->w, glfm->w.width, glfm->w.height); +} + +static void onOrientationChanged(GLFMDisplay *display, GLFMInterfaceOrientation orientation) { struct stl_window_glfm *glfm = (struct stl_window_glfm *)glfmGetUserData(display); - if (glfm->w.render_callback) { - glfm->w.render_callback(glfm->w.userdata); + if (orientation & (GLFMInterfaceOrientationPortrait | GLFMInterfaceOrientationPortraitUpsideDown)) { + if (!(global.orientation & (GLFMInterfaceOrientationPortrait | GLFMInterfaceOrientationPortraitUpsideDown))) { + swap_dimensions_and_send_resize(glfm); + } + } else if (orientation & (GLFMInterfaceOrientationLandscapeLeft | GLFMInterfaceOrientationLandscapeRight)) { + if (!(global.orientation & (GLFMInterfaceOrientationLandscapeLeft | GLFMInterfaceOrientationLandscapeRight))) { + swap_dimensions_and_send_resize(glfm); + } } + global.orientation = orientation; +} + +static u8 glfm_to_stela_touch[] = { + [GLFMTouchPhaseHover] = STELA_TOUCH_HOVER, + [GLFMTouchPhaseBegan] = STELA_TOUCH_BEGAN, + [GLFMTouchPhaseMoved] = STELA_TOUCH_MOVED, + [GLFMTouchPhaseEnded] = STELA_TOUCH_ENDED, + [GLFMTouchPhaseCancelled] = STELA_TOUCH_CANCELLED +}; + +static bool onTouch(GLFMDisplay *display, s32 touch, GLFMTouchPhase phase, f64 x, f64 y) +{ + struct stl_window_glfm *glfm = (struct stl_window_glfm *)glfmGetUserData(display); + stl_window_send_touch_event(&glfm->w, touch, glfm_to_stela_touch[phase], x, y); + return true; } void glfmMain(GLFMDisplay *display) { - nn_common_init(); + nn_common_init("glfmMain"); stl_global_init(false); global.display = display; +#define STELA_INCLUDE_DEPTH_BUFFER glfmSetDisplayConfig(display, - GLFMRenderingAPIOpenGLES2, + GLFMRenderingAPIOpenGLES32, GLFMColorFormatRGBA8888, +#ifdef STELA_INCLUDE_DEPTH_BUFFER + GLFMDepthFormat24, + GLFMStencilFormat8, +#else GLFMDepthFormatNone, GLFMStencilFormatNone, +#endif GLFMMultisampleNone); + global.orientation = glfmGetInterfaceOrientation(display); + glfmSetDisplayChrome(display, GLFMUserInterfaceChromeNone); + glfmSetMultitouchEnabled(display, true); glfmSetSurfaceCreatedFunc(display, onSurfaceCreated); - glfmSetSurfaceDestroyedFunc(display, onSurfaceDestroyed); glfmSetRenderFunc(display, onDraw); + glfmSetSurfaceDestroyedFunc(display, onSurfaceDestroyed); + glfmSetOrientationChangedFunc(display, onOrientationChanged); + glfmSetTouchFunc(display, onTouch); } static bool window_glfm_create_window(struct stl_window *window, u32 width, u32 height, diff --git a/src/window_glfm.h b/src/window_glfm.h index f3703b9..bfbda04 100644 --- a/src/window_glfm.h +++ b/src/window_glfm.h @@ -7,6 +7,7 @@ struct stl_glfm_global { GLFMDisplay *display; bool did_main; + GLFMInterfaceOrientation orientation; }; struct stl_window_glfm { diff --git a/src/window_glfw.c b/src/window_glfw.c index 5892bfb..b7b3b30 100644 --- a/src/window_glfw.c +++ b/src/window_glfw.c @@ -72,21 +72,31 @@ void stl_global_close(void) glfwTerminate(); } -static void key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 mods) +static void resize_callback(GLFWwindow *window, s32 event_width, s32 event_height) { struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); - (void)scancode; - (void)mods; - al_assert(key >= 0 && key <= UINT16_MAX); - if (key == GLFW_KEY_F25 || key == GLFW_KEY_WORLD_1 || key == GLFW_KEY_WORLD_2) { - log_warn("Unmapped GLFW key pressed (%hu).", (u16)key); + if (event_width <= 0 || event_height <= 0) { + // This happens on Windows when minimizing. return; } - u8 key_state = action == GLFW_PRESS ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED; - if (glfw->w.key_immediate_callback) { - glfw->w.key_immediate_callback(glfw->w.userdata, key_state, (u16)key); + + u32 width = (u32)event_width; + u32 height = (u32)event_height; + if (width == glfw->w.width && height == glfw->w.height) { + return; } - stl_window_send_key_event(&glfw->w, key_state, (u16)key); + + glfw->w.width = (u32)width; + glfw->w.height = (u32)height; + + stl_window_send_resize_event(&glfw->w, glfw->w.width, glfw->w.height); +} + +static void content_scale_callback(GLFWwindow *window, f32 xscale, f32 yscale) +{ + struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); + glfw->scale_x = xscale; + glfw->scale_y = yscale; } static void cursor_position_callback(GLFWwindow *window, f64 xpos, f64 ypos) @@ -97,6 +107,13 @@ static void cursor_position_callback(GLFWwindow *window, f64 xpos, f64 ypos) stl_window_send_pointer_pos_event(&glfw->w, xpos, ypos); } +static void scroll_callback(GLFWwindow *window, f64 xoffset, f64 yoffset) +{ + struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); + (void)xoffset; + stl_window_send_scroll_event(&glfw->w, -yoffset); +} + static void mouse_button_callback(GLFWwindow *window, s32 button, s32 action, s32 mods) { struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); @@ -126,47 +143,20 @@ static void mouse_button_callback(GLFWwindow *window, s32 button, s32 action, s3 } } -static void scroll_callback(GLFWwindow *window, f64 xoffset, f64 yoffset) -{ - struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); - (void)xoffset; - stl_window_send_scroll_event(&glfw->w, -yoffset); -} - -static void resize_callback(GLFWwindow *window, s32 event_width, s32 event_height) +static void key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action, s32 mods) { struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); - if (event_width <= 0 || event_height <= 0) { - // This happens on Windows when minimizing. - return; - } - - u32 width = (u32)event_width; - u32 height = (u32)event_height; - if (width == glfw->w.width && height == glfw->w.height) { + (void)scancode; + (void)mods; + al_assert(key >= 0 && key <= UINT16_MAX); + if (key == GLFW_KEY_F25 || key == GLFW_KEY_WORLD_1 || key == GLFW_KEY_WORLD_2) { + log_warn("Unmapped GLFW key pressed (%hu).", (u16)key); return; } - - glfw->w.width = (u32)width; - glfw->w.height = (u32)height; - - stl_window_send_resize_event(&glfw->w, glfw->w.width, glfw->w.height); -} - -static void content_scale_callback(GLFWwindow *window, f32 xscale, f32 yscale) -{ - struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); - glfw->scale_x = xscale; - glfw->scale_y = yscale; -} - -#ifdef STELA_POLL_INLINE -static void refresh_callback(GLFWwindow *window) -{ - struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window); - stl_window_send_refresh_event(&glfw->w); + u8 key_state = action == GLFW_PRESS ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED; + stl_window_send_key_immediate_event(&glfw->w, key_state, (u16)key); + stl_window_send_key_event(&glfw->w, key_state, (u16)key); } -#endif static void close_callback(GLFWwindow *window) { @@ -264,17 +254,14 @@ static bool window_glfw_create_window(struct stl_window *window, u32 width, u32 glfwSetWindowUserPointer(glfw->window, glfw); - glfwSetKeyCallback(glfw->window, key_callback); - glfwSetCursorPosCallback(glfw->window, cursor_position_callback); - glfwSetMouseButtonCallback(glfw->window, mouse_button_callback); - glfwSetScrollCallback(glfw->window, scroll_callback); //glfwSetFramebufferSizeCallback(glfw->window, resize_callback); glfwSetWindowSizeCallback(glfw->window, resize_callback); glfwSetWindowContentScaleCallback(glfw->window, content_scale_callback); -#ifdef STELA_POLL_INLINE - glfwSetWindowRefreshCallback(glfw->window, refresh_callback); -#endif - // This seems to be called if we block too long after creating a window. + glfwSetCursorPosCallback(glfw->window, cursor_position_callback); + glfwSetScrollCallback(glfw->window, scroll_callback); + glfwSetMouseButtonCallback(glfw->window, mouse_button_callback); + glfwSetKeyCallback(glfw->window, key_callback); + // A Wayland window will trigger CloseCallback if it's lagging too hard. glfwSetWindowCloseCallback(glfw->window, close_callback); return true; @@ -367,6 +354,9 @@ static void window_glfw_toggle_fullscreen(struct stl_window *window) } #ifdef STELA_POLL_INLINE +#ifdef STELA_EVENT_BUFFER +#error "window_glfw_poll() is incompatible with event buffer mode." +#endif static bool window_glfw_poll(struct stl_window *window, bool block) { (void)window; @@ -403,9 +393,6 @@ static void window_glfw_free(struct stl_window **window) if (glfw->window) { glfwDestroyWindow(glfw->window); } -#ifdef STELA_EVENT_BUFFER - al_free(glfw->w.data); -#endif al_free(glfw); *window = NULL; } diff --git a/src/window_kms.c b/src/window_kms.c index 93192e6..15d1532 100644 --- a/src/window_kms.c +++ b/src/window_kms.c @@ -1,4 +1,5 @@ #include "window_kms.h" +#include "common.h" void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct stl_monitor *), void *userdata) { diff --git a/src/window_wayland.c b/src/window_wayland.c index 1ed597d..530daf2 100644 --- a/src/window_wayland.c +++ b/src/window_wayland.c @@ -567,9 +567,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, } u8 key_state = state == WL_KEYBOARD_KEY_STATE_PRESSED ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED; - if (wl->w.key_immediate_callback) { - wl->w.key_immediate_callback(wl->w.userdata, key_state, global.keycodes[key]); - } + stl_window_send_key_immediate_event(&wl->w, key_state, global.keycodes[key]); stl_window_send_key_event(&wl->w, key_state, global.keycodes[key]); } @@ -1040,7 +1038,7 @@ static void window_wayland_set_decorations(struct stl_window *window, bool enabl u32 mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; zxdg_toplevel_decoration_v1_set_mode(wl->zxdg_toplevel_decoration, mode); wl->decorated = false; - } else if (!wl->decorated) { + } else if (enabled && !wl->decorated) { u32 mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; zxdg_toplevel_decoration_v1_set_mode(wl->zxdg_toplevel_decoration, mode); wl->decorated = true; @@ -1116,18 +1114,45 @@ void window_wayland_free(struct stl_window **window) if (wl->layer_shell) zwlr_layer_shell_v1_destroy(wl->layer_shell); if (wl->compositor) wl_compositor_destroy(wl->compositor); #ifdef STELA_API_OPENGL - if (stl_egl_is_ready(&wl->egl)) { - stl_egl_destroy_context(&wl->egl); - } -#endif -#ifdef STELA_EVENT_BUFFER - al_free(wl->w.data); + if (stl_egl_is_ready(&wl->egl)) stl_egl_destroy_context(&wl->egl); #endif al_free(wl); *window = NULL; } -#ifdef STELA_API_OPENGL +#if defined STELA_API_VULKAN +static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL get_vk_proc_address(VkInstance inst, const char *name) +{ + void *vk_module = dlopen("libvulkan.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!vk_module) return NULL; + PFN_vkVoidFunction vk_get_proc_addr = dlsym(vk_module, "vkGetInstanceProcAddr"); + if (!vk_get_proc_addr) return NULL; + return (PFN_vkVoidFunction)vk_get_proc_addr(inst, name); +} + +static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL window_win32_get_vk_proc_address(VkInstance inst, const char *name) +{ + if (strcmp(name, "vkGetInstanceProcAddr") == 0) { + return (PFN_vkVoidFunction)vk_get_proc_addr; + } + return vk_get_proc_addr(inst, name); +} + +static VkResult window_win32_vk_create_surface(void *window, VkInstance inst, VkSurfaceKHR *surface) +{ + struct stl_window_win32 *w32 = (struct stl_window_win32 *)window; + (void)w32; + (void)inst; + (void)surface; + return VK_ERROR_EXTENSION_NOT_PRESENT; +} + +static const char *const *window_win32_vk_get_extensions(u32 *num) +{ + (void)num; + return NULL; +} +#elif defined STELA_API_OPENGL static bool window_wayland_gl_loader_load(void *window) { struct stl_window_wayland *wl = (struct stl_window_wayland *)window; diff --git a/src/window_win32.c b/src/window_win32.c index 7edee49..f4baca8 100644 --- a/src/window_win32.c +++ b/src/window_win32.c @@ -8,6 +8,17 @@ #ifdef STELA_API_OPENGL #include "gl_common.h" +// https://registry.khronos.org/OpenGL/api/GL/wgl.h +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 + #define STELA_GL_API 1 #define STELA_GLES_API 2 @@ -728,9 +739,7 @@ static LRESULT CALLBACK DisplayWndProc(HWND Window, UINT Message, WPARAM WParam, case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: - if (w32->w.key_immediate_callback) { - w32->w.key_immediate_callback(w32->w.userdata, MESSAGE_TO_KEY_STATE(Message), Global.keycodes[WParam]); - } + stl_window_send_key_immediate_event(&w32->w, MESSAGE_TO_KEY_STATE(Message), Global.keycodes[WParam]); goto intercept; case WM_SIZE: goto intercept; @@ -890,6 +899,7 @@ static bool window_win32_create_window(struct stl_window *window, u32 width, u32 stl_window_created(&w32->w, width, height, flags); w32->Decorated = TRUE; + w32->UserDecorated = TRUE; w32->Prev.Style = GetWindowLong(w32->Window, GWL_STYLE); w32->WindowMoving = FALSE; w32->MouseButtonMask = 0; @@ -938,7 +948,7 @@ static void set_window_decorations(struct stl_window_win32 *w32, bool enabled) Style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU); SetWindowLong(w32->Window, GWL_STYLE, Style); w32->Decorated = FALSE; - } else if (!w32->Decorated) { + } else if (enabled && !w32->Decorated) { al_assert(w32->Prev.Style != 0); SetWindowLong(w32->Window, GWL_STYLE, w32->Prev.Style); w32->Decorated = TRUE; @@ -966,7 +976,9 @@ static void window_win32_toggle_fullscreen(struct stl_window *window) struct stl_monitor_win32 *Monitor = w32->Prev.Monitor; s32 X = w32->Prev.X - Monitor->X; s32 Y = w32->Prev.Y - Monitor->Y; - set_window_decorations(w32, true); + if (w32->UserDecorated) { + set_window_decorations(w32, true); + } ShowCursor(TRUE); SetWindowPos(w32->Window, HWND_NOTOPMOST, X, Y, w32->Prev.Width, w32->Prev.Height, SWP_FRAMECHANGED); } @@ -976,9 +988,12 @@ static void window_win32_toggle_fullscreen(struct stl_window *window) static void window_win32_set_decorations(struct stl_window *window, bool enabled) { struct stl_window_win32 *w32 = (struct stl_window_win32 *)window; - set_window_decorations(w32, enabled); - UINT Flags = SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE; - SetWindowPos(w32->Window, 0, 0, 0, 0, 0, Flags); + w32->UserDecorated = enabled; + if (!w32->w.fullscreen) { + set_window_decorations(w32, enabled); + UINT Flags = SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE; + SetWindowPos(w32->Window, 0, 0, 0, 0, 0, Flags); + } } static void win32_handle_message(struct stl_window_win32 *w32, MSG *Message) @@ -1076,6 +1091,9 @@ static void win32_handle_message(struct stl_window_win32 *w32, MSG *Message) } #ifdef STELA_POLL_INLINE +#ifdef STELA_EVENT_BUFFER +#error "window_win32_poll() is incompatible with event buffer mode." +#endif static bool window_win32_poll(struct stl_window *window, bool block) { struct stl_window_win32 *w32 = (struct stl_window_win32 *)window; @@ -1117,9 +1135,6 @@ static void window_win32_free(struct stl_window **window) struct stl_window_win32 *w32 = (struct stl_window_win32 *)*window; SendMessageW(Global.ServiceWindow, DESTROY_DANGEROUS_WINDOW, (WPARAM)w32->Window, 0); al_wstr_free(&w32->WindowName); -#ifdef STELA_EVENT_BUFFER - al_free(wl->w.data); -#endif al_free(w32); *window = NULL; } @@ -1129,8 +1144,7 @@ static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetVKProcAddress(VkInstance Inst { HMODULE VKModule = LoadLibraryA("vulkan-1.dll"); PFN_vkGetInstanceProcAddr GetInstanceProcAddr = (void *)GetProcAddress(VKModule, "vkGetInstanceProcAddr"); - PFN_vkVoidFunction proc = (PFN_vkVoidFunction)GetInstanceProcAddr(Inst, Name); - return proc; + return (PFN_vkVoidFunction)GetInstanceProcAddr(Inst, Name); } static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL window_win32_get_vk_proc_address(VkInstance inst, const char *name) diff --git a/src/window_win32.h b/src/window_win32.h index 35b0dc5..5fbb0f3 100644 --- a/src/window_win32.h +++ b/src/window_win32.h @@ -46,6 +46,7 @@ struct stl_window_win32 { LONG Style; } Prev; BOOL Decorated; + BOOL UserDecorated; BOOL WindowMoving; POINTS LastMousePos; u32 MouseButtonMask; diff --git a/src/window_x11.c b/src/window_x11.c index 0d8d870..06b6d51 100644 --- a/src/window_x11.c +++ b/src/window_x11.c @@ -253,9 +253,7 @@ static void handle_next_xevent(struct stl_window_x11 *xw) case KeyPress: case KeyRelease: { u8 key_state = xev.type == KeyPress ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED; - if (xw->w.key_immediate_callback) { - xw->w.key_immediate_callback(xw->w.userdata, key_state, xev.xkey.keycode); - } + stl_window_send_key_immediate_event(&xw->w, key_state, xev.xkey.keycode); stl_window_send_key_event(&xw->w, key_state, xev.xkey.keycode); break; } @@ -307,9 +305,6 @@ static void window_x11_free(struct stl_window **window) { struct stl_window_x11 *xw = (struct stl_window_x11 *)*window; // @TODO: Cleanup x11 stuff. -#ifdef STELA_EVENT_BUFFER - al_free(xw->w.data); -#endif al_free(xw); *window = NULL; } diff --git a/subprojects/libalabaster.wrap b/subprojects/libalabaster.wrap index 243dff8..81771ed 100644 --- a/subprojects/libalabaster.wrap +++ b/subprojects/libalabaster.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://git.akon.city/libalabaster -revision = ec99011aca3a9b92964c653d74d693e693ac052f +revision = b403770e7eb6e0a5a8ca14a24f91dbf214ffe917 depth = 1 diff --git a/subprojects/libnaunet.wrap b/subprojects/libnaunet.wrap index 3f43502..8388a93 100644 --- a/subprojects/libnaunet.wrap +++ b/subprojects/libnaunet.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://git.akon.city/libnaunet -revision = 6993b9814769668fb03b4d282734f20f63b16f9c +revision = 393e266f6bfceb25a97cd1cf28dfc72cac9e9f81 depth = 1 |