From f3f1661f69f180d50bf108811914de7ea5425a20 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Fri, 16 Apr 2021 19:38:26 +0200 Subject: [PATCH 01/49] sokol_app.h: start with multiwindow --- sokol_app.h | 622 +++++++++++++++++++++++++++++----------------------- 1 file changed, 344 insertions(+), 278 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 3619c0056..a041ff867 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1324,48 +1324,75 @@ typedef struct sapp_icon_desc { sapp_image_desc images[SAPP_MAX_ICONIMAGES]; } sapp_icon_desc; +/* + sapp_window_desc -typedef struct sapp_desc { + FIXME: docs +*/ +typedef struct sapp_window_desc { void (*init_cb)(void); // these are the user-provided callbacks without user data void (*frame_cb)(void); void (*cleanup_cb)(void); void (*event_cb)(const sapp_event*); - void (*fail_cb)(const char*); void* user_data; // these are the user-provided callbacks with user data void (*init_userdata_cb)(void*); void (*frame_userdata_cb)(void*); void (*cleanup_userdata_cb)(void*); void (*event_userdata_cb)(const sapp_event*, void*); - void (*fail_userdata_cb)(const char*, void*); - int width; // the preferred width of the window / canvas - int height; // the preferred height of the window / canvas + const char* title; // the window title as UTF-8 encoded string + int x; + int y; + int width; + int height; int sample_count; // MSAA sample count int swap_interval; // the preferred swap interval (ignored on some platforms) bool high_dpi; // whether the rendering canvas is full-resolution on HighDPI displays bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) - const char* window_title; // the window title as UTF-8 encoded string bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR - bool enable_clipboard; // enable clipboard access, default is false - int clipboard_size; // max size of clipboard content in bytes bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false int max_dropped_files; // max number of dropped files to process (default: 1) int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8 file path (default: 2048) - sapp_icon_desc icon; // the initial window icon to set - - /* backend-specific options */ - bool gl_force_gles2; // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available - bool win32_console_utf8; // if true, set the output console codepage to UTF-8 - bool win32_console_create; // if true, attach stdout/stderr to a new console window - bool win32_console_attach; // if true, attach stdout/stderr to parent process - const char* html5_canvas_name; // the name (id) of the HTML5 canvas element, default is "canvas" - bool html5_canvas_resize; // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked - bool html5_preserve_drawing_buffer; // HTML5 only: whether to preserve default framebuffer content between frames - bool html5_premultiplied_alpha; // HTML5 only: whether the rendered pixels use premultiplied alpha convention - bool html5_ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) - bool ios_keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas + bool enable_clipboard; + int clipboard_size; +} sapp_window_desc; + +typedef struct sapp_gl_desc { + bool force_gles2; // if true, setup GLES2/WebGL even if GLES3/WebGL2 is available +} sapp_gl_desc; + +typedef struct sapp_win32_desc { + bool console_utf8; // if true, set the output console codepage to UTF-8 + bool console_create; // if true, attach stdout/stderr to a new console window + bool console_attach; // if true, attach stdout/stderr to parent process +} sapp_win32_desc; + +typedef struct sapp_html5_desc { + const char* canvas_name; // the name (id) of the HTML5 canvas element, default is "canvas" + bool canvas_resize; // if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked + bool preserve_drawing_buffer; // HTML5 only: whether to preserve default framebuffer content between frames + bool premultiplied_alpha; // HTML5 only: whether the rendered pixels use premultiplied alpha convention + bool ask_leave_site; // initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) +} sapp_html5_desc; + +typedef struct sapp_ios_desc { + bool keyboard_resizes_canvas; // if true, showing the iOS keyboard shrinks the canvas +} sapp_ios_desc; + +typedef struct sapp_desc { + sapp_window_desc window; + sapp_icon_desc icon; // FIXME: per-window icons? + sapp_gl_desc gl; + sapp_win32_desc win32; + sapp_html5_desc html5; + sapp_ios_desc ios; + + // FIXME: fail callback for error handling isn't all that useful... + void* fail_user_data; + void (*fail_cb)(const char*); + void (*fail_userdata_cb)(const char*, void*); } sapp_desc; /* HTML5 specific: request and response structs for @@ -1798,13 +1825,17 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif // SOKOL_GLCORE33 typedef struct { - uint32_t flags_changed_store; - uint8_t mouse_buttons; - NSWindow* window; + NSWindow* ns_window; NSTrackingArea* tracking_area; - _sapp_macos_app_delegate* app_dlg; - _sapp_macos_window_delegate* win_dlg; + _sapp_macos_window_delegate* delegate; _sapp_macos_view* view; + uint32_t flags_changed_store; + uint8_t mouse_buttons; +} _sapp_macos_window_t; + +typedef struct { + _sapp_macos_window_t win; + _sapp_macos_app_delegate* app_delegate; #if defined(SOKOL_METAL) id mtl_device; #endif @@ -1869,10 +1900,12 @@ typedef struct { bool wants_show_keyboard; bool wants_hide_keyboard; bool mouse_lock_requested; + bool ask_leave_site; uint16_t mouse_buttons; #if defined(SOKOL_WGPU) _sapp_wgpu_t wgpu; #endif + char canvas_selector[_SAPP_MAX_TITLE_LENGTH]; } _sapp_emsc_t; #endif // _SAPP_EMSCRIPTEN @@ -2247,30 +2280,62 @@ typedef struct { } _sapp_mouse_t; typedef struct { - sapp_desc desc; - bool valid; + uint32_t id; +} _sapp_slot_t; + +typedef struct { + _sapp_slot_t slot; + sapp_window_desc desc; + int window_width; + int window_height; + int framebuffer_width; + int framebuffer_height; + float dpi_scale; bool fullscreen; - bool gles2_fallback; bool first_frame; bool init_called; bool cleanup_called; + bool event_consumed; + _sapp_mouse_t mouse; + _sapp_clipboard_t clipboard; + _sapp_drop_t drop; + char title[_SAPP_MAX_TITLE_LENGTH]; + #if defined(_SAPP_MACOS) + _sapp_macos_window_t macos; + #elif defined(_SAPP_IOS) + _sapp_ios_window_t ios; + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_window_t emsc; + #elif defined(_SAPP_WIN32) + _sapp_win32_window_t win32; + #if defined(SOKOL_D3D11) + _sapp_d3d11_window_t d3d11; + #elif defined(SOKOL_GLCORE33) + _sapp_wgl_window_t wgl; + #endif + #elif defined(_SAPP_UWP) + _sapp_uwp_window_t uwp; + #if defined(SOKOL_D3D11) + _sapp_d3d11_window_t d3d11; + #endif + #elif defined(_SAPP_ANDROID) + _sapp_android_window_t android; + #elif defined(_SAPP_LINUX) + _sapp_x11_window_t x11; + _sapp_glx_window_t glx; + #endif +} _sapp_window_t; + +typedef struct { + sapp_desc desc; + _sapp_window_t window; + bool valid; + bool gles2_fallback; bool quit_requested; bool quit_ordered; - bool event_consumed; - bool html5_ask_leave_site; bool onscreen_keyboard_shown; - int window_width; - int window_height; - int framebuffer_width; - int framebuffer_height; - int sample_count; - int swap_interval; - float dpi_scale; uint64_t frame_count; sapp_event event; - _sapp_mouse_t mouse; - _sapp_clipboard_t clipboard; - _sapp_drop_t drop; sapp_icon_desc default_icon_desc; uint32_t* default_icon_pixels; #if defined(_SAPP_MACOS) @@ -2297,9 +2362,6 @@ typedef struct { _sapp_x11_t x11; _sapp_glx_t glx; #endif - char html5_canvas_selector[_SAPP_MAX_TITLE_LENGTH]; - char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */ - wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */ sapp_keycode keycodes[SAPP_MAX_KEYCODES]; } _sapp_t; static _sapp_t _sapp; @@ -2310,7 +2372,7 @@ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { _sapp.desc.fail_cb(msg); } else if (_sapp.desc.fail_userdata_cb) { - _sapp.desc.fail_userdata_cb(msg, _sapp.desc.user_data); + _sapp.desc.fail_userdata_cb(msg, _sapp.desc.fail_user_data); } else { SOKOL_LOG(msg); @@ -2319,49 +2381,49 @@ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { } _SOKOL_PRIVATE void _sapp_call_init(void) { - if (_sapp.desc.init_cb) { - _sapp.desc.init_cb(); + if (_sapp.desc.window.init_cb) { + _sapp.desc.window.init_cb(); } - else if (_sapp.desc.init_userdata_cb) { - _sapp.desc.init_userdata_cb(_sapp.desc.user_data); + else if (_sapp.desc.window.init_userdata_cb) { + _sapp.desc.window.init_userdata_cb(_sapp.desc.window.user_data); } - _sapp.init_called = true; + _sapp.window.init_called = true; } _SOKOL_PRIVATE void _sapp_call_frame(void) { - if (_sapp.init_called && !_sapp.cleanup_called) { - if (_sapp.desc.frame_cb) { - _sapp.desc.frame_cb(); + if (_sapp.window.init_called && !_sapp.window.cleanup_called) { + if (_sapp.desc.window.frame_cb) { + _sapp.desc.window.frame_cb(); } - else if (_sapp.desc.frame_userdata_cb) { - _sapp.desc.frame_userdata_cb(_sapp.desc.user_data); + else if (_sapp.desc.window.frame_userdata_cb) { + _sapp.desc.window.frame_userdata_cb(_sapp.desc.window.user_data); } } } _SOKOL_PRIVATE void _sapp_call_cleanup(void) { - if (!_sapp.cleanup_called) { - if (_sapp.desc.cleanup_cb) { - _sapp.desc.cleanup_cb(); + if (!_sapp.window.cleanup_called) { + if (_sapp.desc.window.cleanup_cb) { + _sapp.desc.window.cleanup_cb(); } - else if (_sapp.desc.cleanup_userdata_cb) { - _sapp.desc.cleanup_userdata_cb(_sapp.desc.user_data); + else if (_sapp.desc.window.cleanup_userdata_cb) { + _sapp.desc.window.cleanup_userdata_cb(_sapp.desc.window.user_data); } - _sapp.cleanup_called = true; + _sapp.window.cleanup_called = true; } } _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { - if (!_sapp.cleanup_called) { - if (_sapp.desc.event_cb) { - _sapp.desc.event_cb(e); + if (!_sapp.window.cleanup_called) { + if (_sapp.desc.window.event_cb) { + _sapp.desc.window.event_cb(e); } - else if (_sapp.desc.event_userdata_cb) { - _sapp.desc.event_userdata_cb(e, _sapp.desc.user_data); + else if (_sapp.desc.window.event_userdata_cb) { + _sapp.desc.window.event_userdata_cb(e, _sapp.desc.window.user_data); } } - if (_sapp.event_consumed) { - _sapp.event_consumed = false; + if (_sapp.window.event_consumed) { + _sapp.window.event_consumed = false; return true; } else { @@ -2370,11 +2432,11 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { } _SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { - SOKOL_ASSERT(_sapp.drop.buffer); - SOKOL_ASSERT((index >= 0) && (index <= _sapp.drop.max_files)); - int offset = index * _sapp.drop.max_path_length; - SOKOL_ASSERT(offset < _sapp.drop.buf_size); - return &_sapp.drop.buffer[offset]; + SOKOL_ASSERT(_sapp.window.drop.buffer); + SOKOL_ASSERT((index >= 0) && (index <= _sapp.window.drop.max_files)); + int offset = index * _sapp.window.drop.max_path_length; + SOKOL_ASSERT(offset < _sapp.window.drop.buf_size); + return &_sapp.window.drop.buffer[offset]; } /* Copy a string into a fixed size buffer with guaranteed zero- @@ -2407,61 +2469,62 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { } } -_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { - sapp_desc desc = *in_desc; +_SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in_desc) { + sapp_window_desc desc = *in_desc; + desc.title = _sapp_def(desc.title, "sokol_app"); desc.width = _sapp_def(desc.width, 640); desc.height = _sapp_def(desc.height, 480); desc.sample_count = _sapp_def(desc.sample_count, 1); desc.swap_interval = _sapp_def(desc.swap_interval, 1); - desc.html5_canvas_name = _sapp_def(desc.html5_canvas_name, "canvas"); - desc.clipboard_size = _sapp_def(desc.clipboard_size, 8192); desc.max_dropped_files = _sapp_def(desc.max_dropped_files, 1); desc.max_dropped_file_path_length = _sapp_def(desc.max_dropped_file_path_length, 2048); - desc.window_title = _sapp_def(desc.window_title, "sokol_app"); + desc.clipboard_size = _sapp_def(desc.clipboard_size, 8192); + return desc; +} + +_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { + sapp_desc desc = *in_desc; + desc.window = _sapp_window_defaults(&desc.window); + desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas"); return desc; } _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _SAPP_CLEAR(_sapp_t, _sapp); _sapp.desc = _sapp_desc_defaults(desc); - _sapp.first_frame = true; - _sapp.window_width = _sapp.desc.width; - _sapp.window_height = _sapp.desc.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - _sapp.sample_count = _sapp.desc.sample_count; - _sapp.swap_interval = _sapp.desc.swap_interval; - _sapp.html5_canvas_selector[0] = '#'; - _sapp_strcpy(_sapp.desc.html5_canvas_name, &_sapp.html5_canvas_selector[1], sizeof(_sapp.html5_canvas_selector) - 1); - _sapp.desc.html5_canvas_name = &_sapp.html5_canvas_selector[1]; - _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; - _sapp.clipboard.enabled = _sapp.desc.enable_clipboard; - if (_sapp.clipboard.enabled) { - _sapp.clipboard.buf_size = _sapp.desc.clipboard_size; - _sapp.clipboard.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.clipboard.buf_size); - } - _sapp.drop.enabled = _sapp.desc.enable_dragndrop; - if (_sapp.drop.enabled) { - _sapp.drop.max_files = _sapp.desc.max_dropped_files; - _sapp.drop.max_path_length = _sapp.desc.max_dropped_file_path_length; - _sapp.drop.buf_size = _sapp.drop.max_files * _sapp.drop.max_path_length; - _sapp.drop.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.drop.buf_size); - } - _sapp_strcpy(_sapp.desc.window_title, _sapp.window_title, sizeof(_sapp.window_title)); - _sapp.desc.window_title = _sapp.window_title; - _sapp.dpi_scale = 1.0f; - _sapp.fullscreen = _sapp.desc.fullscreen; - _sapp.mouse.shown = true; + _sapp.window.desc = _sapp.desc.window; + _sapp.window.first_frame = true; + _sapp.window.window_width = _sapp.desc.window.width; + _sapp.window.window_height = _sapp.desc.window.height; + _sapp.window.framebuffer_width = _sapp.window.window_width; + _sapp.window.framebuffer_height = _sapp.window.window_height; + _sapp.window.clipboard.enabled = _sapp.desc.window.enable_clipboard; + if (_sapp.window.clipboard.enabled) { + _sapp.window.clipboard.buf_size = _sapp.desc.window.clipboard_size; + _sapp.window.clipboard.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.window.clipboard.buf_size); + } + _sapp.window.drop.enabled = _sapp.desc.window.enable_dragndrop; + if (_sapp.window.drop.enabled) { + _sapp.window.drop.max_files = _sapp.desc.window.max_dropped_files; + _sapp.window.drop.max_path_length = _sapp.desc.window.max_dropped_file_path_length; + _sapp.window.drop.buf_size = _sapp.window.drop.max_files * _sapp.window.drop.max_path_length; + _sapp.window.drop.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.window.drop.buf_size); + } + _sapp_strcpy(_sapp.desc.window.title, _sapp.window.title, sizeof(_sapp.window.title)); + _sapp.desc.window.title = _sapp.window.title; + _sapp.window.dpi_scale = 1.0f; + _sapp.window.fullscreen = _sapp.desc.window.fullscreen; + _sapp.window.mouse.shown = true; } _SOKOL_PRIVATE void _sapp_discard_state(void) { - if (_sapp.clipboard.enabled) { - SOKOL_ASSERT(_sapp.clipboard.buffer); - SOKOL_FREE((void*)_sapp.clipboard.buffer); + if (_sapp.window.clipboard.enabled) { + SOKOL_ASSERT(_sapp.window.clipboard.buffer); + SOKOL_FREE((void*)_sapp.window.clipboard.buffer); } - if (_sapp.drop.enabled) { - SOKOL_ASSERT(_sapp.drop.buffer); - SOKOL_FREE((void*)_sapp.drop.buffer); + if (_sapp.window.drop.enabled) { + SOKOL_ASSERT(_sapp.window.drop.buffer); + SOKOL_FREE((void*)_sapp.window.drop.buffer); } if (_sapp.default_icon_pixels) { SOKOL_FREE((void*)_sapp.default_icon_pixels); @@ -2474,19 +2537,19 @@ _SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) { _sapp.event.type = type; _sapp.event.frame_count = _sapp.frame_count; _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; - _sapp.event.window_width = _sapp.window_width; - _sapp.event.window_height = _sapp.window_height; - _sapp.event.framebuffer_width = _sapp.framebuffer_width; - _sapp.event.framebuffer_height = _sapp.framebuffer_height; - _sapp.event.mouse_x = _sapp.mouse.x; - _sapp.event.mouse_y = _sapp.mouse.y; - _sapp.event.mouse_dx = _sapp.mouse.dx; - _sapp.event.mouse_dy = _sapp.mouse.dy; + _sapp.event.window_width = _sapp.window.window_width; + _sapp.event.window_height = _sapp.window.window_height; + _sapp.event.framebuffer_width = _sapp.window.framebuffer_width; + _sapp.event.framebuffer_height = _sapp.window.framebuffer_height; + _sapp.event.mouse_x = _sapp.window.mouse.x; + _sapp.event.mouse_y = _sapp.window.mouse.y; + _sapp.event.mouse_dx = _sapp.window.mouse.dx; + _sapp.event.mouse_dy = _sapp.window.mouse.dy; } _SOKOL_PRIVATE bool _sapp_events_enabled(void) { /* only send events when an event callback is set, and the init function was called */ - return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called; + return (_sapp.desc.window.event_cb || _sapp.desc.window.event_userdata_cb) && _sapp.window.init_called; } _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { @@ -2499,15 +2562,15 @@ _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { } _SOKOL_PRIVATE void _sapp_clear_drop_buffer(void) { - if (_sapp.drop.enabled) { - SOKOL_ASSERT(_sapp.drop.buffer); - memset(_sapp.drop.buffer, 0, (size_t)_sapp.drop.buf_size); + if (_sapp.window.drop.enabled) { + SOKOL_ASSERT(_sapp.window.drop.buffer); + memset(_sapp.window.drop.buffer, 0, (size_t)_sapp.window.drop.buf_size); } } _SOKOL_PRIVATE void _sapp_frame(void) { - if (_sapp.first_frame) { - _sapp.first_frame = false; + if (_sapp.window.first_frame) { + _sapp.window.first_frame = false; _sapp_call_init(); } _sapp_call_frame(); @@ -2805,14 +2868,14 @@ _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) { _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { // NOTE: it's safe to call [release] on a nil object - _SAPP_OBJC_RELEASE(_sapp.macos.tracking_area); - _SAPP_OBJC_RELEASE(_sapp.macos.app_dlg); - _SAPP_OBJC_RELEASE(_sapp.macos.win_dlg); - _SAPP_OBJC_RELEASE(_sapp.macos.view); + _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); + _SAPP_OBJC_RELEASE(_sapp.macos.win.delegate); + _SAPP_OBJC_RELEASE(_sapp.macos.win.view); + _SAPP_OBJC_RELEASE(_sapp.macos.app_delegate); #if defined(SOKOL_METAL) _SAPP_OBJC_RELEASE(_sapp.macos.mtl_device); #endif - _SAPP_OBJC_RELEASE(_sapp.macos.window); + _SAPP_OBJC_RELEASE(_sapp.macos.win.ns_window); } _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { @@ -2823,8 +2886,8 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { // the dummy icon will be visible for a short time sapp_set_icon(&_sapp.desc.icon); NSApp.activationPolicy = NSApplicationActivationPolicyRegular; - _sapp.macos.app_dlg = [[_sapp_macos_app_delegate alloc] init]; - NSApp.delegate = _sapp.macos.app_dlg; + _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; + NSApp.delegate = _sapp.macos.app_delegate; [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; // NOTE: [NSApp run] never returns, instead cleanup code @@ -2900,30 +2963,30 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { */ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { #if defined(SOKOL_METAL) - const NSRect fb_rect = [_sapp.macos.view bounds]; - _sapp.framebuffer_width = fb_rect.size.width * _sapp.dpi_scale; - _sapp.framebuffer_height = fb_rect.size.height * _sapp.dpi_scale; + const NSRect fb_rect = [_sapp.macos.win.view bounds]; + _sapp.window.framebuffer_width = fb_rect.size.width * _sapp.window.dpi_scale; + _sapp.window.framebuffer_height = fb_rect.size.height * _sapp.window.dpi_scale; #elif defined(SOKOL_GLCORE33) const NSRect fb_rect = [_sapp.macos.view convertRectToBacking:[_sapp.macos.view frame]]; _sapp.framebuffer_width = fb_rect.size.width; _sapp.framebuffer_height = fb_rect.size.height; #endif - const NSRect bounds = [_sapp.macos.view bounds]; - _sapp.window_width = bounds.size.width; - _sapp.window_height = bounds.size.height; - if (_sapp.framebuffer_width == 0) { - _sapp.framebuffer_width = 1; + const NSRect bounds = [_sapp.macos.win.view bounds]; + _sapp.window.window_width = bounds.size.width; + _sapp.window.window_height = bounds.size.height; + if (_sapp.window.framebuffer_width == 0) { + _sapp.window.framebuffer_width = 1; } - if (_sapp.framebuffer_height == 0) { - _sapp.framebuffer_height = 1; + if (_sapp.window.framebuffer_height == 0) { + _sapp.window.framebuffer_height = 1; } - if (_sapp.window_width == 0) { - _sapp.window_width = 1; + if (_sapp.window.window_width == 0) { + _sapp.window.window_width = 1; } - if (_sapp.window_height == 0) { - _sapp.window_height = 1; + if (_sapp.window.window_height == 0) { + _sapp.window.window_height = 1; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; + _sapp.window.dpi_scale = (float)_sapp.window.framebuffer_width / (float)_sapp.window.window_width; /* NOTE: _sapp_macos_update_dimensions() isn't called each frame, but only when the window size actually changes, so resizing the MTKView's @@ -2931,8 +2994,8 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { identical drawableSize. */ #if defined(SOKOL_METAL) - CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height }; - _sapp.macos.view.drawableSize = drawable_size; + CGSize drawable_size = { (CGFloat) _sapp.window.framebuffer_width, (CGFloat) _sapp.window.framebuffer_height }; + _sapp.macos.win.view.drawableSize = drawable_size; #endif } @@ -2941,8 +3004,8 @@ _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { windowDidEnterFullscreen / windowDidExitFullscreen event handlers */ - _sapp.fullscreen = !_sapp.fullscreen; - [_sapp.macos.window toggleFullScreen:nil]; + _sapp.window.fullscreen = !_sapp.window.fullscreen; + [_sapp.macos.win.ns_window toggleFullScreen:nil]; } _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { @@ -2954,39 +3017,46 @@ _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { } _SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.buffer); + SOKOL_ASSERT(_sapp.window.clipboard.buffer); @autoreleasepool { - _sapp.clipboard.buffer[0] = 0; + _sapp.window.clipboard.buffer[0] = 0; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return _sapp.clipboard.buffer; + return _sapp.window.clipboard.buffer; } NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; if (!str) { - return _sapp.clipboard.buffer; + return _sapp.window.clipboard.buffer; } - _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + _sapp_strcpy([str UTF8String], _sapp.window.clipboard.buffer, _sapp.window.clipboard.buf_size); } - return _sapp.clipboard.buffer; + return _sapp.window.clipboard.buffer; } _SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { - [_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]]; + [_sapp.macos.win.ns_window setTitle: [NSString stringWithUTF8String:_sapp.window.title]]; } _SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) { - if (!_sapp.mouse.locked) { + if (!_sapp.window.mouse.locked) { const NSPoint mouse_pos = event.locationInWindow; - float new_x = mouse_pos.x * _sapp.dpi_scale; - float new_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1; + float new_x = mouse_pos.x * _sapp.window.dpi_scale; + float new_y = _sapp.window.framebuffer_height - (mouse_pos.y * _sapp.window.dpi_scale) - 1; /* don't update dx/dy in the very first update */ - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; + if (_sapp.window.mouse.pos_valid) { + _sapp.window.mouse.dx = new_x - _sapp.window.mouse.x; + _sapp.window.mouse.dy = new_y - _sapp.window.mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; + _sapp.window.mouse.x = new_x; + _sapp.window.mouse.y = new_y; + _sapp.window.mouse.pos_valid = true; + } +} + +_SOKOL_PRIVATE void _sapp_macos_update_mouse_delta(NSEvent* event) { + if (_sapp.window.mouse.locked) { + _sapp.window.mouse.dx = [event deltaX]; + _sapp.window.mouse.dy = [event deltaY]; } } @@ -3001,12 +3071,12 @@ _SOKOL_PRIVATE void _sapp_macos_show_mouse(bool visible) { } _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { + if (lock == _sapp.window.mouse.locked) { return; } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; + _sapp.window.mouse.dx = 0.0f; + _sapp.window.mouse.dy = 0.0f; + _sapp.window.mouse.locked = lock; /* NOTE that this code doesn't warp the mouse cursor to the window center as everybody else does it. This lead to a spike in the @@ -3017,7 +3087,7 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { NOTE also that the hide/show of the mouse cursor should properly stack with calls to sapp_show_mouse() */ - if (_sapp.mouse.locked) { + if (_sapp.window.mouse.locked) { CGAssociateMouseAndMouseCursorPosition(NO); CGDisplayHideCursor(kCGDirectMainDisplay); } @@ -3063,58 +3133,58 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_frame(); if (_sapp.quit_requested || _sapp.quit_ordered) { - [_sapp.macos.window performClose:nil]; + [_sapp.macos.win.ns_window performClose:nil]; } } @implementation _sapp_macos_app_delegate - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); - if (_sapp.fullscreen) { + if (_sapp.window.fullscreen) { NSRect screen_rect = NSScreen.mainScreen.frame; - _sapp.window_width = screen_rect.size.width; - _sapp.window_height = screen_rect.size.height; + _sapp.window.window_width = screen_rect.size.width; + _sapp.window.window_height = screen_rect.size.height; } - if (_sapp.desc.high_dpi) { - _sapp.framebuffer_width = 2 * _sapp.window_width; - _sapp.framebuffer_height = 2 * _sapp.window_height; + if (_sapp.desc.window.high_dpi) { + _sapp.window.framebuffer_width = 2 * _sapp.window.window_width; + _sapp.window.framebuffer_height = 2 * _sapp.window.window_height; } else { - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; + _sapp.window.framebuffer_width = _sapp.window.window_width; + _sapp.window.framebuffer_height = _sapp.window.window_height; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + _sapp.window.dpi_scale = (float)_sapp.window.framebuffer_width / (float) _sapp.window.window_width; const NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - NSRect window_rect = NSMakeRect(0, 0, _sapp.window_width, _sapp.window_height); - _sapp.macos.window = [[_sapp_macos_window alloc] + NSRect window_rect = NSMakeRect(0, 0, _sapp.window.window_width, _sapp.window.window_height); + _sapp.macos.win.ns_window = [[_sapp_macos_window alloc] initWithContentRect:window_rect styleMask:style backing:NSBackingStoreBuffered defer:NO]; - _sapp.macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate - _sapp.macos.window.title = [NSString stringWithUTF8String:_sapp.window_title]; - _sapp.macos.window.acceptsMouseMovedEvents = YES; - _sapp.macos.window.restorable = YES; + _sapp.macos.win.ns_window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate + _sapp.macos.win.ns_window.title = [NSString stringWithUTF8String:_sapp.window.title]; + _sapp.macos.win.ns_window.acceptsMouseMovedEvents = YES; + _sapp.macos.win.ns_window.restorable = YES; - _sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init]; - _sapp.macos.window.delegate = _sapp.macos.win_dlg; + _sapp.macos.win.delegate = [[_sapp_macos_window_delegate alloc] init]; + _sapp.macos.win.ns_window.delegate = _sapp.macos.win.delegate; #if defined(SOKOL_METAL) _sapp.macos.mtl_device = MTLCreateSystemDefaultDevice(); - _sapp.macos.view = [[_sapp_macos_view alloc] init]; - [_sapp.macos.view updateTrackingAreas]; - _sapp.macos.view.preferredFramesPerSecond = 60 / _sapp.swap_interval; - _sapp.macos.view.device = _sapp.macos.mtl_device; - _sapp.macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; - _sapp.macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.macos.view.sampleCount = (NSUInteger) _sapp.sample_count; - _sapp.macos.view.autoResizeDrawable = false; - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - _sapp.macos.view.layer.magnificationFilter = kCAFilterNearest; + _sapp.macos.win.view = [[_sapp_macos_view alloc] init]; + [_sapp.macos.win.view updateTrackingAreas]; + _sapp.macos.win.view.preferredFramesPerSecond = 60 / _sapp.window.desc.swap_interval; + _sapp.macos.win.view.device = _sapp.macos.mtl_device; + _sapp.macos.win.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; + _sapp.macos.win.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + _sapp.macos.win.view.sampleCount = (NSUInteger) _sapp.window.desc.sample_count; + _sapp.macos.win.view.autoResizeDrawable = false; + _sapp.macos.win.ns_window.contentView = _sapp.macos.win.view; + [_sapp.macos.win.ns_window makeFirstResponder:_sapp.macos.win.view]; + _sapp.macos.win.view.layer.magnificationFilter = kCAFilterNearest; #elif defined(SOKOL_GLCORE33) NSOpenGLPixelFormatAttribute attrs[32]; int i = 0; @@ -3161,14 +3231,14 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { timer_obj = nil; #endif _sapp.valid = true; - if (_sapp.fullscreen) { + if (_sapp.window.fullscreen) { /* on GL, this already toggles a rendered frame, so set the valid flag before */ - [_sapp.macos.window toggleFullScreen:self]; + [_sapp.macos.win.ns_window toggleFullScreen:self]; } else { - [_sapp.macos.window center]; + [_sapp.macos.win.ns_window center]; } - [_sapp.macos.window makeKeyAndOrderFront:nil]; + [_sapp.macos.win.ns_window makeKeyAndOrderFront:nil]; _sapp_macos_update_dimensions(); [NSEvent setMouseCoalescingEnabled:NO]; } @@ -3212,7 +3282,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)windowDidResize:(NSNotification*)notification { _SOKOL_UNUSED(notification); _sapp_macos_update_dimensions(); - if (!_sapp.first_frame) { + if (!_sapp.window.first_frame) { _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED); } } @@ -3229,12 +3299,12 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)windowDidEnterFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.fullscreen = true; + _sapp.window.fullscreen = true; } - (void)windowDidExitFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.fullscreen = false; + _sapp.window.fullscreen = false; } @end @@ -3264,11 +3334,11 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { NSPasteboard *pboard = [sender draggingPasteboard]; if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { _sapp_clear_drop_buffer(); - _sapp.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.drop.max_files) ? _sapp.drop.max_files : pboard.pasteboardItems.count; + _sapp.window.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.window.drop.max_files) ? _sapp.window.drop.max_files : pboard.pasteboardItems.count; bool drop_failed = false; - for (int i = 0; i < _sapp.drop.num_files; i++) { + for (int i = 0; i < _sapp.window.drop.num_files; i++) { NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; - if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { + if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.window.drop.max_path_length)) { SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); drop_failed = true; break; @@ -3282,7 +3352,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } else { _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; + _sapp.window.drop.num_files = 0; } return YES; } @@ -3382,9 +3452,9 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { return YES; } - (void)updateTrackingAreas { - if (_sapp.macos.tracking_area != nil) { - [self removeTrackingArea:_sapp.macos.tracking_area]; - _SAPP_OBJC_RELEASE(_sapp.macos.tracking_area); + if (_sapp.macos.win.tracking_area != nil) { + [self removeTrackingArea:_sapp.macos.win.tracking_area]; + _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); } const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | @@ -3392,8 +3462,8 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { NSTrackingCursorUpdate | NSTrackingInVisibleRect | NSTrackingAssumeInside; - _sapp.macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - [self addTrackingArea:_sapp.macos.tracking_area]; + _sapp.macos.win.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; + [self addTrackingArea:_sapp.macos.win.tracking_area]; [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent*)event { @@ -3401,82 +3471,70 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { /* don't send mouse enter/leave while dragging (so that it behaves the same as on Windows while SetCapture is active */ - if (0 == _sapp.macos.mouse_buttons) { + if (0 == _sapp.macos.win.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } } - (void)mouseExited:(NSEvent*)event { _sapp_macos_update_mouse(event); - if (0 == _sapp.macos.mouse_buttons) { + if (0 == _sapp.macos.win.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } } - (void)mouseDown:(NSEvent*)event { _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mods(event)); - _sapp.macos.mouse_buttons |= (1< 0) ? _sapp.framebuffer_width : 1; + return (_sapp.window.framebuffer_width > 0) ? _sapp.window.framebuffer_width : 1; } SOKOL_API_IMPL float sapp_widthf(void) { @@ -10590,7 +10652,7 @@ SOKOL_API_IMPL float sapp_widthf(void) { } SOKOL_API_IMPL int sapp_height(void) { - return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1; + return (_sapp.window.framebuffer_height > 0) ? _sapp.window.framebuffer_height : 1; } SOKOL_API_IMPL float sapp_heightf(void) { @@ -10620,15 +10682,15 @@ SOKOL_API_IMPL int sapp_depth_format(void) { } SOKOL_API_IMPL int sapp_sample_count(void) { - return _sapp.sample_count; + return _sapp.window.desc.sample_count; } SOKOL_API_IMPL bool sapp_high_dpi(void) { - return _sapp.desc.high_dpi && (_sapp.dpi_scale >= 1.5f); + return _sapp.desc.window.high_dpi && (_sapp.window.dpi_scale >= 1.5f); } SOKOL_API_IMPL float sapp_dpi_scale(void) { - return _sapp.dpi_scale; + return _sapp.window.dpi_scale; } SOKOL_API_IMPL bool sapp_gles2(void) { @@ -10652,7 +10714,7 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { } SOKOL_APP_API_DECL bool sapp_is_fullscreen(void) { - return _sapp.fullscreen; + return _sapp.window.fullscreen; } SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { @@ -10669,7 +10731,7 @@ SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { /* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ SOKOL_API_IMPL void sapp_show_mouse(bool show) { - if (_sapp.mouse.shown != show) { + if (_sapp.window.mouse.shown != show) { #if defined(_SAPP_MACOS) _sapp_macos_show_mouse(show); #elif defined(_SAPP_WIN32) @@ -10679,12 +10741,12 @@ SOKOL_API_IMPL void sapp_show_mouse(bool show) { #elif defined(_SAPP_UWP) _sapp_uwp_show_mouse(show); #endif - _sapp.mouse.shown = show; + _sapp.window.mouse.shown = show; } } SOKOL_API_IMPL bool sapp_mouse_shown(void) { - return _sapp.mouse.shown; + return _sapp.window.mouse.shown; } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { @@ -10702,7 +10764,7 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - return _sapp.mouse.locked; + return _sapp.window.mouse.locked; } SOKOL_API_IMPL void sapp_request_quit(void) { @@ -10718,13 +10780,13 @@ SOKOL_API_IMPL void sapp_quit(void) { } SOKOL_API_IMPL void sapp_consume_event(void) { - _sapp.event_consumed = true; + _sapp.window.event_consumed = true; } /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { - SOKOL_ASSERT(_sapp.clipboard.enabled); - if (!_sapp.clipboard.enabled) { + SOKOL_ASSERT(_sapp.window.clipboard.enabled); + if (!_sapp.window.clipboard.enabled) { return; } SOKOL_ASSERT(str); @@ -10737,12 +10799,12 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { #else /* not implemented */ #endif - _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + _sapp_strcpy(str, _sapp.window.clipboard.buffer, _sapp.window.clipboard.buf_size); } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.enabled); - if (!_sapp.clipboard.enabled) { + SOKOL_ASSERT(_sapp.window.clipboard.enabled); + if (!_sapp.window.clipboard.enabled) { return ""; } #if defined(_SAPP_MACOS) @@ -10759,7 +10821,7 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { SOKOL_API_IMPL void sapp_set_window_title(const char* title) { SOKOL_ASSERT(title); - _sapp_strcpy(title, _sapp.window_title, sizeof(_sapp.window_title)); + _sapp_strcpy(title, _sapp.window.title, sizeof(_sapp.window.title)); #if defined(_SAPP_MACOS) _sapp_macos_update_window_title(); #elif defined(_SAPP_WIN32) @@ -10798,26 +10860,26 @@ SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { } SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - SOKOL_ASSERT(_sapp.drop.enabled); - return _sapp.drop.num_files; + SOKOL_ASSERT(_sapp.window.drop.enabled); + return _sapp.window.drop.num_files; } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - SOKOL_ASSERT(_sapp.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); - SOKOL_ASSERT(_sapp.drop.buffer); - if (!_sapp.drop.enabled) { + SOKOL_ASSERT(_sapp.window.drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.window.drop.num_files)); + SOKOL_ASSERT(_sapp.window.drop.buffer); + if (!_sapp.window.drop.enabled) { return ""; } - if ((index < 0) || (index >= _sapp.drop.max_files)) { + if ((index < 0) || (index >= _sapp.window.drop.max_files)) { return ""; } return (const char*) _sapp_dropped_file_path_ptr(index); } SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { - SOKOL_ASSERT(_sapp.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); + SOKOL_ASSERT(_sapp.window.drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.window.drop.num_files)); #if defined(_SAPP_EMSCRIPTEN) if (!_sapp.drop.enabled) { return 0; @@ -10830,7 +10892,7 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { - SOKOL_ASSERT(_sapp.drop.enabled); + SOKOL_ASSERT(_sapp.window.drop.enabled); SOKOL_ASSERT(request); SOKOL_ASSERT(request->callback); SOKOL_ASSERT(request->buffer_ptr); @@ -10885,7 +10947,7 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [_sapp.macos.win.view currentRenderPassDescriptor]; #else const void* obj = (__bridge const void*) [_sapp.ios.view currentRenderPassDescriptor]; #endif @@ -10900,7 +10962,7 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; + const void* obj = (__bridge const void*) [_sapp.macos.win.view currentDrawable]; #else const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; #endif @@ -10913,7 +10975,7 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { SOKOL_API_IMPL const void* sapp_macos_get_window(void) { #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.macos.window; + const void* obj = (__bridge const void*) _sapp.macos.win.ns_window; SOKOL_ASSERT(obj); return obj; #else @@ -11037,7 +11099,11 @@ SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) { } SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { - _sapp.html5_ask_leave_site = ask; + #if defined(_SAPP_EMSCRIPTEN) + _sapp.emsc.ask_leave_site = ask; + #else + (void)ask; + #endif } #endif /* SOKOL_APP_IMPL */ From 660b4050ca6104a57c7a95f5f3781f3d046ecc3f Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 17 Apr 2021 14:08:24 +0200 Subject: [PATCH 02/49] sokol_app.h: window pool code, and some better platform-specific code structure --- sokol_app.h | 316 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 298 insertions(+), 18 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index a041ff867..d198d2516 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1015,6 +1015,7 @@ extern "C" { /* misc constants */ enum { + SAPP_INVALID_ID = 0, SAPP_MAX_TOUCHPOINTS = 8, SAPP_MAX_MOUSEBUTTONS = 3, SAPP_MAX_KEYCODES = 512, @@ -1382,6 +1383,7 @@ typedef struct sapp_ios_desc { } sapp_ios_desc; typedef struct sapp_desc { + int window_pool_size; sapp_window_desc window; sapp_icon_desc icon; // FIXME: per-window icons? sapp_gl_desc gl; @@ -2245,6 +2247,14 @@ typedef struct { #define _SAPP_PIXELFORMAT_DEPTH (41) #define _SAPP_PIXELFORMAT_DEPTH_STENCIL (42) +/* this MUST be 0 */ +#define _SAPP_INVALID_SLOT_INDEX (0) + +#define _SAPP_SLOT_SHIFT (16) +#define _SAPP_SLOT_MASK ((1<<_SAPP_SLOT_SHIFT)-1) +#define _SAPP_MAX_POOL_SIZE (1<<_SAPP_SLOT_SHIFT) +#define _SAPP_DEFAULT_POOL_SIZE (128) + #if defined(_SAPP_MACOS) || defined(_SAPP_IOS) // this is ARC compatible #if defined(__cplusplus) @@ -2256,6 +2266,17 @@ typedef struct { #define _SAPP_CLEAR(type, item) { memset(&item, 0, sizeof(item)); } #endif +typedef struct { + int size; + int queue_top; + uint32_t* gen_ctrs; + int* free_queue; +} _sapp_pool_t; + +typedef struct { + uint32_t id; +} _sapp_slot_t; + typedef struct { bool enabled; int buf_size; @@ -2279,10 +2300,6 @@ typedef struct { bool pos_valid; } _sapp_mouse_t; -typedef struct { - uint32_t id; -} _sapp_slot_t; - typedef struct { _sapp_slot_t slot; sapp_window_desc desc; @@ -2326,8 +2343,14 @@ typedef struct { #endif } _sapp_window_t; +typedef struct { + _sapp_pool_t pool; + _sapp_window_t* windows; +} _sapp_window_pool_t; + typedef struct { sapp_desc desc; + _sapp_window_pool_t window_pool; _sapp_window_t window; bool valid; bool gles2_fallback; @@ -2366,7 +2389,210 @@ typedef struct { } _sapp_t; static _sapp_t _sapp; -/*=== PRIVATE HELPER FUNCTIONS ===============================================*/ +// forward-declared platform-specific functions +#if defined(_SAPP_MACOS) +_SOKOL_PRIVATE void _sapp_macos_init_backend(void); +_SOKOL_PRIVATE void _sapp_macos_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_IOS) +_SOKOL_PRIVATE void _sapp_ios_init_backend(void); +_SOKOL_PRIVATE void _sapp_ios_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_EMSCRIPTEN) +_SOKOL_PRIVATE void _sapp_emsc_init_backend(void); +_SOKOL_PRIVATE void _sapp_emsc_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_WIN32) +_SOKOL_PRIVATE void _sapp_win32_init_backend(void); +_SOKOL_PRIVATE void _sapp_win32_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_UWP) +_SOKOL_PRIVATE void _sapp_uwp_init_backend(void); +_SOKOL_PRIVATE void _sapp_uwp_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_ANDROID) +_SOKOL_PRIVATE void _sapp_android_init_backend(void); +_SOKOL_PRIVATE void _sapp_android_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win); +#elif defined(_SAPP_LINUX) +_SOKOL_PRIVATE void _sapp_x11_init_backend(void); +_SOKOL_PRIVATE void _sapp_x11_discard_backend(void); +_SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); +#endif + +/*=== POOL IMPLEMENTATION ====================================================*/ +_SOKOL_PRIVATE void _sapp_init_pool(_sapp_pool_t* pool, int num) { + SOKOL_ASSERT(pool && (num >= 1)); + /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */ + pool->size = num + 1; + pool->queue_top = 0; + /* generation counters indexable by pool slot index, slot 0 is reserved */ + pool->gen_ctrs = (uint32_t*) SOKOL_CALLOC((size_t)pool->size, sizeof(uint32_t)); + SOKOL_ASSERT(pool->gen_ctrs); + /* it's not a bug to only reserve 'num' here */ + pool->free_queue = (int*) SOKOL_CALLOC((size_t)num, sizeof(int)); + SOKOL_ASSERT(pool->free_queue); + /* never allocate the zero-th pool item since the invalid id is 0 */ + for (int i = pool->size-1; i >= 1; i--) { + pool->free_queue[pool->queue_top++] = i; + } +} + +_SOKOL_PRIVATE void _sapp_discard_pool(_sapp_pool_t* pool) { + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + SOKOL_FREE(pool->free_queue); + pool->free_queue = 0; + SOKOL_ASSERT(pool->gen_ctrs); + SOKOL_FREE(pool->gen_ctrs); + pool->gen_ctrs = 0; + pool->size = 0; + pool->queue_top = 0; +} + +_SOKOL_PRIVATE int _sapp_pool_alloc_index(_sapp_pool_t* pool) { + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + if (pool->queue_top > 0) { + int slot_index = pool->free_queue[--pool->queue_top]; + SOKOL_ASSERT((slot_index > 0) && (slot_index < pool->size)); + return slot_index; + } + else { + /* pool exhausted */ + return _SAPP_INVALID_SLOT_INDEX; + } +} + +_SOKOL_PRIVATE void _sapp_pool_free_index(_sapp_pool_t* pool, int slot_index) { + SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < pool->size)); + SOKOL_ASSERT(pool); + SOKOL_ASSERT(pool->free_queue); + SOKOL_ASSERT(pool->queue_top < pool->size); + #ifdef SOKOL_DEBUG + /* debug check against double-free */ + for (int i = 0; i < pool->queue_top; i++) { + SOKOL_ASSERT(pool->free_queue[i] != slot_index); + } + #endif + pool->free_queue[pool->queue_top++] = slot_index; + SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); +} + +_SOKOL_PRIVATE void _sapp_reset_slot(_sapp_slot_t* slot) { + SOKOL_ASSERT(slot); + memset(slot, 0, sizeof(_sapp_slot_t)); +} + +/* allocate the slot at slot_index: + - bump the slot's generation counter + - create a resource id from the generation counter and slot index + - set the slot's id to this id + - set the slot's state to ALLOC + - return the resource id +*/ +_SOKOL_PRIVATE uint32_t _sapp_slot_alloc(_sapp_pool_t* pool, _sapp_slot_t* slot, int slot_index) { + SOKOL_ASSERT(pool && pool->gen_ctrs); + SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < pool->size)); + SOKOL_ASSERT(slot->id == SAPP_INVALID_ID); + uint32_t ctr = ++pool->gen_ctrs[slot_index]; + slot->id = (ctr<<_SAPP_SLOT_SHIFT)|(slot_index & _SAPP_SLOT_MASK); + return slot->id; +} + +_SOKOL_PRIVATE int _sapp_slot_index(uint32_t id) { + int slot_index = (int) (id & _SAPP_SLOT_MASK); + SOKOL_ASSERT(_SAPP_INVALID_SLOT_INDEX != slot_index); + return slot_index; +} + +_SOKOL_PRIVATE void _sapp_setup_window_pool(_sapp_window_pool_t* window_pool, const sapp_desc* desc) { + SOKOL_ASSERT(window_pool); + SOKOL_ASSERT((desc->window_pool_size > 0) && (desc->window_pool_size < _SAPP_MAX_POOL_SIZE)); + _sapp_init_pool(&window_pool->pool, desc->window_pool_size); + window_pool->windows = (_sapp_window_t*) SOKOL_CALLOC((size_t)window_pool->pool.size, sizeof(_sapp_window_t)); + SOKOL_ASSERT(window_pool->windows); +} + +_SOKOL_PRIVATE void _sapp_discard_window_pool(_sapp_window_pool_t* window_pool) { + SOKOL_ASSERT(window_pool); + SOKOL_ASSERT(window_pool->windows); + SOKOL_FREE(window_pool->windows); window_pool->windows = 0; + _sapp_discard_pool(&window_pool->pool); +} + +/* returns pointer to window by id without matching id check */ +_SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(const _sapp_window_pool_t* win_pool, uint32_t win_id) { + SOKOL_ASSERT(win_pool && (SAPP_INVALID_ID != win_id)); + int slot_index = _sapp_slot_index(win_id); + SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < win_pool->pool.size)); + return &win_pool->windows[slot_index]; +} + +/* returns pointer to window with matching id check, may return 0 */ +_SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(const _sapp_window_pool_t* win_pool, uint32_t win_id) { + if (SAPP_INVALID_ID != win_id) { + _sapp_window_t* win = _sapp_window_at(win_pool, win_id); + if (win->slot.id == win_id) { + return win; + } + } + return 0; +} + +_SOKOL_PRIVATE bool _sapp_create_window(_sapp_window_t* win, const sapp_window_desc* desc) { + #if defined(_SAPP_MACOS) + return _sapp_macos_create_window(win, desc); + #elif defined(_SAPP_IOS) + return _sapp_ios_create_window(win, desc); + #elif defined(_SAPP_EMSCRIPTEN) + return _sapp_emsc_create_window(win, desc); + #elif defined(_SAPP_WIN32) + return _sapp_win32_create_window(win, desc); + #elif defined(_SAPP_UWP) + return _sapp_uwp_create_window(win, desc); + #elif defined(_SAPP_ANDROID) + return _sapp_android_create_window(win, desc); + #elif defined(_SAPP_LINUX) + return _sapp_x11_create_window(win, desc); + #endif +} + +_SOKOL_PRIVATE void _sapp_destroy_window(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + _sapp_macos_destroy_window(win); + #elif defined(_SAPP_IOS) + _sapp_ios_destroy_window(win); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_destroy_window(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_destroy_window(win); + #elif defined(_SAPP_UWP) + _sapp_uwp_destroy_window(win); + #elif defined(_SAPP_ANDROID) + _sapp_android_destroy_window(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_destroy_window(win); + #endif +} + +_SOKOL_PRIVATE void _sapp_destroy_all_windows(_sapp_window_pool_t* win_pool) { + SOKOL_ASSERT(win_pool); + for (int i = 0; i < win_pool->pool.size; i++) { + uint32_t win_id = win_pool->windows[i].slot.id; + if (SAPP_INVALID_ID != win_id) { + _sapp_destroy_window(&win_pool->windows[i]); + } + } +} + _SOKOL_PRIVATE void _sapp_fail(const char* msg) { if (_sapp.desc.fail_cb) { _sapp.desc.fail_cb(msg); @@ -2482,8 +2708,45 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in return desc; } +_SOKOL_PRIVATE void _sapp_init_backend(void) { + #if defined(_SAPP_MACOS) + _sapp_macos_init_backend(); + #elif defined(_SAPP_IOS) + _sapp_ios_init_backend(); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_init_backend(); + #elif defined(_SAPP_WIN32) + _sapp_win32_init_backend(); + #elif defined(_SAPP_UWP) + _sapp_uwp_init_backend(); + #elif defined(_SAPP_ANDROID) + _sapp_android_init_backend(); + #elif defined(_SAPP_LINUX) + _sapp_x11_init_backend(); + #endif +} + +_SOKOL_PRIVATE void _sapp_discard_backend(void) { + #if defined(_SAPP_MACOS) + _sapp_macos_discard_backend(); + #elif defined(_SAPP_IOS) + _sapp_ios_discard_backend(); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_discard_backend(); + #elif defined(_SAPP_WIN32) + _sapp_win32_discard_backend(); + #elif defined(_SAPP_UWP) + _sapp_uwp_discard_backend(); + #elif defined(_SAPP_ANDROID) + _sapp_android_discard_backend(); + #elif defined(_SAPP_LINUX) + _sapp_x11_discard_backend(); + #endif +} + _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { sapp_desc desc = *in_desc; + desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE); desc.window = _sapp_window_defaults(&desc.window); desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas"); return desc; @@ -2515,9 +2778,13 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.window.dpi_scale = 1.0f; _sapp.window.fullscreen = _sapp.desc.window.fullscreen; _sapp.window.mouse.shown = true; + _sapp_setup_window_pool(&_sapp.window_pool, desc); + _sapp_init_backend(); } _SOKOL_PRIVATE void _sapp_discard_state(void) { + _sapp_destroy_all_windows(&_sapp.window_pool); + _sapp_discard_window_pool(&_sapp.window_pool); if (_sapp.window.clipboard.enabled) { SOKOL_ASSERT(_sapp.window.clipboard.buffer); SOKOL_FREE((void*)_sapp.window.clipboard.buffer); @@ -2529,6 +2796,7 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { if (_sapp.default_icon_pixels) { SOKOL_FREE((void*)_sapp.default_icon_pixels); } + _sapp_discard_backend(); _SAPP_CLEAR(_sapp_t, _sapp); } @@ -2866,7 +3134,21 @@ _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) { _sapp.keycodes[0x4E] = SAPP_KEYCODE_KP_SUBTRACT; } -_SOKOL_PRIVATE void _sapp_macos_discard_state(void) { +/* called from _sapp_init_state() */ +_SOKOL_PRIVATE void _sapp_macos_init_backend(void) { + _sapp_macos_init_keytable(); + [NSApplication sharedApplication]; + // set the application dock icon as early as possible, otherwise + // the dummy icon will be visible for a short time + sapp_set_icon(&_sapp.desc.icon); + NSApp.activationPolicy = NSApplicationActivationPolicyRegular; + _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; + NSApp.delegate = _sapp.macos.app_delegate; + [NSApp activateIgnoringOtherApps:YES]; +} + +/* called from _sapp_discard_state() */ +_SOKOL_PRIVATE void _sapp_macos_discard_backend(void) { // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); _SAPP_OBJC_RELEASE(_sapp.macos.win.delegate); @@ -2880,18 +3162,17 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_macos_init_keytable(); - [NSApplication sharedApplication]; - // set the application dock icon as early as possible, otherwise - // the dummy icon will be visible for a short time - sapp_set_icon(&_sapp.desc.icon); - NSApp.activationPolicy = NSApplicationActivationPolicyRegular; - _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; - NSApp.delegate = _sapp.macos.app_delegate; - [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; - // NOTE: [NSApp run] never returns, instead cleanup code - // must be put into applicationWillTerminate + // NOTE: [NSApp run] never returns, cleanup code is in applicationWillTerminate instead +} + +_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc) { + // FIXME + return false; +} + +_SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { + // FIXME } /* MacOS entry function */ @@ -3251,7 +3532,6 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)applicationWillTerminate:(NSNotification*)notification { _SOKOL_UNUSED(notification); _sapp_call_cleanup(); - _sapp_macos_discard_state(); _sapp_discard_state(); } @end From 6057fc68bf967e4975b19c7db236d685270e5292 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 18 Apr 2021 16:48:35 +0200 Subject: [PATCH 03/49] some intermediate code cleanup --- sokol_app.h | 104 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index d198d2516..195ed4574 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1022,6 +1022,9 @@ enum { SAPP_MAX_ICONIMAGES = 8, }; +/* a window handle */ +typedef struct sapp_window { uint32_t id; } sapp_window; + /* sapp_event_type @@ -2391,38 +2394,38 @@ static _sapp_t _sapp; // forward-declared platform-specific functions #if defined(_SAPP_MACOS) -_SOKOL_PRIVATE void _sapp_macos_init_backend(void); -_SOKOL_PRIVATE void _sapp_macos_discard_backend(void); +_SOKOL_PRIVATE void _sapp_macos_init_state(void); +_SOKOL_PRIVATE void _sapp_macos_discard_state(void); _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_IOS) -_SOKOL_PRIVATE void _sapp_ios_init_backend(void); -_SOKOL_PRIVATE void _sapp_ios_discard_backend(void); +_SOKOL_PRIVATE void _sapp_ios_init_state(void); +_SOKOL_PRIVATE void _sapp_ios_discard_state(void); _SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_EMSCRIPTEN) -_SOKOL_PRIVATE void _sapp_emsc_init_backend(void); -_SOKOL_PRIVATE void _sapp_emsc_discard_backend(void); +_SOKOL_PRIVATE void _sapp_emsc_init_state(void); +_SOKOL_PRIVATE void _sapp_emsc_discard_state(void); _SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_WIN32) -_SOKOL_PRIVATE void _sapp_win32_init_backend(void); -_SOKOL_PRIVATE void _sapp_win32_discard_backend(void); +_SOKOL_PRIVATE void _sapp_win32_init_state(void); +_SOKOL_PRIVATE void _sapp_win32_discard_state(void); _SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_UWP) -_SOKOL_PRIVATE void _sapp_uwp_init_backend(void); -_SOKOL_PRIVATE void _sapp_uwp_discard_backend(void); +_SOKOL_PRIVATE void _sapp_uwp_init_state(void); +_SOKOL_PRIVATE void _sapp_uwp_discard_state(void); _SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_ANDROID) -_SOKOL_PRIVATE void _sapp_android_init_backend(void); -_SOKOL_PRIVATE void _sapp_android_discard_backend(void); +_SOKOL_PRIVATE void _sapp_android_init_state(void); +_SOKOL_PRIVATE void _sapp_android_discard_state(void); _SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_LINUX) -_SOKOL_PRIVATE void _sapp_x11_init_backend(void); -_SOKOL_PRIVATE void _sapp_x11_discard_backend(void); +_SOKOL_PRIVATE void _sapp_x11_init_state(void); +_SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win, const sapp_window_desc* desc); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); #endif @@ -2528,6 +2531,11 @@ _SOKOL_PRIVATE void _sapp_discard_window_pool(_sapp_window_pool_t* window_pool) _sapp_discard_pool(&window_pool->pool); } +_SOKOL_PRIVATE sapp_window _sapp_make_window_id(uint32_t win_id) { + sapp_window res = { win_id }; + return res; +} + /* returns pointer to window by id without matching id check */ _SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(const _sapp_window_pool_t* win_pool, uint32_t win_id) { SOKOL_ASSERT(win_pool && (SAPP_INVALID_ID != win_id)); @@ -2708,42 +2716,52 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in return desc; } -_SOKOL_PRIVATE void _sapp_init_backend(void) { +_SOKOL_PRIVATE void _sapp_platform_init_state(void) { #if defined(_SAPP_MACOS) - _sapp_macos_init_backend(); + _sapp_macos_init_state(); #elif defined(_SAPP_IOS) - _sapp_ios_init_backend(); + _sapp_ios_init_state(); #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_init_backend(); + _sapp_emsc_init_state(); #elif defined(_SAPP_WIN32) - _sapp_win32_init_backend(); + _sapp_win32_init_state(); #elif defined(_SAPP_UWP) - _sapp_uwp_init_backend(); + _sapp_uwp_init_state(); #elif defined(_SAPP_ANDROID) - _sapp_android_init_backend(); + _sapp_android_init_state(); #elif defined(_SAPP_LINUX) - _sapp_x11_init_backend(); + _sapp_x11_init_state(); #endif } -_SOKOL_PRIVATE void _sapp_discard_backend(void) { +_SOKOL_PRIVATE void _sapp_platform_discard_state(void) { #if defined(_SAPP_MACOS) - _sapp_macos_discard_backend(); + _sapp_macos_discard_state(); #elif defined(_SAPP_IOS) - _sapp_ios_discard_backend(); + _sapp_ios_discard_state(); #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_discard_backend(); + _sapp_emsc_discard_state(); #elif defined(_SAPP_WIN32) - _sapp_win32_discard_backend(); + _sapp_win32_discard_state(); #elif defined(_SAPP_UWP) - _sapp_uwp_discard_backend(); + _sapp_uwp_discard_state(); #elif defined(_SAPP_ANDROID) - _sapp_android_discard_backend(); + _sapp_android_discard_state(); #elif defined(_SAPP_LINUX) - _sapp_x11_discard_backend(); + _sapp_x11_discard_state(); #endif } +_SOKOL_PRIVATE sapp_window _sapp_open_window(const sapp_window_desc* desc) { + SOKOL_ASSERT(desc); + // FIXME + return _sapp_make_window_id(SAPP_INVALID_ID); +} + +_SOKOL_PRIVATE void _sapp_close_window(sapp_window win_id) { + // FIXME +} + _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { sapp_desc desc = *in_desc; desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE); @@ -2778,8 +2796,8 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.window.dpi_scale = 1.0f; _sapp.window.fullscreen = _sapp.desc.window.fullscreen; _sapp.window.mouse.shown = true; - _sapp_setup_window_pool(&_sapp.window_pool, desc); - _sapp_init_backend(); + _sapp_setup_window_pool(&_sapp.window_pool, &_sapp.desc); + _sapp_platform_init_state(); } _SOKOL_PRIVATE void _sapp_discard_state(void) { @@ -2796,7 +2814,7 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { if (_sapp.default_icon_pixels) { SOKOL_FREE((void*)_sapp.default_icon_pixels); } - _sapp_discard_backend(); + _sapp_platform_discard_state(); _SAPP_CLEAR(_sapp_t, _sapp); } @@ -3135,20 +3153,12 @@ _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) { } /* called from _sapp_init_state() */ -_SOKOL_PRIVATE void _sapp_macos_init_backend(void) { +_SOKOL_PRIVATE void _sapp_macos_init_state(void) { _sapp_macos_init_keytable(); - [NSApplication sharedApplication]; - // set the application dock icon as early as possible, otherwise - // the dummy icon will be visible for a short time - sapp_set_icon(&_sapp.desc.icon); - NSApp.activationPolicy = NSApplicationActivationPolicyRegular; - _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; - NSApp.delegate = _sapp.macos.app_delegate; - [NSApp activateIgnoringOtherApps:YES]; } /* called from _sapp_discard_state() */ -_SOKOL_PRIVATE void _sapp_macos_discard_backend(void) { +_SOKOL_PRIVATE void _sapp_macos_discard_state(void) { // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); _SAPP_OBJC_RELEASE(_sapp.macos.win.delegate); @@ -3162,6 +3172,14 @@ _SOKOL_PRIVATE void _sapp_macos_discard_backend(void) { _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { _sapp_init_state(desc); + [NSApplication sharedApplication]; + // set the application dock icon as early as possible, otherwise + // the dummy icon will be visible for a short time + sapp_set_icon(&_sapp.desc.icon); + NSApp.activationPolicy = NSApplicationActivationPolicyRegular; + _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; + NSApp.delegate = _sapp.macos.app_delegate; + [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; // NOTE: [NSApp run] never returns, cleanup code is in applicationWillTerminate instead } From 292ab0fff144f839e34f18fd8dd84fda54ea484d Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 18 Apr 2021 18:47:23 +0200 Subject: [PATCH 04/49] continue with macOS window code --- sokol_app.h | 574 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 334 insertions(+), 240 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 195ed4574..184005fb7 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1830,7 +1830,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif // SOKOL_GLCORE33 typedef struct { - NSWindow* ns_window; + NSWindow* window; NSTrackingArea* tracking_area; _sapp_macos_window_delegate* delegate; _sapp_macos_view* view; @@ -1839,7 +1839,6 @@ typedef struct { } _sapp_macos_window_t; typedef struct { - _sapp_macos_window_t win; _sapp_macos_app_delegate* app_delegate; #if defined(SOKOL_METAL) id mtl_device; @@ -2261,12 +2260,15 @@ typedef struct { #if defined(_SAPP_MACOS) || defined(_SAPP_IOS) // this is ARC compatible #if defined(__cplusplus) - #define _SAPP_CLEAR(type, item) { item = (type) { }; } + #define _SAPP_CLEAR_ITEM(type, item) { item = (type) { }; } + #define _SAPP_CLEAR_PTR(type, ptr) { *ptr = (type) { }; } #else - #define _SAPP_CLEAR(type, item) { item = (type) { 0 }; } + #define _SAPP_CLEAR_ITEM(type, item) { item = (type) { 0 }; } + #define _SAPP_CLEAR_PTR(type, ptr) { *ptr = (type) { 0 }; } #endif #else - #define _SAPP_CLEAR(type, item) { memset(&item, 0, sizeof(item)); } + #define _SAPP_CLEAR_ITEM(type, item) { memset(&item, 0, sizeof(item)); } + #define _SAPP_CLEAR_PTR(type, ptr) { memset(ptr, 0, sizeof(type)); } #endif typedef struct { @@ -2306,6 +2308,8 @@ typedef struct { typedef struct { _sapp_slot_t slot; sapp_window_desc desc; + int pos_x; + int pos_y; int window_width; int window_height; int framebuffer_width; @@ -2354,6 +2358,8 @@ typedef struct { typedef struct { sapp_desc desc; _sapp_window_pool_t window_pool; + uint32_t main_window_id; + uint32_t cur_window_id; _sapp_window_t window; bool valid; bool gles2_fallback; @@ -2389,6 +2395,7 @@ typedef struct { _sapp_glx_t glx; #endif sapp_keycode keycodes[SAPP_MAX_KEYCODES]; + char desc_window_title[_SAPP_MAX_TITLE_LENGTH]; } _sapp_t; static _sapp_t _sapp; @@ -2396,37 +2403,37 @@ static _sapp_t _sapp; #if defined(_SAPP_MACOS) _SOKOL_PRIVATE void _sapp_macos_init_state(void); _SOKOL_PRIVATE void _sapp_macos_discard_state(void); -_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_IOS) _SOKOL_PRIVATE void _sapp_ios_init_state(void); _SOKOL_PRIVATE void _sapp_ios_discard_state(void); -_SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_EMSCRIPTEN) _SOKOL_PRIVATE void _sapp_emsc_init_state(void); _SOKOL_PRIVATE void _sapp_emsc_discard_state(void); -_SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_WIN32) _SOKOL_PRIVATE void _sapp_win32_init_state(void); _SOKOL_PRIVATE void _sapp_win32_discard_state(void); -_SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_UWP) _SOKOL_PRIVATE void _sapp_uwp_init_state(void); _SOKOL_PRIVATE void _sapp_uwp_discard_state(void); -_SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_ANDROID) _SOKOL_PRIVATE void _sapp_android_init_state(void); _SOKOL_PRIVATE void _sapp_android_discard_state(void); -_SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win); #elif defined(_SAPP_LINUX) _SOKOL_PRIVATE void _sapp_x11_init_state(void); _SOKOL_PRIVATE void _sapp_x11_discard_state(void); -_SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win, const sapp_window_desc* desc); +_SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); #endif @@ -2489,11 +2496,6 @@ _SOKOL_PRIVATE void _sapp_pool_free_index(_sapp_pool_t* pool, int slot_index) { SOKOL_ASSERT(pool->queue_top <= (pool->size-1)); } -_SOKOL_PRIVATE void _sapp_reset_slot(_sapp_slot_t* slot) { - SOKOL_ASSERT(slot); - memset(slot, 0, sizeof(_sapp_slot_t)); -} - /* allocate the slot at slot_index: - bump the slot's generation counter - create a resource id from the generation counter and slot index @@ -2516,38 +2518,32 @@ _SOKOL_PRIVATE int _sapp_slot_index(uint32_t id) { return slot_index; } -_SOKOL_PRIVATE void _sapp_setup_window_pool(_sapp_window_pool_t* window_pool, const sapp_desc* desc) { - SOKOL_ASSERT(window_pool); +_SOKOL_PRIVATE void _sapp_setup_window_pool(const sapp_desc* desc) { SOKOL_ASSERT((desc->window_pool_size > 0) && (desc->window_pool_size < _SAPP_MAX_POOL_SIZE)); - _sapp_init_pool(&window_pool->pool, desc->window_pool_size); - window_pool->windows = (_sapp_window_t*) SOKOL_CALLOC((size_t)window_pool->pool.size, sizeof(_sapp_window_t)); - SOKOL_ASSERT(window_pool->windows); -} - -_SOKOL_PRIVATE void _sapp_discard_window_pool(_sapp_window_pool_t* window_pool) { - SOKOL_ASSERT(window_pool); - SOKOL_ASSERT(window_pool->windows); - SOKOL_FREE(window_pool->windows); window_pool->windows = 0; - _sapp_discard_pool(&window_pool->pool); + _sapp_init_pool(&_sapp.window_pool.pool, desc->window_pool_size); + _sapp.window_pool.windows = (_sapp_window_t*) SOKOL_CALLOC((size_t)_sapp.window_pool.pool.size, sizeof(_sapp_window_t)); + SOKOL_ASSERT(_sapp.window_pool.windows); } -_SOKOL_PRIVATE sapp_window _sapp_make_window_id(uint32_t win_id) { - sapp_window res = { win_id }; - return res; +_SOKOL_PRIVATE void _sapp_discard_window_pool(void) { + SOKOL_ASSERT(_sapp.window_pool.windows); + SOKOL_FREE(_sapp.window_pool.windows); _sapp.window_pool.windows = 0; + _sapp_discard_pool(&_sapp.window_pool.pool); } /* returns pointer to window by id without matching id check */ -_SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(const _sapp_window_pool_t* win_pool, uint32_t win_id) { - SOKOL_ASSERT(win_pool && (SAPP_INVALID_ID != win_id)); +_SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(uint32_t win_id) { + SOKOL_ASSERT(SAPP_INVALID_ID != win_id); int slot_index = _sapp_slot_index(win_id); - SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < win_pool->pool.size)); - return &win_pool->windows[slot_index]; + SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < _sapp.window_pool.pool.size)); + SOKOL_ASSERT(_sapp.window_pool.windows); + return &_sapp.window_pool.windows[slot_index]; } /* returns pointer to window with matching id check, may return 0 */ -_SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(const _sapp_window_pool_t* win_pool, uint32_t win_id) { +_SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(uint32_t win_id) { if (SAPP_INVALID_ID != win_id) { - _sapp_window_t* win = _sapp_window_at(win_pool, win_id); + _sapp_window_t* win = _sapp_window_at(win_id); if (win->slot.id == win_id) { return win; } @@ -2555,25 +2551,46 @@ _SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(const _sapp_window_pool_t* wi return 0; } -_SOKOL_PRIVATE bool _sapp_create_window(_sapp_window_t* win, const sapp_window_desc* desc) { +_SOKOL_PRIVATE sapp_window _sapp_make_window_id(uint32_t win_id) { + sapp_window res = { win_id }; + return res; +} + +_SOKOL_PRIVATE uint32_t _sapp_alloc_window_id(void) { + int slot_index = _sapp_pool_alloc_index(&_sapp.window_pool.pool); + if (_SAPP_INVALID_SLOT_INDEX != slot_index) { + return _sapp_slot_alloc(&_sapp.window_pool.pool, &_sapp.window_pool.windows[slot_index].slot, slot_index); + } + else { + /* pool is exhausted */ + return SAPP_INVALID_ID; + } +} + +_SOKOL_PRIVATE void _sapp_free_window_id(uint32_t win_id) { + SOKOL_ASSERT(SAPP_INVALID_ID != win_id); + _sapp_pool_free_index(&_sapp.window_pool.pool, _sapp_slot_index(win_id)); +} + +_SOKOL_PRIVATE bool _sapp_platform_create_window(_sapp_window_t* win) { #if defined(_SAPP_MACOS) - return _sapp_macos_create_window(win, desc); + return _sapp_macos_create_window(win); #elif defined(_SAPP_IOS) - return _sapp_ios_create_window(win, desc); + return _sapp_ios_create_window(win); #elif defined(_SAPP_EMSCRIPTEN) - return _sapp_emsc_create_window(win, desc); + return _sapp_emsc_create_window(win); #elif defined(_SAPP_WIN32) - return _sapp_win32_create_window(win, desc); + return _sapp_win32_create_window(win); #elif defined(_SAPP_UWP) - return _sapp_uwp_create_window(win, desc); + return _sapp_uwp_create_window(win); #elif defined(_SAPP_ANDROID) - return _sapp_android_create_window(win, desc); + return _sapp_android_create_window(win); #elif defined(_SAPP_LINUX) - return _sapp_x11_create_window(win, desc); + return _sapp_x11_create_window(win); #endif } -_SOKOL_PRIVATE void _sapp_destroy_window(_sapp_window_t* win) { +_SOKOL_PRIVATE void _sapp_platform_destroy_window(_sapp_window_t* win) { #if defined(_SAPP_MACOS) _sapp_macos_destroy_window(win); #elif defined(_SAPP_IOS) @@ -2591,16 +2608,6 @@ _SOKOL_PRIVATE void _sapp_destroy_window(_sapp_window_t* win) { #endif } -_SOKOL_PRIVATE void _sapp_destroy_all_windows(_sapp_window_pool_t* win_pool) { - SOKOL_ASSERT(win_pool); - for (int i = 0; i < win_pool->pool.size; i++) { - uint32_t win_id = win_pool->windows[i].slot.id; - if (SAPP_INVALID_ID != win_id) { - _sapp_destroy_window(&win_pool->windows[i]); - } - } -} - _SOKOL_PRIVATE void _sapp_fail(const char* msg) { if (_sapp.desc.fail_cb) { _sapp.desc.fail_cb(msg); @@ -2752,14 +2759,118 @@ _SOKOL_PRIVATE void _sapp_platform_discard_state(void) { #endif } -_SOKOL_PRIVATE sapp_window _sapp_open_window(const sapp_window_desc* desc) { - SOKOL_ASSERT(desc); - // FIXME - return _sapp_make_window_id(SAPP_INVALID_ID); +_SOKOL_PRIVATE bool _sapp_init_clipboard(_sapp_clipboard_t* clipboard, const sapp_window_desc* desc) { + SOKOL_ASSERT(clipboard && desc); + SOKOL_ASSERT(0 == clipboard->buffer); + clipboard->enabled = desc->enable_clipboard; + if (clipboard->enabled) { + clipboard->buf_size = desc->clipboard_size; + clipboard->buffer = (char*) SOKOL_CALLOC(1, (size_t)clipboard->buf_size); + if (0 == clipboard->buffer) { + SOKOL_LOG("failed to allocate clipboard buffer!"); + return false; + } + } + return true; +} + +_SOKOL_PRIVATE void _sapp_discard_clipboard(_sapp_clipboard_t* clipboard) { + SOKOL_ASSERT(clipboard); + if (0 != clipboard->buffer) { + SOKOL_FREE(clipboard->buffer); + } + _SAPP_CLEAR_PTR(_sapp_clipboard_t, clipboard); +} + +_SOKOL_PRIVATE bool _sapp_init_drop(_sapp_drop_t* drop, const sapp_window_desc* desc) { + SOKOL_ASSERT(drop && desc); + SOKOL_ASSERT(0 == drop->buffer); + drop->enabled = desc->enable_dragndrop; + if (drop->enabled) { + drop->max_files = desc->max_dropped_files; + drop->max_path_length = desc->max_dropped_file_path_length; + drop->buf_size = drop->max_files * drop->max_path_length; + drop->buffer = (char*) SOKOL_CALLOC(1, (size_t)drop->buf_size); + if (0 == drop->buffer) { + SOKOL_LOG("failed to allocate drag'n'drop buffer!"); + return false; + } + } + return true; } -_SOKOL_PRIVATE void _sapp_close_window(sapp_window win_id) { - // FIXME +_SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { + SOKOL_ASSERT(drop); + if (0 != drop->buffer) { + SOKOL_FREE(drop->buffer); + } + _SAPP_CLEAR_PTR(_sapp_drop_t, drop); +} + +_SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (0 == win) { + return; + } + _sapp_discard_drop(&win->drop); + _sapp_discard_clipboard(&win->clipboard); + _sapp_platform_destroy_window(win); + _sapp_free_window_id(win_id); + _SAPP_CLEAR_PTR(_sapp_window_t, win); +} + +_SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { + SOKOL_ASSERT(desc); + + const uint32_t win_id = _sapp_alloc_window_id(); + if (SAPP_INVALID_ID == win_id) { + SOKOL_LOG("window pool exhausted") + return SAPP_INVALID_ID; + } + + // platform-agnostic initialization + _sapp_window_t* win = _sapp_window_at(win_id); + SOKOL_ASSERT(win); + win->desc = *desc; + win->pos_x = desc->x; + win->pos_y = desc->y; + win->window_width = desc->width; + win->window_height = desc->height; + win->framebuffer_width = desc->width; + win->framebuffer_height = desc->height; + win->dpi_scale = 1.0f; + win->fullscreen = desc->fullscreen; + win->first_frame = true; + win->mouse.shown = true; + if (!_sapp_init_clipboard(&win->clipboard, &win->desc)) { + SOKOL_LOG("clipboard initialization failed!"); + return SAPP_INVALID_ID; + } + if (!_sapp_init_drop(&win->drop, &win->desc)) { + SOKOL_LOG("drag'n'drop initialization failed!"); + _sapp_discard_clipboard(&win->clipboard); + return SAPP_INVALID_ID; + } + _sapp_strcpy(desc->title, &win->title[0], sizeof(win->title)); + win->desc.title = &win->title[0]; // redirect transient pointer to persistent copy + + // platform-specific window creation and initialization + if (!_sapp_platform_create_window(win)) { + _sapp_discard_drop(&win->drop); + _sapp_discard_clipboard(&win->clipboard); + return SAPP_INVALID_ID; + } + return win_id; +} + +_SOKOL_PRIVATE void _sapp_destroy_all_windows(void) { + SOKOL_ASSERT(_sapp.window_pool.windows); + for (int i = 0; i < _sapp.window_pool.pool.size; i++) { + uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + if (SAPP_INVALID_ID != win_id) { + _sapp_destroy_window(win_id); + } + } } _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { @@ -2771,51 +2882,26 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { } _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { - _SAPP_CLEAR(_sapp_t, _sapp); + _SAPP_CLEAR_ITEM(_sapp_t, _sapp); _sapp.desc = _sapp_desc_defaults(desc); - _sapp.window.desc = _sapp.desc.window; - _sapp.window.first_frame = true; - _sapp.window.window_width = _sapp.desc.window.width; - _sapp.window.window_height = _sapp.desc.window.height; - _sapp.window.framebuffer_width = _sapp.window.window_width; - _sapp.window.framebuffer_height = _sapp.window.window_height; - _sapp.window.clipboard.enabled = _sapp.desc.window.enable_clipboard; - if (_sapp.window.clipboard.enabled) { - _sapp.window.clipboard.buf_size = _sapp.desc.window.clipboard_size; - _sapp.window.clipboard.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.window.clipboard.buf_size); - } - _sapp.window.drop.enabled = _sapp.desc.window.enable_dragndrop; - if (_sapp.window.drop.enabled) { - _sapp.window.drop.max_files = _sapp.desc.window.max_dropped_files; - _sapp.window.drop.max_path_length = _sapp.desc.window.max_dropped_file_path_length; - _sapp.window.drop.buf_size = _sapp.window.drop.max_files * _sapp.window.drop.max_path_length; - _sapp.window.drop.buffer = (char*) SOKOL_CALLOC(1, (size_t)_sapp.window.drop.buf_size); - } - _sapp_strcpy(_sapp.desc.window.title, _sapp.window.title, sizeof(_sapp.window.title)); - _sapp.desc.window.title = _sapp.window.title; - _sapp.window.dpi_scale = 1.0f; - _sapp.window.fullscreen = _sapp.desc.window.fullscreen; - _sapp.window.mouse.shown = true; - _sapp_setup_window_pool(&_sapp.window_pool, &_sapp.desc); + _sapp_setup_window_pool(&_sapp.desc); _sapp_platform_init_state(); + + // copy title string in desc to backing store and patch transient pointer + _sapp_strcpy(desc->window.title, &_sapp.desc_window_title[0], sizeof(_sapp.desc_window_title)); + _sapp.desc.window.title = &_sapp.desc_window_title[0]; + // FIXME: what about the icon image pointers? } _SOKOL_PRIVATE void _sapp_discard_state(void) { - _sapp_destroy_all_windows(&_sapp.window_pool); - _sapp_discard_window_pool(&_sapp.window_pool); - if (_sapp.window.clipboard.enabled) { - SOKOL_ASSERT(_sapp.window.clipboard.buffer); - SOKOL_FREE((void*)_sapp.window.clipboard.buffer); - } - if (_sapp.window.drop.enabled) { - SOKOL_ASSERT(_sapp.window.drop.buffer); - SOKOL_FREE((void*)_sapp.window.drop.buffer); - } + _sapp_destroy_all_windows(); + _sapp_discard_window_pool(); + _sapp_platform_discard_state(); if (_sapp.default_icon_pixels) { SOKOL_FREE((void*)_sapp.default_icon_pixels); + _sapp.default_icon_pixels = 0; } - _sapp_platform_discard_state(); - _SAPP_CLEAR(_sapp_t, _sapp); + _SAPP_CLEAR_ITEM(_sapp_t, _sapp); } _SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) { @@ -3155,42 +3241,144 @@ _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) { /* called from _sapp_init_state() */ _SOKOL_PRIVATE void _sapp_macos_init_state(void) { _sapp_macos_init_keytable(); + // set the application dock icon as early as possible, otherwise + // the dummy icon will be visible for a short time + sapp_set_icon(&_sapp.desc.icon); + NSApp.activationPolicy = NSApplicationActivationPolicyRegular; + _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; + NSApp.delegate = _sapp.macos.app_delegate; + [NSApp activateIgnoringOtherApps:YES]; + #if defined(SOKOL_METAL) + _sapp.macos.mtl_device = MTLCreateSystemDefaultDevice(); + #endif } /* called from _sapp_discard_state() */ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { // NOTE: it's safe to call [release] on a nil object - _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); - _SAPP_OBJC_RELEASE(_sapp.macos.win.delegate); - _SAPP_OBJC_RELEASE(_sapp.macos.win.view); _SAPP_OBJC_RELEASE(_sapp.macos.app_delegate); #if defined(SOKOL_METAL) _SAPP_OBJC_RELEASE(_sapp.macos.mtl_device); #endif - _SAPP_OBJC_RELEASE(_sapp.macos.win.ns_window); } _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { - _sapp_init_state(desc); [NSApplication sharedApplication]; - // set the application dock icon as early as possible, otherwise - // the dummy icon will be visible for a short time - sapp_set_icon(&_sapp.desc.icon); - NSApp.activationPolicy = NSApplicationActivationPolicyRegular; - _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; - NSApp.delegate = _sapp.macos.app_delegate; - [NSApp activateIgnoringOtherApps:YES]; + _sapp_init_state(desc); [NSApp run]; // NOTE: [NSApp run] never returns, cleanup code is in applicationWillTerminate instead } -_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win, const sapp_window_desc* desc) { - // FIXME - return false; +_SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { + SOKOL_ASSERT(win); + if (win->fullscreen) { + NSRect screen_rect = NSScreen.mainScreen.frame; + win->window_width = screen_rect.size.width; + win->window_height = screen_rect.size.height; + } + if (win->desc.high_dpi) { + // FIXME: is there something like iOS 'nativeScale' on macOS? + win->framebuffer_width = 2 * win->window_width; + win->framebuffer_height = 2 * win->window_height; + } + else { + win->framebuffer_width = win->window_width; + win->framebuffer_height = win->window_height; + } + win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; + const NSUInteger style = + NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable | + NSWindowStyleMaskResizable; + NSRect window_rect = NSMakeRect(win->pos_x, win->pos_y, win->window_width, win->window_height); + win->macos.window = [[_sapp_macos_window alloc] + initWithContentRect:window_rect + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; + win->macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate + win->macos.window.title = [NSString stringWithUTF8String:win->title]; + win->macos.window.acceptsMouseMovedEvents = YES; + win->macos.window.restorable = YES; + + win->macos.delegate = [[_sapp_macos_window_delegate alloc] init]; + win->macos.window.delegate = win->macos.delegate; + #if defined(SOKOL_METAL) + win->macos.view = [[_sapp_macos_view alloc] init]; + [win->macos.view updateTrackingAreas]; + win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; + win->macos.view.device = _sapp.macos.mtl_device; + win->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; + win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + win->macos.view.sampleCount = (NSUInteger) win->desc.sample_count; + win->macos.view.autoResizeDrawable = false; + win->macos.window.contentView = win->macos.view; + [win->macos.window makeFirstResponder:win->macos.view]; + win->macos.view.layer.magnificationFilter = kCAFilterNearest; + #elif defined(SOKOL_GLCORE33) + NSOpenGLPixelFormatAttribute attrs[32]; + int i = 0; + attrs[i++] = NSOpenGLPFAAccelerated; + attrs[i++] = NSOpenGLPFADoubleBuffer; + attrs[i++] = NSOpenGLPFAOpenGLProfile; attrs[i++] = NSOpenGLProfileVersion3_2Core; + attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24; + attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8; + attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24; + attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8; + if (_sapp.sample_count > 1) { + attrs[i++] = NSOpenGLPFAMultisample; + attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; + attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.sample_count; + } + else { + attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; + } + attrs[i++] = 0; + NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + SOKOL_ASSERT(glpixelformat_obj != nil); + + _sapp.macos.view = [[_sapp_macos_view alloc] + initWithFrame:window_rect + pixelFormat:glpixelformat_obj]; + _SAPP_OBJC_RELEASE(glpixelformat_obj); + [_sapp.macos.view updateTrackingAreas]; + if (_sapp.desc.high_dpi) { + [_sapp.macos.view setWantsBestResolutionOpenGLSurface:YES]; + } + else { + [_sapp.macos.view setWantsBestResolutionOpenGLSurface:NO]; + } + + _sapp.macos.window.contentView = _sapp.macos.view; + [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; + + NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 + target:_sapp.macos.view + selector:@selector(timerFired:) + userInfo:nil + repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode]; + timer_obj = nil; + #endif + if (win->fullscreen) { + /* on GL, this already toggles a rendered frame, so set the valid flag before */ + [win->macos.window toggleFullScreen:NSApp]; + } + else { + [win->macos.window center]; + } + [win->macos.window makeKeyAndOrderFront:nil]; + return true; } _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { - // FIXME + SOKOL_ASSERT(win); + // NOTE: it's safe to call [release] on a nil object + _SAPP_OBJC_RELEASE(win->macos.tracking_area); + _SAPP_OBJC_RELEASE(win->macos.delegate); + _SAPP_OBJC_RELEASE(win->macos.view); + _SAPP_OBJC_RELEASE(win->macos.window); } /* MacOS entry function */ @@ -3262,7 +3450,7 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { */ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { #if defined(SOKOL_METAL) - const NSRect fb_rect = [_sapp.macos.win.view bounds]; + const NSRect fb_rect = [_sapp.window.macos.view bounds]; _sapp.window.framebuffer_width = fb_rect.size.width * _sapp.window.dpi_scale; _sapp.window.framebuffer_height = fb_rect.size.height * _sapp.window.dpi_scale; #elif defined(SOKOL_GLCORE33) @@ -3270,7 +3458,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { _sapp.framebuffer_width = fb_rect.size.width; _sapp.framebuffer_height = fb_rect.size.height; #endif - const NSRect bounds = [_sapp.macos.win.view bounds]; + const NSRect bounds = [_sapp.window.macos.view bounds]; _sapp.window.window_width = bounds.size.width; _sapp.window.window_height = bounds.size.height; if (_sapp.window.framebuffer_width == 0) { @@ -3294,7 +3482,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { */ #if defined(SOKOL_METAL) CGSize drawable_size = { (CGFloat) _sapp.window.framebuffer_width, (CGFloat) _sapp.window.framebuffer_height }; - _sapp.macos.win.view.drawableSize = drawable_size; + _sapp.window.macos.view.drawableSize = drawable_size; #endif } @@ -3304,7 +3492,7 @@ _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { event handlers */ _sapp.window.fullscreen = !_sapp.window.fullscreen; - [_sapp.macos.win.ns_window toggleFullScreen:nil]; + [_sapp.window.macos.window toggleFullScreen:nil]; } _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { @@ -3333,7 +3521,7 @@ _SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { } _SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { - [_sapp.macos.win.ns_window setTitle: [NSString stringWithUTF8String:_sapp.window.title]]; + [_sapp.window.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window.title]]; } _SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) { @@ -3432,114 +3620,20 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_frame(); if (_sapp.quit_requested || _sapp.quit_ordered) { - [_sapp.macos.win.ns_window performClose:nil]; + [_sapp.window.macos.window performClose:nil]; } } @implementation _sapp_macos_app_delegate - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); - if (_sapp.window.fullscreen) { - NSRect screen_rect = NSScreen.mainScreen.frame; - _sapp.window.window_width = screen_rect.size.width; - _sapp.window.window_height = screen_rect.size.height; - } - if (_sapp.desc.window.high_dpi) { - _sapp.window.framebuffer_width = 2 * _sapp.window.window_width; - _sapp.window.framebuffer_height = 2 * _sapp.window.window_height; - } - else { - _sapp.window.framebuffer_width = _sapp.window.window_width; - _sapp.window.framebuffer_height = _sapp.window.window_height; - } - _sapp.window.dpi_scale = (float)_sapp.window.framebuffer_width / (float) _sapp.window.window_width; - const NSUInteger style = - NSWindowStyleMaskTitled | - NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | - NSWindowStyleMaskResizable; - NSRect window_rect = NSMakeRect(0, 0, _sapp.window.window_width, _sapp.window.window_height); - _sapp.macos.win.ns_window = [[_sapp_macos_window alloc] - initWithContentRect:window_rect - styleMask:style - backing:NSBackingStoreBuffered - defer:NO]; - _sapp.macos.win.ns_window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate - _sapp.macos.win.ns_window.title = [NSString stringWithUTF8String:_sapp.window.title]; - _sapp.macos.win.ns_window.acceptsMouseMovedEvents = YES; - _sapp.macos.win.ns_window.restorable = YES; - - _sapp.macos.win.delegate = [[_sapp_macos_window_delegate alloc] init]; - _sapp.macos.win.ns_window.delegate = _sapp.macos.win.delegate; - #if defined(SOKOL_METAL) - _sapp.macos.mtl_device = MTLCreateSystemDefaultDevice(); - _sapp.macos.win.view = [[_sapp_macos_view alloc] init]; - [_sapp.macos.win.view updateTrackingAreas]; - _sapp.macos.win.view.preferredFramesPerSecond = 60 / _sapp.window.desc.swap_interval; - _sapp.macos.win.view.device = _sapp.macos.mtl_device; - _sapp.macos.win.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; - _sapp.macos.win.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.macos.win.view.sampleCount = (NSUInteger) _sapp.window.desc.sample_count; - _sapp.macos.win.view.autoResizeDrawable = false; - _sapp.macos.win.ns_window.contentView = _sapp.macos.win.view; - [_sapp.macos.win.ns_window makeFirstResponder:_sapp.macos.win.view]; - _sapp.macos.win.view.layer.magnificationFilter = kCAFilterNearest; - #elif defined(SOKOL_GLCORE33) - NSOpenGLPixelFormatAttribute attrs[32]; - int i = 0; - attrs[i++] = NSOpenGLPFAAccelerated; - attrs[i++] = NSOpenGLPFADoubleBuffer; - attrs[i++] = NSOpenGLPFAOpenGLProfile; attrs[i++] = NSOpenGLProfileVersion3_2Core; - attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24; - attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8; - attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24; - attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8; - if (_sapp.sample_count > 1) { - attrs[i++] = NSOpenGLPFAMultisample; - attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; - attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.sample_count; - } - else { - attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; - } - attrs[i++] = 0; - NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; - SOKOL_ASSERT(glpixelformat_obj != nil); - _sapp.macos.view = [[_sapp_macos_view alloc] - initWithFrame:window_rect - pixelFormat:glpixelformat_obj]; - _SAPP_OBJC_RELEASE(glpixelformat_obj); - [_sapp.macos.view updateTrackingAreas]; - if (_sapp.desc.high_dpi) { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:YES]; - } - else { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:NO]; - } + _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); + _sapp.cur_window_id = _sapp.main_window_id; - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - - NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 - target:_sapp.macos.view - selector:@selector(timerFired:) - userInfo:nil - repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode]; - timer_obj = nil; - #endif - _sapp.valid = true; - if (_sapp.window.fullscreen) { - /* on GL, this already toggles a rendered frame, so set the valid flag before */ - [_sapp.macos.win.ns_window toggleFullScreen:self]; - } - else { - [_sapp.macos.win.ns_window center]; - } - [_sapp.macos.win.ns_window makeKeyAndOrderFront:nil]; - _sapp_macos_update_dimensions(); [NSEvent setMouseCoalescingEnabled:NO]; + _sapp_macos_update_dimensions(); + _sapp.valid = true; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -3750,9 +3844,9 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { return YES; } - (void)updateTrackingAreas { - if (_sapp.macos.win.tracking_area != nil) { - [self removeTrackingArea:_sapp.macos.win.tracking_area]; - _SAPP_OBJC_RELEASE(_sapp.macos.win.tracking_area); + if (_sapp.window.macos.tracking_area != nil) { + [self removeTrackingArea:_sapp.window.macos.tracking_area]; + _SAPP_OBJC_RELEASE(_sapp.window.macos.tracking_area); } const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | @@ -3760,8 +3854,8 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { NSTrackingCursorUpdate | NSTrackingInVisibleRect | NSTrackingAssumeInside; - _sapp.macos.win.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - [self addTrackingArea:_sapp.macos.win.tracking_area]; + _sapp.window.macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; + [self addTrackingArea:_sapp.window.macos.tracking_area]; [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent*)event { @@ -3769,48 +3863,48 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { /* don't send mouse enter/leave while dragging (so that it behaves the same as on Windows while SetCapture is active */ - if (0 == _sapp.macos.win.mouse_buttons) { + if (0 == _sapp.window.macos.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } } - (void)mouseExited:(NSEvent*)event { _sapp_macos_update_mouse(event); - if (0 == _sapp.macos.win.mouse_buttons) { + if (0 == _sapp.window.macos.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } } - (void)mouseDown:(NSEvent*)event { _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mods(event)); - _sapp.macos.win.mouse_buttons |= (1< Date: Mon, 19 Apr 2021 20:07:48 +0200 Subject: [PATCH 05/49] continue with macOS window code --- sokol_app.h | 302 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 175 insertions(+), 127 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 184005fb7..5127f40c9 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1817,23 +1817,27 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } @interface _sapp_macos_app_delegate : NSObject @end @interface _sapp_macos_window : NSWindow +@property uint32_t win_id; @end @interface _sapp_macos_window_delegate : NSObject +@property uint32_t win_id; @end #if defined(SOKOL_METAL) @interface _sapp_macos_view : MTKView + @property uint32_t win_id; @end #elif defined(SOKOL_GLCORE33) @interface _sapp_macos_view : NSOpenGLView + @property uint32_t win_id; - (void)timerFired:(id)sender; @end #endif // SOKOL_GLCORE33 typedef struct { - NSWindow* window; - NSTrackingArea* tracking_area; + _sapp_macos_window* window; _sapp_macos_window_delegate* delegate; _sapp_macos_view* view; + NSTrackingArea* tracking_area; uint32_t flags_changed_store; uint8_t mouse_buttons; } _sapp_macos_window_t; @@ -2360,7 +2364,8 @@ typedef struct { _sapp_window_pool_t window_pool; uint32_t main_window_id; uint32_t cur_window_id; - _sapp_window_t window; + uint32_t pushed_window_id; + _sapp_window_t* cur_window; bool valid; bool gles2_fallback; bool quit_requested; @@ -2621,50 +2626,51 @@ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { SOKOL_ABORT(); } -_SOKOL_PRIVATE void _sapp_call_init(void) { - if (_sapp.desc.window.init_cb) { - _sapp.desc.window.init_cb(); +_SOKOL_PRIVATE void _sapp_call_init(_sapp_window_t* win) { + SOKOL_ASSERT(!win->init_called); + if (win->desc.init_cb) { + win->desc.init_cb(); } - else if (_sapp.desc.window.init_userdata_cb) { - _sapp.desc.window.init_userdata_cb(_sapp.desc.window.user_data); + else if (win->desc.init_userdata_cb) { + win->desc.init_userdata_cb(win->desc.user_data); } - _sapp.window.init_called = true; + win->init_called = true; } -_SOKOL_PRIVATE void _sapp_call_frame(void) { - if (_sapp.window.init_called && !_sapp.window.cleanup_called) { - if (_sapp.desc.window.frame_cb) { - _sapp.desc.window.frame_cb(); +_SOKOL_PRIVATE void _sapp_call_frame(_sapp_window_t* win) { + if (win->init_called && !win->cleanup_called) { + if (win->desc.frame_cb) { + win->desc.frame_cb(); } - else if (_sapp.desc.window.frame_userdata_cb) { - _sapp.desc.window.frame_userdata_cb(_sapp.desc.window.user_data); + else if (win->desc.frame_userdata_cb) { + win->desc.frame_userdata_cb(win->desc.user_data); } } } -_SOKOL_PRIVATE void _sapp_call_cleanup(void) { - if (!_sapp.window.cleanup_called) { - if (_sapp.desc.window.cleanup_cb) { - _sapp.desc.window.cleanup_cb(); +_SOKOL_PRIVATE void _sapp_call_cleanup(_sapp_window_t* win) { + if (!win->cleanup_called) { + if (win->desc.cleanup_cb) { + win->desc.cleanup_cb(); } - else if (_sapp.desc.window.cleanup_userdata_cb) { - _sapp.desc.window.cleanup_userdata_cb(_sapp.desc.window.user_data); + else if (win->desc.cleanup_userdata_cb) { + win->desc.cleanup_userdata_cb(win->desc.user_data); } - _sapp.window.cleanup_called = true; + win->cleanup_called = true; } } -_SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { - if (!_sapp.window.cleanup_called) { - if (_sapp.desc.window.event_cb) { - _sapp.desc.window.event_cb(e); +_SOKOL_PRIVATE bool _sapp_call_event(_sapp_window_t* win, const sapp_event* e) { + if (!win->cleanup_called) { + if (win->desc.event_cb) { + win->desc.event_cb(e); } - else if (_sapp.desc.window.event_userdata_cb) { - _sapp.desc.window.event_userdata_cb(e, _sapp.desc.window.user_data); + else if (win->desc.event_userdata_cb) { + win->desc.event_userdata_cb(e, win->desc.user_data); } } - if (_sapp.window.event_consumed) { - _sapp.window.event_consumed = false; + if (win->event_consumed) { + win->event_consumed = false; return true; } else { @@ -2672,12 +2678,12 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { } } -_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { - SOKOL_ASSERT(_sapp.window.drop.buffer); - SOKOL_ASSERT((index >= 0) && (index <= _sapp.window.drop.max_files)); - int offset = index * _sapp.window.drop.max_path_length; - SOKOL_ASSERT(offset < _sapp.window.drop.buf_size); - return &_sapp.window.drop.buffer[offset]; +_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(_sapp_window_t* win, int index) { + SOKOL_ASSERT(win->drop.buffer); + SOKOL_ASSERT((index >= 0) && (index <= win->drop.max_files)); + int offset = index * win->drop.max_path_length; + SOKOL_ASSERT(offset < win->drop.buf_size); + return &win->drop.buffer[offset]; } /* Copy a string into a fixed size buffer with guaranteed zero- @@ -2723,6 +2729,22 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in return desc; } +// makes a window the current window and returns pointer to window struct, CAN RETURN NULL! +_SOKOL_PRIVATE _sapp_window_t* _sapp_push_current_window(uint32_t win_id) { + SOKOL_ASSERT(SAPP_INVALID_ID == _sapp.pushed_window_id); + _sapp.pushed_window_id = _sapp.cur_window_id; + _sapp.cur_window_id = win_id; + _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); + return _sapp.cur_window; +} + +_SOKOL_PRIVATE void _sapp_pop_current_window(void) { + SOKOL_ASSERT(SAPP_INVALID_ID != _sapp.pushed_window_id); + _sapp.cur_window_id = _sapp.pushed_window_id; + _sapp.pushed_window_id = SAPP_INVALID_ID; + _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); +} + _SOKOL_PRIVATE void _sapp_platform_init_state(void) { #if defined(_SAPP_MACOS) _sapp_macos_init_state(); @@ -2808,15 +2830,17 @@ _SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { } _SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { - _sapp_window_t* win = _sapp_lookup_window(win_id); + _sapp_window_t* win = _sapp_push_current_window(win_id); if (0 == win) { return; } + _sapp_call_cleanup(win); _sapp_discard_drop(&win->drop); _sapp_discard_clipboard(&win->clipboard); _sapp_platform_destroy_window(win); _sapp_free_window_id(win_id); _SAPP_CLEAR_PTR(_sapp_window_t, win); + _sapp_pop_current_window(); } _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { @@ -2904,24 +2928,25 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { _SAPP_CLEAR_ITEM(_sapp_t, _sapp); } -_SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) { +_SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* win, sapp_event_type type) { memset(&_sapp.event, 0, sizeof(_sapp.event)); _sapp.event.type = type; _sapp.event.frame_count = _sapp.frame_count; _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; - _sapp.event.window_width = _sapp.window.window_width; - _sapp.event.window_height = _sapp.window.window_height; - _sapp.event.framebuffer_width = _sapp.window.framebuffer_width; - _sapp.event.framebuffer_height = _sapp.window.framebuffer_height; - _sapp.event.mouse_x = _sapp.window.mouse.x; - _sapp.event.mouse_y = _sapp.window.mouse.y; - _sapp.event.mouse_dx = _sapp.window.mouse.dx; - _sapp.event.mouse_dy = _sapp.window.mouse.dy; + _sapp.event.window_width = win->window_width; + _sapp.event.window_height = win->window_height; + _sapp.event.framebuffer_width = win->framebuffer_width; + _sapp.event.framebuffer_height = win->framebuffer_height; + _sapp.event.mouse_x = win->mouse.x; + _sapp.event.mouse_y = win->mouse.y; + _sapp.event.mouse_dx = win->mouse.dx; + _sapp.event.mouse_dy = win->mouse.dy; } -_SOKOL_PRIVATE bool _sapp_events_enabled(void) { +_SOKOL_PRIVATE bool _sapp_events_enabled(_sapp_window_t* win) { + SOKOL_ASSERT(win); /* only send events when an event callback is set, and the init function was called */ - return (_sapp.desc.window.event_cb || _sapp.desc.window.event_userdata_cb) && _sapp.window.init_called; + return (win->desc.event_cb || win->desc.event_userdata_cb) && win->init_called; } _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { @@ -2933,20 +2958,24 @@ _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { } } -_SOKOL_PRIVATE void _sapp_clear_drop_buffer(void) { - if (_sapp.window.drop.enabled) { - SOKOL_ASSERT(_sapp.window.drop.buffer); - memset(_sapp.window.drop.buffer, 0, (size_t)_sapp.window.drop.buf_size); +_SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* win) { + SOKOL_ASSERT(win); + if (win->drop.enabled) { + SOKOL_ASSERT(win->drop.buffer); + memset(win->drop.buffer, 0, (size_t)win->drop.buf_size); } } _SOKOL_PRIVATE void _sapp_frame(void) { - if (_sapp.window.first_frame) { - _sapp.window.first_frame = false; - _sapp_call_init(); + // FIXME: loop over all windows + _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); + if (win->first_frame) { + win->first_frame = false; + _sapp_call_init(win); } - _sapp_call_frame(); + _sapp_call_frame(win); _sapp.frame_count++; + _sapp_pop_current_window(); } _SOKOL_PRIVATE bool _sapp_image_validate(const sapp_image_desc* desc) { @@ -3297,15 +3326,18 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { styleMask:style backing:NSBackingStoreBuffered defer:NO]; + win->macos.window.win_id = win->slot.id; win->macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate win->macos.window.title = [NSString stringWithUTF8String:win->title]; win->macos.window.acceptsMouseMovedEvents = YES; win->macos.window.restorable = YES; win->macos.delegate = [[_sapp_macos_window_delegate alloc] init]; + win->macos.delegate.win_id = win->slot.id; win->macos.window.delegate = win->macos.delegate; #if defined(SOKOL_METAL) win->macos.view = [[_sapp_macos_view alloc] init]; + win->macos.view.win_id = win->slot.id; [win->macos.view updateTrackingAreas]; win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; win->macos.view.device = _sapp.macos.mtl_device; @@ -3418,29 +3450,29 @@ _SOKOL_PRIVATE uint32_t _sapp_macos_mods(NSEvent* ev) { return m; } -_SOKOL_PRIVATE void _sapp_macos_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); +_SOKOL_PRIVATE void _sapp_macos_mouse_event(_sapp_window_t* win, sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { + if (_sapp_events_enabled(win)) { + _sapp_init_event(win, type); _sapp.event.mouse_button = btn; _sapp.event.modifiers = mod; - _sapp_call_event(&_sapp.event); + _sapp_call_event(win, &_sapp.event); } } -_SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); +_SOKOL_PRIVATE void _sapp_macos_key_event(_sapp_window_t* win, sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { + if (_sapp_events_enabled(win)) { + _sapp_init_event(win, type); _sapp.event.key_code = key; _sapp.event.key_repeat = repeat; _sapp.event.modifiers = mod; - _sapp_call_event(&_sapp.event); + _sapp_call_event(win, &_sapp.event); } } -_SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(type); - _sapp_call_event(&_sapp.event); +_SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type type) { + if (_sapp_events_enabled(win)) { + _sapp_init_event(win, type); + _sapp_call_event(win, &_sapp.event); } } @@ -3448,32 +3480,35 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { can dynamically update the DPI scaling factor when a window is moved between HighDPI / LowDPI screens. */ -_SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { +_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { #if defined(SOKOL_METAL) - const NSRect fb_rect = [_sapp.window.macos.view bounds]; - _sapp.window.framebuffer_width = fb_rect.size.width * _sapp.window.dpi_scale; - _sapp.window.framebuffer_height = fb_rect.size.height * _sapp.window.dpi_scale; + /* FIXME: hmm dpi_scale is used here with the old value, but updated + further down... this looks wrong? + */ + const NSRect fb_rect = [win->macos.view bounds]; + win->framebuffer_width = fb_rect.size.width * win->dpi_scale; + win->framebuffer_height = fb_rect.size.height * win->dpi_scale; #elif defined(SOKOL_GLCORE33) - const NSRect fb_rect = [_sapp.macos.view convertRectToBacking:[_sapp.macos.view frame]]; - _sapp.framebuffer_width = fb_rect.size.width; - _sapp.framebuffer_height = fb_rect.size.height; + const NSRect fb_rect = [win->macos.view convertRectToBacking:[win->macos.view frame]]; + win->framebuffer_width = fb_rect.size.width; + win->framebuffer_height = fb_rect.size.height; #endif - const NSRect bounds = [_sapp.window.macos.view bounds]; - _sapp.window.window_width = bounds.size.width; - _sapp.window.window_height = bounds.size.height; - if (_sapp.window.framebuffer_width == 0) { - _sapp.window.framebuffer_width = 1; + const NSRect bounds = [win->macos.view bounds]; + win->window_width = bounds.size.width; + win->window_height = bounds.size.height; + if (win->framebuffer_width == 0) { + win->framebuffer_width = 1; } - if (_sapp.window.framebuffer_height == 0) { - _sapp.window.framebuffer_height = 1; + if (win->framebuffer_height == 0) { + win->framebuffer_height = 1; } - if (_sapp.window.window_width == 0) { - _sapp.window.window_width = 1; + if (win->window_width == 0) { + win->window_width = 1; } - if (_sapp.window.window_height == 0) { - _sapp.window.window_height = 1; + if (win->window_height == 0) { + win->window_height = 1; } - _sapp.window.dpi_scale = (float)_sapp.window.framebuffer_width / (float)_sapp.window.window_width; + win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; /* NOTE: _sapp_macos_update_dimensions() isn't called each frame, but only when the window size actually changes, so resizing the MTKView's @@ -3481,18 +3516,18 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { identical drawableSize. */ #if defined(SOKOL_METAL) - CGSize drawable_size = { (CGFloat) _sapp.window.framebuffer_width, (CGFloat) _sapp.window.framebuffer_height }; - _sapp.window.macos.view.drawableSize = drawable_size; + CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; + win->macos.view.drawableSize = drawable_size; #endif } -_SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { +_SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(_sapp_window_t* win) { /* NOTE: the _sapp.fullscreen flag is also notified by the windowDidEnterFullscreen / windowDidExitFullscreen event handlers */ - _sapp.window.fullscreen = !_sapp.window.fullscreen; - [_sapp.window.macos.window toggleFullScreen:nil]; + win->fullscreen = !win->fullscreen; + [win->macos.window toggleFullScreen:nil]; } _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { @@ -3503,47 +3538,47 @@ _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { } } -_SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.window.clipboard.buffer); +_SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(_sapp_window_t* win) { + SOKOL_ASSERT(win->clipboard.buffer); @autoreleasepool { - _sapp.window.clipboard.buffer[0] = 0; + win->clipboard.buffer[0] = 0; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return _sapp.window.clipboard.buffer; + return win->clipboard.buffer; } NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; if (!str) { - return _sapp.window.clipboard.buffer; + return win->clipboard.buffer; } - _sapp_strcpy([str UTF8String], _sapp.window.clipboard.buffer, _sapp.window.clipboard.buf_size); + _sapp_strcpy([str UTF8String], win->clipboard.buffer, win->clipboard.buf_size); } - return _sapp.window.clipboard.buffer; + return win->clipboard.buffer; } -_SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { - [_sapp.window.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window.title]]; +_SOKOL_PRIVATE void _sapp_macos_update_window_title(_sapp_window_t* win) { + [win->macos.window setTitle: [NSString stringWithUTF8String:win->title]]; } -_SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) { - if (!_sapp.window.mouse.locked) { +_SOKOL_PRIVATE void _sapp_macos_update_mouse(_sapp_window_t* win, NSEvent* event) { + if (!win->mouse.locked) { const NSPoint mouse_pos = event.locationInWindow; - float new_x = mouse_pos.x * _sapp.window.dpi_scale; - float new_y = _sapp.window.framebuffer_height - (mouse_pos.y * _sapp.window.dpi_scale) - 1; + float new_x = mouse_pos.x * win->dpi_scale; + float new_y = win->framebuffer_height - (mouse_pos.y * win->dpi_scale) - 1; /* don't update dx/dy in the very first update */ - if (_sapp.window.mouse.pos_valid) { - _sapp.window.mouse.dx = new_x - _sapp.window.mouse.x; - _sapp.window.mouse.dy = new_y - _sapp.window.mouse.y; + if (win->mouse.pos_valid) { + win->mouse.dx = new_x - win->mouse.x; + win->mouse.dy = new_y - win->mouse.y; } - _sapp.window.mouse.x = new_x; - _sapp.window.mouse.y = new_y; - _sapp.window.mouse.pos_valid = true; + win->mouse.x = new_x; + win->mouse.y = new_y; + win->mouse.pos_valid = true; } } -_SOKOL_PRIVATE void _sapp_macos_update_mouse_delta(NSEvent* event) { - if (_sapp.window.mouse.locked) { - _sapp.window.mouse.dx = [event deltaX]; - _sapp.window.mouse.dy = [event deltaY]; +_SOKOL_PRIVATE void _sapp_macos_update_mouse_delta(_sapp_window_t* win, NSEvent* event) { + if (win->mouse.locked) { + win->mouse.dx = [event deltaX]; + win->mouse.dy = [event deltaY]; } } @@ -3557,13 +3592,13 @@ _SOKOL_PRIVATE void _sapp_macos_show_mouse(bool visible) { } } -_SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { - if (lock == _sapp.window.mouse.locked) { +_SOKOL_PRIVATE void _sapp_macos_lock_mouse(_sapp_window_t* win, bool lock) { + if (lock == win->mouse.locked) { return; } - _sapp.window.mouse.dx = 0.0f; - _sapp.window.mouse.dy = 0.0f; - _sapp.window.mouse.locked = lock; + win->mouse.dx = 0.0f; + win->mouse.dy = 0.0f; + win->mouse.locked = lock; /* NOTE that this code doesn't warp the mouse cursor to the window center as everybody else does it. This lead to a spike in the @@ -3574,7 +3609,7 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { NOTE also that the hide/show of the mouse cursor should properly stack with calls to sapp_show_mouse() */ - if (_sapp.window.mouse.locked) { + if (win->mouse.locked) { CGAssociateMouseAndMouseCursorPosition(NO); CGDisplayHideCursor(kCGDirectMainDisplay); } @@ -3619,20 +3654,25 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_frame(); + // FIXME FIXME FIXME if (_sapp.quit_requested || _sapp.quit_ordered) { - [_sapp.window.macos.window performClose:nil]; + _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); + SOKOL_ASSERT(win); + [win->macos.window performClose:nil]; + _sapp_pop_current_window(); } } @implementation _sapp_macos_app_delegate + - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); - _sapp.cur_window_id = _sapp.main_window_id; - [NSEvent setMouseCoalescingEnabled:NO]; - _sapp_macos_update_dimensions(); + _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); + _sapp_macos_update_dimensions(win); + _sapp_pop_current_window(); _sapp.valid = true; } @@ -3643,12 +3683,13 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)applicationWillTerminate:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_call_cleanup(); _sapp_discard_state(); } @end @implementation _sapp_macos_window_delegate +@synthesize win_id; + - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); /* only give user-code a chance to intervene when sapp_quit() wasn't already called */ @@ -3657,7 +3698,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { a chance to intervene via sapp_cancel_quit() */ _sapp.quit_requested = true; - _sapp_macos_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); + _sapp_window_t* win = _sapp_push_current_window(self.win_id); + _sapp_macos_app_event(win, SAPP_EVENTTYPE_QUIT_REQUESTED); + _sapp_pop_current_window(); /* user code hasn't intervened, quit the app */ if (_sapp.quit_requested) { _sapp.quit_ordered = true; @@ -3673,6 +3716,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)windowDidResize:(NSNotification*)notification { _SOKOL_UNUSED(notification); +//FIXME _sapp_push_current_window(self.win_id) _sapp_macos_update_dimensions(); if (!_sapp.window.first_frame) { _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED); @@ -3701,6 +3745,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { @end @implementation _sapp_macos_window +@synthesize win_id; + - (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType @@ -3754,6 +3800,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { @end @implementation _sapp_macos_view +@synthesize win_id; + #if defined(SOKOL_GLCORE33) /* NOTE: this is a hack/fix when the initial window size has been clipped by macOS because it didn't fit on the screen, in that case the From 58c8c4b9c6148fe65a17ffd7c0a5c4440fdfa825 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 20 Apr 2021 18:09:06 +0200 Subject: [PATCH 06/49] sokol_app.h macOS: multiwindow wip --- sokol_app.h | 392 ++++++++++++++++++++++++++++------------------------ 1 file changed, 209 insertions(+), 183 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 5127f40c9..9904d1127 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2364,7 +2364,7 @@ typedef struct { _sapp_window_pool_t window_pool; uint32_t main_window_id; uint32_t cur_window_id; - uint32_t pushed_window_id; + uint32_t stored_window_id; _sapp_window_t* cur_window; bool valid; bool gles2_fallback; @@ -2730,18 +2730,18 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in } // makes a window the current window and returns pointer to window struct, CAN RETURN NULL! -_SOKOL_PRIVATE _sapp_window_t* _sapp_push_current_window(uint32_t win_id) { - SOKOL_ASSERT(SAPP_INVALID_ID == _sapp.pushed_window_id); - _sapp.pushed_window_id = _sapp.cur_window_id; +_SOKOL_PRIVATE _sapp_window_t* _sapp_push_window(uint32_t win_id) { + SOKOL_ASSERT(SAPP_INVALID_ID == _sapp.stored_window_id); + _sapp.stored_window_id = _sapp.cur_window_id; _sapp.cur_window_id = win_id; _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(_sapp.cur_window); return _sapp.cur_window; } -_SOKOL_PRIVATE void _sapp_pop_current_window(void) { - SOKOL_ASSERT(SAPP_INVALID_ID != _sapp.pushed_window_id); - _sapp.cur_window_id = _sapp.pushed_window_id; - _sapp.pushed_window_id = SAPP_INVALID_ID; +_SOKOL_PRIVATE void _sapp_pop_window(void) { + _sapp.cur_window_id = _sapp.stored_window_id; + _sapp.stored_window_id = SAPP_INVALID_ID; _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); } @@ -2830,17 +2830,14 @@ _SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { } _SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { - _sapp_window_t* win = _sapp_push_current_window(win_id); - if (0 == win) { - return; - } + _sapp_window_t* win = _sapp_push_window(win_id); _sapp_call_cleanup(win); _sapp_discard_drop(&win->drop); _sapp_discard_clipboard(&win->clipboard); _sapp_platform_destroy_window(win); _sapp_free_window_id(win_id); _SAPP_CLEAR_PTR(_sapp_window_t, win); - _sapp_pop_current_window(); + _sapp_pop_window(); } _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { @@ -2968,14 +2965,14 @@ _SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* win) { _SOKOL_PRIVATE void _sapp_frame(void) { // FIXME: loop over all windows - _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); + _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); if (win->first_frame) { win->first_frame = false; _sapp_call_init(win); } _sapp_call_frame(win); _sapp.frame_count++; - _sapp_pop_current_window(); + _sapp_pop_window(); } _SOKOL_PRIVATE bool _sapp_image_validate(const sapp_image_desc* desc) { @@ -3656,10 +3653,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_frame(); // FIXME FIXME FIXME if (_sapp.quit_requested || _sapp.quit_ordered) { - _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); - SOKOL_ASSERT(win); + _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); [win->macos.window performClose:nil]; - _sapp_pop_current_window(); + _sapp_pop_window(); } } @@ -3670,9 +3666,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); [NSEvent setMouseCoalescingEnabled:NO]; - _sapp_window_t* win = _sapp_push_current_window(_sapp.main_window_id); + _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); _sapp_macos_update_dimensions(win); - _sapp_pop_current_window(); + _sapp_pop_window(); _sapp.valid = true; } @@ -3698,9 +3694,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { a chance to intervene via sapp_cancel_quit() */ _sapp.quit_requested = true; - _sapp_window_t* win = _sapp_push_current_window(self.win_id); + _sapp_window_t* win = _sapp_push_window(self.win_id); _sapp_macos_app_event(win, SAPP_EVENTTYPE_QUIT_REQUESTED); - _sapp_pop_current_window(); + _sapp_pop_window(); /* user code hasn't intervened, quit the app */ if (_sapp.quit_requested) { _sapp.quit_ordered = true; @@ -3716,31 +3712,42 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)windowDidResize:(NSNotification*)notification { _SOKOL_UNUSED(notification); -//FIXME _sapp_push_current_window(self.win_id) - _sapp_macos_update_dimensions(); - if (!_sapp.window.first_frame) { - _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED); + _sapp_window_t* win = _sapp_push_window(self.win_id); + if (win) { + _sapp_macos_update_dimensions(win); + if (!win->first_frame) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); + } } + _sapp_pop_window(); } - (void)windowDidMiniaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_ICONIFIED); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_app_event(win, SAPP_EVENTTYPE_ICONIFIED); + _sapp_pop_window(); } - (void)windowDidDeminiaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_RESTORED); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESTORED); + _sapp_pop_window(); } - (void)windowDidEnterFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.window.fullscreen = true; + _sapp_window_t* win = _sapp_push_window(self.win_id); + win->fullscreen = true; + _sapp_pop_window(); } - (void)windowDidExitFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.window.fullscreen = false; + _sapp_window_t* win = _sapp_push_window(self.win_id); + win->fullscreen = false; + _sapp_pop_window(); } @end @@ -3768,34 +3775,37 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } - (BOOL)performDragOperation:(id)sender { + BOOL retval = NO; #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 + _sapp_window_t* win = _sapp_push_window(self.win_id); NSPasteboard *pboard = [sender draggingPasteboard]; if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { - _sapp_clear_drop_buffer(); - _sapp.window.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.window.drop.max_files) ? _sapp.window.drop.max_files : pboard.pasteboardItems.count; + _sapp_clear_drop_buffer(win); + win->drop.num_files = ((int)pboard.pasteboardItems.count > win->drop.max_files) ? win->drop.max_files : pboard.pasteboardItems.count; bool drop_failed = false; - for (int i = 0; i < _sapp.window.drop.num_files; i++) { + for (int i = 0; i < win->drop.num_files; i++) { NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; - if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.window.drop.max_path_length)) { + if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(win, i), win->drop.max_path_length)) { SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); drop_failed = true; break; } } if (!drop_failed) { - if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - _sapp_call_event(&_sapp.event); + if (_sapp_events_enabled(win)) { + _sapp_init_event(win, SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(win, &_sapp.event); } } else { - _sapp_clear_drop_buffer(); - _sapp.window.drop.num_files = 0; + _sapp_clear_drop_buffer(win); + win->drop.num_files = 0; } - return YES; + retval = YES; } + _sapp_pop_window(); #endif - return NO; + return retval; } @end @@ -3813,7 +3823,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { the correct dimensions. */ - (void)reshape { - _sapp_macos_update_dimensions(); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_update_dimensions(win); + _sapp_pop_window(self.win_id); [super reshape]; } - (void)timerFired:(id)sender { @@ -3829,53 +3841,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } #endif -_SOKOL_PRIVATE void _sapp_macos_poll_input_events() { - /* - - NOTE: late event polling temporarily out-commented to check if this - causes infrequent and almost impossible to reproduce probelms with the - window close events, see: - https://github.com/floooh/sokol/pull/483#issuecomment-805148815 - - - const NSEventMask mask = NSEventMaskLeftMouseDown | - NSEventMaskLeftMouseUp| - NSEventMaskRightMouseDown | - NSEventMaskRightMouseUp | - NSEventMaskMouseMoved | - NSEventMaskLeftMouseDragged | - NSEventMaskRightMouseDragged | - NSEventMaskMouseEntered | - NSEventMaskMouseExited | - NSEventMaskKeyDown | - NSEventMaskKeyUp | - NSEventMaskCursorUpdate | - NSEventMaskScrollWheel | - NSEventMaskTabletPoint | - NSEventMaskTabletProximity | - NSEventMaskOtherMouseDown | - NSEventMaskOtherMouseUp | - NSEventMaskOtherMouseDragged | - NSEventMaskPressure | - NSEventMaskDirectTouch; - @autoreleasepool { - for (;;) { - // NOTE: using NSDefaultRunLoopMode here causes stuttering in the GL backend, - // see: https://github.com/floooh/sokol/issues/486 - NSEvent* event = [NSApp nextEventMatchingMask:mask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES]; - if (event == nil) { - break; - } - [NSApp sendEvent:event]; - } - } - */ -} - - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); - /* Catch any last-moment input events */ - _sapp_macos_poll_input_events(); _sapp_macos_frame(); #if !defined(SOKOL_METAL) [[_sapp.macos.view openGLContext] flushBuffer]; @@ -3892,9 +3859,10 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { return YES; } - (void)updateTrackingAreas { - if (_sapp.window.macos.tracking_area != nil) { - [self removeTrackingArea:_sapp.window.macos.tracking_area]; - _SAPP_OBJC_RELEASE(_sapp.window.macos.tracking_area); + _sapp_window_t* win = _sapp_push_window(self.win_id); + if (win->macos.tracking_area != nil) { + [self removeTrackingArea:win->macos.tracking_area]; + _SAPP_OBJC_RELEASE(win->macos.tracking_area); } const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | @@ -3902,84 +3870,110 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { NSTrackingCursorUpdate | NSTrackingInVisibleRect | NSTrackingAssumeInside; - _sapp.window.macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - [self addTrackingArea:_sapp.window.macos.tracking_area]; + win->macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; + [self addTrackingArea:win->macos.tracking_area]; [super updateTrackingAreas]; + _sapp_pop_window(); } - (void)mouseEntered:(NSEvent*)event { - _sapp_macos_update_mouse(event); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_update_mouse(win, event); /* don't send mouse enter/leave while dragging (so that it behaves the same as on Windows while SetCapture is active */ - if (0 == _sapp.window.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + if (0 == win->macos.mouse_buttons) { + _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } + _sapp_pop_window(); } - (void)mouseExited:(NSEvent*)event { - _sapp_macos_update_mouse(event); - if (0 == _sapp.window.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_update_mouse(win, event); + if (0 == win->macos.mouse_buttons) { + _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); } + _sapp_pop_window(); } - (void)mouseDown:(NSEvent*)event { - _sapp_macos_update_mouse(event); - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mods(event)); - _sapp.window.macos.mouse_buttons |= (1<macos.mouse_buttons |= (1<macos.mouse_buttons &= ~(1<macos.mouse_buttons |= (1<macos.mouse_buttons &= ~(1<macos.mouse_buttons |= (1<macos.mouse_buttons &= (1< 0.0f) || (_sapp_absf(dy) > 0.0f)) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(win, SAPP_EVENTTYPE_MOUSE_SCROLL); _sapp.event.modifiers = _sapp_macos_mods(event); _sapp.event.scroll_x = dx; _sapp.event.scroll_y = dy; - _sapp_call_event(&_sapp.event); + _sapp_call_event(win, &_sapp.event); } } + _sapp_pop_window(); } - (void)keyDown:(NSEvent*)event { - if (_sapp_events_enabled()) { + _sapp_window_t* win = _sapp_push_window(self.win_id); + if (_sapp_events_enabled(win)) { const uint32_t mods = _sapp_macos_mods(event); /* NOTE: macOS doesn't send keyUp events while the Cmd key is pressed, as a workaround, to prevent key presses from sticking we'll send a keyup event following right after the keydown if SUPER is also pressed */ const sapp_keycode key_code = _sapp_translate_key(event.keyCode); - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods); + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods); if (0 != (mods & SAPP_MODIFIER_SUPER)) { - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP, key_code, event.isARepeat, mods); + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, key_code, event.isARepeat, mods); } const NSString* chars = event.characters; const NSUInteger len = chars.length; if (len > 0) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); + _sapp_init_event(win, SAPP_EVENTTYPE_CHAR); _sapp.event.modifiers = mods; for (NSUInteger i = 0; i < len; i++) { const unichar codepoint = [chars characterAtIndex:i]; @@ -4019,26 +4015,30 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { } _sapp.event.char_code = codepoint; _sapp.event.key_repeat = event.isARepeat; - _sapp_call_event(&_sapp.event); + _sapp_call_event(win, &_sapp.event); } } /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ - if (_sapp.window.clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(&_sapp.event); + if (win->clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { + _sapp_init_event(win, SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_call_event(win, &_sapp.event); } } + _sapp_pop_window(); } - (void)keyUp:(NSEvent*)event { - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP, + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, _sapp_translate_key(event.keyCode), event.isARepeat, _sapp_macos_mods(event)); + _sapp_pop_window(); } - (void)flagsChanged:(NSEvent*)event { - const uint32_t old_f = _sapp.window.macos.flags_changed_store; + _sapp_window_t* win = _sapp_push_window(self.win_id); + const uint32_t old_f = win->macos.flags_changed_store; const uint32_t new_f = event.modifierFlags; - _sapp.window.macos.flags_changed_store = new_f; + win->macos.flags_changed_store = new_f; sapp_keycode key_code = SAPP_KEYCODE_INVALID; bool down = false; if ((new_f ^ old_f) & NSEventModifierFlagShift) { @@ -4058,17 +4058,20 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events() { down = 0 != (new_f & NSEventModifierFlagCommand); } if (key_code != SAPP_KEYCODE_INVALID) { - _sapp_macos_key_event(down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, + _sapp_macos_key_event(win, down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, key_code, false, _sapp_macos_mods(event)); } + _sapp_pop_window(); } - (void)cursorUpdate:(NSEvent*)event { _SOKOL_UNUSED(event); - if (_sapp.desc.window.user_cursor) { - _sapp_macos_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR); + _sapp_window_t* win = _sapp_push_window(self.win_id); + if (win->desc.user_cursor) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_UPDATE_CURSOR); } + _sapp_pop_window(); } @end @@ -11084,7 +11087,8 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) { } SOKOL_API_IMPL int sapp_width(void) { - return (_sapp.window.framebuffer_width > 0) ? _sapp.window.framebuffer_width : 1; + SOKOL_ASSERT(_sapp.cur_window); + return (_sapp.cur_window->framebuffer_width > 0) ? _sapp.cur_window->framebuffer_width : 1; } SOKOL_API_IMPL float sapp_widthf(void) { @@ -11092,7 +11096,8 @@ SOKOL_API_IMPL float sapp_widthf(void) { } SOKOL_API_IMPL int sapp_height(void) { - return (_sapp.window.framebuffer_height > 0) ? _sapp.window.framebuffer_height : 1; + SOKOL_ASSERT(_sapp.cur_window); + return (_sapp.cur_window->framebuffer_height > 0) ? _sapp.cur_window->framebuffer_height : 1; } SOKOL_API_IMPL float sapp_heightf(void) { @@ -11122,15 +11127,18 @@ SOKOL_API_IMPL int sapp_depth_format(void) { } SOKOL_API_IMPL int sapp_sample_count(void) { - return _sapp.window.desc.sample_count; + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->desc.sample_count; } SOKOL_API_IMPL bool sapp_high_dpi(void) { - return _sapp.desc.window.high_dpi && (_sapp.window.dpi_scale >= 1.5f); + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->desc.high_dpi && (_sapp.cur_window->dpi_scale >= 1.5f); } SOKOL_API_IMPL float sapp_dpi_scale(void) { - return _sapp.window.dpi_scale; + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->dpi_scale; } SOKOL_API_IMPL bool sapp_gles2(void) { @@ -11154,12 +11162,14 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { } SOKOL_APP_API_DECL bool sapp_is_fullscreen(void) { - return _sapp.window.fullscreen; + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->fullscreen; } SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { + SOKOL_ASSERT(_sapp.cur_window); #if defined(_SAPP_MACOS) - _sapp_macos_toggle_fullscreen(); + _sapp_macos_toggle_fullscreen(_sapp.cur_window); #elif defined(_SAPP_WIN32) _sapp_win32_toggle_fullscreen(); #elif defined(_SAPP_UWP) @@ -11171,7 +11181,8 @@ SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { /* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ SOKOL_API_IMPL void sapp_show_mouse(bool show) { - if (_sapp.window.mouse.shown != show) { + SOKOL_ASSERT(_sapp.cur_window); + if (_sapp.cur_window->mouse.shown != show) { #if defined(_SAPP_MACOS) _sapp_macos_show_mouse(show); #elif defined(_SAPP_WIN32) @@ -11181,17 +11192,19 @@ SOKOL_API_IMPL void sapp_show_mouse(bool show) { #elif defined(_SAPP_UWP) _sapp_uwp_show_mouse(show); #endif - _sapp.window.mouse.shown = show; + _sapp.cur_window->mouse.shown = show; } } SOKOL_API_IMPL bool sapp_mouse_shown(void) { - return _sapp.window.mouse.shown; + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->mouse.shown; } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { + SOKOL_ASSERT(_sapp.cur_window); #if defined(_SAPP_MACOS) - _sapp_macos_lock_mouse(lock); + _sapp_macos_lock_mouse(_sapp.cur_window, lock); #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_lock_mouse(lock); #elif defined(_SAPP_WIN32) @@ -11204,7 +11217,8 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - return _sapp.window.mouse.locked; + SOKOL_ASSERT(_sapp.cur_window); + return _sapp.cur_window->mouse.locked; } SOKOL_API_IMPL void sapp_request_quit(void) { @@ -11220,13 +11234,15 @@ SOKOL_API_IMPL void sapp_quit(void) { } SOKOL_API_IMPL void sapp_consume_event(void) { - _sapp.window.event_consumed = true; + SOKOL_ASSERT(_sapp.cur_window); + _sapp.cur_window->event_consumed = true; } /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { - SOKOL_ASSERT(_sapp.window.clipboard.enabled); - if (!_sapp.window.clipboard.enabled) { + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->clipboard.enabled); + if (!_sapp.cur_window->clipboard.enabled) { return; } SOKOL_ASSERT(str); @@ -11239,31 +11255,33 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { #else /* not implemented */ #endif - _sapp_strcpy(str, _sapp.window.clipboard.buffer, _sapp.window.clipboard.buf_size); + _sapp_strcpy(str, _sapp.cur_window->clipboard.buffer, _sapp.cur_window->clipboard.buf_size); } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.window.clipboard.enabled); - if (!_sapp.window.clipboard.enabled) { + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->clipboard.enabled); + if (!_sapp.cur_window->clipboard.enabled) { return ""; } #if defined(_SAPP_MACOS) - return _sapp_macos_get_clipboard_string(); + return _sapp_macos_get_clipboard_string(_sapp.cur_window); #elif defined(_SAPP_EMSCRIPTEN) return _sapp.clipboard.buffer; #elif defined(_SAPP_WIN32) return _sapp_win32_get_clipboard_string(); #else /* not implemented */ - return _sapp.clipboard.buffer; + return _sapp.cur_window->clipboard.buffer; #endif } SOKOL_API_IMPL void sapp_set_window_title(const char* title) { SOKOL_ASSERT(title); - _sapp_strcpy(title, _sapp.window.title, sizeof(_sapp.window.title)); + SOKOL_ASSERT(_sapp.cur_window); + _sapp_strcpy(title, _sapp.cur_window->title, sizeof(_sapp.cur_window->title)); #if defined(_SAPP_MACOS) - _sapp_macos_update_window_title(); + _sapp_macos_update_window_title(_sapp.cur_window); #elif defined(_SAPP_WIN32) _sapp_win32_update_window_title(); #elif defined(_SAPP_LINUX) @@ -11300,28 +11318,31 @@ SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { } SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - SOKOL_ASSERT(_sapp.window.drop.enabled); - return _sapp.window.drop.num_files; + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->drop.enabled); + return _sapp.cur_window->drop.num_files; } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - SOKOL_ASSERT(_sapp.window.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.window.drop.num_files)); - SOKOL_ASSERT(_sapp.window.drop.buffer); - if (!_sapp.window.drop.enabled) { + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.cur_window->drop.num_files)); + SOKOL_ASSERT(_sapp.cur_window->drop.buffer); + if (!_sapp.cur_window->drop.enabled) { return ""; } - if ((index < 0) || (index >= _sapp.window.drop.max_files)) { + if ((index < 0) || (index >= _sapp.cur_window->drop.max_files)) { return ""; } - return (const char*) _sapp_dropped_file_path_ptr(index); + return (const char*) _sapp_dropped_file_path_ptr(_sapp.cur_window, index); } SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { - SOKOL_ASSERT(_sapp.window.drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.window.drop.num_files)); + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.cur_window->drop.num_files)); #if defined(_SAPP_EMSCRIPTEN) - if (!_sapp.drop.enabled) { + if (!_sapp.cur_window->drop.enabled) { return 0; } return sapp_js_dropped_file_size(index); @@ -11332,7 +11353,8 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { - SOKOL_ASSERT(_sapp.window.drop.enabled); + SOKOL_ASSERT(_sapp.cur_window); + SOKOL_ASSERT(_sapp.cur_window->drop.enabled); SOKOL_ASSERT(request); SOKOL_ASSERT(request->callback); SOKOL_ASSERT(request->buffer_ptr); @@ -11385,9 +11407,10 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_ASSERT(_sapp.valid); + SOKOL_ASSERT(_sapp.cur_window); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.window.macos.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [_sapp.cur_window->macos.view currentRenderPassDescriptor]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; #endif @@ -11400,9 +11423,10 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { SOKOL_ASSERT(_sapp.valid); + SOKOL_ASSERT(_sapp.cur_window); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.window.macos.view currentDrawable]; + const void* obj = (__bridge const void*) [_sapp.cur_window->macos.view currentDrawable]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; #endif @@ -11414,8 +11438,10 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { } SOKOL_API_IMPL const void* sapp_macos_get_window(void) { + SOKOL_ASSERT(_sapp.valid); + SOKOL_ASSERT(_sapp.cur_window); #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.window.macos.window; + const void* obj = (__bridge const void*) _sapp.cur_window->macos.window; SOKOL_ASSERT(obj); return obj; #else From 8f86a7225a4dd07feda2db0eddbcbddf849092dd Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 20 Apr 2021 20:10:22 +0200 Subject: [PATCH 07/49] sokol_app.h macOS: more multiwindow wip --- sokol_app.h | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 9904d1127..c8b233aa2 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1432,6 +1432,10 @@ extern sapp_desc sokol_main(int argc, char* argv[]); /* returns true after sokol-app has been initialized */ SOKOL_APP_API_DECL bool sapp_isvalid(void); +/* open a new window */ +SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); +/* close a window */ +SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); /* returns the current framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_width(void); /* same as sapp_width(), but returns float */ @@ -1466,8 +1470,6 @@ SOKOL_APP_API_DECL bool sapp_mouse_shown(); SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock); /* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */ SOKOL_APP_API_DECL bool sapp_mouse_locked(void); -/* return the userdata pointer optionally provided in sapp_desc */ -SOKOL_APP_API_DECL void* sapp_userdata(void); /* return a copy of the sapp_desc structure */ SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void); /* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ @@ -2716,7 +2718,7 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { } } -_SOKOL_PRIVATE sapp_window_desc _sapp_window_defaults(const sapp_window_desc* in_desc) { +_SOKOL_PRIVATE sapp_window_desc _sapp_window_desc_defaults(const sapp_window_desc* in_desc) { sapp_window_desc desc = *in_desc; desc.title = _sapp_def(desc.title, "sokol_app"); desc.width = _sapp_def(desc.width, 640); @@ -2897,7 +2899,7 @@ _SOKOL_PRIVATE void _sapp_destroy_all_windows(void) { _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { sapp_desc desc = *in_desc; desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE); - desc.window = _sapp_window_defaults(&desc.window); + desc.window = _sapp_window_desc_defaults(&desc.window); desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas"); return desc; } @@ -2963,16 +2965,13 @@ _SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* win) { } } -_SOKOL_PRIVATE void _sapp_frame(void) { - // FIXME: loop over all windows - _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); +_SOKOL_PRIVATE void _sapp_frame(_sapp_window_t* win) { if (win->first_frame) { win->first_frame = false; _sapp_call_init(win); } _sapp_call_frame(win); _sapp.frame_count++; - _sapp_pop_window(); } _SOKOL_PRIVATE bool _sapp_image_validate(const sapp_image_desc* desc) { @@ -3649,13 +3648,11 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu CGImageRelease(cg_img); } -_SOKOL_PRIVATE void _sapp_macos_frame(void) { - _sapp_frame(); +_SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { + _sapp_frame(win); // FIXME FIXME FIXME if (_sapp.quit_requested || _sapp.quit_ordered) { - _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); [win->macos.window performClose:nil]; - _sapp_pop_window(); } } @@ -3843,10 +3840,12 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); - _sapp_macos_frame(); + _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_macos_frame(win); #if !defined(SOKOL_METAL) [[_sapp.macos.view openGLContext] flushBuffer]; #endif + _sapp_pop_window(); } - (BOOL)isOpaque { @@ -11074,8 +11073,14 @@ SOKOL_API_IMPL bool sapp_isvalid(void) { return _sapp.valid; } -SOKOL_API_IMPL void* sapp_userdata(void) { - return _sapp.desc.window.user_data; +SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { + SOKOL_ASSERT(in_desc); + const sapp_window_desc desc = _sapp_window_desc_defaults(in_desc); + return _sapp_make_window_id(_sapp_create_window(&desc)); +} + +SOKOL_API_IMPL void sapp_close_window(sapp_window window) { + // FIXME } SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { From 1c5a562fbf7a15eccb6bc6f6a93079343e518e41 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 21 Apr 2021 20:14:52 +0200 Subject: [PATCH 08/49] sokol_gfx.h: move Metal semaphore into _sg_context_t --- sokol_gfx.h | 119 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index acda3dc42..5cd66021c 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -3702,6 +3702,9 @@ typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; + struct { + dispatch_semaphore_t sem; + } mtl; } _sg_mtl_context_t; typedef _sg_mtl_context_t _sg_context_t; @@ -3740,7 +3743,6 @@ typedef struct { _sg_mtl_state_cache_t state_cache; _sg_sampler_cache_t sampler_cache; _sg_mtl_idpool_t idpool; - dispatch_semaphore_t sem; id device; id cmd_queue; id cmd_buffer; @@ -4037,6 +4039,7 @@ typedef struct { bool valid; sg_desc desc; /* original desc with default values patched in */ uint32_t frame_index; + sg_context main_context; sg_context active_context; sg_pass cur_pass; sg_pipeline cur_pipeline; @@ -9978,7 +9981,6 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _sg.mtl.user_data = desc->context.metal.user_data; _sg.mtl.frame_index = 1; _sg.mtl.ub_size = desc->uniform_buffer_size; - _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); _sg.mtl.device = (__bridge id) desc->context.metal.device; _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; MTLResourceOptions res_opts = MTLResourceCPUCacheModeWriteCombined; @@ -9996,20 +9998,11 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { SOKOL_ASSERT(_sg.mtl.valid); - /* wait for the last frame to finish */ - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); - } - /* semaphore must be "relinquished" before destruction */ - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - dispatch_semaphore_signal(_sg.mtl.sem); - } _sg_mtl_destroy_sampler_cache(_sg.mtl.frame_index); _sg_mtl_garbage_collect(_sg.mtl.frame_index + SG_NUM_INFLIGHT_FRAMES + 2); _sg_mtl_destroy_pool(); _sg.mtl.valid = false; - _SG_OBJC_RELEASE(_sg.mtl.sem); _SG_OBJC_RELEASE(_sg.mtl.device); _SG_OBJC_RELEASE(_sg.mtl.cmd_queue); for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { @@ -10047,14 +10040,21 @@ _SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); + ctx->mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); return SG_RESOURCESTATE_VALID; } _SOKOL_PRIVATE void _sg_mtl_destroy_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); - _SOKOL_UNUSED(ctx); - /* empty */ + /* wait for the last frame to finish */ + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + dispatch_semaphore_wait(ctx->mtl.sem, DISPATCH_TIME_FOREVER); + } + /* semaphore must be "relinquished" before destruction */ + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + dispatch_semaphore_signal(ctx->mtl.sem); + } + _SG_OBJC_RELEASE(ctx->mtl.sem); } _SOKOL_PRIVATE void _sg_mtl_activate_context(_sg_context_t* ctx) { @@ -10562,8 +10562,9 @@ _SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_ds_image(const _sg_pass_t* pass) { return pass->mtl.ds_att.image; } -_SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { +_SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, const sg_pass_action* action, int w, int h) { SOKOL_ASSERT(action); + SOKOL_ASSERT(ctx); SOKOL_ASSERT(!_sg.mtl.in_pass); SOKOL_ASSERT(_sg.mtl.cmd_queue); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); @@ -10576,12 +10577,13 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a /* if this is the first pass in the frame, create a command buffer */ if (nil == _sg.mtl.cmd_buffer) { /* block until the oldest frame in flight has finished */ - dispatch_semaphore_wait(_sg.mtl.sem, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(ctx->mtl.sem, DISPATCH_TIME_FOREVER); _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; + __block dispatch_semaphore_t block_sem = ctx->mtl.sem; [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { // NOTE: this code is called on a different thread! _SOKOL_UNUSED(cmd_buffer); - dispatch_semaphore_signal(_sg.mtl.sem); + dispatch_semaphore_signal(block_sem); }]; } @@ -10699,8 +10701,9 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a _sg_mtl_bind_uniform_buffers(); } -_SOKOL_PRIVATE void _sg_mtl_end_pass(void) { +_SOKOL_PRIVATE void _sg_mtl_end_pass(_sg_context_t* ctx) { SOKOL_ASSERT(_sg.mtl.in_pass); + _SOKOL_UNUSED(ctx); _sg.mtl.in_pass = false; _sg.mtl.pass_valid = false; if (nil != _sg.mtl.cmd_encoder) { @@ -10710,12 +10713,13 @@ _SOKOL_PRIVATE void _sg_mtl_end_pass(void) { } } -_SOKOL_PRIVATE void _sg_mtl_commit(void) { +_SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { SOKOL_ASSERT(!_sg.mtl.in_pass); SOKOL_ASSERT(!_sg.mtl.pass_valid); SOKOL_ASSERT(_sg.mtl.drawable_cb || _sg.mtl.drawable_userdata_cb); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); + _SOKOL_UNUSED(ctx); #if defined(_SG_TARGET_MACOS) [_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, (NSUInteger)_sg.mtl.cur_ub_offset)]; @@ -12990,33 +12994,33 @@ static inline _sg_image_t* _sg_pass_ds_image(const _sg_pass_t* pass) { #endif } -static inline void _sg_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { +static inline void _sg_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, const sg_pass_action* action, int w, int h) { #if defined(_SOKOL_ANY_GL) - _sg_gl_begin_pass(pass, action, w, h); + _sg_gl_begin_pass(ctx, pass, action, w, h); #elif defined(SOKOL_METAL) - _sg_mtl_begin_pass(pass, action, w, h); + _sg_mtl_begin_pass(ctx, pass, action, w, h); #elif defined(SOKOL_D3D11) - _sg_d3d11_begin_pass(pass, action, w, h); + _sg_d3d11_begin_pass(ctx, pass, action, w, h); #elif defined(SOKOL_WGPU) - _sg_wgpu_begin_pass(pass, action, w, h); + _sg_wgpu_begin_pass(ctx, pass, action, w, h); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_begin_pass(pass, action, w, h); + _sg_dummy_begin_pass(ctx, pass, action, w, h); #else #error("INVALID BACKEND"); #endif } -static inline void _sg_end_pass(void) { +static inline void _sg_end_pass(_sg_context_t* ctx) { #if defined(_SOKOL_ANY_GL) - _sg_gl_end_pass(); + _sg_gl_end_pass(ctx); #elif defined(SOKOL_METAL) - _sg_mtl_end_pass(); + _sg_mtl_end_pass(ctx); #elif defined(SOKOL_D3D11) - _sg_d3d11_end_pass(); + _sg_d3d11_end_pass(ctx); #elif defined(SOKOL_WGPU) - _sg_wgpu_end_pass(); + _sg_wgpu_end_pass(ctx); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_end_pass(); + _sg_dummy_end_pass(ctx); #else #error("INVALID BACKEND"); #endif @@ -13124,17 +13128,17 @@ static inline void _sg_draw(int base_element, int num_elements, int num_instance #endif } -static inline void _sg_commit(void) { +static inline void _sg_commit(_sg_context_t* ctx) { #if defined(_SOKOL_ANY_GL) - _sg_gl_commit(); + _sg_gl_commit(ctx); #elif defined(SOKOL_METAL) - _sg_mtl_commit(); + _sg_mtl_commit(ctx); #elif defined(SOKOL_D3D11) - _sg_d3d11_commit(); + _sg_d3d11_commit(ctx); #elif defined(SOKOL_WGPU) - _sg_wgpu_commit(); + _sg_wgpu_commit(ctx); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_commit(); + _sg_dummy_commit(ctx); #else #error("INVALID BACKEND"); #endif @@ -13502,6 +13506,18 @@ _SOKOL_PRIVATE _sg_context_t* _sg_lookup_context(const _sg_pools_t* p, uint32_t return 0; } +_SOKOL_PRIVATE _sg_context_t* _sg_active_context(void) { + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.active_context.id); + SOKOL_ASSERT(ctx); + return ctx; +} + +_SOKOL_PRIVATE _sg_context_t* _sg_main_context(void) { + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.main_context.id); + SOKOL_ASSERT(ctx); + return ctx; +} + _SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { /* this is a bit dumb since it loops over all pool slots to find the occupied slots, on the other hand it is only ever @@ -14749,20 +14765,16 @@ SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { _sg_setup_backend(&_sg.desc); _sg.valid = true; sg_setup_context(); + _sg.main_context = _sg.active_context; } SOKOL_API_IMPL void sg_shutdown(void) { - /* can only delete resources for the currently set context here, if multiple + /* can only delete resources for the main context here, if multiple contexts are used, the app code must take care of properly releasing them (since only the app code can switch between 3D-API contexts) */ - if (_sg.active_context.id != SG_INVALID_ID) { - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.active_context.id); - if (ctx) { - _sg_destroy_all_resources(&_sg.pools, _sg.active_context.id); - _sg_destroy_context(ctx); - } - } + _sg_destroy_all_resources(&_sg.pools, _sg.main_context.id); + _sg_destroy_context(_sg_main_context()); _sg_discard_backend(); _sg_discard_pools(&_sg.pools); _sg.valid = false; @@ -14821,6 +14833,12 @@ SOKOL_API_IMPL sg_context sg_setup_context(void) { SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); _sg_destroy_all_resources(&_sg.pools, ctx_id.id); + if (ctx_id.id == _sg.active_context.id) { + _sg.active_context.id = SG_INVALID_ID; + } + if (ctx_id.id == _sg.main_context.id) { + _sg.main_context.id = SG_INVALID_ID; + } _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); if (ctx) { _sg_destroy_context(ctx); @@ -14828,14 +14846,13 @@ SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { _sg_reset_slot(&ctx->slot); _sg_pool_free_index(&_sg.pools.context_pool, _sg_slot_index(ctx_id.id)); } - _sg.active_context.id = SG_INVALID_ID; _sg_activate_context(0); } SOKOL_API_IMPL void sg_activate_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); _sg.active_context = ctx_id; - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); + _sg_context_t* ctx = _sg_active_context(); /* NOTE: ctx can be 0 here if the context is no longer valid */ _sg_activate_context(ctx); } @@ -15206,7 +15223,7 @@ SOKOL_API_IMPL void sg_begin_default_pass(const sg_pass_action* pass_action, int _sg_resolve_default_pass_action(pass_action, &pa); _sg.cur_pass.id = SG_INVALID_ID; _sg.pass_valid = true; - _sg_begin_pass(0, &pa, width, height); + _sg_begin_pass(_sg_active_context(), 0, &pa, width, height); _SG_TRACE_ARGS(begin_default_pass, pass_action, width, height); } @@ -15228,7 +15245,7 @@ SOKOL_API_IMPL void sg_begin_pass(sg_pass pass_id, const sg_pass_action* pass_ac SOKOL_ASSERT(img); const int w = img->cmn.width; const int h = img->cmn.height; - _sg_begin_pass(pass, &pa, w, h); + _sg_begin_pass(_sg_active_context(), pass, &pa, w, h); _SG_TRACE_ARGS(begin_pass, pass_id, pass_action); } else { @@ -15418,7 +15435,7 @@ SOKOL_API_IMPL void sg_end_pass(void) { _SG_TRACE_NOARGS(err_pass_invalid); return; } - _sg_end_pass(); + _sg_end_pass(_sg_active_context()); _sg.cur_pass.id = SG_INVALID_ID; _sg.cur_pipeline.id = SG_INVALID_ID; _sg.pass_valid = false; @@ -15427,7 +15444,7 @@ SOKOL_API_IMPL void sg_end_pass(void) { SOKOL_API_IMPL void sg_commit(void) { SOKOL_ASSERT(_sg.valid); - _sg_commit(); + _sg_commit(_sg_active_context()); _SG_TRACE_NOARGS(commit); _sg.frame_index++; } From 6bc2e2dc6685620b0359c777ef3e872c4af8f335 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 21 Apr 2021 20:15:11 +0200 Subject: [PATCH 09/49] destroy main window last --- sokol_app.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sokol_app.h b/sokol_app.h index 840eba23e..c2b67e240 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2890,12 +2890,14 @@ _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { _SOKOL_PRIVATE void _sapp_destroy_all_windows(void) { SOKOL_ASSERT(_sapp.window_pool.windows); + // make sure to destroy the main window last for (int i = 0; i < _sapp.window_pool.pool.size; i++) { uint32_t win_id = _sapp.window_pool.windows[i].slot.id; - if (SAPP_INVALID_ID != win_id) { + if ((SAPP_INVALID_ID != win_id) && (_sapp.main_window_id != win_id)) { _sapp_destroy_window(win_id); } } + _sapp_destroy_window(_sapp.main_window_id); } _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { From 236be4bd1e9493ff97688000492e54c6eac06f6a Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 22 Apr 2021 18:28:28 +0200 Subject: [PATCH 10/49] sokol_gfx.h metal: move uniform buffers into _sg_context_t --- sokol_gfx.h | 90 ++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index 5cd66021c..56b2eb5c2 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -3704,6 +3704,8 @@ typedef struct { _sg_slot_t slot; struct { dispatch_semaphore_t sem; + uint32_t cur_ub_index; + id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; } mtl; } _sg_mtl_context_t; typedef _sg_mtl_context_t _sg_context_t; @@ -3731,8 +3733,6 @@ typedef struct { const void*(*drawable_cb)(void); const void*(*drawable_userdata_cb)(void*); void* user_data; - uint32_t frame_index; - uint32_t cur_frame_rotate_index; int ub_size; int cur_ub_offset; uint8_t* cur_ub_base_ptr; @@ -3747,7 +3747,6 @@ typedef struct { id cmd_queue; id cmd_buffer; id cmd_encoder; - id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; } _sg_mtl_backend_t; /*=== WGPU BACKEND DECLARATIONS ==============================================*/ @@ -9979,82 +9978,82 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _sg.mtl.drawable_cb = desc->context.metal.drawable_cb; _sg.mtl.drawable_userdata_cb = desc->context.metal.drawable_userdata_cb; _sg.mtl.user_data = desc->context.metal.user_data; - _sg.mtl.frame_index = 1; _sg.mtl.ub_size = desc->uniform_buffer_size; _sg.mtl.device = (__bridge id) desc->context.metal.device; _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; - MTLResourceOptions res_opts = MTLResourceCPUCacheModeWriteCombined; - #if defined(_SG_TARGET_MACOS) - res_opts |= MTLResourceStorageModeManaged; - #endif - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - _sg.mtl.uniform_buffers[i] = [_sg.mtl.device - newBufferWithLength:(NSUInteger)_sg.mtl.ub_size - options:res_opts - ]; - } _sg_mtl_init_caps(); } _SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { SOKOL_ASSERT(_sg.mtl.valid); - _sg_mtl_destroy_sampler_cache(_sg.mtl.frame_index); - _sg_mtl_garbage_collect(_sg.mtl.frame_index + SG_NUM_INFLIGHT_FRAMES + 2); + _sg_mtl_destroy_sampler_cache(_sg.frame_index); + _sg_mtl_garbage_collect(_sg.frame_index + SG_NUM_INFLIGHT_FRAMES + 2); _sg_mtl_destroy_pool(); _sg.mtl.valid = false; _SG_OBJC_RELEASE(_sg.mtl.device); _SG_OBJC_RELEASE(_sg.mtl.cmd_queue); - for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { - _SG_OBJC_RELEASE(_sg.mtl.uniform_buffers[i]); - } /* NOTE: MTLCommandBuffer and MTLRenderCommandEncoder are auto-released */ _sg.mtl.cmd_buffer = nil; _sg.mtl.cmd_encoder = nil; } -_SOKOL_PRIVATE void _sg_mtl_bind_uniform_buffers(void) { +_SOKOL_PRIVATE void _sg_mtl_bind_uniform_buffers(_sg_context_t* ctx) { SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); for (int slot = 0; slot < SG_MAX_SHADERSTAGE_UBS; slot++) { [_sg.mtl.cmd_encoder - setVertexBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] + setVertexBuffer:ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] offset:0 atIndex:(NSUInteger)slot]; [_sg.mtl.cmd_encoder - setFragmentBuffer:_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] + setFragmentBuffer:ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] offset:0 atIndex:(NSUInteger)slot]; } } -_SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { +_SOKOL_PRIVATE void _sg_mtl_reset_state_cache(_sg_context_t* ctx) { _sg_mtl_clear_state_cache(); /* need to restore the uniform buffer binding (normally happens in _sg_mtl_begin_pass() */ if (nil != _sg.mtl.cmd_encoder) { - _sg_mtl_bind_uniform_buffers(); + _sg_mtl_bind_uniform_buffers(ctx); } } _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); ctx->mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); + MTLResourceOptions res_opts = MTLResourceCPUCacheModeWriteCombined; + #if defined(_SG_TARGET_MACOS) + res_opts |= MTLResourceStorageModeManaged; + #endif + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + ctx->mtl.uniform_buffers[i] = [_sg.mtl.device + newBufferWithLength:(NSUInteger)_sg.mtl.ub_size + options:res_opts + ]; + } return SG_RESOURCESTATE_VALID; } _SOKOL_PRIVATE void _sg_mtl_destroy_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); - /* wait for the last frame to finish */ + // wait for the last frame to finish + // FIXME: does this loop actually make any sense??? for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { dispatch_semaphore_wait(ctx->mtl.sem, DISPATCH_TIME_FOREVER); } - /* semaphore must be "relinquished" before destruction */ + // semaphore must be "relinquished" before destruction for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { dispatch_semaphore_signal(ctx->mtl.sem); } _SG_OBJC_RELEASE(ctx->mtl.sem); + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { + _SG_OBJC_RELEASE(ctx->mtl.uniform_buffers[i]); + } } _SOKOL_PRIVATE void _sg_mtl_activate_context(_sg_context_t* ctx) { @@ -10091,7 +10090,7 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_buffer(_sg_buffer_t* buf) { SOKOL_ASSERT(buf); for (int slot = 0; slot < buf->cmn.num_slots; slot++) { /* it's valid to call release resource with '0' */ - _sg_mtl_release_resource(_sg.mtl.frame_index, buf->mtl.buf[slot]); + _sg_mtl_release_resource(_sg.frame_index, buf->mtl.buf[slot]); } } @@ -10303,10 +10302,10 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_image(_sg_image_t* img) { SOKOL_ASSERT(img); /* it's valid to call release resource with a 'null resource' */ for (int slot = 0; slot < img->cmn.num_slots; slot++) { - _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.tex[slot]); + _sg_mtl_release_resource(_sg.frame_index, img->mtl.tex[slot]); } - _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.depth_tex); - _sg_mtl_release_resource(_sg.mtl.frame_index, img->mtl.msaa_tex); + _sg_mtl_release_resource(_sg.frame_index, img->mtl.depth_tex); + _sg_mtl_release_resource(_sg.frame_index, img->mtl.msaa_tex); /* NOTE: sampler state objects are shared and not released until shutdown */ } @@ -10388,10 +10387,10 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const _SOKOL_PRIVATE void _sg_mtl_destroy_shader(_sg_shader_t* shd) { SOKOL_ASSERT(shd); /* it is valid to call _sg_mtl_release_resource with a 'null resource' */ - _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); - _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib); - _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); - _sg_mtl_release_resource(_sg.mtl.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib); + _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_func); + _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib); + _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_func); + _sg_mtl_release_resource(_sg.frame_index, shd->mtl.stage[SG_SHADERSTAGE_FS].mtl_lib); } _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) { @@ -10512,8 +10511,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s _SOKOL_PRIVATE void _sg_mtl_destroy_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); /* it's valid to call release resource with a 'null resource' */ - _sg_mtl_release_resource(_sg.mtl.frame_index, pip->mtl.rps); - _sg_mtl_release_resource(_sg.mtl.frame_index, pip->mtl.dss); + _sg_mtl_release_resource(_sg.frame_index, pip->mtl.rps); + _sg_mtl_release_resource(_sg.frame_index, pip->mtl.dss); } _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) { @@ -10589,7 +10588,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con /* if this is first pass in frame, get uniform buffer base pointer */ if (0 == _sg.mtl.cur_ub_base_ptr) { - _sg.mtl.cur_ub_base_ptr = (uint8_t*)[_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] contents]; + _sg.mtl.cur_ub_base_ptr = (uint8_t*)[ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] contents]; } /* initialize a render pass descriptor */ @@ -10698,7 +10697,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con } /* bind the global uniform buffer, this only happens once per pass */ - _sg_mtl_bind_uniform_buffers(); + _sg_mtl_bind_uniform_buffers(ctx); } _SOKOL_PRIVATE void _sg_mtl_end_pass(_sg_context_t* ctx) { @@ -10722,7 +10721,7 @@ _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { _SOKOL_UNUSED(ctx); #if defined(_SG_TARGET_MACOS) - [_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, (NSUInteger)_sg.mtl.cur_ub_offset)]; + [ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] didModifyRange:NSMakeRange(0, (NSUInteger)_sg.mtl.cur_ub_offset)]; #endif /* present, commit and signal semaphore when done */ @@ -10739,13 +10738,12 @@ _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { [_sg.mtl.cmd_buffer commit]; /* garbage-collect resources pending for release */ - _sg_mtl_garbage_collect(_sg.mtl.frame_index); + _sg_mtl_garbage_collect(_sg.frame_index); /* rotate uniform buffer slot */ - if (++_sg.mtl.cur_frame_rotate_index >= SG_NUM_INFLIGHT_FRAMES) { - _sg.mtl.cur_frame_rotate_index = 0; + if (++ctx->mtl.cur_ub_index >= SG_NUM_INFLIGHT_FRAMES) { + ctx->mtl.cur_ub_index = 0; } - _sg.mtl.frame_index++; _sg.mtl.cur_ub_offset = 0; _sg.mtl.cur_ub_base_ptr = 0; /* NOTE: MTLCommandBuffer is autoreleased */ @@ -12738,11 +12736,11 @@ static inline void _sg_discard_backend(void) { #endif } -static inline void _sg_reset_state_cache(void) { +static inline void _sg_reset_state_cache(_sg_context_t* ctx) { #if defined(_SOKOL_ANY_GL) _sg_gl_reset_state_cache(); #elif defined(SOKOL_METAL) - _sg_mtl_reset_state_cache(); + _sg_mtl_reset_state_cache(ctx); #elif defined(SOKOL_D3D11) _sg_d3d11_reset_state_cache(); #elif defined(SOKOL_WGPU) @@ -15451,7 +15449,7 @@ SOKOL_API_IMPL void sg_commit(void) { SOKOL_API_IMPL void sg_reset_state_cache(void) { SOKOL_ASSERT(_sg.valid); - _sg_reset_state_cache(); + _sg_reset_state_cache(_sg_active_context()); _SG_TRACE_NOARGS(reset_state_cache); } From dd7b4685207663c17025f32c3a462de72e896dea Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Fri, 23 Apr 2021 17:58:11 +0200 Subject: [PATCH 11/49] sokol_app.h metal: autoreleasepool in view's drawRect method --- sokol_app.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index c2b67e240..f6ef0f6b1 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3852,10 +3852,12 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_frame(win); - #if !defined(SOKOL_METAL) - [[_sapp.macos.view openGLContext] flushBuffer]; - #endif + @autoreleasepool { + _sapp_macos_frame(win); + #if !defined(SOKOL_METAL) + [[_sapp.macos.view openGLContext] flushBuffer]; + #endif + } _sapp_pop_window(); } @@ -4394,7 +4396,9 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { @implementation _sapp_ios_view - (void)drawRect:(CGRect)rect { _SOKOL_UNUSED(rect); - _sapp_ios_frame(); + @autoreleasepool + _sapp_ios_frame(); + } } - (BOOL)isOpaque { return YES; From 205e0314aa9c624329366b428d20adcc572c9636 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 24 Apr 2021 17:07:18 +0200 Subject: [PATCH 12/49] sokol_gfx.h: keep track of rendered context frames --- sokol_gfx.h | 82 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index 56b2eb5c2..6d4695ed7 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -667,9 +667,10 @@ enum { SG_MAX_SHADERSTAGE_IMAGES = 12, SG_MAX_SHADERSTAGE_UBS = 4, SG_MAX_UB_MEMBERS = 16, - SG_MAX_VERTEX_ATTRIBUTES = 16, /* NOTE: actual max vertex attrs can be less on GLES2, see sg_limits! */ + SG_MAX_VERTEX_ATTRIBUTES = 16, // NOTE: actual max vertex attrs can be less on GLES2, see sg_limits! SG_MAX_MIPMAPS = 16, - SG_MAX_TEXTUREARRAY_LAYERS = 128 + SG_MAX_TEXTUREARRAY_LAYERS = 128, + SG_MAX_CONTEXTS = 64, // must be number of bits in an uint64_t! }; /* @@ -2357,9 +2358,11 @@ SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip_id); SOKOL_GFX_API_DECL void sg_fail_pass(sg_pass pass_id); /* rendering contexts (optional) */ -SOKOL_GFX_API_DECL sg_context sg_setup_context(void); +SOKOL_GFX_API_DECL sg_context sg_make_context(const sg_context_desc* desc); +SOKOL_GFX_API_DECL void sg_destroy_context(sg_context ctx_id); +SOKOL_GFX_API_DECL sg_context sg_default_context(void); +SOKOL_GFX_API_DECL sg_context sg_active_context(void); SOKOL_GFX_API_DECL void sg_activate_context(sg_context ctx_id); -SOKOL_GFX_API_DECL void sg_discard_context(sg_context ctx_id); /* Backend-specific helper functions, these may come in handy for mixing sokol-gfx rendering with 'native backend' rendering functions. @@ -3467,7 +3470,6 @@ typedef struct { bool in_pass; int cur_pass_width; int cur_pass_height; - _sg_context_t* cur_context; _sg_pass_t* cur_pass; sg_pass cur_pass_id; _sg_gl_state_cache_t cache; @@ -4036,9 +4038,11 @@ typedef enum { typedef struct { bool valid; - sg_desc desc; /* original desc with default values patched in */ - uint32_t frame_index; - sg_context main_context; + sg_desc desc; // original desc with default values patched in + uint64_t context_mask; // one bit for each existing context + uint64_t commit_mask; // each sg_commit() per context sets a bit here + uint32_t frame_index; // bumped at "end of frame" when (context_mask == commit_mask) + sg_context default_context; sg_context active_context; sg_pass cur_pass; sg_pipeline cur_pipeline; @@ -13510,12 +13514,18 @@ _SOKOL_PRIVATE _sg_context_t* _sg_active_context(void) { return ctx; } -_SOKOL_PRIVATE _sg_context_t* _sg_main_context(void) { - _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.main_context.id); +_SOKOL_PRIVATE _sg_context_t* _sg_default_context(void) { + _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, _sg.default_context.id); SOKOL_ASSERT(ctx); return ctx; } +_SOKOL_PRIVATE uint64_t _sg_context_bitmask(uint32_t ctx_id) { + int index = _sg_slot_index(ctx_id) - 1; + SOKOL_ASSERT((index >= 0) && (index < SG_MAX_CONTEXTS)); + return (1ULL << index); +} + _SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { /* this is a bit dumb since it loops over all pool slots to find the occupied slots, on the other hand it is only ever @@ -14757,13 +14767,14 @@ SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { _sg.desc.uniform_buffer_size = _sg_def(_sg.desc.uniform_buffer_size, _SG_DEFAULT_UB_SIZE); _sg.desc.staging_buffer_size = _sg_def(_sg.desc.staging_buffer_size, _SG_DEFAULT_STAGING_SIZE); _sg.desc.sampler_cache_size = _sg_def(_sg.desc.sampler_cache_size, _SG_DEFAULT_SAMPLER_CACHE_CAPACITY); + SOKOL_ASSERT(_sg.desc.context_pool_size <= SG_MAX_CONTEXTS); _sg_setup_pools(&_sg.pools, &_sg.desc); _sg.frame_index = 1; _sg_setup_backend(&_sg.desc); _sg.valid = true; - sg_setup_context(); - _sg.main_context = _sg.active_context; + _sg.default_context = sg_make_context(&_sg.desc.context); + sg_activate_context(_sg.default_context); } SOKOL_API_IMPL void sg_shutdown(void) { @@ -14771,8 +14782,8 @@ SOKOL_API_IMPL void sg_shutdown(void) { contexts are used, the app code must take care of properly releasing them (since only the app code can switch between 3D-API contexts) */ - _sg_destroy_all_resources(&_sg.pools, _sg.main_context.id); - _sg_destroy_context(_sg_main_context()); + _sg_destroy_all_resources(&_sg.pools, _sg.default_context.id); + _sg_destroy_context(_sg_default_context()); _sg_discard_backend(); _sg_discard_pools(&_sg.pools); _sg.valid = false; @@ -14809,8 +14820,9 @@ SOKOL_API_IMPL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt) { return _sg.formats[fmt_index]; } -SOKOL_API_IMPL sg_context sg_setup_context(void) { +SOKOL_API_IMPL sg_context sg_make_context(const sg_context_desc* desc) { SOKOL_ASSERT(_sg.valid); + // FIXME: actually make use of desc sg_context res; int slot_index = _sg_pool_alloc_index(&_sg.pools.context_pool); if (_SG_INVALID_SLOT_INDEX != slot_index) { @@ -14818,24 +14830,28 @@ SOKOL_API_IMPL sg_context sg_setup_context(void) { _sg_context_t* ctx = _sg_context_at(&_sg.pools, res.id); ctx->slot.state = _sg_create_context(ctx); SOKOL_ASSERT(ctx->slot.state == SG_RESOURCESTATE_VALID); - _sg_activate_context(ctx); + const uint64_t ctx_mask = _sg_context_bitmask(res.id); + SOKOL_ASSERT(0 == (_sg.context_mask & ctx_mask)); + _sg.context_mask |= ctx_mask; } else { /* pool is exhausted */ res.id = SG_INVALID_ID; } - _sg.active_context = res; return res; } -SOKOL_API_IMPL void sg_discard_context(sg_context ctx_id) { +SOKOL_API_IMPL void sg_destroy_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); + const uint64_t ctx_mask = _sg_context_bitmask(ctx_id.id); + SOKOL_ASSERT(ctx_mask == (_sg.context_mask & ctx_mask)); + _sg.context_mask &= ~ctx_mask; _sg_destroy_all_resources(&_sg.pools, ctx_id.id); if (ctx_id.id == _sg.active_context.id) { _sg.active_context.id = SG_INVALID_ID; } - if (ctx_id.id == _sg.main_context.id) { - _sg.main_context.id = SG_INVALID_ID; + if (ctx_id.id == _sg.default_context.id) { + _sg.default_context.id = SG_INVALID_ID; } _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); if (ctx) { @@ -14855,6 +14871,17 @@ SOKOL_API_IMPL void sg_activate_context(sg_context ctx_id) { _sg_activate_context(ctx); } +SOKOL_API_IMPL sg_context sg_default_context(void) { + SOKOL_ASSERT(_sg.valid); + return _sg.default_context; +} + +SOKOL_API_IMPL sg_context sg_active_context(void) { + SOKOL_ASSERT(_sg.valid); + SOKOL_ASSERT(SG_INVALID_ID != _sg.active_context.id); + return _sg.active_context; +} + SOKOL_API_IMPL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(trace_hooks); @@ -15442,9 +15469,22 @@ SOKOL_API_IMPL void sg_end_pass(void) { SOKOL_API_IMPL void sg_commit(void) { SOKOL_ASSERT(_sg.valid); + /* FIXME: add a proper error log message here, if the context bit + is already set, this either means that sg_commit() was called twice + in the same frame and same context, or that not all contexts + had been rendered to in the last frame. + */ + const uint64_t ctx_mask = _sg_context_bitmask(_sg.active_context.id); + SOKOL_ASSERT(0 == (_sg.commit_mask & ctx_mask)); + SOKOL_ASSERT(ctx_mask == (_sg.context_mask & ctx_mask)); + _sg.commit_mask |= ctx_mask; _sg_commit(_sg_active_context()); _SG_TRACE_NOARGS(commit); - _sg.frame_index++; + if (_sg.commit_mask == _sg.context_mask) { + // check for end of frame + _sg.frame_index++; + _sg.commit_mask = 0; + } } SOKOL_API_IMPL void sg_reset_state_cache(void) { From e59af70221274dd785e62feeaf5ceb145871e5b3 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 24 Apr 2021 18:33:40 +0200 Subject: [PATCH 13/49] sokol_gfx.h: each context has its own MTLCommandQueue --- sokol_gfx.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index 6d4695ed7..377f301fb 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -3706,6 +3706,7 @@ typedef struct { _sg_slot_t slot; struct { dispatch_semaphore_t sem; + id cmd_queue; uint32_t cur_ub_index; id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; } mtl; @@ -3746,7 +3747,6 @@ typedef struct { _sg_sampler_cache_t sampler_cache; _sg_mtl_idpool_t idpool; id device; - id cmd_queue; id cmd_buffer; id cmd_encoder; } _sg_mtl_backend_t; @@ -9984,7 +9984,6 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _sg.mtl.user_data = desc->context.metal.user_data; _sg.mtl.ub_size = desc->uniform_buffer_size; _sg.mtl.device = (__bridge id) desc->context.metal.device; - _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; _sg_mtl_init_caps(); } @@ -9996,7 +9995,6 @@ _SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { _sg.mtl.valid = false; _SG_OBJC_RELEASE(_sg.mtl.device); - _SG_OBJC_RELEASE(_sg.mtl.cmd_queue); /* NOTE: MTLCommandBuffer and MTLRenderCommandEncoder are auto-released */ _sg.mtl.cmd_buffer = nil; _sg.mtl.cmd_encoder = nil; @@ -10030,6 +10028,7 @@ _SOKOL_PRIVATE void _sg_mtl_reset_state_cache(_sg_context_t* ctx) { _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); ctx->mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); + ctx->mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; MTLResourceOptions res_opts = MTLResourceCPUCacheModeWriteCombined; #if defined(_SG_TARGET_MACOS) res_opts |= MTLResourceStorageModeManaged; @@ -10058,6 +10057,7 @@ _SOKOL_PRIVATE void _sg_mtl_destroy_context(_sg_context_t* ctx) { for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { _SG_OBJC_RELEASE(ctx->mtl.uniform_buffers[i]); } + _SG_OBJC_RELEASE(ctx->mtl.cmd_queue); } _SOKOL_PRIVATE void _sg_mtl_activate_context(_sg_context_t* ctx) { @@ -10569,7 +10569,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con SOKOL_ASSERT(action); SOKOL_ASSERT(ctx); SOKOL_ASSERT(!_sg.mtl.in_pass); - SOKOL_ASSERT(_sg.mtl.cmd_queue); + SOKOL_ASSERT(ctx->mtl.cmd_queue); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); SOKOL_ASSERT(_sg.mtl.renderpass_descriptor_cb || _sg.mtl.renderpass_descriptor_userdata_cb); _sg.mtl.in_pass = true; @@ -10581,7 +10581,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con if (nil == _sg.mtl.cmd_buffer) { /* block until the oldest frame in flight has finished */ dispatch_semaphore_wait(ctx->mtl.sem, DISPATCH_TIME_FOREVER); - _sg.mtl.cmd_buffer = [_sg.mtl.cmd_queue commandBufferWithUnretainedReferences]; + _sg.mtl.cmd_buffer = [ctx->mtl.cmd_queue commandBufferWithUnretainedReferences]; __block dispatch_semaphore_t block_sem = ctx->mtl.sem; [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { // NOTE: this code is called on a different thread! @@ -15475,13 +15475,17 @@ SOKOL_API_IMPL void sg_commit(void) { had been rendered to in the last frame. */ const uint64_t ctx_mask = _sg_context_bitmask(_sg.active_context.id); - SOKOL_ASSERT(0 == (_sg.commit_mask & ctx_mask)); + +// FIXME: with the "automatic" MTKView timing in sokol_app.h, the draw +// callbacks are not strictly called round-robin, which would cause +// the following assert to trigger +// SOKOL_ASSERT(0 == (_sg.commit_mask & ctx_mask)); SOKOL_ASSERT(ctx_mask == (_sg.context_mask & ctx_mask)); _sg.commit_mask |= ctx_mask; _sg_commit(_sg_active_context()); _SG_TRACE_NOARGS(commit); + // once all context's have been rendered, it's "safe" to advance the frame if (_sg.commit_mask == _sg.context_mask) { - // check for end of frame _sg.frame_index++; _sg.commit_mask = 0; } From f36116580e8cda380eb0d3558530a78ff4783610 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 24 Apr 2021 18:34:25 +0200 Subject: [PATCH 14/49] sokol_app.h: experiement with GLFW-style render loop --- sokol_app.h | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/sokol_app.h b/sokol_app.h index f6ef0f6b1..26ecdd348 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2975,6 +2975,7 @@ _SOKOL_PRIVATE void _sapp_frame(_sapp_window_t* win) { _sapp_call_init(win); } _sapp_call_frame(win); + // FIXME: this needs to be per window _sapp.frame_count++; } @@ -3291,11 +3292,47 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { #endif } + +// FIXME: this is for a GLFW-style "explicit" render loop +/* +_SOKOL_PRIVATE void _sapp_macos_process_events(void){ + NSEvent* event; + do { + event = [NSApp nextEventMatchingMask: NSEventMaskAny + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; + + if (event != NULL) { + [NSApp sendEvent:event]; + } + } + while (event != NULL); +} +*/ + _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApplication sharedApplication]; _sapp_init_state(desc); [NSApp run]; - // NOTE: [NSApp run] never returns, cleanup code is in applicationWillTerminate instead + +// FIXME: this is for a GLFW-style "explicit" render loop +/* + while (!_sapp.quit_ordered) { + _sapp_macos_process_events(); + for (int i = 0; i < _sapp.window_pool.pool.size; i++) { + const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + #if defined(SOKOL_METAL) + [win->macos.view draw]; + #else + #error "FIXME: GL" + #endif + } + } + } +*/ } _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { @@ -3340,6 +3377,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.win_id = win->slot.id; [win->macos.view updateTrackingAreas]; win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; +// FIXME: this is for a GLFW-style "explicit" render loop +// win->macos.view.paused = true; +// win->macos.view.enableSetNeedsDisplay = false; win->macos.view.device = _sapp.macos.mtl_device; win->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; @@ -3678,6 +3718,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { _sapp_macos_update_dimensions(win); _sapp_pop_window(); _sapp.valid = true; + +// FIXME: this is for a GLFW-style "explicit" render loop +// [NSApp stop:nil]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { From 7ea7a4ff83508822d41b6f0a3c334c221d4e9ffb Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 25 Apr 2021 16:14:35 +0200 Subject: [PATCH 15/49] sokol_app.h: go back to application callbacks instead of window callbacks --- sokol_app.h | 693 +++++++++++++++++++++++++++------------------------- 1 file changed, 354 insertions(+), 339 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 26ecdd348..8c3350dd3 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1334,17 +1334,6 @@ typedef struct sapp_icon_desc { FIXME: docs */ typedef struct sapp_window_desc { - void (*init_cb)(void); // these are the user-provided callbacks without user data - void (*frame_cb)(void); - void (*cleanup_cb)(void); - void (*event_cb)(const sapp_event*); - - void* user_data; // these are the user-provided callbacks with user data - void (*init_userdata_cb)(void*); - void (*frame_userdata_cb)(void*); - void (*cleanup_userdata_cb)(void*); - void (*event_userdata_cb)(const sapp_event*, void*); - const char* title; // the window title as UTF-8 encoded string int x; int y; @@ -1386,6 +1375,17 @@ typedef struct sapp_ios_desc { } sapp_ios_desc; typedef struct sapp_desc { + void (*init_cb)(void); // these are the user-provided callbacks without user data + void (*frame_cb)(void); + void (*cleanup_cb)(void); + void (*event_cb)(const sapp_event*); + + void* user_data; // these are the user-provided callbacks with user data + void (*init_userdata_cb)(void*); + void (*frame_userdata_cb)(void*); + void (*cleanup_userdata_cb)(void*); + void (*event_userdata_cb)(const sapp_event*, void*); + int window_pool_size; sapp_window_desc window; sapp_icon_desc icon; // FIXME: per-window icons? @@ -1436,6 +1436,8 @@ SOKOL_APP_API_DECL bool sapp_isvalid(void); SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); /* close a window */ SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); +/* FIXME set the current 'window context' */ +SOKOL_APP_API_DECL void sapp_use_window(sapp_window window); /* returns the current framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_width(void); /* same as sapp_width(), but returns float */ @@ -2324,10 +2326,6 @@ typedef struct { int framebuffer_height; float dpi_scale; bool fullscreen; - bool first_frame; - bool init_called; - bool cleanup_called; - bool event_consumed; _sapp_mouse_t mouse; _sapp_clipboard_t clipboard; _sapp_drop_t drop; @@ -2368,9 +2366,11 @@ typedef struct { _sapp_window_pool_t window_pool; uint32_t main_window_id; uint32_t cur_window_id; - uint32_t stored_window_id; - _sapp_window_t* cur_window; bool valid; + bool first_frame; + bool init_called; + bool cleanup_called; + bool event_consumed; bool gles2_fallback; bool quit_requested; bool quit_ordered; @@ -2630,51 +2630,51 @@ _SOKOL_PRIVATE void _sapp_fail(const char* msg) { SOKOL_ABORT(); } -_SOKOL_PRIVATE void _sapp_call_init(_sapp_window_t* win) { - SOKOL_ASSERT(!win->init_called); - if (win->desc.init_cb) { - win->desc.init_cb(); +_SOKOL_PRIVATE void _sapp_call_init(void) { + SOKOL_ASSERT(!_sapp.init_called); + if (_sapp.desc.init_cb) { + _sapp.desc.init_cb(); } - else if (win->desc.init_userdata_cb) { - win->desc.init_userdata_cb(win->desc.user_data); + else if (_sapp.desc.init_userdata_cb) { + _sapp.desc.init_userdata_cb(_sapp.desc.user_data); } - win->init_called = true; + _sapp.init_called = true; } -_SOKOL_PRIVATE void _sapp_call_frame(_sapp_window_t* win) { - if (win->init_called && !win->cleanup_called) { - if (win->desc.frame_cb) { - win->desc.frame_cb(); +_SOKOL_PRIVATE void _sapp_call_frame(void) { + if (_sapp.init_called && !_sapp.cleanup_called) { + if (_sapp.desc.frame_cb) { + _sapp.desc.frame_cb(); } - else if (win->desc.frame_userdata_cb) { - win->desc.frame_userdata_cb(win->desc.user_data); + else if (_sapp.desc.frame_userdata_cb) { + _sapp.desc.frame_userdata_cb(_sapp.desc.user_data); } } } -_SOKOL_PRIVATE void _sapp_call_cleanup(_sapp_window_t* win) { - if (!win->cleanup_called) { - if (win->desc.cleanup_cb) { - win->desc.cleanup_cb(); +_SOKOL_PRIVATE void _sapp_call_cleanup(void) { + if (!_sapp.cleanup_called) { + if (_sapp.desc.cleanup_cb) { + _sapp.desc.cleanup_cb(); } - else if (win->desc.cleanup_userdata_cb) { - win->desc.cleanup_userdata_cb(win->desc.user_data); + else if (_sapp.desc.cleanup_userdata_cb) { + _sapp.desc.cleanup_userdata_cb(_sapp.desc.user_data); } - win->cleanup_called = true; + _sapp.cleanup_called = true; } } -_SOKOL_PRIVATE bool _sapp_call_event(_sapp_window_t* win, const sapp_event* e) { - if (!win->cleanup_called) { - if (win->desc.event_cb) { - win->desc.event_cb(e); +_SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { + if (!_sapp.cleanup_called) { + if (_sapp.desc.event_cb) { + _sapp.desc.event_cb(e); } - else if (win->desc.event_userdata_cb) { - win->desc.event_userdata_cb(e, win->desc.user_data); + else if (_sapp.desc.event_userdata_cb) { + _sapp.desc.event_userdata_cb(e, _sapp.desc.user_data); } } - if (win->event_consumed) { - win->event_consumed = false; + if (_sapp.event_consumed) { + _sapp.event_consumed = false; return true; } else { @@ -2682,7 +2682,7 @@ _SOKOL_PRIVATE bool _sapp_call_event(_sapp_window_t* win, const sapp_event* e) { } } -_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(_sapp_window_t* win, int index) { +_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(const _sapp_window_t* win, int index) { SOKOL_ASSERT(win->drop.buffer); SOKOL_ASSERT((index >= 0) && (index <= win->drop.max_files)); int offset = index * win->drop.max_path_length; @@ -2733,22 +2733,6 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_desc_defaults(const sapp_window_des return desc; } -// makes a window the current window and returns pointer to window struct, CAN RETURN NULL! -_SOKOL_PRIVATE _sapp_window_t* _sapp_push_window(uint32_t win_id) { - SOKOL_ASSERT(SAPP_INVALID_ID == _sapp.stored_window_id); - _sapp.stored_window_id = _sapp.cur_window_id; - _sapp.cur_window_id = win_id; - _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window; -} - -_SOKOL_PRIVATE void _sapp_pop_window(void) { - _sapp.cur_window_id = _sapp.stored_window_id; - _sapp.stored_window_id = SAPP_INVALID_ID; - _sapp.cur_window = _sapp_lookup_window(_sapp.cur_window_id); -} - _SOKOL_PRIVATE void _sapp_platform_init_state(void) { #if defined(_SAPP_MACOS) _sapp_macos_init_state(); @@ -2834,14 +2818,13 @@ _SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { } _SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { - _sapp_window_t* win = _sapp_push_window(win_id); - _sapp_call_cleanup(win); + _sapp_window_t* win = _sapp_lookup_window(win_id); + SOKOL_ASSERT(win); _sapp_discard_drop(&win->drop); _sapp_discard_clipboard(&win->clipboard); _sapp_platform_destroy_window(win); _sapp_free_window_id(win_id); _SAPP_CLEAR_PTR(_sapp_window_t, win); - _sapp_pop_window(); } _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { @@ -2865,7 +2848,6 @@ _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { win->framebuffer_height = desc->height; win->dpi_scale = 1.0f; win->fullscreen = desc->fullscreen; - win->first_frame = true; win->mouse.shown = true; if (!_sapp_init_clipboard(&win->clipboard, &win->desc)) { SOKOL_LOG("clipboard initialization failed!"); @@ -2911,6 +2893,7 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _SAPP_CLEAR_ITEM(_sapp_t, _sapp); _sapp.desc = _sapp_desc_defaults(desc); + _sapp.first_frame = true; _sapp_setup_window_pool(&_sapp.desc); _sapp_platform_init_state(); @@ -2921,6 +2904,7 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { } _SOKOL_PRIVATE void _sapp_discard_state(void) { + _sapp_call_cleanup(); _sapp_destroy_all_windows(); _sapp_discard_window_pool(); _sapp_platform_discard_state(); @@ -2946,10 +2930,9 @@ _SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* win, sapp_event_type type) _sapp.event.mouse_dy = win->mouse.dy; } -_SOKOL_PRIVATE bool _sapp_events_enabled(_sapp_window_t* win) { - SOKOL_ASSERT(win); +_SOKOL_PRIVATE bool _sapp_events_enabled(void) { /* only send events when an event callback is set, and the init function was called */ - return (win->desc.event_cb || win->desc.event_userdata_cb) && win->init_called; + return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called; } _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { @@ -2969,13 +2952,12 @@ _SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* win) { } } -_SOKOL_PRIVATE void _sapp_frame(_sapp_window_t* win) { - if (win->first_frame) { - win->first_frame = false; - _sapp_call_init(win); +_SOKOL_PRIVATE void _sapp_frame(void) { + if (_sapp.first_frame) { + _sapp.first_frame = false; + _sapp_call_init(); } - _sapp_call_frame(win); - // FIXME: this needs to be per window + _sapp_call_frame(); _sapp.frame_count++; } @@ -3294,7 +3276,6 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { // FIXME: this is for a GLFW-style "explicit" render loop -/* _SOKOL_PRIVATE void _sapp_macos_process_events(void){ NSEvent* event; do { @@ -3309,7 +3290,6 @@ _SOKOL_PRIVATE void _sapp_macos_process_events(void){ } while (event != NULL); } -*/ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApplication sharedApplication]; @@ -3317,9 +3297,9 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApp run]; // FIXME: this is for a GLFW-style "explicit" render loop -/* while (!_sapp.quit_ordered) { _sapp_macos_process_events(); + _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; _sapp_window_t* win = _sapp_lookup_window(win_id); @@ -3331,8 +3311,11 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { #endif } } + // FIXME FIXME FIXME + // if (_sapp.quit_requested || _sapp.quit_ordered) { + // [win->macos.window performClose:nil]; + // } } -*/ } _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { @@ -3491,28 +3474,28 @@ _SOKOL_PRIVATE uint32_t _sapp_macos_mods(NSEvent* ev) { } _SOKOL_PRIVATE void _sapp_macos_mouse_event(_sapp_window_t* win, sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { - if (_sapp_events_enabled(win)) { + if (_sapp_events_enabled()) { _sapp_init_event(win, type); _sapp.event.mouse_button = btn; _sapp.event.modifiers = mod; - _sapp_call_event(win, &_sapp.event); + _sapp_call_event(&_sapp.event); } } _SOKOL_PRIVATE void _sapp_macos_key_event(_sapp_window_t* win, sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { - if (_sapp_events_enabled(win)) { + if (_sapp_events_enabled()) { _sapp_init_event(win, type); _sapp.event.key_code = key; _sapp.event.key_repeat = repeat; _sapp.event.modifiers = mod; - _sapp_call_event(win, &_sapp.event); + _sapp_call_event(&_sapp.event); } } _SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type type) { - if (_sapp_events_enabled(win)) { + if (_sapp_events_enabled()) { _sapp_init_event(win, type); - _sapp_call_event(win, &_sapp.event); + _sapp_call_event(&_sapp.event); } } @@ -3692,20 +3675,13 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu CGImageRelease(cg_img); } -_SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { - _sapp_frame(win); - // FIXME FIXME FIXME - if (_sapp.quit_requested || _sapp.quit_ordered) { - [win->macos.window performClose:nil]; - } -} - @implementation _sapp_macos_app_delegate - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); + _sapp.cur_window_id = _sapp.main_window_id; // FIXME: maybe the activation stuff here needs to be moved before // the makeKeyAndOrderFront call, see here: @@ -3714,13 +3690,12 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { [NSApp activateIgnoringOtherApps:YES]; [NSEvent setMouseCoalescingEnabled:NO]; - _sapp_window_t* win = _sapp_push_window(_sapp.main_window_id); + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); + SOKOL_ASSERT(win); _sapp_macos_update_dimensions(win); - _sapp_pop_window(); _sapp.valid = true; -// FIXME: this is for a GLFW-style "explicit" render loop -// [NSApp stop:nil]; + [NSApp stop:nil]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -3745,9 +3720,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { a chance to intervene via sapp_cancel_quit() */ _sapp.quit_requested = true; - _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + SOKOL_ASSERT(win); _sapp_macos_app_event(win, SAPP_EVENTTYPE_QUIT_REQUESTED); - _sapp_pop_window(); /* user code hasn't intervened, quit the app */ if (_sapp.quit_requested) { _sapp.quit_ordered = true; @@ -3763,42 +3738,45 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { - (void)windowDidResize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); if (win) { _sapp_macos_update_dimensions(win); - if (!win->first_frame) { + if (!_sapp.first_frame) { _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); } } - _sapp_pop_window(); } - (void)windowDidMiniaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_app_event(win, SAPP_EVENTTYPE_ICONIFIED); - _sapp_pop_window(); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_ICONIFIED); + } } - (void)windowDidDeminiaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESTORED); - _sapp_pop_window(); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESTORED); + } } - (void)windowDidEnterFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_push_window(self.win_id); - win->fullscreen = true; - _sapp_pop_window(); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + win->fullscreen = true; + } } - (void)windowDidExitFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_push_window(self.win_id); - win->fullscreen = false; - _sapp_pop_window(); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + win->fullscreen = false; + } } @end @@ -3828,7 +3806,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { - (BOOL)performDragOperation:(id)sender { BOOL retval = NO; #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 - _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + SOKOL_ASSERT(win); NSPasteboard *pboard = [sender draggingPasteboard]; if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { _sapp_clear_drop_buffer(win); @@ -3843,9 +3822,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { } } if (!drop_failed) { - if (_sapp_events_enabled(win)) { + if (_sapp_events_enabled()) { _sapp_init_event(win, SAPP_EVENTTYPE_FILES_DROPPED); - _sapp_call_event(win, &_sapp.event); + _sapp_call_event(&_sapp.event); } } else { @@ -3854,7 +3833,6 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { } retval = YES; } - _sapp_pop_window(); #endif return retval; } @@ -3874,9 +3852,10 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { the correct dimensions. */ - (void)reshape { - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_update_dimensions(win); - _sapp_pop_window(self.win_id); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_update_dimensions(win); + } [super reshape]; } - (void)timerFired:(id)sender { @@ -3894,14 +3873,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); - _sapp_window_t* win = _sapp_push_window(self.win_id); - @autoreleasepool { - _sapp_macos_frame(win); - #if !defined(SOKOL_METAL) - [[_sapp.macos.view openGLContext] flushBuffer]; - #endif - } - _sapp_pop_window(); + #if !defined(SOKOL_METAL) + [[_sapp.macos.view openGLContext] flushBuffer]; + #endif } - (BOOL)isOpaque { @@ -3914,7 +3888,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { return YES; } - (void)updateTrackingAreas { - _sapp_window_t* win = _sapp_push_window(self.win_id); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + SOKOL_ASSERT(win); if (win->macos.tracking_area != nil) { [self removeTrackingArea:win->macos.tracking_area]; _SAPP_OBJC_RELEASE(win->macos.tracking_area); @@ -3928,205 +3903,221 @@ _SOKOL_PRIVATE void _sapp_macos_frame(_sapp_window_t* win) { win->macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; [self addTrackingArea:win->macos.tracking_area]; [super updateTrackingAreas]; - _sapp_pop_window(); } - (void)mouseEntered:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_update_mouse(win, event); - /* don't send mouse enter/leave while dragging (so that it behaves the same as - on Windows while SetCapture is active - */ - if (0 == win->macos.mouse_buttons) { - _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_update_mouse(win, event); + /* don't send mouse enter/leave while dragging (so that it behaves the same as + on Windows while SetCapture is active + */ + if (0 == win->macos.mouse_buttons) { + _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + } } - _sapp_pop_window(); } - (void)mouseExited:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_update_mouse(win, event); - if (0 == win->macos.mouse_buttons) { - _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_update_mouse(win, event); + if (0 == win->macos.mouse_buttons) { + _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mods(event)); + } } - _sapp_pop_window(); } - (void)mouseDown:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_update_mouse(win, event); - _sapp_macos_mouse_event(win, SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mods(event)); - win->macos.mouse_buttons |= (1<macos.mouse_buttons |= (1<macos.mouse_buttons &= ~(1<macos.mouse_buttons &= ~(1<macos.mouse_buttons |= (1<macos.mouse_buttons |= (1<macos.mouse_buttons &= ~(1<macos.mouse_buttons &= ~(1<macos.mouse_buttons |= (1<macos.mouse_buttons |= (1<macos.mouse_buttons &= (1<macos.mouse_buttons &= (1< 0.0f) || (_sapp_absf(dy) > 0.0f)) { - _sapp_init_event(win, SAPP_EVENTTYPE_MOUSE_SCROLL); - _sapp.event.modifiers = _sapp_macos_mods(event); - _sapp.event.scroll_x = dx; - _sapp.event.scroll_y = dy; - _sapp_call_event(win, &_sapp.event); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_update_mouse(win, event); + if (_sapp_events_enabled()) { + float dx = (float) event.scrollingDeltaX; + float dy = (float) event.scrollingDeltaY; + if (event.hasPreciseScrollingDeltas) { + dx *= 0.1; + dy *= 0.1; + } + if ((_sapp_absf(dx) > 0.0f) || (_sapp_absf(dy) > 0.0f)) { + _sapp_init_event(win, SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp.event.modifiers = _sapp_macos_mods(event); + _sapp.event.scroll_x = dx; + _sapp.event.scroll_y = dy; + _sapp_call_event(&_sapp.event); + } } } - _sapp_pop_window(); } - (void)keyDown:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - if (_sapp_events_enabled(win)) { - const uint32_t mods = _sapp_macos_mods(event); - /* NOTE: macOS doesn't send keyUp events while the Cmd key is pressed, - as a workaround, to prevent key presses from sticking we'll send - a keyup event following right after the keydown if SUPER is also pressed - */ - const sapp_keycode key_code = _sapp_translate_key(event.keyCode); - _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods); - if (0 != (mods & SAPP_MODIFIER_SUPER)) { - _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, key_code, event.isARepeat, mods); - } - const NSString* chars = event.characters; - const NSUInteger len = chars.length; - if (len > 0) { - _sapp_init_event(win, SAPP_EVENTTYPE_CHAR); - _sapp.event.modifiers = mods; - for (NSUInteger i = 0; i < len; i++) { - const unichar codepoint = [chars characterAtIndex:i]; - if ((codepoint & 0xFF00) == 0xF700) { - continue; + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + if (_sapp_events_enabled()) { + const uint32_t mods = _sapp_macos_mods(event); + /* NOTE: macOS doesn't send keyUp events while the Cmd key is pressed, + as a workaround, to prevent key presses from sticking we'll send + a keyup event following right after the keydown if SUPER is also pressed + */ + const sapp_keycode key_code = _sapp_translate_key(event.keyCode); + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods); + if (0 != (mods & SAPP_MODIFIER_SUPER)) { + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, key_code, event.isARepeat, mods); + } + const NSString* chars = event.characters; + const NSUInteger len = chars.length; + if (len > 0) { + _sapp_init_event(win, SAPP_EVENTTYPE_CHAR); + _sapp.event.modifiers = mods; + for (NSUInteger i = 0; i < len; i++) { + const unichar codepoint = [chars characterAtIndex:i]; + if ((codepoint & 0xFF00) == 0xF700) { + continue; + } + _sapp.event.char_code = codepoint; + _sapp.event.key_repeat = event.isARepeat; + _sapp_call_event(&_sapp.event); } - _sapp.event.char_code = codepoint; - _sapp.event.key_repeat = event.isARepeat; - _sapp_call_event(win, &_sapp.event); } - } - /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ - if (win->clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(win, SAPP_EVENTTYPE_CLIPBOARD_PASTED); - _sapp_call_event(win, &_sapp.event); + /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ + if (win->clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { + _sapp_init_event(win, SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_call_event(&_sapp.event); + } } } - _sapp_pop_window(); } - (void)keyUp:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, - _sapp_translate_key(event.keyCode), - event.isARepeat, - _sapp_macos_mods(event)); - _sapp_pop_window(); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + _sapp_macos_key_event(win, SAPP_EVENTTYPE_KEY_UP, + _sapp_translate_key(event.keyCode), + event.isARepeat, + _sapp_macos_mods(event)); + } } - (void)flagsChanged:(NSEvent*)event { - _sapp_window_t* win = _sapp_push_window(self.win_id); - const uint32_t old_f = win->macos.flags_changed_store; - const uint32_t new_f = event.modifierFlags; - win->macos.flags_changed_store = new_f; - sapp_keycode key_code = SAPP_KEYCODE_INVALID; - bool down = false; - if ((new_f ^ old_f) & NSEventModifierFlagShift) { - key_code = SAPP_KEYCODE_LEFT_SHIFT; - down = 0 != (new_f & NSEventModifierFlagShift); - } - if ((new_f ^ old_f) & NSEventModifierFlagControl) { - key_code = SAPP_KEYCODE_LEFT_CONTROL; - down = 0 != (new_f & NSEventModifierFlagControl); - } - if ((new_f ^ old_f) & NSEventModifierFlagOption) { - key_code = SAPP_KEYCODE_LEFT_ALT; - down = 0 != (new_f & NSEventModifierFlagOption); - } - if ((new_f ^ old_f) & NSEventModifierFlagCommand) { - key_code = SAPP_KEYCODE_LEFT_SUPER; - down = 0 != (new_f & NSEventModifierFlagCommand); - } - if (key_code != SAPP_KEYCODE_INVALID) { - _sapp_macos_key_event(win, down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, - key_code, - false, - _sapp_macos_mods(event)); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + const uint32_t old_f = win->macos.flags_changed_store; + const uint32_t new_f = event.modifierFlags; + win->macos.flags_changed_store = new_f; + sapp_keycode key_code = SAPP_KEYCODE_INVALID; + bool down = false; + if ((new_f ^ old_f) & NSEventModifierFlagShift) { + key_code = SAPP_KEYCODE_LEFT_SHIFT; + down = 0 != (new_f & NSEventModifierFlagShift); + } + if ((new_f ^ old_f) & NSEventModifierFlagControl) { + key_code = SAPP_KEYCODE_LEFT_CONTROL; + down = 0 != (new_f & NSEventModifierFlagControl); + } + if ((new_f ^ old_f) & NSEventModifierFlagOption) { + key_code = SAPP_KEYCODE_LEFT_ALT; + down = 0 != (new_f & NSEventModifierFlagOption); + } + if ((new_f ^ old_f) & NSEventModifierFlagCommand) { + key_code = SAPP_KEYCODE_LEFT_SUPER; + down = 0 != (new_f & NSEventModifierFlagCommand); + } + if (key_code != SAPP_KEYCODE_INVALID) { + _sapp_macos_key_event(win, down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, + key_code, + false, + _sapp_macos_mods(event)); + } } - _sapp_pop_window(); } - (void)cursorUpdate:(NSEvent*)event { _SOKOL_UNUSED(event); - _sapp_window_t* win = _sapp_push_window(self.win_id); - if (win->desc.user_cursor) { - _sapp_macos_app_event(win, SAPP_EVENTTYPE_UPDATE_CURSOR); + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + if (win->desc.user_cursor) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_UPDATE_CURSOR); + } } - _sapp_pop_window(); } @end @@ -11141,6 +11132,11 @@ SOKOL_API_IMPL void sapp_close_window(sapp_window window) { // FIXME } +SOKOL_API_IMPL void sapp_use_window(sapp_window window) { + SOKOL_ASSERT(SAPP_INVALID_ID != window.id); + _sapp.cur_window_id = window.id; +} + SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { return _sapp.desc; } @@ -11150,8 +11146,9 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) { } SOKOL_API_IMPL int sapp_width(void) { - SOKOL_ASSERT(_sapp.cur_window); - return (_sapp.cur_window->framebuffer_width > 0) ? _sapp.cur_window->framebuffer_width : 1; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return (win->framebuffer_width > 0) ? win->framebuffer_width : 1; } SOKOL_API_IMPL float sapp_widthf(void) { @@ -11159,8 +11156,9 @@ SOKOL_API_IMPL float sapp_widthf(void) { } SOKOL_API_IMPL int sapp_height(void) { - SOKOL_ASSERT(_sapp.cur_window); - return (_sapp.cur_window->framebuffer_height > 0) ? _sapp.cur_window->framebuffer_height : 1; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return (win->framebuffer_height > 0) ? win->framebuffer_height : 1; } SOKOL_API_IMPL float sapp_heightf(void) { @@ -11190,18 +11188,21 @@ SOKOL_API_IMPL int sapp_depth_format(void) { } SOKOL_API_IMPL int sapp_sample_count(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->desc.sample_count; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->desc.sample_count; } SOKOL_API_IMPL bool sapp_high_dpi(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->desc.high_dpi && (_sapp.cur_window->dpi_scale >= 1.5f); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->desc.high_dpi && (win->dpi_scale >= 1.5f); } SOKOL_API_IMPL float sapp_dpi_scale(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->dpi_scale; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->dpi_scale; } SOKOL_API_IMPL bool sapp_gles2(void) { @@ -11225,14 +11226,16 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { } SOKOL_APP_API_DECL bool sapp_is_fullscreen(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->fullscreen; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->fullscreen; } SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { - SOKOL_ASSERT(_sapp.cur_window); + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); #if defined(_SAPP_MACOS) - _sapp_macos_toggle_fullscreen(_sapp.cur_window); + _sapp_macos_toggle_fullscreen(win); #elif defined(_SAPP_WIN32) _sapp_win32_toggle_fullscreen(); #elif defined(_SAPP_UWP) @@ -11244,8 +11247,9 @@ SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { /* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ SOKOL_API_IMPL void sapp_show_mouse(bool show) { - SOKOL_ASSERT(_sapp.cur_window); - if (_sapp.cur_window->mouse.shown != show) { + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + if (win->mouse.shown != show) { #if defined(_SAPP_MACOS) _sapp_macos_show_mouse(show); #elif defined(_SAPP_WIN32) @@ -11255,19 +11259,21 @@ SOKOL_API_IMPL void sapp_show_mouse(bool show) { #elif defined(_SAPP_UWP) _sapp_uwp_show_mouse(show); #endif - _sapp.cur_window->mouse.shown = show; + win->mouse.shown = show; } } SOKOL_API_IMPL bool sapp_mouse_shown(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->mouse.shown; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->mouse.shown; } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { - SOKOL_ASSERT(_sapp.cur_window); + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); #if defined(_SAPP_MACOS) - _sapp_macos_lock_mouse(_sapp.cur_window, lock); + _sapp_macos_lock_mouse(win, lock); #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_lock_mouse(lock); #elif defined(_SAPP_WIN32) @@ -11280,8 +11286,9 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - SOKOL_ASSERT(_sapp.cur_window); - return _sapp.cur_window->mouse.locked; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + return win->mouse.locked; } SOKOL_API_IMPL void sapp_request_quit(void) { @@ -11297,15 +11304,15 @@ SOKOL_API_IMPL void sapp_quit(void) { } SOKOL_API_IMPL void sapp_consume_event(void) { - SOKOL_ASSERT(_sapp.cur_window); - _sapp.cur_window->event_consumed = true; + _sapp.event_consumed = true; } /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->clipboard.enabled); - if (!_sapp.cur_window->clipboard.enabled) { + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->clipboard.enabled); + if (!win->clipboard.enabled) { return; } SOKOL_ASSERT(str); @@ -11318,17 +11325,18 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { #else /* not implemented */ #endif - _sapp_strcpy(str, _sapp.cur_window->clipboard.buffer, _sapp.cur_window->clipboard.buf_size); + _sapp_strcpy(str, win->clipboard.buffer, win->clipboard.buf_size); } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->clipboard.enabled); - if (!_sapp.cur_window->clipboard.enabled) { + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->clipboard.enabled); + if (!win->clipboard.enabled) { return ""; } #if defined(_SAPP_MACOS) - return _sapp_macos_get_clipboard_string(_sapp.cur_window); + return _sapp_macos_get_clipboard_string(win); #elif defined(_SAPP_EMSCRIPTEN) return _sapp.clipboard.buffer; #elif defined(_SAPP_WIN32) @@ -11341,10 +11349,11 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { SOKOL_API_IMPL void sapp_set_window_title(const char* title) { SOKOL_ASSERT(title); - SOKOL_ASSERT(_sapp.cur_window); - _sapp_strcpy(title, _sapp.cur_window->title, sizeof(_sapp.cur_window->title)); + _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + _sapp_strcpy(title, win->title, sizeof(win->title)); #if defined(_SAPP_MACOS) - _sapp_macos_update_window_title(_sapp.cur_window); + _sapp_macos_update_window_title(win); #elif defined(_SAPP_WIN32) _sapp_win32_update_window_title(); #elif defined(_SAPP_LINUX) @@ -11381,31 +11390,33 @@ SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { } SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->drop.enabled); - return _sapp.cur_window->drop.num_files; + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->drop.enabled); + return win->drop.num_files; } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.cur_window->drop.num_files)); - SOKOL_ASSERT(_sapp.cur_window->drop.buffer); - if (!_sapp.cur_window->drop.enabled) { + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); + SOKOL_ASSERT(win->drop.buffer); + if (!win->drop.enabled) { return ""; } - if ((index < 0) || (index >= _sapp.cur_window->drop.max_files)) { + if ((index < 0) || (index >= win->drop.max_files)) { return ""; } - return (const char*) _sapp_dropped_file_path_ptr(_sapp.cur_window, index); + return (const char*) _sapp_dropped_file_path_ptr(win, index); } SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < _sapp.cur_window->drop.num_files)); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); #if defined(_SAPP_EMSCRIPTEN) - if (!_sapp.cur_window->drop.enabled) { + if (!win->drop.enabled) { return 0; } return sapp_js_dropped_file_size(index); @@ -11416,8 +11427,9 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { - SOKOL_ASSERT(_sapp.cur_window); - SOKOL_ASSERT(_sapp.cur_window->drop.enabled); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->drop.enabled); SOKOL_ASSERT(request); SOKOL_ASSERT(request->callback); SOKOL_ASSERT(request->buffer_ptr); @@ -11470,10 +11482,11 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_ASSERT(_sapp.valid); - SOKOL_ASSERT(_sapp.cur_window); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.cur_window->macos.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [win->macos.view currentRenderPassDescriptor]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; #endif @@ -11486,10 +11499,11 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { SOKOL_ASSERT(_sapp.valid); - SOKOL_ASSERT(_sapp.cur_window); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.cur_window->macos.view currentDrawable]; + const void* obj = (__bridge const void*) [win->macos.view currentDrawable]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; #endif @@ -11502,9 +11516,10 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { SOKOL_API_IMPL const void* sapp_macos_get_window(void) { SOKOL_ASSERT(_sapp.valid); - SOKOL_ASSERT(_sapp.cur_window); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + SOKOL_ASSERT(win); #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.cur_window->macos.window; + const void* obj = (__bridge const void*) win->macos.window; SOKOL_ASSERT(obj); return obj; #else From baf1327390c4e5b21186b1fe0a8b34c683cf7343 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 26 Apr 2021 20:18:53 +0200 Subject: [PATCH 16/49] sokol_app.h: trigger rendering with CVDisplayLink --- sokol_app.h | 72 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 8c3350dd3..2abe7b176 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1821,6 +1821,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } /*== MACOS DECLARATIONS ======================================================*/ #if defined(_SAPP_MACOS) @interface _sapp_macos_app_delegate : NSObject +- (void)drawFrame; @end @interface _sapp_macos_window : NSWindow @property uint32_t win_id; @@ -1853,6 +1854,8 @@ typedef struct { #if defined(SOKOL_METAL) id mtl_device; #endif + dispatch_source_t display_source; + CVDisplayLinkRef display_link; } _sapp_macos_t; #endif // _SAPP_MACOS @@ -3267,6 +3270,9 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void) { /* called from _sapp_discard_state() */ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { + CVDisplayLinkStop(_sapp.macos.display_link); + CVDisplayLinkRelease(_sapp.macos.display_link); + _sapp.macos.display_link = nil; // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(_sapp.macos.app_delegate); #if defined(SOKOL_METAL) @@ -3276,6 +3282,7 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { // FIXME: this is for a GLFW-style "explicit" render loop +/* _SOKOL_PRIVATE void _sapp_macos_process_events(void){ NSEvent* event; do { @@ -3283,13 +3290,13 @@ _SOKOL_PRIVATE void _sapp_macos_process_events(void){ untilDate: nil inMode: NSDefaultRunLoopMode dequeue: YES]; - if (event != NULL) { [NSApp sendEvent:event]; } } while (event != NULL); } +*/ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApplication sharedApplication]; @@ -3297,6 +3304,7 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApp run]; // FIXME: this is for a GLFW-style "explicit" render loop +/* while (!_sapp.quit_ordered) { _sapp_macos_process_events(); _sapp_frame(); @@ -3316,6 +3324,7 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { // [win->macos.window performClose:nil]; // } } +*/ } _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { @@ -3360,9 +3369,8 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.win_id = win->slot.id; [win->macos.view updateTrackingAreas]; win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; -// FIXME: this is for a GLFW-style "explicit" render loop -// win->macos.view.paused = true; -// win->macos.view.enableSetNeedsDisplay = false; + win->macos.view.paused = YES; + win->macos.view.enableSetNeedsDisplay = NO; win->macos.view.device = _sapp.macos.mtl_device; win->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; @@ -3675,8 +3683,45 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu CGImageRelease(cg_img); } +_SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( + CVDisplayLinkRef displayLink, + const CVTimeStamp* now, + const CVTimeStamp* outputTime, + CVOptionFlags flagsIn, + CVOptionFlags* flagsOut, + void* displayLinkContext) +{ + _SOKOL_UNUSED(displayLink); + _SOKOL_UNUSED(now); + _SOKOL_UNUSED(outputTime); + _SOKOL_UNUSED(flagsIn); + _SOKOL_UNUSED(flagsOut); + dispatch_source_t source = (__bridge dispatch_source_t) displayLinkContext; + dispatch_source_merge_data(source, 1); + return kCVReturnSuccess; +} + @implementation _sapp_macos_app_delegate +- (void)drawFrame { + _sapp_frame(); + for (int i = 0; i < _sapp.window_pool.pool.size; i++) { + const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + #if defined(SOKOL_METAL) + [win->macos.view draw]; + #else + #error "FIXME: GL" + #endif + } + } + // FIXME FIXME FIXME + // if (_sapp.quit_requested || _sapp.quit_ordered) { + // [win->macos.window performClose:nil]; + // } +} + - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); @@ -3690,12 +3735,29 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu [NSApp activateIgnoringOtherApps:YES]; [NSEvent setMouseCoalescingEnabled:NO]; + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); _sapp_macos_update_dimensions(win); _sapp.valid = true; - [NSApp stop:nil]; + // setup display link + // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc + _sapp.macos.display_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_event_handler(_sapp.macos.display_source, ^(){ + @autoreleasepool { + [_sapp.macos.app_delegate drawFrame]; + } + }); + dispatch_resume(_sapp.macos.display_source); + + CVDisplayLinkCreateWithActiveCGDisplays(&_sapp.macos.display_link); + CVDisplayLinkSetOutputCallback(_sapp.macos.display_link, &_sapp_macos_displaylink_callback, (__bridge void*)_sapp.macos.display_source); + CGDirectDisplayID disp_id = (CGDirectDisplayID) [NSScreen.mainScreen.deviceDescription[@"NSScreenNumber"] unsignedIntegerValue]; + CVDisplayLinkSetCurrentCGDisplay(_sapp.macos.display_link, disp_id); + CVDisplayLinkStart(_sapp.macos.display_link); + +// [NSApp stop:nil]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { From e089f5175265177d6ffad5d72bddbb0575ea6fd1 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 27 Apr 2021 20:30:07 +0200 Subject: [PATCH 17/49] sokol_app.h metal: add window rps and drawable callbacks --- sokol_app.h | 72 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 2abe7b176..92733e7bc 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1436,8 +1436,10 @@ SOKOL_APP_API_DECL bool sapp_isvalid(void); SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); /* close a window */ SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); -/* FIXME set the current 'window context' */ +/* set the current 'window context' */ SOKOL_APP_API_DECL void sapp_use_window(sapp_window window); +/* get the main window */ +SOKOL_APP_API_DECL sapp_window sapp_main_window(void); /* returns the current framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_width(void); /* same as sapp_width(), but returns float */ @@ -1512,10 +1514,14 @@ SOKOL_APP_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_req /* Metal: get bridged pointer to Metal device object */ SOKOL_APP_API_DECL const void* sapp_metal_get_device(void); -/* Metal: get bridged pointer to this frame's renderpass descriptor */ +/* Metal: get bridged pointer to the main window's renderpass descriptor for this frame */ SOKOL_APP_API_DECL const void* sapp_metal_get_renderpass_descriptor(void); -/* Metal: get bridged pointer to current drawable */ +/* Metal: get bridged pointer to a window's renderpass descriptor for this frame */ +SOKOL_APP_API_DECL const void* sapp_metal_get_window_renderpass_descriptor(sapp_window window); +/* Metal: get bridged pointer to the main window's current drawable */ SOKOL_APP_API_DECL const void* sapp_metal_get_drawable(void); +/* Metal: get bridged pointer to a window's current drawable */ +SOKOL_APP_API_DECL const void* sapp_metal_get_window_drawable(sapp_window window); /* macOS: get bridged pointer to macOS NSWindow */ SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); /* iOS: get bridged pointer to iOS UIWindow */ @@ -11199,6 +11205,10 @@ SOKOL_API_IMPL void sapp_use_window(sapp_window window) { _sapp.cur_window_id = window.id; } +SOKOL_API_IMPL sapp_window sapp_main_window(void) { + return _sapp_make_window_id(_sapp.main_window_id); +} + SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { return _sapp.desc; } @@ -11542,40 +11552,56 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { #endif } -SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { +SOKOL_API_IMPL const void* sapp_metal_get_window_renderpass_descriptor(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [win->macos.view currentRenderPassDescriptor]; - #else - const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; - #endif - SOKOL_ASSERT(obj); - return obj; + const _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + #if defined(_SAPP_MACOS) + const void* obj = (__bridge const void*) [win->macos.view currentRenderPassDescriptor]; + #else + const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; + #endif + SOKOL_ASSERT(obj); + return obj; + } + else { + return 0; + } #else return 0; #endif } -SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { +SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { + return sapp_metal_get_window_renderpass_descriptor(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_metal_get_window_drawable(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); #if defined(SOKOL_METAL) - #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [win->macos.view currentDrawable]; - #else - const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; - #endif - SOKOL_ASSERT(obj); - return obj; + const _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + #if defined(_SAPP_MACOS) + const void* obj = (__bridge const void*) [win->macos.view currentDrawable]; + #else + const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; + #endif + SOKOL_ASSERT(obj); + return obj; + } + else { + return 0; + } #else return 0; #endif } +SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { + return sapp_metal_get_window_drawable(sapp_main_window()); +} + SOKOL_API_IMPL const void* sapp_macos_get_window(void) { SOKOL_ASSERT(_sapp.valid); const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); From abf6d31366b7bbec82fc7fef29d90ee4787c44aa Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 27 Apr 2021 20:31:54 +0200 Subject: [PATCH 18/49] sokol_gfx.h: sg_commit loops through all active contexts --- sokol_gfx.h | 160 ++++++++++++++++++++++------------------------------ 1 file changed, 69 insertions(+), 91 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index 377f301fb..cf9014df5 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -3705,9 +3705,17 @@ typedef _sg_pass_attachment_common_t _sg_pass_attachment_t; typedef struct { _sg_slot_t slot; struct { + const void*(*renderpass_descriptor_cb)(void); + const void*(*renderpass_descriptor_userdata_cb)(void*); + const void*(*drawable_cb)(void); + const void*(*drawable_userdata_cb)(void*); + void* user_data; dispatch_semaphore_t sem; id cmd_queue; + id cmd_buffer; uint32_t cur_ub_index; + int cur_ub_offset; + uint8_t* cur_ub_base_ptr; id uniform_buffers[SG_NUM_INFLIGHT_FRAMES]; } mtl; } _sg_mtl_context_t; @@ -3731,14 +3739,7 @@ typedef struct { typedef struct { bool valid; - const void*(*renderpass_descriptor_cb)(void); - const void*(*renderpass_descriptor_userdata_cb)(void*); - const void*(*drawable_cb)(void); - const void*(*drawable_userdata_cb)(void*); - void* user_data; int ub_size; - int cur_ub_offset; - uint8_t* cur_ub_base_ptr; bool in_pass; bool pass_valid; int cur_width; @@ -3747,7 +3748,6 @@ typedef struct { _sg_sampler_cache_t sampler_cache; _sg_mtl_idpool_t idpool; id device; - id cmd_buffer; id cmd_encoder; } _sg_mtl_backend_t; @@ -4039,9 +4039,7 @@ typedef enum { typedef struct { bool valid; sg_desc desc; // original desc with default values patched in - uint64_t context_mask; // one bit for each existing context - uint64_t commit_mask; // each sg_commit() per context sets a bit here - uint32_t frame_index; // bumped at "end of frame" when (context_mask == commit_mask) + uint32_t frame_index; sg_context default_context; sg_context active_context; sg_pass cur_pass; @@ -9977,11 +9975,6 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _sg_mtl_init_sampler_cache(desc); _sg_mtl_clear_state_cache(); _sg.mtl.valid = true; - _sg.mtl.renderpass_descriptor_cb = desc->context.metal.renderpass_descriptor_cb; - _sg.mtl.renderpass_descriptor_userdata_cb = desc->context.metal.renderpass_descriptor_userdata_cb; - _sg.mtl.drawable_cb = desc->context.metal.drawable_cb; - _sg.mtl.drawable_userdata_cb = desc->context.metal.drawable_userdata_cb; - _sg.mtl.user_data = desc->context.metal.user_data; _sg.mtl.ub_size = desc->uniform_buffer_size; _sg.mtl.device = (__bridge id) desc->context.metal.device; _sg_mtl_init_caps(); @@ -9996,7 +9989,6 @@ _SOKOL_PRIVATE void _sg_mtl_discard_backend(void) { _SG_OBJC_RELEASE(_sg.mtl.device); /* NOTE: MTLCommandBuffer and MTLRenderCommandEncoder are auto-released */ - _sg.mtl.cmd_buffer = nil; _sg.mtl.cmd_encoder = nil; } @@ -10025,10 +10017,15 @@ _SOKOL_PRIVATE void _sg_mtl_reset_state_cache(_sg_context_t* ctx) { } } -_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { +_SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx, const sg_context_desc* desc) { SOKOL_ASSERT(ctx); ctx->mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); ctx->mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; + ctx->mtl.renderpass_descriptor_cb = desc->metal.renderpass_descriptor_cb; + ctx->mtl.renderpass_descriptor_userdata_cb = desc->metal.renderpass_descriptor_userdata_cb; + ctx->mtl.drawable_cb = desc->metal.drawable_cb; + ctx->mtl.drawable_userdata_cb = desc->metal.drawable_userdata_cb; + ctx->mtl.user_data = desc->metal.user_data; MTLResourceOptions res_opts = MTLResourceCPUCacheModeWriteCombined; #if defined(_SG_TARGET_MACOS) res_opts |= MTLResourceStorageModeManaged; @@ -10044,6 +10041,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_context(_sg_context_t* ctx) { _SOKOL_PRIVATE void _sg_mtl_destroy_context(_sg_context_t* ctx) { SOKOL_ASSERT(ctx); + SOKOL_ASSERT(ctx->mtl.cmd_buffer == nil); // wait for the last frame to finish // FIXME: does this loop actually make any sense??? for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { @@ -10571,19 +10569,19 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con SOKOL_ASSERT(!_sg.mtl.in_pass); SOKOL_ASSERT(ctx->mtl.cmd_queue); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.mtl.renderpass_descriptor_cb || _sg.mtl.renderpass_descriptor_userdata_cb); + SOKOL_ASSERT(ctx->mtl.renderpass_descriptor_cb || ctx->mtl.renderpass_descriptor_userdata_cb); _sg.mtl.in_pass = true; _sg.mtl.cur_width = w; _sg.mtl.cur_height = h; _sg_mtl_clear_state_cache(); /* if this is the first pass in the frame, create a command buffer */ - if (nil == _sg.mtl.cmd_buffer) { + if (nil == ctx->mtl.cmd_buffer) { /* block until the oldest frame in flight has finished */ dispatch_semaphore_wait(ctx->mtl.sem, DISPATCH_TIME_FOREVER); - _sg.mtl.cmd_buffer = [ctx->mtl.cmd_queue commandBufferWithUnretainedReferences]; + ctx->mtl.cmd_buffer = [ctx->mtl.cmd_queue commandBufferWithUnretainedReferences]; __block dispatch_semaphore_t block_sem = ctx->mtl.sem; - [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { + [ctx->mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { // NOTE: this code is called on a different thread! _SOKOL_UNUSED(cmd_buffer); dispatch_semaphore_signal(block_sem); @@ -10591,8 +10589,8 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con } /* if this is first pass in frame, get uniform buffer base pointer */ - if (0 == _sg.mtl.cur_ub_base_ptr) { - _sg.mtl.cur_ub_base_ptr = (uint8_t*)[ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] contents]; + if (0 == ctx->mtl.cur_ub_base_ptr) { + ctx->mtl.cur_ub_base_ptr = (uint8_t*)[ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] contents]; } /* initialize a render pass descriptor */ @@ -10603,11 +10601,11 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con } else { /* default render pass, call user-provided callback to provide render pass descriptor */ - if (_sg.mtl.renderpass_descriptor_cb) { - pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_cb(); + if (ctx->mtl.renderpass_descriptor_cb) { + pass_desc = (__bridge MTLRenderPassDescriptor*) ctx->mtl.renderpass_descriptor_cb(); } else { - pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_userdata_cb(_sg.mtl.user_data); + pass_desc = (__bridge MTLRenderPassDescriptor*) ctx->mtl.renderpass_descriptor_userdata_cb(ctx->mtl.user_data); } } @@ -10694,7 +10692,7 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, con } /* create a render command encoder, this might return nil if window is minimized */ - _sg.mtl.cmd_encoder = [_sg.mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc]; + _sg.mtl.cmd_encoder = [ctx->mtl.cmd_buffer renderCommandEncoderWithDescriptor:pass_desc]; if (nil == _sg.mtl.cmd_encoder) { _sg.mtl.pass_valid = false; return; @@ -10719,27 +10717,27 @@ _SOKOL_PRIVATE void _sg_mtl_end_pass(_sg_context_t* ctx) { _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { SOKOL_ASSERT(!_sg.mtl.in_pass); SOKOL_ASSERT(!_sg.mtl.pass_valid); - SOKOL_ASSERT(_sg.mtl.drawable_cb || _sg.mtl.drawable_userdata_cb); + SOKOL_ASSERT(ctx->mtl.drawable_cb || ctx->mtl.drawable_userdata_cb); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(nil != _sg.mtl.cmd_buffer); + SOKOL_ASSERT(nil != ctx->mtl.cmd_buffer); _SOKOL_UNUSED(ctx); #if defined(_SG_TARGET_MACOS) - [ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] didModifyRange:NSMakeRange(0, (NSUInteger)_sg.mtl.cur_ub_offset)]; + [ctx->mtl.uniform_buffers[ctx->mtl.cur_ub_index] didModifyRange:NSMakeRange(0, (NSUInteger)ctx->mtl.cur_ub_offset)]; #endif /* present, commit and signal semaphore when done */ id cur_drawable = nil; - if (_sg.mtl.drawable_cb) { - cur_drawable = (__bridge id) _sg.mtl.drawable_cb(); + if (ctx->mtl.drawable_cb) { + cur_drawable = (__bridge id) ctx->mtl.drawable_cb(); } else { - cur_drawable = (__bridge id) _sg.mtl.drawable_userdata_cb(_sg.mtl.user_data); + cur_drawable = (__bridge id) ctx->mtl.drawable_userdata_cb(ctx->mtl.user_data); } if (nil != cur_drawable) { - [_sg.mtl.cmd_buffer presentDrawable:cur_drawable]; + [ctx->mtl.cmd_buffer presentDrawable:cur_drawable]; } - [_sg.mtl.cmd_buffer commit]; + [ctx->mtl.cmd_buffer commit]; /* garbage-collect resources pending for release */ _sg_mtl_garbage_collect(_sg.frame_index); @@ -10748,10 +10746,10 @@ _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { if (++ctx->mtl.cur_ub_index >= SG_NUM_INFLIGHT_FRAMES) { ctx->mtl.cur_ub_index = 0; } - _sg.mtl.cur_ub_offset = 0; - _sg.mtl.cur_ub_base_ptr = 0; + ctx->mtl.cur_ub_offset = 0; + ctx->mtl.cur_ub_base_ptr = 0; /* NOTE: MTLCommandBuffer is autoreleased */ - _sg.mtl.cmd_buffer = nil; + ctx->mtl.cmd_buffer = nil; } _SOKOL_PRIVATE void _sg_mtl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) { @@ -10893,14 +10891,14 @@ _SOKOL_PRIVATE void _sg_mtl_apply_bindings( } } -_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { +_SOKOL_PRIVATE void _sg_mtl_apply_uniforms(_sg_context_t* ctx, sg_shader_stage stage_index, int ub_index, const sg_range* data) { SOKOL_ASSERT(_sg.mtl.in_pass); if (!_sg.mtl.pass_valid) { return; } SOKOL_ASSERT(nil != _sg.mtl.cmd_encoder); - SOKOL_ASSERT(((size_t)_sg.mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); - SOKOL_ASSERT((_sg.mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); + SOKOL_ASSERT(((size_t)ctx->mtl.cur_ub_offset + data->size) <= (size_t)_sg.mtl.ub_size); + SOKOL_ASSERT((ctx->mtl.cur_ub_offset & (_SG_MTL_UB_ALIGN-1)) == 0); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline && _sg.mtl.state_cache.cur_pipeline->shader); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->slot.id == _sg.mtl.state_cache.cur_pipeline_id.id); SOKOL_ASSERT(_sg.mtl.state_cache.cur_pipeline->shader->slot.id == _sg.mtl.state_cache.cur_pipeline->cmn.shader_id.id); @@ -10908,15 +10906,15 @@ _SOKOL_PRIVATE void _sg_mtl_apply_uniforms(sg_shader_stage stage_index, int ub_i SOKOL_ASSERT(data->size <= _sg.mtl.state_cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size); /* copy to global uniform buffer, record offset into cmd encoder, and advance offset */ - uint8_t* dst = &_sg.mtl.cur_ub_base_ptr[_sg.mtl.cur_ub_offset]; + uint8_t* dst = &ctx->mtl.cur_ub_base_ptr[ctx->mtl.cur_ub_offset]; memcpy(dst, data->ptr, data->size); if (stage_index == SG_SHADERSTAGE_VS) { - [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; + [_sg.mtl.cmd_encoder setVertexBufferOffset:(NSUInteger)ctx->mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; } else { - [_sg.mtl.cmd_encoder setFragmentBufferOffset:(NSUInteger)_sg.mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; + [_sg.mtl.cmd_encoder setFragmentBufferOffset:(NSUInteger)ctx->mtl.cur_ub_offset atIndex:(NSUInteger)ub_index]; } - _sg.mtl.cur_ub_offset = _sg_roundup(_sg.mtl.cur_ub_offset + (int)data->size, _SG_MTL_UB_ALIGN); + ctx->mtl.cur_ub_offset = _sg_roundup(ctx->mtl.cur_ub_offset + (int)data->size, _SG_MTL_UB_ALIGN); } _SOKOL_PRIVATE void _sg_mtl_draw(int base_element, int num_elements, int num_instances) { @@ -12772,17 +12770,17 @@ static inline void _sg_activate_context(_sg_context_t* ctx) { #endif } -static inline sg_resource_state _sg_create_context(_sg_context_t* ctx) { +static inline sg_resource_state _sg_create_context(_sg_context_t* ctx, const sg_context_desc* desc) { #if defined(_SOKOL_ANY_GL) - return _sg_gl_create_context(ctx); + return _sg_gl_create_context(ctx, desc); #elif defined(SOKOL_METAL) - return _sg_mtl_create_context(ctx); + return _sg_mtl_create_context(ctx, desc); #elif defined(SOKOL_D3D11) - return _sg_d3d11_create_context(ctx); + return _sg_d3d11_create_context(ctx, desc); #elif defined(SOKOL_WGPU) - return _sg_wgpu_create_context(ctx); + return _sg_wgpu_create_context(ctx, desc); #elif defined(SOKOL_DUMMY_BACKEND) - return _sg_dummy_create_context(ctx); + return _sg_dummy_create_context(ctx, desc); #else #error("INVALID BACKEND"); #endif @@ -13098,17 +13096,17 @@ static inline void _sg_apply_bindings( #endif } -static inline void _sg_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { +static inline void _sg_apply_uniforms(_sg_context_t* ctx, sg_shader_stage stage_index, int ub_index, const sg_range* data) { #if defined(_SOKOL_ANY_GL) - _sg_gl_apply_uniforms(stage_index, ub_index, data); + _sg_gl_apply_uniforms(ctx, stage_index, ub_index, data); #elif defined(SOKOL_METAL) - _sg_mtl_apply_uniforms(stage_index, ub_index, data); + _sg_mtl_apply_uniforms(ctx, stage_index, ub_index, data); #elif defined(SOKOL_D3D11) - _sg_d3d11_apply_uniforms(stage_index, ub_index, data); + _sg_d3d11_apply_uniforms(ctx, stage_index, ub_index, data); #elif defined(SOKOL_WGPU) - _sg_wgpu_apply_uniforms(stage_index, ub_index, data); + _sg_wgpu_apply_uniforms(ctx, stage_index, ub_index, data); #elif defined(SOKOL_DUMMY_BACKEND) - _sg_dummy_apply_uniforms(stage_index, ub_index, data); + _sg_dummy_apply_uniforms(ctx, stage_index, ub_index, data); #else #error("INVALID BACKEND"); #endif @@ -13520,12 +13518,6 @@ _SOKOL_PRIVATE _sg_context_t* _sg_default_context(void) { return ctx; } -_SOKOL_PRIVATE uint64_t _sg_context_bitmask(uint32_t ctx_id) { - int index = _sg_slot_index(ctx_id) - 1; - SOKOL_ASSERT((index >= 0) && (index < SG_MAX_CONTEXTS)); - return (1ULL << index); -} - _SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { /* this is a bit dumb since it loops over all pool slots to find the occupied slots, on the other hand it is only ever @@ -14828,11 +14820,8 @@ SOKOL_API_IMPL sg_context sg_make_context(const sg_context_desc* desc) { if (_SG_INVALID_SLOT_INDEX != slot_index) { res.id = _sg_slot_alloc(&_sg.pools.context_pool, &_sg.pools.contexts[slot_index].slot, slot_index); _sg_context_t* ctx = _sg_context_at(&_sg.pools, res.id); - ctx->slot.state = _sg_create_context(ctx); + ctx->slot.state = _sg_create_context(ctx, desc); SOKOL_ASSERT(ctx->slot.state == SG_RESOURCESTATE_VALID); - const uint64_t ctx_mask = _sg_context_bitmask(res.id); - SOKOL_ASSERT(0 == (_sg.context_mask & ctx_mask)); - _sg.context_mask |= ctx_mask; } else { /* pool is exhausted */ @@ -14843,9 +14832,6 @@ SOKOL_API_IMPL sg_context sg_make_context(const sg_context_desc* desc) { SOKOL_API_IMPL void sg_destroy_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); - const uint64_t ctx_mask = _sg_context_bitmask(ctx_id.id); - SOKOL_ASSERT(ctx_mask == (_sg.context_mask & ctx_mask)); - _sg.context_mask &= ~ctx_mask; _sg_destroy_all_resources(&_sg.pools, ctx_id.id); if (ctx_id.id == _sg.active_context.id) { _sg.active_context.id = SG_INVALID_ID; @@ -15417,7 +15403,7 @@ SOKOL_API_IMPL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const if (!_sg.next_draw_valid) { _SG_TRACE_NOARGS(err_draw_invalid); } - _sg_apply_uniforms(stage, ub_index, data); + _sg_apply_uniforms(_sg_active_context(), stage, ub_index, data); _SG_TRACE_ARGS(apply_uniforms, stage, ub_index, data); } @@ -15469,26 +15455,18 @@ SOKOL_API_IMPL void sg_end_pass(void) { SOKOL_API_IMPL void sg_commit(void) { SOKOL_ASSERT(_sg.valid); - /* FIXME: add a proper error log message here, if the context bit - is already set, this either means that sg_commit() was called twice - in the same frame and same context, or that not all contexts - had been rendered to in the last frame. - */ - const uint64_t ctx_mask = _sg_context_bitmask(_sg.active_context.id); - -// FIXME: with the "automatic" MTKView timing in sokol_app.h, the draw -// callbacks are not strictly called round-robin, which would cause -// the following assert to trigger -// SOKOL_ASSERT(0 == (_sg.commit_mask & ctx_mask)); - SOKOL_ASSERT(ctx_mask == (_sg.context_mask & ctx_mask)); - _sg.commit_mask |= ctx_mask; - _sg_commit(_sg_active_context()); - _SG_TRACE_NOARGS(commit); - // once all context's have been rendered, it's "safe" to advance the frame - if (_sg.commit_mask == _sg.context_mask) { - _sg.frame_index++; - _sg.commit_mask = 0; + + // do per-context commit actions and bump frame index + for (int i = 1; i < _sg.pools.context_pool.size; i++) { + if (_sg.pools.contexts[i].slot.id != SG_INVALID_ID) { + const sg_resource_state state = _sg.pools.contexts[i].slot.state; + if (state == SG_RESOURCESTATE_VALID) { + _sg_commit(&_sg.pools.contexts[i]); + } + } } + _sg.frame_index++; + _SG_TRACE_NOARGS(commit); } SOKOL_API_IMPL void sg_reset_state_cache(void) { From 852fbb904921534cea92c8ae4da969a255f28ef1 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 27 Apr 2021 20:32:16 +0200 Subject: [PATCH 19/49] sokol_glue.h: helper function to fill per-window sg_context_desc --- sokol_glue.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sokol_glue.h b/sokol_glue.h index 74ecb7c32..5eae6ca1e 100644 --- a/sokol_glue.h +++ b/sokol_glue.h @@ -95,6 +95,7 @@ extern "C" { #if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED) SOKOL_GLUE_API_DECL sg_context_desc sapp_sgcontext(void); +SOKOL_GLUE_API_DECL sg_context_desc sapp_window_sgcontext(sapp_window win); #endif #ifdef __cplusplus @@ -111,6 +112,16 @@ SOKOL_GLUE_API_DECL sg_context_desc sapp_sgcontext(void); #define SOKOL_API_IMPL #endif +static const void* _sglue_metal_get_renderpass_descriptor(void* user_data) { + sapp_window win = { (uint32_t) user_data }; + return sapp_metal_get_window_renderpass_descriptor(win); +} + +static const void* _sglue_metal_get_drawable(void* user_data) { + sapp_window win = { (uint32_t) user_data }; + return sapp_metal_get_window_drawable(win); +} + #if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED) SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) { sg_context_desc desc; @@ -132,6 +143,28 @@ SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) { desc.wgpu.depth_stencil_view_cb = sapp_wgpu_get_depth_stencil_view; return desc; } + +SOKOL_API_IMPL sg_context_desc sapp_window_sgcontext(sapp_window window) { + sg_context_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.color_format = (sg_pixel_format) sapp_color_format(); + desc.depth_format = (sg_pixel_format) sapp_depth_format(); + desc.sample_count = sapp_sample_count(); + desc.gl.force_gles2 = sapp_gles2(); + desc.metal.device = sapp_metal_get_device(); + desc.metal.renderpass_descriptor_userdata_cb = _sglue_metal_get_renderpass_descriptor; + desc.metal.drawable_userdata_cb = _sglue_metal_get_drawable; + desc.metal.user_data = (void*)(uintptr_t)window.id; + desc.d3d11.device = sapp_d3d11_get_device(); + desc.d3d11.device_context = sapp_d3d11_get_device_context(); + desc.d3d11.render_target_view_cb = sapp_d3d11_get_render_target_view; + desc.d3d11.depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view; + desc.wgpu.device = sapp_wgpu_get_device(); + desc.wgpu.render_view_cb = sapp_wgpu_get_render_view; + desc.wgpu.resolve_view_cb = sapp_wgpu_get_resolve_view; + desc.wgpu.depth_stencil_view_cb = sapp_wgpu_get_depth_stencil_view; + return desc; +} #endif #endif /* SOKOL_GLUE_IMPL */ From e66df1096c04d8f267e40392d49d5a0366472b38 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 28 Apr 2021 19:46:03 +0200 Subject: [PATCH 20/49] sokol_app.h: single-window vs multi-window APIs --- sokol_app.h | 531 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 342 insertions(+), 189 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 92733e7bc..796353ff0 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1430,78 +1430,112 @@ typedef struct sapp_html5_fetch_request { /* user-provided functions */ extern sapp_desc sokol_main(int argc, char* argv[]); +/* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ +SOKOL_APP_API_DECL void sapp_run(const sapp_desc* desc); /* returns true after sokol-app has been initialized */ SOKOL_APP_API_DECL bool sapp_isvalid(void); -/* open a new window */ -SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); -/* close a window */ -SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); -/* set the current 'window context' */ -SOKOL_APP_API_DECL void sapp_use_window(sapp_window window); -/* get the main window */ -SOKOL_APP_API_DECL sapp_window sapp_main_window(void); -/* returns the current framebuffer width in pixels */ +/* return a copy of the sapp_desc structure */ +SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void); +/* get the current frame counter (for comparison with sapp_event.frame_count) */ +SOKOL_APP_API_DECL uint64_t sapp_frame_count(void); +/* get main window's color pixel format */ +SOKOL_APP_API_DECL int sapp_color_format(void); +/* get main window's depth pixel format */ +SOKOL_APP_API_DECL int sapp_depth_format(void); +/* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ +SOKOL_APP_API_DECL void sapp_request_quit(void); +/* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */ +SOKOL_APP_API_DECL void sapp_cancel_quit(void); +/* initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) */ +SOKOL_APP_API_DECL void sapp_quit(void); +/* call from inside event callback to consume the current event (don't forward to platform) */ +SOKOL_APP_API_DECL void sapp_consume_event(void); +/* show or hide the mobile device onscreen keyboard */ +SOKOL_APP_API_DECL void sapp_show_keyboard(bool show); +/* return true if the mobile device onscreen keyboard is currently shown */ +SOKOL_APP_API_DECL bool sapp_keyboard_shown(void); +/* show or hide the mouse cursor */ +SOKOL_APP_API_DECL void sapp_show_mouse(bool show); +/* show or hide the mouse cursor */ +SOKOL_APP_API_DECL bool sapp_mouse_shown(); +/* enable/disable mouse-pointer-lock mode */ +SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock); +/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */ +SOKOL_APP_API_DECL bool sapp_mouse_locked(void); +/* set application/window icon (only on desktop platforms) */ +SOKOL_APP_API_DECL void sapp_set_icon(const sapp_icon_desc* icon_desc); + +/*=== single-window functions (return properties of the main window) =========*/ + +/* get framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_width(void); /* same as sapp_width(), but returns float */ SOKOL_APP_API_DECL float sapp_widthf(void); -/* returns the current framebuffer height in pixels */ +/* get framebuffer height in pixels */ SOKOL_APP_API_DECL int sapp_height(void); /* same as sapp_height(), but returns float */ SOKOL_APP_API_DECL float sapp_heightf(void); -/* get default framebuffer color pixel format */ -SOKOL_APP_API_DECL int sapp_color_format(void); -/* get default framebuffer depth pixel format */ -SOKOL_APP_API_DECL int sapp_depth_format(void); -/* get default framebuffer sample count */ +/* get main window's sample count */ SOKOL_APP_API_DECL int sapp_sample_count(void); /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ SOKOL_APP_API_DECL bool sapp_high_dpi(void); /* returns the dpi scaling factor (window pixels to framebuffer pixels) */ SOKOL_APP_API_DECL float sapp_dpi_scale(void); -/* show or hide the mobile device onscreen keyboard */ -SOKOL_APP_API_DECL void sapp_show_keyboard(bool show); -/* return true if the mobile device onscreen keyboard is currently shown */ -SOKOL_APP_API_DECL bool sapp_keyboard_shown(void); /* query fullscreen mode */ SOKOL_APP_API_DECL bool sapp_is_fullscreen(void); /* toggle fullscreen mode */ SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void); -/* show or hide the mouse cursor */ -SOKOL_APP_API_DECL void sapp_show_mouse(bool show); -/* show or hide the mouse cursor */ -SOKOL_APP_API_DECL bool sapp_mouse_shown(); -/* enable/disable mouse-pointer-lock mode */ -SOKOL_APP_API_DECL void sapp_lock_mouse(bool lock); -/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */ -SOKOL_APP_API_DECL bool sapp_mouse_locked(void); -/* return a copy of the sapp_desc structure */ -SOKOL_APP_API_DECL sapp_desc sapp_query_desc(void); -/* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */ -SOKOL_APP_API_DECL void sapp_request_quit(void); -/* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */ -SOKOL_APP_API_DECL void sapp_cancel_quit(void); -/* initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) */ -SOKOL_APP_API_DECL void sapp_quit(void); -/* call from inside event callback to consume the current event (don't forward to platform) */ -SOKOL_APP_API_DECL void sapp_consume_event(void); -/* get the current frame counter (for comparison with sapp_event.frame_count) */ -SOKOL_APP_API_DECL uint64_t sapp_frame_count(void); +/* set the main window title (only on desktop platforms) */ +SOKOL_APP_API_DECL void sapp_set_title(const char* str); + +/*=== multi-window functions =================================================*/ + +/* open a new window and return window handle */ +SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); +/* close a window */ +SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); +/* get the main window handle */ +SOKOL_APP_API_DECL sapp_window sapp_main_window(void); +/* start iterating over open windows */ +SOKOL_APP_API_DECL sapp_window sapp_first_window(void); +/* continue iterating over open windows, returns invalid handle when finished */ +SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); +/* test if a window handle is valid */ +SOKOL_APP_API_DECL bool sapp_valid_window(sapp_window window); +/* get window handle's slot index (>= 0 and < sapp_desc.window_pool_size, useful for associating data with windows) */ +SOKOL_APP_API_DECL int sapp_window_index(sapp_window window); +/* get window's framebuffer width in pixels */ +SOKOL_APP_API_DECL int sapp_window_width(sapp_window window); +/* same as sapp_window_width(), but returns float */ +SOKOL_APP_API_DECL float sapp_window_widthf(sapp_window window); +/* get window's framebuffer height in pixels */ +SOKOL_APP_API_DECL int sapp_window_height(sapp_window window); +/* same as sapp_window_height(), but returns float */ +SOKOL_APP_API_DECL float sapp_window_heightf(sapp_window window); +/* get a window's sample count */ +SOKOL_APP_API_DECL int sapp_window_sample_count(sapp_window window); +/* returns true when high_dpi was requested for a window, and actually running in a high-dpi scenario */ +SOKOL_APP_API_DECL bool sapp_window_high_dpi(sapp_window window); +/* returns a window's dpi scaling factor (window pixels to framebuffer pixels) */ +SOKOL_APP_API_DECL float sapp_window_dpi_scale(sapp_window window); +/* query if a window is currently in fullscreen mode */ +SOKOL_APP_API_DECL bool sapp_window_is_fullscreen(sapp_window window); +/* toggle a window to and from fullscreen mode */ +SOKOL_APP_API_DECL void sapp_window_toggle_fullscreen(sapp_window window); +/* set window's title (only on desktop platforms) */ +SOKOL_APP_API_DECL void sapp_window_set_title(sapp_window window, const char* str); + +// FIXME FIXME FIXME: are these per window or better global? + /* write string into clipboard */ SOKOL_APP_API_DECL void sapp_set_clipboard_string(const char* str); /* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */ SOKOL_APP_API_DECL const char* sapp_get_clipboard_string(void); -/* set the window title (only on desktop platforms) */ -SOKOL_APP_API_DECL void sapp_set_window_title(const char* str); -/* set the window icon (only on Windows and Linux) */ -SOKOL_APP_API_DECL void sapp_set_icon(const sapp_icon_desc* icon_desc); /* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED event) */ SOKOL_APP_API_DECL int sapp_get_num_dropped_files(void); /* gets the dropped file paths */ SOKOL_APP_API_DECL const char* sapp_get_dropped_file_path(int index); -/* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ -SOKOL_APP_API_DECL void sapp_run(const sapp_desc* desc); - /* GL: return true when GLES2 fallback is active (to detect fallback from GLES3) */ SOKOL_APP_API_DECL bool sapp_gles2(void); @@ -1523,9 +1557,9 @@ SOKOL_APP_API_DECL const void* sapp_metal_get_drawable(void); /* Metal: get bridged pointer to a window's current drawable */ SOKOL_APP_API_DECL const void* sapp_metal_get_window_drawable(sapp_window window); /* macOS: get bridged pointer to macOS NSWindow */ -SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); +SOKOL_APP_API_DECL const void* sapp_macos_get_nswindow(sapp_window window); /* iOS: get bridged pointer to iOS UIWindow */ -SOKOL_APP_API_DECL const void* sapp_ios_get_window(void); +SOKOL_APP_API_DECL const void* sapp_ios_get_uiwindow(void); /* D3D11: get pointer to ID3D11Device object */ SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); @@ -2374,7 +2408,6 @@ typedef struct { sapp_desc desc; _sapp_window_pool_t window_pool; uint32_t main_window_id; - uint32_t cur_window_id; bool valid; bool first_frame; bool init_called; @@ -3732,7 +3765,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _SOKOL_UNUSED(aNotification); _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); - _sapp.cur_window_id = _sapp.main_window_id; // FIXME: maybe the activation stuff here needs to be moved before // the makeKeyAndOrderFront call, see here: @@ -11149,6 +11181,93 @@ int main(int argc, char* argv[]) { #endif /* SOKOL_NO_ENTRY */ #endif /* _SAPP_LINUX */ +/*== single- vs multi-window helper functions ================================*/ + +_SOKOL_PRIVATE int _sapp_window_sample_count(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + return win ? win->desc.sample_count : 1; +} + +_SOKOL_PRIVATE int _sapp_window_width(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win && (win->framebuffer_width > 0)) { + return win->framebuffer_width; + } + else { + return 1; + } +} + +_SOKOL_PRIVATE int _sapp_window_height(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win && (win->framebuffer_height > 0)) { + return win->framebuffer_height; + } + else { + return 1; + } +} + +_SOKOL_PRIVATE bool _sapp_window_high_dpi(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->desc.high_dpi && (win->dpi_scale >= 1.5f); + } + else { + return false; + } +} + +_SOKOL_PRIVATE float _sapp_window_dpi_scale(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->dpi_scale; + } + else { + return 1.0f; + } +} + +_SOKOL_PRIVATE bool _sapp_window_is_fullscreen(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->fullscreen; + } + else { + return false; + } +} + +_SOKOL_PRIVATE void _sapp_window_toggle_fullscreen(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + #if defined(_SAPP_MACOS) + _sapp_macos_toggle_fullscreen(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_toggle_fullscreen(); + #elif defined(_SAPP_UWP) + _sapp_uwp_toggle_fullscreen(); + #elif defined(_SAPP_LINUX) + _sapp_x11_toggle_fullscreen(); + #endif + } +} + +SOKOL_API_IMPL void _sapp_window_set_title(uint32_t win_id, const char* title) { + SOKOL_ASSERT(title); + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + _sapp_strcpy(title, win->title, sizeof(win->title)); + #if defined(_SAPP_MACOS) + _sapp_macos_update_window_title(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_update_window_title(); + #elif defined(_SAPP_LINUX) + _sapp_x11_update_window_title(); + #endif + } +} + /*== PUBLIC API FUNCTIONS ====================================================*/ #if defined(SOKOL_NO_ENTRY) SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { @@ -11190,25 +11309,6 @@ SOKOL_API_IMPL bool sapp_isvalid(void) { return _sapp.valid; } -SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { - SOKOL_ASSERT(in_desc); - const sapp_window_desc desc = _sapp_window_desc_defaults(in_desc); - return _sapp_make_window_id(_sapp_create_window(&desc)); -} - -SOKOL_API_IMPL void sapp_close_window(sapp_window window) { - // FIXME -} - -SOKOL_API_IMPL void sapp_use_window(sapp_window window) { - SOKOL_ASSERT(SAPP_INVALID_ID != window.id); - _sapp.cur_window_id = window.id; -} - -SOKOL_API_IMPL sapp_window sapp_main_window(void) { - return _sapp_make_window_id(_sapp.main_window_id); -} - SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { return _sapp.desc; } @@ -11217,26 +11317,6 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) { return _sapp.frame_count; } -SOKOL_API_IMPL int sapp_width(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return (win->framebuffer_width > 0) ? win->framebuffer_width : 1; -} - -SOKOL_API_IMPL float sapp_widthf(void) { - return (float)sapp_width(); -} - -SOKOL_API_IMPL int sapp_height(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return (win->framebuffer_height > 0) ? win->framebuffer_height : 1; -} - -SOKOL_API_IMPL float sapp_heightf(void) { - return (float)sapp_height(); -} - SOKOL_API_IMPL int sapp_color_format(void) { #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) switch (_sapp.emsc.wgpu.render_format) { @@ -11259,26 +11339,20 @@ SOKOL_API_IMPL int sapp_depth_format(void) { return _SAPP_PIXELFORMAT_DEPTH_STENCIL; } -SOKOL_API_IMPL int sapp_sample_count(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return win->desc.sample_count; +SOKOL_API_IMPL void sapp_request_quit(void) { + _sapp.quit_requested = true; } -SOKOL_API_IMPL bool sapp_high_dpi(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return win->desc.high_dpi && (win->dpi_scale >= 1.5f); +SOKOL_API_IMPL void sapp_cancel_quit(void) { + _sapp.quit_requested = false; } -SOKOL_API_IMPL float sapp_dpi_scale(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return win->dpi_scale; +SOKOL_API_IMPL void sapp_quit(void) { + _sapp.quit_ordered = true; } -SOKOL_API_IMPL bool sapp_gles2(void) { - return _sapp.gles2_fallback; +SOKOL_API_IMPL void sapp_consume_event(void) { + _sapp.event_consumed = true; } SOKOL_API_IMPL void sapp_show_keyboard(bool show) { @@ -11297,29 +11371,10 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { return _sapp.onscreen_keyboard_shown; } -SOKOL_APP_API_DECL bool sapp_is_fullscreen(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - return win->fullscreen; -} - -SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void) { - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - #if defined(_SAPP_MACOS) - _sapp_macos_toggle_fullscreen(win); - #elif defined(_SAPP_WIN32) - _sapp_win32_toggle_fullscreen(); - #elif defined(_SAPP_UWP) - _sapp_uwp_toggle_fullscreen(); - #elif defined(_SAPP_LINUX) - _sapp_x11_toggle_fullscreen(); - #endif -} - /* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ SOKOL_API_IMPL void sapp_show_mouse(bool show) { - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + // FIXME: is this actually a per-window function?? + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); if (win->mouse.shown != show) { #if defined(_SAPP_MACOS) @@ -11336,13 +11391,15 @@ SOKOL_API_IMPL void sapp_show_mouse(bool show) { } SOKOL_API_IMPL bool sapp_mouse_shown(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + // FIXME: is this actually a per-window function?? + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); return win->mouse.shown; } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + // FIXME: is this actually a per-window function?? + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); #if defined(_SAPP_MACOS) _sapp_macos_lock_mouse(win, lock); @@ -11358,30 +11415,160 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + // FIXME: is this actually a per-window function?? + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); return win->mouse.locked; } -SOKOL_API_IMPL void sapp_request_quit(void) { - _sapp.quit_requested = true; +SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { + SOKOL_ASSERT(desc); + if (desc->sokol_default) { + if (0 == _sapp.default_icon_pixels) { + _sapp_setup_default_icon(); + } + SOKOL_ASSERT(0 != _sapp.default_icon_pixels); + desc = &_sapp.default_icon_desc; + } + const int num_images = _sapp_icon_num_images(desc); + if (num_images == 0) { + return; + } + SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); + if (!_sapp_validate_icon_desc(desc, num_images)) { + return; + } + #if defined(_SAPP_MACOS) + _sapp_macos_set_icon(desc, num_images); + #elif defined(_SAPP_WIN32) + _sapp_win32_set_icon(desc, num_images); + #elif defined(_SAPP_LINUX) + _sapp_x11_set_icon(desc, num_images); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_set_icon(desc, num_images); + #endif } -SOKOL_API_IMPL void sapp_cancel_quit(void) { - _sapp.quit_requested = false; +SOKOL_API_IMPL int sapp_width(void) { + return _sapp_window_width(_sapp.main_window_id); } -SOKOL_API_IMPL void sapp_quit(void) { - _sapp.quit_ordered = true; +SOKOL_API_IMPL float sapp_widthf(void) { + return (float)_sapp_window_width(_sapp.main_window_id); } -SOKOL_API_IMPL void sapp_consume_event(void) { - _sapp.event_consumed = true; +SOKOL_API_IMPL int sapp_height(void) { + return _sapp_window_height(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_heightf(void) { + return (float)_sapp_window_height(_sapp.main_window_id); +} + +SOKOL_API_IMPL int sapp_sample_count(void) { + return _sapp_window_sample_count(_sapp.main_window_id); +} + +SOKOL_API_IMPL bool sapp_high_dpi(void) { + return _sapp_window_high_dpi(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_dpi_scale(void) { + return _sapp_window_dpi_scale(_sapp.main_window_id); +} + +SOKOL_API_IMPL bool sapp_is_fullscreen(void) { + return _sapp_window_is_fullscreen(_sapp.main_window_id); +} + +SOKOL_API_IMPL void sapp_toggle_fullscreen(void) { + _sapp_window_toggle_fullscreen(_sapp.main_window_id); +} + +SOKOL_API_IMPL void sapp_set_title(const char* title) { + _sapp_window_set_title(_sapp.main_window_id, title); +} + +SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { + SOKOL_ASSERT(in_desc); + const sapp_window_desc desc = _sapp_window_desc_defaults(in_desc); + return _sapp_make_window_id(_sapp_create_window(&desc)); +} + +SOKOL_API_IMPL void sapp_close_window(sapp_window window) { + // FIXME FIXME FIXME +} + +SOKOL_API_IMPL sapp_window sapp_main_window(void) { + return _sapp_make_window_id(_sapp.main_window_id); +} + +SOKOL_API_IMPL sapp_window sapp_first_window(void) { + SOKOL_ASSERT(false && "FIXME FIXME FIXME"); + return _sapp_make_window_id(SAPP_INVALID_ID); +} + +SOKOL_API_IMPL sapp_window sapp_next_window(sapp_window window) { + SOKOL_ASSERT(false && "FIXME FIXME FIXME"); + return _sapp_make_window_id(SAPP_INVALID_ID); +} + +SOKOL_API_IMPL bool sapp_valid_window(sapp_window window) { + return 0 != _sapp_lookup_window(window.id); +} + +SOKOL_API_IMPL int sapp_window_index(sapp_window window) { + SOKOL_ASSERT(SAPP_INVALID_ID != window.id); + int slot_index = _sapp_slot_index(window.id); + SOKOL_ASSERT(slot_index > 0); + slot_index -= 1; + SOKOL_ASSERT(slot_index < _sapp.desc.window_pool_size); + return slot_index; +} + +SOKOL_API_IMPL int sapp_window_width(sapp_window window) { + return _sapp_window_width(window.id); +} + +SOKOL_API_IMPL float sapp_window_widthf(sapp_window window) { + return (float)_sapp_window_width(window.id); +} + +SOKOL_API_IMPL int sapp_window_height(sapp_window window) { + return _sapp_window_height(window.id); +} + +SOKOL_API_IMPL float sapp_window_heightf(sapp_window window) { + return (float)_sapp_window_height(window.id); +} + +SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window) { + return _sapp_window_sample_count(window.id); +} + +SOKOL_API_IMPL bool sapp_window_high_dpi(sapp_window window) { + return _sapp_window_high_dpi(window.id); +} + +SOKOL_API_IMPL float sapp_window_dpi_scale(sapp_window window) { + return _sapp_window_dpi_scale(window.id); +} + +SOKOL_API_IMPL bool sapp_window_is_fullscreen(sapp_window window) { + return _sapp_window_is_fullscreen(window.id); +} + +SOKOL_API_IMPL void sapp_window_toggle_fullscreen(sapp_window window) { + _sapp_window_toggle_fullscreen(window.id); +} + +SOKOL_API_IMPL void sapp_window_set_title(sapp_window window, const char* title) { + _sapp_window_set_title(window.id, title); } /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->clipboard.enabled); if (!win->clipboard.enabled) { @@ -11401,7 +11588,7 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->clipboard.enabled); if (!win->clipboard.enabled) { @@ -11419,57 +11606,15 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { #endif } -SOKOL_API_IMPL void sapp_set_window_title(const char* title) { - SOKOL_ASSERT(title); - _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); - _sapp_strcpy(title, win->title, sizeof(win->title)); - #if defined(_SAPP_MACOS) - _sapp_macos_update_window_title(win); - #elif defined(_SAPP_WIN32) - _sapp_win32_update_window_title(); - #elif defined(_SAPP_LINUX) - _sapp_x11_update_window_title(); - #endif -} - -SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { - SOKOL_ASSERT(desc); - if (desc->sokol_default) { - if (0 == _sapp.default_icon_pixels) { - _sapp_setup_default_icon(); - } - SOKOL_ASSERT(0 != _sapp.default_icon_pixels); - desc = &_sapp.default_icon_desc; - } - const int num_images = _sapp_icon_num_images(desc); - if (num_images == 0) { - return; - } - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - if (!_sapp_validate_icon_desc(desc, num_images)) { - return; - } - #if defined(_SAPP_MACOS) - _sapp_macos_set_icon(desc, num_images); - #elif defined(_SAPP_WIN32) - _sapp_win32_set_icon(desc, num_images); - #elif defined(_SAPP_LINUX) - _sapp_x11_set_icon(desc, num_images); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_set_icon(desc, num_images); - #endif -} - SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); return win->drop.num_files; } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); SOKOL_ASSERT(win->drop.buffer); @@ -11482,8 +11627,12 @@ SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { return (const char*) _sapp_dropped_file_path_ptr(win, index); } +SOKOL_API_IMPL bool sapp_gles2(void) { + return _sapp.gles2_fallback; +} + SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); @@ -11499,7 +11648,7 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); + const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); SOKOL_ASSERT(request); @@ -11602,14 +11751,18 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { return sapp_metal_get_window_drawable(sapp_main_window()); } -SOKOL_API_IMPL const void* sapp_macos_get_window(void) { +SOKOL_API_IMPL const void* sapp_macos_get_nswindow(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.cur_window_id); - SOKOL_ASSERT(win); #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) win->macos.window; - SOKOL_ASSERT(obj); - return obj; + const _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + const void* obj = (__bridge const void*) win->macos.window; + SOKOL_ASSERT(obj); + return obj; + } + else { + return 0; + } #else return 0; #endif From 16cf91a1e4ecadf524341f157a30060a8bd95231 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 2 May 2021 17:37:50 +0200 Subject: [PATCH 21/49] sokol_app.h: start ditching MTKView, use CAMetalLayer directly --- sokol_app.h | 110 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 21 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 796353ff0..9c54b7401 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1870,7 +1870,10 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } @property uint32_t win_id; @end #if defined(SOKOL_METAL) - @interface _sapp_macos_view : MTKView + @interface _sapp_macos_metal_view : NSView + @property (nonatomic, readonly) CAMetalLayer *metal_layer; + @end + @interface _sapp_macos_view : _sapp_macos_metal_view @property uint32_t win_id; @end #elif defined(SOKOL_GLCORE33) @@ -1887,6 +1890,10 @@ typedef struct { NSTrackingArea* tracking_area; uint32_t flags_changed_store; uint8_t mouse_buttons; + #if defined(SOKOL_METAL) + MTLRenderPassDescriptor* renderpass_desc; + id current_drawable; + #endif } _sapp_macos_window_t; typedef struct { @@ -1894,7 +1901,7 @@ typedef struct { #if defined(SOKOL_METAL) id mtl_device; #endif - dispatch_source_t display_source; + dispatch_source_t dispatch_source; CVDisplayLinkRef display_link; } _sapp_macos_t; @@ -3311,6 +3318,7 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void) { _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { CVDisplayLinkStop(_sapp.macos.display_link); CVDisplayLinkRelease(_sapp.macos.display_link); + dispatch_source_cancel(_sapp.macos.dispatch_source); _sapp.macos.display_link = nil; // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(_sapp.macos.app_delegate); @@ -3404,9 +3412,13 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.delegate.win_id = win->slot.id; win->macos.window.delegate = win->macos.delegate; #if defined(SOKOL_METAL) - win->macos.view = [[_sapp_macos_view alloc] init]; + win->macos.view = [[_sapp_macos_view alloc] initWithFrame:window_rect]; win->macos.view.win_id = win->slot.id; + win->macos.view.metal_layer.device = _sapp.macos.mtl_device; + win->macos.view.metal_layer.pixelFormat = MTLPixelFormatBGRA8Unorm; + win->macos.view.metal_layer.maximumDrawableCount = 2; [win->macos.view updateTrackingAreas]; + /* win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; win->macos.view.paused = YES; win->macos.view.enableSetNeedsDisplay = NO; @@ -3415,9 +3427,13 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; win->macos.view.sampleCount = (NSUInteger) win->desc.sample_count; win->macos.view.autoResizeDrawable = false; + */ win->macos.window.contentView = win->macos.view; [win->macos.window makeFirstResponder:win->macos.view]; - win->macos.view.layer.magnificationFilter = kCAFilterNearest; + //win->macos.view.layer.magnificationFilter = kCAFilterNearest; + + win->macos.renderpass_desc = [MTLRenderPassDescriptor new]; + win->macos.renderpass_desc.colorAttachments[0].storeAction = MTLStoreActionStore; #elif defined(SOKOL_GLCORE33) NSOpenGLPixelFormatAttribute attrs[32]; int i = 0; @@ -3477,6 +3493,7 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { SOKOL_ASSERT(win); // NOTE: it's safe to call [release] on a nil object + _SAPP_OBJC_RELEASE(win->macos.renderpass_desc); _SAPP_OBJC_RELEASE(win->macos.tracking_area); _SAPP_OBJC_RELEASE(win->macos.delegate); _SAPP_OBJC_RELEASE(win->macos.view); @@ -3587,7 +3604,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { */ #if defined(SOKOL_METAL) CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; - win->macos.view.drawableSize = drawable_size; +// win->macos.view.drawableSize = drawable_size; #endif } @@ -3740,6 +3757,26 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( return kCVReturnSuccess; } +_SOKOL_PRIVATE const void* _sapp_macos_metal_renderpass_descriptor(_sapp_window_t* win) { + SOKOL_ASSERT(win); + SOKOL_ASSERT(nil == win->macos.current_drawable); +static uint32_t frame_count = 0; +__builtin_printf("%d: before nextDrawable %p\n", frame_count, win); + win->macos.current_drawable = [win->macos.view.metal_layer nextDrawable]; +__builtin_printf("%d: after nextDrawable %p\n", frame_count++, win); + win->macos.renderpass_desc.colorAttachments[0].texture = win->macos.current_drawable.texture; + return (__bridge const void*) win->macos.renderpass_desc; +} + +_SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { + SOKOL_ASSERT(win); + SOKOL_ASSERT(nil != win->macos.current_drawable); + const void* drawable = (__bridge const void*) win->macos.current_drawable; + // current_drawable is autoreleased at end of frame + win->macos.current_drawable = nil; + return drawable; +} + @implementation _sapp_macos_app_delegate - (void)drawFrame { @@ -3749,7 +3786,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { #if defined(SOKOL_METAL) - [win->macos.view draw]; + //[win->macos.view draw]; #else #error "FIXME: GL" #endif @@ -3781,16 +3818,16 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( // setup display link // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc - _sapp.macos.display_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); - dispatch_source_set_event_handler(_sapp.macos.display_source, ^(){ + _sapp.macos.dispatch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_event_handler(_sapp.macos.dispatch_source, ^(){ @autoreleasepool { [_sapp.macos.app_delegate drawFrame]; } }); - dispatch_resume(_sapp.macos.display_source); + dispatch_resume(_sapp.macos.dispatch_source); CVDisplayLinkCreateWithActiveCGDisplays(&_sapp.macos.display_link); - CVDisplayLinkSetOutputCallback(_sapp.macos.display_link, &_sapp_macos_displaylink_callback, (__bridge void*)_sapp.macos.display_source); + CVDisplayLinkSetOutputCallback(_sapp.macos.display_link, &_sapp_macos_displaylink_callback, (__bridge void*)_sapp.macos.dispatch_source); CGDirectDisplayID disp_id = (CGDirectDisplayID) [NSScreen.mainScreen.deviceDescription[@"NSScreenNumber"] unsignedIntegerValue]; CVDisplayLinkSetCurrentCGDisplay(_sapp.macos.display_link, disp_id); CVDisplayLinkStart(_sapp.macos.display_link); @@ -3810,7 +3847,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @end @implementation _sapp_macos_window_delegate -@synthesize win_id; +//@synthesize win_id; - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); @@ -3881,7 +3918,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @end @implementation _sapp_macos_window -@synthesize win_id; - (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style @@ -3938,8 +3974,44 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } @end +@implementation _sapp_macos_metal_view + +- (instancetype) initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.wantsLayer = YES; + self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; + _metal_layer = (CAMetalLayer*) self.layer; + self.layer.delegate = self; + } + return self; +} + +- (CALayer*)makeBackingLayer { + return [CAMetalLayer layer]; +} + +- (void)viewDidMoveToWindow { + // fixme: resize drawable +} + +- (void)viewDidChangeBackingProperties { + [super viewDidChangeBackingProperties]; +// [self resizeDrawable:self.window.screen.backingScaleFactor]; +} + +- (void)setFrameSize:(NSSize)size { + [super setFrameSize:size]; +// [self resizeDrawable:self.window.screen.backingScaleFactor]; +} + +- (void)setBoundsSize:(NSSize)size { + [super setBoundsSize:size]; +// [self resizeDrawable:self.window.screen.backingScaleFactor]; +} +@end + @implementation _sapp_macos_view -@synthesize win_id; #if defined(SOKOL_GLCORE33) /* NOTE: this is a hack/fix when the initial window size has been clipped by @@ -11704,15 +11776,13 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { SOKOL_API_IMPL const void* sapp_metal_get_window_renderpass_descriptor(sapp_window window) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) - const _sapp_window_t* win = _sapp_lookup_window(window.id); + _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [win->macos.view currentRenderPassDescriptor]; + return _sapp_macos_metal_renderpass_descriptor(win); #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; #endif - SOKOL_ASSERT(obj); - return obj; } else { return 0; @@ -11729,15 +11799,13 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_API_IMPL const void* sapp_metal_get_window_drawable(sapp_window window) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) - const _sapp_window_t* win = _sapp_lookup_window(window.id); + _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [win->macos.view currentDrawable]; + return _sapp_macos_metal_drawable(win); #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; #endif - SOKOL_ASSERT(obj); - return obj; } else { return 0; From 99d7d888799d436d0c088d249622f72b0a71c86c Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 3 May 2021 18:49:01 +0200 Subject: [PATCH 22/49] Revert "sokol_app.h: start ditching MTKView, use CAMetalLayer directly" This reverts commit 16cf91a1e4ecadf524341f157a30060a8bd95231. --- sokol_app.h | 110 ++++++++++------------------------------------------ 1 file changed, 21 insertions(+), 89 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 9c54b7401..796353ff0 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1870,10 +1870,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } @property uint32_t win_id; @end #if defined(SOKOL_METAL) - @interface _sapp_macos_metal_view : NSView - @property (nonatomic, readonly) CAMetalLayer *metal_layer; - @end - @interface _sapp_macos_view : _sapp_macos_metal_view + @interface _sapp_macos_view : MTKView @property uint32_t win_id; @end #elif defined(SOKOL_GLCORE33) @@ -1890,10 +1887,6 @@ typedef struct { NSTrackingArea* tracking_area; uint32_t flags_changed_store; uint8_t mouse_buttons; - #if defined(SOKOL_METAL) - MTLRenderPassDescriptor* renderpass_desc; - id current_drawable; - #endif } _sapp_macos_window_t; typedef struct { @@ -1901,7 +1894,7 @@ typedef struct { #if defined(SOKOL_METAL) id mtl_device; #endif - dispatch_source_t dispatch_source; + dispatch_source_t display_source; CVDisplayLinkRef display_link; } _sapp_macos_t; @@ -3318,7 +3311,6 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void) { _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { CVDisplayLinkStop(_sapp.macos.display_link); CVDisplayLinkRelease(_sapp.macos.display_link); - dispatch_source_cancel(_sapp.macos.dispatch_source); _sapp.macos.display_link = nil; // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(_sapp.macos.app_delegate); @@ -3412,13 +3404,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.delegate.win_id = win->slot.id; win->macos.window.delegate = win->macos.delegate; #if defined(SOKOL_METAL) - win->macos.view = [[_sapp_macos_view alloc] initWithFrame:window_rect]; + win->macos.view = [[_sapp_macos_view alloc] init]; win->macos.view.win_id = win->slot.id; - win->macos.view.metal_layer.device = _sapp.macos.mtl_device; - win->macos.view.metal_layer.pixelFormat = MTLPixelFormatBGRA8Unorm; - win->macos.view.metal_layer.maximumDrawableCount = 2; [win->macos.view updateTrackingAreas]; - /* win->macos.view.preferredFramesPerSecond = 60 / win->desc.swap_interval; win->macos.view.paused = YES; win->macos.view.enableSetNeedsDisplay = NO; @@ -3427,13 +3415,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; win->macos.view.sampleCount = (NSUInteger) win->desc.sample_count; win->macos.view.autoResizeDrawable = false; - */ win->macos.window.contentView = win->macos.view; [win->macos.window makeFirstResponder:win->macos.view]; - //win->macos.view.layer.magnificationFilter = kCAFilterNearest; - - win->macos.renderpass_desc = [MTLRenderPassDescriptor new]; - win->macos.renderpass_desc.colorAttachments[0].storeAction = MTLStoreActionStore; + win->macos.view.layer.magnificationFilter = kCAFilterNearest; #elif defined(SOKOL_GLCORE33) NSOpenGLPixelFormatAttribute attrs[32]; int i = 0; @@ -3493,7 +3477,6 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { SOKOL_ASSERT(win); // NOTE: it's safe to call [release] on a nil object - _SAPP_OBJC_RELEASE(win->macos.renderpass_desc); _SAPP_OBJC_RELEASE(win->macos.tracking_area); _SAPP_OBJC_RELEASE(win->macos.delegate); _SAPP_OBJC_RELEASE(win->macos.view); @@ -3604,7 +3587,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { */ #if defined(SOKOL_METAL) CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; -// win->macos.view.drawableSize = drawable_size; + win->macos.view.drawableSize = drawable_size; #endif } @@ -3757,26 +3740,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( return kCVReturnSuccess; } -_SOKOL_PRIVATE const void* _sapp_macos_metal_renderpass_descriptor(_sapp_window_t* win) { - SOKOL_ASSERT(win); - SOKOL_ASSERT(nil == win->macos.current_drawable); -static uint32_t frame_count = 0; -__builtin_printf("%d: before nextDrawable %p\n", frame_count, win); - win->macos.current_drawable = [win->macos.view.metal_layer nextDrawable]; -__builtin_printf("%d: after nextDrawable %p\n", frame_count++, win); - win->macos.renderpass_desc.colorAttachments[0].texture = win->macos.current_drawable.texture; - return (__bridge const void*) win->macos.renderpass_desc; -} - -_SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { - SOKOL_ASSERT(win); - SOKOL_ASSERT(nil != win->macos.current_drawable); - const void* drawable = (__bridge const void*) win->macos.current_drawable; - // current_drawable is autoreleased at end of frame - win->macos.current_drawable = nil; - return drawable; -} - @implementation _sapp_macos_app_delegate - (void)drawFrame { @@ -3786,7 +3749,7 @@ _SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { #if defined(SOKOL_METAL) - //[win->macos.view draw]; + [win->macos.view draw]; #else #error "FIXME: GL" #endif @@ -3818,16 +3781,16 @@ _SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { // setup display link // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc - _sapp.macos.dispatch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); - dispatch_source_set_event_handler(_sapp.macos.dispatch_source, ^(){ + _sapp.macos.display_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); + dispatch_source_set_event_handler(_sapp.macos.display_source, ^(){ @autoreleasepool { [_sapp.macos.app_delegate drawFrame]; } }); - dispatch_resume(_sapp.macos.dispatch_source); + dispatch_resume(_sapp.macos.display_source); CVDisplayLinkCreateWithActiveCGDisplays(&_sapp.macos.display_link); - CVDisplayLinkSetOutputCallback(_sapp.macos.display_link, &_sapp_macos_displaylink_callback, (__bridge void*)_sapp.macos.dispatch_source); + CVDisplayLinkSetOutputCallback(_sapp.macos.display_link, &_sapp_macos_displaylink_callback, (__bridge void*)_sapp.macos.display_source); CGDirectDisplayID disp_id = (CGDirectDisplayID) [NSScreen.mainScreen.deviceDescription[@"NSScreenNumber"] unsignedIntegerValue]; CVDisplayLinkSetCurrentCGDisplay(_sapp.macos.display_link, disp_id); CVDisplayLinkStart(_sapp.macos.display_link); @@ -3847,7 +3810,7 @@ _SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { @end @implementation _sapp_macos_window_delegate -//@synthesize win_id; +@synthesize win_id; - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); @@ -3918,6 +3881,7 @@ _SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { @end @implementation _sapp_macos_window +@synthesize win_id; - (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style @@ -3974,44 +3938,8 @@ _SOKOL_PRIVATE const void* _sapp_macos_metal_drawable(_sapp_window_t* win) { } @end -@implementation _sapp_macos_metal_view - -- (instancetype) initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self) { - self.wantsLayer = YES; - self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; - _metal_layer = (CAMetalLayer*) self.layer; - self.layer.delegate = self; - } - return self; -} - -- (CALayer*)makeBackingLayer { - return [CAMetalLayer layer]; -} - -- (void)viewDidMoveToWindow { - // fixme: resize drawable -} - -- (void)viewDidChangeBackingProperties { - [super viewDidChangeBackingProperties]; -// [self resizeDrawable:self.window.screen.backingScaleFactor]; -} - -- (void)setFrameSize:(NSSize)size { - [super setFrameSize:size]; -// [self resizeDrawable:self.window.screen.backingScaleFactor]; -} - -- (void)setBoundsSize:(NSSize)size { - [super setBoundsSize:size]; -// [self resizeDrawable:self.window.screen.backingScaleFactor]; -} -@end - @implementation _sapp_macos_view +@synthesize win_id; #if defined(SOKOL_GLCORE33) /* NOTE: this is a hack/fix when the initial window size has been clipped by @@ -11776,13 +11704,15 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { SOKOL_API_IMPL const void* sapp_metal_get_window_renderpass_descriptor(sapp_window window) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) - _sapp_window_t* win = _sapp_lookup_window(window.id); + const _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { #if defined(_SAPP_MACOS) - return _sapp_macos_metal_renderpass_descriptor(win); + const void* obj = (__bridge const void*) [win->macos.view currentRenderPassDescriptor]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentRenderPassDescriptor]; #endif + SOKOL_ASSERT(obj); + return obj; } else { return 0; @@ -11799,13 +11729,15 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { SOKOL_API_IMPL const void* sapp_metal_get_window_drawable(sapp_window window) { SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) - _sapp_window_t* win = _sapp_lookup_window(window.id); + const _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { #if defined(_SAPP_MACOS) - return _sapp_macos_metal_drawable(win); + const void* obj = (__bridge const void*) [win->macos.view currentDrawable]; #else const void* obj = (__bridge const void*) [_sapp.window.ios.view currentDrawable]; #endif + SOKOL_ASSERT(obj); + return obj; } else { return 0; From ccfdb17de967111cd0dcd76404957b2024badd8a Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 3 May 2021 19:46:37 +0200 Subject: [PATCH 23/49] more multiwindow wip --- sokol_app.h | 192 +++++++++++++++++++++++++++++---------------------- sokol_glue.h | 4 +- 2 files changed, 112 insertions(+), 84 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 796353ff0..a75d5e7d2 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1494,11 +1494,13 @@ SOKOL_APP_API_DECL void sapp_set_title(const char* str); SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); /* close a window */ SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); +/* start rendering into a window */ +SOKOL_APP_API_DECL void sapp_activate_window_context(sapp_window window); /* get the main window handle */ SOKOL_APP_API_DECL sapp_window sapp_main_window(void); -/* start iterating over open windows */ +/* start iterating over windows */ SOKOL_APP_API_DECL sapp_window sapp_first_window(void); -/* continue iterating over open windows, returns invalid handle when finished */ +/* continue iterating over windows, returns invalid handle when finished */ SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); /* test if a window handle is valid */ SOKOL_APP_API_DECL bool sapp_valid_window(sapp_window window); @@ -2456,6 +2458,7 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void); _SOKOL_PRIVATE void _sapp_macos_discard_state(void); _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_IOS) _SOKOL_PRIVATE void _sapp_ios_init_state(void); _SOKOL_PRIVATE void _sapp_ios_discard_state(void); @@ -2466,11 +2469,13 @@ _SOKOL_PRIVATE void _sapp_emsc_init_state(void); _SOKOL_PRIVATE void _sapp_emsc_discard_state(void); _SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_emsc_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_WIN32) _SOKOL_PRIVATE void _sapp_win32_init_state(void); _SOKOL_PRIVATE void _sapp_win32_discard_state(void); _SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_UWP) _SOKOL_PRIVATE void _sapp_uwp_init_state(void); _SOKOL_PRIVATE void _sapp_uwp_discard_state(void); @@ -2486,6 +2491,7 @@ _SOKOL_PRIVATE void _sapp_x11_init_state(void); _SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* desc, int num_images); #endif /*=== POOL IMPLEMENTATION ====================================================*/ @@ -2659,6 +2665,18 @@ _SOKOL_PRIVATE void _sapp_platform_destroy_window(_sapp_window_t* win) { #endif } +_SOKOL_PRIVATE void _sapp_platform_set_icon(const sapp_icon_desc* desc, int num_images) { + #if defined(_SAPP_MACOS) + _sapp_macos_set_icon(desc, num_images); + #elif defined(_SAPP_WIN32) + _sapp_win32_set_icon(desc, num_images); + #elif defined(_SAPP_LINUX) + _sapp_x11_set_icon(desc, num_images); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_set_icon(desc, num_images); + #endif +} + _SOKOL_PRIVATE void _sapp_fail(const char* msg) { if (_sapp.desc.fail_cb) { _sapp.desc.fail_cb(msg); @@ -3166,6 +3184,25 @@ _SOKOL_PRIVATE void _sapp_setup_default_icon(void) { SOKOL_ASSERT(dst == dst_end); } +_SOKOL_PRIVATE void _sapp_set_icon(const sapp_icon_desc* desc) { + if (desc->sokol_default) { + if (0 == _sapp.default_icon_pixels) { + _sapp_setup_default_icon(); + } + SOKOL_ASSERT(0 != _sapp.default_icon_pixels); + desc = &_sapp.default_icon_desc; + } + const int num_images = _sapp_icon_num_images(desc); + if (num_images == 0) { + return; + } + SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); + if (!_sapp_validate_icon_desc(desc, num_images)) { + return; + } + _sapp_platform_set_icon(desc, num_images); +} + /*== MacOS/iOS ===============================================================*/ #if defined(_SAPP_APPLE) @@ -3297,7 +3334,7 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void) { _sapp_macos_init_keytable(); // set the application dock icon as early as possible, otherwise // the dummy icon will be visible for a short time - sapp_set_icon(&_sapp.desc.icon); + _sapp_set_icon(&_sapp.desc.icon); NSApp.activationPolicy = NSApplicationActivationPolicyRegular; _sapp.macos.app_delegate = [[_sapp_macos_app_delegate alloc] init]; NSApp.delegate = _sapp.macos.app_delegate; @@ -3319,51 +3356,10 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { #endif } - -// FIXME: this is for a GLFW-style "explicit" render loop -/* -_SOKOL_PRIVATE void _sapp_macos_process_events(void){ - NSEvent* event; - do { - event = [NSApp nextEventMatchingMask: NSEventMaskAny - untilDate: nil - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if (event != NULL) { - [NSApp sendEvent:event]; - } - } - while (event != NULL); -} -*/ - _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApplication sharedApplication]; _sapp_init_state(desc); [NSApp run]; - -// FIXME: this is for a GLFW-style "explicit" render loop -/* - while (!_sapp.quit_ordered) { - _sapp_macos_process_events(); - _sapp_frame(); - for (int i = 0; i < _sapp.window_pool.pool.size; i++) { - const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; - _sapp_window_t* win = _sapp_lookup_window(win_id); - if (win) { - #if defined(SOKOL_METAL) - [win->macos.view draw]; - #else - #error "FIXME: GL" - #endif - } - } - // FIXME FIXME FIXME - // if (_sapp.quit_requested || _sapp.quit_ordered) { - // [win->macos.window performClose:nil]; - // } - } -*/ } _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { @@ -3766,18 +3762,13 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); - // FIXME: maybe the activation stuff here needs to be moved before - // the makeKeyAndOrderFront call, see here: - // https://github.com/floooh/sokol/pull/515#issuecomment-824221751 NSApp.activationPolicy = NSApplicationActivationPolicyRegular; [NSApp activateIgnoringOtherApps:YES]; - [NSEvent setMouseCoalescingEnabled:NO]; _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); _sapp_macos_update_dimensions(win); - _sapp.valid = true; // setup display link // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc @@ -3795,7 +3786,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( CVDisplayLinkSetCurrentCGDisplay(_sapp.macos.display_link, disp_id); CVDisplayLinkStart(_sapp.macos.display_link); -// [NSApp stop:nil]; + _sapp.valid = true; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -5694,7 +5685,7 @@ _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { #endif _sapp.valid = true; _sapp_emsc_register_eventhandlers(); - sapp_set_icon(&desc->icon); + _sapp_set_icon(&desc->icon); /* start the frame loop */ emscripten_request_animation_frame_loop(_sapp_emsc_frame, 0); @@ -7212,7 +7203,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_win32_uwp_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); _sapp_win32_init_dpi(); _sapp_win32_create_window(); - sapp_set_icon(&desc->icon); + _sapp_set_icon(&desc->icon); #if defined(SOKOL_D3D11) _sapp_d3d11_create_device_and_swapchain(); _sapp_d3d11_create_default_render_target(); @@ -11135,7 +11126,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_glx_choose_visual(&visual, &depth); _sapp_x11_create_window(visual, depth); _sapp_glx_create_context(); - sapp_set_icon(&desc->icon); + _sapp_set_icon(&desc->icon); _sapp.valid = true; _sapp_x11_show_window(); if (_sapp.fullscreen) { @@ -11253,7 +11244,7 @@ _SOKOL_PRIVATE void _sapp_window_toggle_fullscreen(uint32_t win_id) { } } -SOKOL_API_IMPL void _sapp_window_set_title(uint32_t win_id, const char* title) { +_SOKOL_PRIVATE void _sapp_window_set_title(uint32_t win_id, const char* title) { SOKOL_ASSERT(title); _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { @@ -11310,14 +11301,17 @@ SOKOL_API_IMPL bool sapp_isvalid(void) { } SOKOL_API_IMPL sapp_desc sapp_query_desc(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp.desc; } SOKOL_API_IMPL uint64_t sapp_frame_count(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp.frame_count; } SOKOL_API_IMPL int sapp_color_format(void) { + SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) switch (_sapp.emsc.wgpu.render_format) { case WGPUTextureFormat_RGBA8Unorm: @@ -11336,26 +11330,32 @@ SOKOL_API_IMPL int sapp_color_format(void) { } SOKOL_API_IMPL int sapp_depth_format(void) { + SOKOL_ASSERT(_sapp.valid); return _SAPP_PIXELFORMAT_DEPTH_STENCIL; } SOKOL_API_IMPL void sapp_request_quit(void) { + SOKOL_ASSERT(_sapp.valid); _sapp.quit_requested = true; } SOKOL_API_IMPL void sapp_cancel_quit(void) { + SOKOL_ASSERT(_sapp.valid); _sapp.quit_requested = false; } SOKOL_API_IMPL void sapp_quit(void) { + SOKOL_ASSERT(_sapp.valid); _sapp.quit_ordered = true; } SOKOL_API_IMPL void sapp_consume_event(void) { + SOKOL_ASSERT(_sapp.valid); _sapp.event_consumed = true; } SOKOL_API_IMPL void sapp_show_keyboard(bool show) { + SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_IOS) _sapp_ios_show_keyboard(show); #elif defined(_SAPP_EMSCRIPTEN) @@ -11368,11 +11368,13 @@ SOKOL_API_IMPL void sapp_show_keyboard(bool show) { } SOKOL_API_IMPL bool sapp_keyboard_shown(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp.onscreen_keyboard_shown; } /* NOTE that sapp_show_mouse() does not "stack" like the Win32 or macOS API functions! */ SOKOL_API_IMPL void sapp_show_mouse(bool show) { + SOKOL_ASSERT(_sapp.valid); // FIXME: is this actually a per-window function?? _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); @@ -11391,6 +11393,7 @@ SOKOL_API_IMPL void sapp_show_mouse(bool show) { } SOKOL_API_IMPL bool sapp_mouse_shown(void) { + SOKOL_ASSERT(_sapp.valid); // FIXME: is this actually a per-window function?? const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); @@ -11398,6 +11401,7 @@ SOKOL_API_IMPL bool sapp_mouse_shown(void) { } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { + SOKOL_ASSERT(_sapp.valid); // FIXME: is this actually a per-window function?? _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); @@ -11415,6 +11419,7 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { + SOKOL_ASSERT(_sapp.valid); // FIXME: is this actually a per-window function?? const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); @@ -11422,102 +11427,106 @@ SOKOL_API_IMPL bool sapp_mouse_locked(void) { } SOKOL_API_IMPL void sapp_set_icon(const sapp_icon_desc* desc) { + SOKOL_ASSERT(_sapp.valid); SOKOL_ASSERT(desc); - if (desc->sokol_default) { - if (0 == _sapp.default_icon_pixels) { - _sapp_setup_default_icon(); - } - SOKOL_ASSERT(0 != _sapp.default_icon_pixels); - desc = &_sapp.default_icon_desc; - } - const int num_images = _sapp_icon_num_images(desc); - if (num_images == 0) { - return; - } - SOKOL_ASSERT((num_images > 0) && (num_images <= SAPP_MAX_ICONIMAGES)); - if (!_sapp_validate_icon_desc(desc, num_images)) { - return; - } - #if defined(_SAPP_MACOS) - _sapp_macos_set_icon(desc, num_images); - #elif defined(_SAPP_WIN32) - _sapp_win32_set_icon(desc, num_images); - #elif defined(_SAPP_LINUX) - _sapp_x11_set_icon(desc, num_images); - #elif defined(_SAPP_EMSCRIPTEN) - _sapp_emsc_set_icon(desc, num_images); - #endif + _sapp_set_icon(desc); } SOKOL_API_IMPL int sapp_width(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_width(_sapp.main_window_id); } SOKOL_API_IMPL float sapp_widthf(void) { + SOKOL_ASSERT(_sapp.valid); return (float)_sapp_window_width(_sapp.main_window_id); } SOKOL_API_IMPL int sapp_height(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_height(_sapp.main_window_id); } SOKOL_API_IMPL float sapp_heightf(void) { + SOKOL_ASSERT(_sapp.valid); return (float)_sapp_window_height(_sapp.main_window_id); } SOKOL_API_IMPL int sapp_sample_count(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_sample_count(_sapp.main_window_id); } SOKOL_API_IMPL bool sapp_high_dpi(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_high_dpi(_sapp.main_window_id); } SOKOL_API_IMPL float sapp_dpi_scale(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_dpi_scale(_sapp.main_window_id); } SOKOL_API_IMPL bool sapp_is_fullscreen(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_is_fullscreen(_sapp.main_window_id); } SOKOL_API_IMPL void sapp_toggle_fullscreen(void) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_toggle_fullscreen(_sapp.main_window_id); } SOKOL_API_IMPL void sapp_set_title(const char* title) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_set_title(_sapp.main_window_id, title); } SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { + SOKOL_ASSERT(_sapp.valid); SOKOL_ASSERT(in_desc); const sapp_window_desc desc = _sapp_window_desc_defaults(in_desc); return _sapp_make_window_id(_sapp_create_window(&desc)); } SOKOL_API_IMPL void sapp_close_window(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + // FIXME FIXME FIXME +} + +SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); // FIXME FIXME FIXME } SOKOL_API_IMPL sapp_window sapp_main_window(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp_make_window_id(_sapp.main_window_id); } SOKOL_API_IMPL sapp_window sapp_first_window(void) { - SOKOL_ASSERT(false && "FIXME FIXME FIXME"); - return _sapp_make_window_id(SAPP_INVALID_ID); + SOKOL_ASSERT(_sapp.valid); + return _sapp_make_window_id(_sapp.main_window_id); } SOKOL_API_IMPL sapp_window sapp_next_window(sapp_window window) { - SOKOL_ASSERT(false && "FIXME FIXME FIXME"); + SOKOL_ASSERT(_sapp.valid); + for (int i = _sapp_slot_index(window.id) + 1; i < _sapp.window_pool.pool.size; i++) { + uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + if (0 != _sapp_lookup_window(win_id)) { + return _sapp_make_window_id(win_id); + } + } return _sapp_make_window_id(SAPP_INVALID_ID); } SOKOL_API_IMPL bool sapp_valid_window(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return 0 != _sapp_lookup_window(window.id); } SOKOL_API_IMPL int sapp_window_index(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); SOKOL_ASSERT(SAPP_INVALID_ID != window.id); int slot_index = _sapp_slot_index(window.id); SOKOL_ASSERT(slot_index > 0); @@ -11527,47 +11536,58 @@ SOKOL_API_IMPL int sapp_window_index(sapp_window window) { } SOKOL_API_IMPL int sapp_window_width(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_width(window.id); } SOKOL_API_IMPL float sapp_window_widthf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return (float)_sapp_window_width(window.id); } SOKOL_API_IMPL int sapp_window_height(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_height(window.id); } SOKOL_API_IMPL float sapp_window_heightf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return (float)_sapp_window_height(window.id); } SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_sample_count(window.id); } SOKOL_API_IMPL bool sapp_window_high_dpi(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_high_dpi(window.id); } SOKOL_API_IMPL float sapp_window_dpi_scale(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_dpi_scale(window.id); } SOKOL_API_IMPL bool sapp_window_is_fullscreen(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); return _sapp_window_is_fullscreen(window.id); } SOKOL_API_IMPL void sapp_window_toggle_fullscreen(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_toggle_fullscreen(window.id); } SOKOL_API_IMPL void sapp_window_set_title(sapp_window window, const char* title) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_set_title(window.id, title); } /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->clipboard.enabled); @@ -11588,6 +11608,7 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { + SOKOL_ASSERT(_sapp.valid); _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->clipboard.enabled); @@ -11607,6 +11628,7 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { } SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { + SOKOL_ASSERT(_sapp.valid); const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); @@ -11614,6 +11636,7 @@ SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { + SOKOL_ASSERT(_sapp.valid); const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); @@ -11628,10 +11651,12 @@ SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { } SOKOL_API_IMPL bool sapp_gles2(void) { + SOKOL_ASSERT(_sapp.valid); return _sapp.gles2_fallback; } SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { + SOKOL_ASSERT(_sapp.valid); const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); @@ -11648,6 +11673,7 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { + SOKOL_ASSERT(_sapp.valid); const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); SOKOL_ASSERT(win->drop.enabled); @@ -11723,11 +11749,11 @@ SOKOL_API_IMPL const void* sapp_metal_get_window_renderpass_descriptor(sapp_wind } SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { + SOKOL_ASSERT(_sapp.valid); return sapp_metal_get_window_renderpass_descriptor(sapp_main_window()); } SOKOL_API_IMPL const void* sapp_metal_get_window_drawable(sapp_window window) { - SOKOL_ASSERT(_sapp.valid); #if defined(SOKOL_METAL) const _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { @@ -11769,6 +11795,7 @@ SOKOL_API_IMPL const void* sapp_macos_get_nswindow(sapp_window window) { } SOKOL_API_IMPL const void* sapp_ios_get_window(void) { + SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_IOS) const void* obj = (__bridge const void*) _sapp.ios.window; SOKOL_ASSERT(obj); @@ -11893,6 +11920,7 @@ SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) { } SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { + SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) _sapp.emsc.ask_leave_site = ask; #else diff --git a/sokol_glue.h b/sokol_glue.h index 5eae6ca1e..027d43e50 100644 --- a/sokol_glue.h +++ b/sokol_glue.h @@ -113,12 +113,12 @@ SOKOL_GLUE_API_DECL sg_context_desc sapp_window_sgcontext(sapp_window win); #endif static const void* _sglue_metal_get_renderpass_descriptor(void* user_data) { - sapp_window win = { (uint32_t) user_data }; + sapp_window win = { (uint32_t)(uintptr_t)user_data }; return sapp_metal_get_window_renderpass_descriptor(win); } static const void* _sglue_metal_get_drawable(void* user_data) { - sapp_window win = { (uint32_t) user_data }; + sapp_window win = { (uint32_t)(uintptr_t)user_data }; return sapp_metal_get_window_drawable(win); } From 23239cfc8cf9309b2bd8983fcd771f2635fc992b Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 4 May 2021 19:32:24 +0200 Subject: [PATCH 24/49] multiwindow intermediate code cleanup --- sokol_app.h | 218 +++++++++++++++++++++++++++------------------------- 1 file changed, 114 insertions(+), 104 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index a75d5e7d2..a06a8331a 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1335,9 +1335,9 @@ typedef struct sapp_icon_desc { */ typedef struct sapp_window_desc { const char* title; // the window title as UTF-8 encoded string - int x; + int x; // window position (if 0,0 a good default might be chosen) int y; - int width; + int width; // window size int height; int sample_count; // MSAA sample count int swap_interval; // the preferred swap interval (ignored on some platforms) @@ -1345,11 +1345,6 @@ typedef struct sapp_window_desc { bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR - bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false - int max_dropped_files; // max number of dropped files to process (default: 1) - int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8 file path (default: 2048) - bool enable_clipboard; - int clipboard_size; } sapp_window_desc; typedef struct sapp_gl_desc { @@ -1387,8 +1382,25 @@ typedef struct sapp_desc { void (*event_userdata_cb)(const sapp_event*, void*); int window_pool_size; - sapp_window_desc window; - sapp_icon_desc icon; // FIXME: per-window icons? + const char* window_title; // the window title as UTF-8 encoded string + int x; + int y; + int width; + int height; + int sample_count; // MSAA sample count + int swap_interval; // the preferred swap interval (ignored on some platforms) + bool high_dpi; // whether the rendering canvas is full-resolution on HighDPI displays + bool fullscreen; // whether the window should be created in fullscreen mode + bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) + bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR + + bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false + int max_dropped_files; // max number of dropped files to process (default: 1) + int max_dropped_file_path_length; // max length in bytes of a dropped UTF-8 file path (default: 2048) + bool enable_clipboard; + int clipboard_size; + sapp_icon_desc icon; + sapp_gl_desc gl; sapp_win32_desc win32; sapp_html5_desc html5; @@ -2372,8 +2384,6 @@ typedef struct { float dpi_scale; bool fullscreen; _sapp_mouse_t mouse; - _sapp_clipboard_t clipboard; - _sapp_drop_t drop; char title[_SAPP_MAX_TITLE_LENGTH]; #if defined(_SAPP_MACOS) _sapp_macos_window_t macos; @@ -2423,6 +2433,8 @@ typedef struct { sapp_event event; sapp_icon_desc default_icon_desc; uint32_t* default_icon_pixels; + _sapp_clipboard_t clipboard; + _sapp_drop_t drop; #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -2742,12 +2754,12 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { } } -_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(const _sapp_window_t* win, int index) { - SOKOL_ASSERT(win->drop.buffer); - SOKOL_ASSERT((index >= 0) && (index <= win->drop.max_files)); - int offset = index * win->drop.max_path_length; - SOKOL_ASSERT(offset < win->drop.buf_size); - return &win->drop.buffer[offset]; +_SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { + SOKOL_ASSERT(_sapp.drop.buffer); + SOKOL_ASSERT((index >= 0) && (index <= _sapp.drop.max_files)); + int offset = index * _sapp.drop.max_path_length; + SOKOL_ASSERT(offset < _sapp.drop.buf_size); + return &_sapp.drop.buffer[offset]; } /* Copy a string into a fixed size buffer with guaranteed zero- @@ -2780,19 +2792,48 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { } } -_SOKOL_PRIVATE sapp_window_desc _sapp_window_desc_defaults(const sapp_window_desc* in_desc) { - sapp_window_desc desc = *in_desc; - desc.title = _sapp_def(desc.title, "sokol_app"); +_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { + sapp_desc desc = *in_desc; + desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE); + desc.window_title = _sapp_def(desc.window_title, "sokol-app"); desc.width = _sapp_def(desc.width, 640); desc.height = _sapp_def(desc.height, 480); desc.sample_count = _sapp_def(desc.sample_count, 1); desc.swap_interval = _sapp_def(desc.swap_interval, 1); + desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas"); desc.max_dropped_files = _sapp_def(desc.max_dropped_files, 1); desc.max_dropped_file_path_length = _sapp_def(desc.max_dropped_file_path_length, 2048); desc.clipboard_size = _sapp_def(desc.clipboard_size, 8192); return desc; } +_SOKOL_PRIVATE sapp_window_desc _sapp_window_desc_defaults(const sapp_window_desc* in_desc) { + sapp_window_desc desc = *in_desc; + desc.title = _sapp_def(desc.title, "sokol-app"); + desc.width = _sapp_def(desc.width, 640); + desc.height = _sapp_def(desc.height, 480); + desc.sample_count = _sapp_def(desc.sample_count, 1); + desc.swap_interval = _sapp_def(desc.swap_interval, 1); + return desc; +} + +_SOKOL_PRIVATE sapp_window_desc _sapp_desc_to_window_desc(const sapp_desc* desc) { + sapp_window_desc wdesc; + memset(&wdesc, 0, sizeof(wdesc)); + wdesc.title = desc->window_title; + wdesc.x = desc->x; + wdesc.y = desc->y; + wdesc.width = desc->width; + wdesc.height = desc->height; + wdesc.sample_count = desc->sample_count; + wdesc.swap_interval = desc->swap_interval; + wdesc.high_dpi = desc->high_dpi; + wdesc.fullscreen = desc->fullscreen; + wdesc.alpha = desc->alpha; + wdesc.user_cursor = desc->user_cursor; + return wdesc; +} + _SOKOL_PRIVATE void _sapp_platform_init_state(void) { #if defined(_SAPP_MACOS) _sapp_macos_init_state(); @@ -2829,7 +2870,7 @@ _SOKOL_PRIVATE void _sapp_platform_discard_state(void) { #endif } -_SOKOL_PRIVATE bool _sapp_init_clipboard(_sapp_clipboard_t* clipboard, const sapp_window_desc* desc) { +_SOKOL_PRIVATE void _sapp_init_clipboard(_sapp_clipboard_t* clipboard, const sapp_desc* desc) { SOKOL_ASSERT(clipboard && desc); SOKOL_ASSERT(0 == clipboard->buffer); clipboard->enabled = desc->enable_clipboard; @@ -2838,10 +2879,9 @@ _SOKOL_PRIVATE bool _sapp_init_clipboard(_sapp_clipboard_t* clipboard, const sap clipboard->buffer = (char*) SOKOL_CALLOC(1, (size_t)clipboard->buf_size); if (0 == clipboard->buffer) { SOKOL_LOG("failed to allocate clipboard buffer!"); - return false; + clipboard->enabled = false; } } - return true; } _SOKOL_PRIVATE void _sapp_discard_clipboard(_sapp_clipboard_t* clipboard) { @@ -2852,7 +2892,7 @@ _SOKOL_PRIVATE void _sapp_discard_clipboard(_sapp_clipboard_t* clipboard) { _SAPP_CLEAR_PTR(_sapp_clipboard_t, clipboard); } -_SOKOL_PRIVATE bool _sapp_init_drop(_sapp_drop_t* drop, const sapp_window_desc* desc) { +_SOKOL_PRIVATE void _sapp_init_drop(_sapp_drop_t* drop, const sapp_desc* desc) { SOKOL_ASSERT(drop && desc); SOKOL_ASSERT(0 == drop->buffer); drop->enabled = desc->enable_dragndrop; @@ -2863,10 +2903,9 @@ _SOKOL_PRIVATE bool _sapp_init_drop(_sapp_drop_t* drop, const sapp_window_desc* drop->buffer = (char*) SOKOL_CALLOC(1, (size_t)drop->buf_size); if (0 == drop->buffer) { SOKOL_LOG("failed to allocate drag'n'drop buffer!"); - return false; + drop->enabled = false; } } - return true; } _SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { @@ -2877,11 +2916,16 @@ _SOKOL_PRIVATE void _sapp_discard_drop(_sapp_drop_t* drop) { _SAPP_CLEAR_PTR(_sapp_drop_t, drop); } +_SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_drop_t* drop) { + if (drop->enabled) { + SOKOL_ASSERT(drop->buffer); + memset(drop->buffer, 0, (size_t)drop->buf_size); + } +} + _SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); SOKOL_ASSERT(win); - _sapp_discard_drop(&win->drop); - _sapp_discard_clipboard(&win->clipboard); _sapp_platform_destroy_window(win); _sapp_free_window_id(win_id); _SAPP_CLEAR_PTR(_sapp_window_t, win); @@ -2909,22 +2953,11 @@ _SOKOL_PRIVATE uint32_t _sapp_create_window(const sapp_window_desc* desc) { win->dpi_scale = 1.0f; win->fullscreen = desc->fullscreen; win->mouse.shown = true; - if (!_sapp_init_clipboard(&win->clipboard, &win->desc)) { - SOKOL_LOG("clipboard initialization failed!"); - return SAPP_INVALID_ID; - } - if (!_sapp_init_drop(&win->drop, &win->desc)) { - SOKOL_LOG("drag'n'drop initialization failed!"); - _sapp_discard_clipboard(&win->clipboard); - return SAPP_INVALID_ID; - } _sapp_strcpy(desc->title, &win->title[0], sizeof(win->title)); win->desc.title = &win->title[0]; // redirect transient pointer to persistent copy // platform-specific window creation and initialization if (!_sapp_platform_create_window(win)) { - _sapp_discard_drop(&win->drop); - _sapp_discard_clipboard(&win->clipboard); return SAPP_INVALID_ID; } return win_id; @@ -2942,24 +2975,18 @@ _SOKOL_PRIVATE void _sapp_destroy_all_windows(void) { _sapp_destroy_window(_sapp.main_window_id); } -_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { - sapp_desc desc = *in_desc; - desc.window_pool_size = _sapp_def(desc.window_pool_size, _SAPP_DEFAULT_POOL_SIZE); - desc.window = _sapp_window_desc_defaults(&desc.window); - desc.html5.canvas_name = _sapp_def(desc.html5.canvas_name, "canvas"); - return desc; -} - _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _SAPP_CLEAR_ITEM(_sapp_t, _sapp); _sapp.desc = _sapp_desc_defaults(desc); _sapp.first_frame = true; _sapp_setup_window_pool(&_sapp.desc); + _sapp_init_clipboard(&_sapp.clipboard, desc); + _sapp_init_drop(&_sapp.drop, desc); _sapp_platform_init_state(); // copy title string in desc to backing store and patch transient pointer - _sapp_strcpy(desc->window.title, &_sapp.desc_window_title[0], sizeof(_sapp.desc_window_title)); - _sapp.desc.window.title = &_sapp.desc_window_title[0]; + _sapp_strcpy(desc->window_title, &_sapp.desc_window_title[0], sizeof(_sapp.desc_window_title)); + _sapp.desc.window_title = &_sapp.desc_window_title[0]; // FIXME: what about the icon image pointers? } @@ -2968,6 +2995,8 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { _sapp_destroy_all_windows(); _sapp_discard_window_pool(); _sapp_platform_discard_state(); + _sapp_discard_drop(&_sapp.drop); + _sapp_discard_clipboard(&_sapp.clipboard); if (_sapp.default_icon_pixels) { SOKOL_FREE((void*)_sapp.default_icon_pixels); _sapp.default_icon_pixels = 0; @@ -3004,14 +3033,6 @@ _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { } } -_SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* win) { - SOKOL_ASSERT(win); - if (win->drop.enabled) { - SOKOL_ASSERT(win->drop.buffer); - memset(win->drop.buffer, 0, (size_t)win->drop.buf_size); - } -} - _SOKOL_PRIVATE void _sapp_frame(void) { if (_sapp.first_frame) { _sapp.first_frame = false; @@ -3410,7 +3431,7 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; win->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; win->macos.view.sampleCount = (NSUInteger) win->desc.sample_count; - win->macos.view.autoResizeDrawable = false; + win->macos.view.autoResizeDrawable = NO; win->macos.window.contentView = win->macos.view; [win->macos.window makeFirstResponder:win->macos.view]; win->macos.view.layer.magnificationFilter = kCAFilterNearest; @@ -3604,21 +3625,21 @@ _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { } } -_SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(_sapp_window_t* win) { - SOKOL_ASSERT(win->clipboard.buffer); +_SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { + SOKOL_ASSERT(_sapp.clipboard.buffer); @autoreleasepool { - win->clipboard.buffer[0] = 0; + _sapp.clipboard.buffer[0] = 0; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return win->clipboard.buffer; + return _sapp.clipboard.buffer; } NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; if (!str) { - return win->clipboard.buffer; + return _sapp.clipboard.buffer; } - _sapp_strcpy([str UTF8String], win->clipboard.buffer, win->clipboard.buf_size); + _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); } - return win->clipboard.buffer; + return _sapp.clipboard.buffer; } _SOKOL_PRIVATE void _sapp_macos_update_window_title(_sapp_window_t* win) { @@ -3739,18 +3760,21 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @implementation _sapp_macos_app_delegate - (void)drawFrame { - _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { #if defined(SOKOL_METAL) + // FIXME: MTKView.draw must be called before currentRenderPassDescriptor + // so that it correctly updates its render target sizes... + // this may be a good reason to drop MTKView :/ [win->macos.view draw]; #else #error "FIXME: GL" #endif } } + _sapp_frame(); // FIXME FIXME FIXME // if (_sapp.quit_requested || _sapp.quit_ordered) { // [win->macos.window performClose:nil]; @@ -3760,7 +3784,8 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { _SOKOL_UNUSED(aNotification); - _sapp.main_window_id = _sapp_create_window(&_sapp.desc.window); + const sapp_window_desc window_desc = _sapp_desc_to_window_desc(&_sapp.desc); + _sapp.main_window_id = _sapp_create_window(&window_desc); NSApp.activationPolicy = NSApplicationActivationPolicyRegular; [NSApp activateIgnoringOtherApps:YES]; @@ -3901,12 +3926,12 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( SOKOL_ASSERT(win); NSPasteboard *pboard = [sender draggingPasteboard]; if ([pboard.types containsObject:NSPasteboardTypeFileURL]) { - _sapp_clear_drop_buffer(win); - win->drop.num_files = ((int)pboard.pasteboardItems.count > win->drop.max_files) ? win->drop.max_files : pboard.pasteboardItems.count; + _sapp_clear_drop_buffer(&_sapp.drop); + _sapp.drop.num_files = ((int)pboard.pasteboardItems.count > _sapp.drop.max_files) ? _sapp.drop.max_files : pboard.pasteboardItems.count; bool drop_failed = false; - for (int i = 0; i < win->drop.num_files; i++) { + for (int i = 0; i < _sapp.drop.num_files; i++) { NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]]; - if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(win, i), win->drop.max_path_length)) { + if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { SOKOL_LOG("sokol_app.h: dropped file path too long (sapp_desc.max_dropped_file_path_length)\n"); drop_failed = true; break; @@ -3919,8 +3944,8 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } } else { - _sapp_clear_drop_buffer(win); - win->drop.num_files = 0; + _sapp_clear_drop_buffer(&_sapp.drop); + _sapp.drop.num_files = 0; } retval = YES; } @@ -4153,7 +4178,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } } /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ - if (win->clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { + if (_sapp.clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { _sapp_init_event(win, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } @@ -4371,7 +4396,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { and automatically renders at Retina resolution. We'll disable autoResize and instead do the resizing in _sapp_ios_update_dimensions() */ - _sapp.ios.view.autoResizeDrawable = false; + _sapp.ios.view.autoResizeDrawable = NO; _sapp.ios.view.userInteractionEnabled = YES; _sapp.ios.view.multipleTouchEnabled = YES; _sapp.ios.view_ctrl = [[UIViewController alloc] init]; @@ -11588,10 +11613,7 @@ SOKOL_API_IMPL void sapp_window_set_title(sapp_window window, const char* title) /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { SOKOL_ASSERT(_sapp.valid); - _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->clipboard.enabled); - if (!win->clipboard.enabled) { + if (!_sapp.clipboard.enabled) { return; } SOKOL_ASSERT(str); @@ -11604,19 +11626,16 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { #else /* not implemented */ #endif - _sapp_strcpy(str, win->clipboard.buffer, win->clipboard.buf_size); + _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); } SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { SOKOL_ASSERT(_sapp.valid); - _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->clipboard.enabled); - if (!win->clipboard.enabled) { + if (!_sapp.clipboard.enabled) { return ""; } #if defined(_SAPP_MACOS) - return _sapp_macos_get_clipboard_string(win); + return _sapp_macos_get_clipboard_string(); #elif defined(_SAPP_EMSCRIPTEN) return _sapp.clipboard.buffer; #elif defined(_SAPP_WIN32) @@ -11629,25 +11648,19 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->drop.enabled); - return win->drop.num_files; + return _sapp.drop.num_files; } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); - SOKOL_ASSERT(win->drop.buffer); - if (!win->drop.enabled) { + SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); + if (!_sapp.drop.enabled) { return ""; } - if ((index < 0) || (index >= win->drop.max_files)) { + if ((index < 0) || (index >= _sapp.drop.max_files)) { return ""; } - return (const char*) _sapp_dropped_file_path_ptr(win, index); + return (const char*) _sapp_dropped_file_path_ptr(index); } SOKOL_API_IMPL bool sapp_gles2(void) { @@ -11657,12 +11670,9 @@ SOKOL_API_IMPL bool sapp_gles2(void) { SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->drop.enabled); - SOKOL_ASSERT((index >= 0) && (index < win->drop.num_files)); + SOKOL_ASSERT((index >= 0) && (index < _sapp.drop.num_files)); #if defined(_SAPP_EMSCRIPTEN) - if (!win->drop.enabled) { + if (!_sapp.drop.enabled) { return 0; } return sapp_js_dropped_file_size(index); @@ -11674,13 +11684,13 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request* request) { SOKOL_ASSERT(_sapp.valid); - const _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->drop.enabled); SOKOL_ASSERT(request); SOKOL_ASSERT(request->callback); SOKOL_ASSERT(request->buffer_ptr); SOKOL_ASSERT(request->buffer_size > 0); + if (!_sapp.drop.enabled) { + return; + } #if defined(_SAPP_EMSCRIPTEN) const int index = request->dropped_file_index; sapp_html5_fetch_error error_code = SAPP_HTML5_FETCH_ERROR_NO_ERROR; From a35bea524ffafe6bd1f399a25a6cda6332c0752a Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 4 May 2021 20:16:00 +0200 Subject: [PATCH 25/49] sokol_gfx.h mtl: ignore context commit if context wasn't rendered to --- sokol_gfx.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index cf9014df5..5167b2d5a 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -10719,7 +10719,6 @@ _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { SOKOL_ASSERT(!_sg.mtl.pass_valid); SOKOL_ASSERT(ctx->mtl.drawable_cb || ctx->mtl.drawable_userdata_cb); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(nil != ctx->mtl.cmd_buffer); _SOKOL_UNUSED(ctx); #if defined(_SG_TARGET_MACOS) @@ -10734,10 +10733,14 @@ _SOKOL_PRIVATE void _sg_mtl_commit(_sg_context_t* ctx) { else { cur_drawable = (__bridge id) ctx->mtl.drawable_userdata_cb(ctx->mtl.user_data); } - if (nil != cur_drawable) { - [ctx->mtl.cmd_buffer presentDrawable:cur_drawable]; + + // cmd_buffer will be nil if nothing was rendered this frame + if (nil != ctx->mtl.cmd_buffer) { + if (nil != cur_drawable) { + [ctx->mtl.cmd_buffer presentDrawable:cur_drawable]; + } + [ctx->mtl.cmd_buffer commit]; } - [ctx->mtl.cmd_buffer commit]; /* garbage-collect resources pending for release */ _sg_mtl_garbage_collect(_sg.frame_index); From f79edaf562ce4901cbbddc65a3ef75a50f5dfdde Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 4 May 2021 20:16:53 +0200 Subject: [PATCH 26/49] sokol_app.h metal: start to fix window close and shutdown behaviour --- sokol_app.h | 67 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index a06a8331a..bca9ea346 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3775,10 +3775,15 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } } _sapp_frame(); - // FIXME FIXME FIXME - // if (_sapp.quit_requested || _sapp.quit_ordered) { - // [win->macos.window performClose:nil]; - // } + if (_sapp.quit_requested && !_sapp.quit_ordered) { + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); + if (win) { + [win->macos.window performClose:nil]; + } + } + if (_sapp.quit_ordered) { + [NSApp terminate:self]; + } } - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { @@ -3814,11 +3819,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp.valid = true; } -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { - _SOKOL_UNUSED(sender); - return YES; -} - - (void)applicationWillTerminate:(NSNotification*)notification { _SOKOL_UNUSED(notification); _sapp_discard_state(); @@ -3830,25 +3830,44 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( - (BOOL)windowShouldClose:(id)sender { _SOKOL_UNUSED(sender); - /* only give user-code a chance to intervene when sapp_quit() wasn't already called */ - if (!_sapp.quit_ordered) { - /* if window should be closed and event handling is enabled, give user code - a chance to intervene via sapp_cancel_quit() - */ - _sapp.quit_requested = true; - _sapp_window_t* win = _sapp_lookup_window(self.win_id); - SOKOL_ASSERT(win); - _sapp_macos_app_event(win, SAPP_EVENTTYPE_QUIT_REQUESTED); - /* user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; + if (self.win_id == _sapp.main_window_id) { + /* only give user-code a chance to intervene when sapp_quit() wasn't already called */ + if (!_sapp.quit_ordered) { + /* if window should be closed and event handling is enabled, give user code + a chance to intervene via sapp_cancel_quit() + */ + _sapp.quit_requested = true; + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + SOKOL_ASSERT(win); + _sapp_macos_app_event(win, SAPP_EVENTTYPE_QUIT_REQUESTED); + /* user code hasn't intervened, quit the app */ + if (_sapp.quit_requested) { + _sapp.quit_ordered = true; + } + } + if (_sapp.quit_ordered) { + return YES; + } + else { + return NO; } } - if (_sapp.quit_ordered) { + else { + // not the main window return YES; } - else { - return NO; +} + +- (void)windowWillClose:(id)sender { + _SOKOL_UNUSED(sender); + // the main window will be closed when the application closes + if (self.win_id != _sapp.main_window_id) { + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + // FIXME: send window close event + // destroy state associated with the window + _sapp_destroy_window(self.win_id); + } } } From 88d92955242f6f6e175df8b4792e36e028cf618c Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 5 May 2021 18:32:02 +0200 Subject: [PATCH 27/49] sokol_app.h metal: fix window/framebuffer resizing --- sokol_app.h | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index bca9ea346..07c45566b 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3597,15 +3597,27 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { } win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; - /* NOTE: _sapp_macos_update_dimensions() isn't called each frame, but only - when the window size actually changes, so resizing the MTKView's - in each call is fine even when MTKView doesn't ignore setting an - identical drawableSize. - */ + int cur_fb_width, cur_fb_height; #if defined(SOKOL_METAL) - CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; - win->macos.view.drawableSize = drawable_size; + const CGSize fb_size = win->macos.view.drawableSize; + cur_fb_width = (int) fb_size.width; + cur_fb_height = (int) fb_size.height; + #else + #error "FIXME GL!" #endif + const bool dim_changed = (win->framebuffer_width != cur_fb_width) || + (win->framebuffer_height != cur_fb_height); + if (dim_changed) { + #if defined(SOKOL_METAL) + CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; + win->macos.view.drawableSize = drawable_size; + #else + #error "FIXME GL!" + #endif + if (!_sapp.first_frame) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); + } + } } _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(_sapp_window_t* win) { @@ -3760,21 +3772,26 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @implementation _sapp_macos_app_delegate - (void)drawFrame { + _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { + /* NOTE: the MTKView drawables MUST be resized right before the dummy draw + invocation, *NOT* from within the event loop, this is because + MTKView lazily resizes some "secondary" surfaces at the start + of the draw method before drawRect callback is called. Setting + the drawableSize in the event loop causes currentRenderPassDescriptor + to return a render pass descriptor with different surfaces sizes + */ + _sapp_macos_update_dimensions(win); #if defined(SOKOL_METAL) - // FIXME: MTKView.draw must be called before currentRenderPassDescriptor - // so that it correctly updates its render target sizes... - // this may be a good reason to drop MTKView :/ [win->macos.view draw]; #else #error "FIXME: GL" #endif } } - _sapp_frame(); if (_sapp.quit_requested && !_sapp.quit_ordered) { _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); if (win) { @@ -3864,24 +3881,12 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( if (self.win_id != _sapp.main_window_id) { _sapp_window_t* win = _sapp_lookup_window(self.win_id); if (win) { - // FIXME: send window close event // destroy state associated with the window _sapp_destroy_window(self.win_id); } } } -- (void)windowDidResize:(NSNotification*)notification { - _SOKOL_UNUSED(notification); - _sapp_window_t* win = _sapp_lookup_window(self.win_id); - if (win) { - _sapp_macos_update_dimensions(win); - if (!_sapp.first_frame) { - _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); - } - } -} - - (void)windowDidMiniaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); _sapp_window_t* win = _sapp_lookup_window(self.win_id); From 9ece3f19a43165d8555dd61b8aa39aac7ab9722d Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Wed, 5 May 2021 19:57:21 +0200 Subject: [PATCH 28/49] sokol_app.h: window closed event --- sokol_app.h | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 07c45566b..f89737732 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1057,6 +1057,7 @@ typedef enum sapp_event_type { SAPP_EVENTTYPE_QUIT_REQUESTED, SAPP_EVENTTYPE_CLIPBOARD_PASTED, SAPP_EVENTTYPE_FILES_DROPPED, + SAPP_EVENTTYPE_WINDOW_CLOSED, _SAPP_EVENTTYPE_NUM, _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFFF } sapp_event_type; @@ -1247,6 +1248,7 @@ enum { */ typedef struct sapp_event { uint64_t frame_count; // current frame counter, always valid, useful for checking if two events were issued in the same frame + sapp_window window; // the window this event is associated with sapp_event_type type; // the event type, always valid sapp_keycode key_code; // the virtual key code, only valid in KEY_UP, KEY_DOWN uint32_t char_code; // the UTF-32 character code, only valid in CHAR events @@ -2754,6 +2756,27 @@ _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) { } } +_SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* win, sapp_event_type type) { + memset(&_sapp.event, 0, sizeof(_sapp.event)); + _sapp.event.type = type; + _sapp.event.window = _sapp_make_window_id(win->slot.id); + _sapp.event.frame_count = _sapp.frame_count; + _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; + _sapp.event.window_width = win->window_width; + _sapp.event.window_height = win->window_height; + _sapp.event.framebuffer_width = win->framebuffer_width; + _sapp.event.framebuffer_height = win->framebuffer_height; + _sapp.event.mouse_x = win->mouse.x; + _sapp.event.mouse_y = win->mouse.y; + _sapp.event.mouse_dx = win->mouse.dx; + _sapp.event.mouse_dy = win->mouse.dy; +} + +_SOKOL_PRIVATE bool _sapp_events_enabled(void) { + /* only send events when an event callback is set, and the init function was called */ + return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called && !_sapp.cleanup_called; +} + _SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) { SOKOL_ASSERT(_sapp.drop.buffer); SOKOL_ASSERT((index >= 0) && (index <= _sapp.drop.max_files)); @@ -2926,6 +2949,10 @@ _SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_drop_t* drop) { _SOKOL_PRIVATE void _sapp_destroy_window(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); SOKOL_ASSERT(win); + if (_sapp_events_enabled() && (win_id != _sapp.main_window_id)) { + _sapp_init_event(win, SAPP_EVENTTYPE_WINDOW_CLOSED); + _sapp_call_event(&_sapp.event); + } _sapp_platform_destroy_window(win); _sapp_free_window_id(win_id); _SAPP_CLEAR_PTR(_sapp_window_t, win); @@ -3004,26 +3031,6 @@ _SOKOL_PRIVATE void _sapp_discard_state(void) { _SAPP_CLEAR_ITEM(_sapp_t, _sapp); } -_SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* win, sapp_event_type type) { - memset(&_sapp.event, 0, sizeof(_sapp.event)); - _sapp.event.type = type; - _sapp.event.frame_count = _sapp.frame_count; - _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID; - _sapp.event.window_width = win->window_width; - _sapp.event.window_height = win->window_height; - _sapp.event.framebuffer_width = win->framebuffer_width; - _sapp.event.framebuffer_height = win->framebuffer_height; - _sapp.event.mouse_x = win->mouse.x; - _sapp.event.mouse_y = win->mouse.y; - _sapp.event.mouse_dx = win->mouse.dx; - _sapp.event.mouse_dy = win->mouse.dy; -} - -_SOKOL_PRIVATE bool _sapp_events_enabled(void) { - /* only send events when an event callback is set, and the init function was called */ - return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called; -} - _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) { if ((scan_code >= 0) && (scan_code < SAPP_MAX_KEYCODES)) { return _sapp.keycodes[scan_code]; From 2f6c1a55446b653bd9bd3463c0bca454dbc788b7 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 11 May 2021 19:54:24 +0200 Subject: [PATCH 29/49] add a temp fixme comment --- sokol_app.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sokol_app.h b/sokol_app.h index f89737732..890a9eca8 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -11547,7 +11547,8 @@ SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { SOKOL_API_IMPL void sapp_close_window(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - // FIXME FIXME FIXME + // FIXME FIXME FIXME: this just sets a flag, closing windows happens + // at end of current frame! } SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { From 1183c90e16da3e6df3de7387762ba6c5e27ab523 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 13 May 2021 13:41:51 +0200 Subject: [PATCH 30/49] sokol_app.h: per-window user data --- sokol_app.h | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 890a9eca8..0ef22cde8 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1347,6 +1347,7 @@ typedef struct sapp_window_desc { bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR + void* user_data; } sapp_window_desc; typedef struct sapp_gl_desc { @@ -1377,12 +1378,12 @@ typedef struct sapp_desc { void (*cleanup_cb)(void); void (*event_cb)(const sapp_event*); - void* user_data; // these are the user-provided callbacks with user data - void (*init_userdata_cb)(void*); + void (*init_userdata_cb)(void*); // these are the user-provided callbacks with user data void (*frame_userdata_cb)(void*); void (*cleanup_userdata_cb)(void*); void (*event_userdata_cb)(const sapp_event*, void*); + void* user_data; int window_pool_size; const char* window_title; // the window title as UTF-8 encoded string int x; @@ -1501,6 +1502,8 @@ SOKOL_APP_API_DECL bool sapp_is_fullscreen(void); SOKOL_APP_API_DECL void sapp_toggle_fullscreen(void); /* set the main window title (only on desktop platforms) */ SOKOL_APP_API_DECL void sapp_set_title(const char* str); +/* get main window userdata pointer */ +SOKOL_APP_API_DECL void* sapp_userdata(void); /*=== multi-window functions =================================================*/ @@ -1518,8 +1521,6 @@ SOKOL_APP_API_DECL sapp_window sapp_first_window(void); SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); /* test if a window handle is valid */ SOKOL_APP_API_DECL bool sapp_valid_window(sapp_window window); -/* get window handle's slot index (>= 0 and < sapp_desc.window_pool_size, useful for associating data with windows) */ -SOKOL_APP_API_DECL int sapp_window_index(sapp_window window); /* get window's framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_window_width(sapp_window window); /* same as sapp_window_width(), but returns float */ @@ -1538,8 +1539,10 @@ SOKOL_APP_API_DECL float sapp_window_dpi_scale(sapp_window window); SOKOL_APP_API_DECL bool sapp_window_is_fullscreen(sapp_window window); /* toggle a window to and from fullscreen mode */ SOKOL_APP_API_DECL void sapp_window_toggle_fullscreen(sapp_window window); -/* set window's title (only on desktop platforms) */ +/* set window title (only on desktop platforms) */ SOKOL_APP_API_DECL void sapp_window_set_title(sapp_window window, const char* str); +/* get window userdata pointer */ +SOKOL_APP_API_DECL void* sapp_window_userdata(sapp_window window); // FIXME FIXME FIXME: are these per window or better global? @@ -2854,6 +2857,7 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_desc_to_window_desc(const sapp_desc* desc) wdesc.fullscreen = desc->fullscreen; wdesc.alpha = desc->alpha; wdesc.user_cursor = desc->user_cursor; + wdesc.user_data = desc->user_data; return wdesc; } @@ -11315,6 +11319,16 @@ _SOKOL_PRIVATE void _sapp_window_set_title(uint32_t win_id, const char* title) { } } +_SOKOL_PRIVATE void* _sapp_window_userdata(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->desc.user_data; + } + else { + return 0; + } +} + /*== PUBLIC API FUNCTIONS ====================================================*/ #if defined(SOKOL_NO_ENTRY) SOKOL_API_IMPL void sapp_run(const sapp_desc* desc) { @@ -11538,6 +11552,11 @@ SOKOL_API_IMPL void sapp_set_title(const char* title) { _sapp_window_set_title(_sapp.main_window_id, title); } +SOKOL_API_IMPL void* sapp_userdata(void) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_userdata(_sapp.main_window_id); +} + SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { SOKOL_ASSERT(_sapp.valid); SOKOL_ASSERT(in_desc); @@ -11582,16 +11601,6 @@ SOKOL_API_IMPL bool sapp_valid_window(sapp_window window) { return 0 != _sapp_lookup_window(window.id); } -SOKOL_API_IMPL int sapp_window_index(sapp_window window) { - SOKOL_ASSERT(_sapp.valid); - SOKOL_ASSERT(SAPP_INVALID_ID != window.id); - int slot_index = _sapp_slot_index(window.id); - SOKOL_ASSERT(slot_index > 0); - slot_index -= 1; - SOKOL_ASSERT(slot_index < _sapp.desc.window_pool_size); - return slot_index; -} - SOKOL_API_IMPL int sapp_window_width(sapp_window window) { SOKOL_ASSERT(_sapp.valid); return _sapp_window_width(window.id); @@ -11642,6 +11651,11 @@ SOKOL_API_IMPL void sapp_window_set_title(sapp_window window, const char* title) _sapp_window_set_title(window.id, title); } +SOKOL_API_IMPL void* sapp_window_userdata(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_userdata(window.id); +} + /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { SOKOL_ASSERT(_sapp.valid); From 4260fb4c6ea02c9b91bc752b7e2db9572a084a69 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 13 May 2021 18:45:22 +0200 Subject: [PATCH 31/49] sokol_app.h: programmatic window close --- sokol_app.h | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 0ef22cde8..bbbb30ed4 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2475,39 +2475,46 @@ _SOKOL_PRIVATE void _sapp_macos_init_state(void); _SOKOL_PRIVATE void _sapp_macos_discard_state(void); _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_IOS) _SOKOL_PRIVATE void _sapp_ios_init_state(void); _SOKOL_PRIVATE void _sapp_ios_discard_state(void); _SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_ios_close_window(_sapp_window_t* win); #elif defined(_SAPP_EMSCRIPTEN) _SOKOL_PRIVATE void _sapp_emsc_init_state(void); _SOKOL_PRIVATE void _sapp_emsc_discard_state(void); _SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_emsc_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_WIN32) _SOKOL_PRIVATE void _sapp_win32_init_state(void); _SOKOL_PRIVATE void _sapp_win32_discard_state(void); _SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_UWP) _SOKOL_PRIVATE void _sapp_uwp_init_state(void); _SOKOL_PRIVATE void _sapp_uwp_discard_state(void); _SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_uwp_close_window(_sapp_window_t* win); #elif defined(_SAPP_ANDROID) _SOKOL_PRIVATE void _sapp_android_init_state(void); _SOKOL_PRIVATE void _sapp_android_discard_state(void); _SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_android_close_window(_sapp_window_t* win); #elif defined(_SAPP_LINUX) _SOKOL_PRIVATE void _sapp_x11_init_state(void); _SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* desc, int num_images); #endif @@ -2682,6 +2689,24 @@ _SOKOL_PRIVATE void _sapp_platform_destroy_window(_sapp_window_t* win) { #endif } +_SOKOL_PRIVATE void _sapp_platform_close_window(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + _sapp_macos_close_window(win); + #elif defined(_SAPP_IOS) + _sapp_ios_close_window(win); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_close_window(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_close_window(win); + #elif defined(_SAPP_UWP) + _sapp_uwp_close_window(win); + #elif defined(_SAPP_ANDROID) + _sapp_android_close_window(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_close_window(win); + #endif +} + _SOKOL_PRIVATE void _sapp_platform_set_icon(const sapp_icon_desc* desc, int num_images) { #if defined(_SAPP_MACOS) _sapp_macos_set_icon(desc, num_images); @@ -3511,6 +3536,12 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { _SAPP_OBJC_RELEASE(win->macos.window); } +_SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win) { + SOKOL_ASSERT(win); + SOKOL_ASSERT(win->macos.window); + [win->macos.window close]; +} + /* MacOS entry function */ #if !defined(SOKOL_NO_ENTRY) int main(int argc, char* argv[]) { @@ -3805,9 +3836,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } if (_sapp.quit_requested && !_sapp.quit_ordered) { _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); - if (win) { - [win->macos.window performClose:nil]; - } + _sapp_macos_close_window(win); } if (_sapp.quit_ordered) { [NSApp terminate:self]; @@ -11566,8 +11595,10 @@ SOKOL_API_IMPL sapp_window sapp_open_window(const sapp_window_desc* in_desc) { SOKOL_API_IMPL void sapp_close_window(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - // FIXME FIXME FIXME: this just sets a flag, closing windows happens - // at end of current frame! + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + _sapp_platform_close_window(win); + } } SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { From 9738382f449efd1073eafb5e17d0b2109c193750 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 16 May 2021 21:53:43 +0200 Subject: [PATCH 32/49] more multiwindow wip --- sokol_app.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index bbbb30ed4..062b45740 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1529,6 +1529,14 @@ SOKOL_APP_API_DECL float sapp_window_widthf(sapp_window window); SOKOL_APP_API_DECL int sapp_window_height(sapp_window window); /* same as sapp_window_height(), but returns float */ SOKOL_APP_API_DECL float sapp_window_heightf(sapp_window window); +/* get x window position */ +SOKOL_APP_API_DECL int sapp_window_posx(sapp_window window); +/* get x window position as float */ +SOKOL_APP_API_DECL float sapp_window_posxf(sapp_window window); +/* get y window position */ +SOKOL_APP_API_DECL int sapp_window_posy(sapp_window window); +/* get y window position as float */ +SOKOL_APP_API_DECL float sapp_window_posyf(sapp_window window); /* get a window's sample count */ SOKOL_APP_API_DECL int sapp_window_sample_count(sapp_window window); /* returns true when high_dpi was requested for a window, and actually running in a high-dpi scenario */ @@ -3605,11 +3613,22 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type t } } +_SOKOL_PRIVATE int _sapp_macos_flipy(_sapp_window_t* win, int y) { + NSRect screen_rect = win->macos.window.screen.frame; + return screen_rect.size.height - y - 1; +} + +_SOKOL_PRIVATE void _sapp_macos_update_window_position(_sapp_window_t* win) { + const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; + win->pos_x = content_rect.origin.x; + win->pos_y = _sapp_macos_flipy(win, content_rect.origin.y); +} + /* NOTE: unlike the iOS version of this function, the macOS version can dynamically update the DPI scaling factor when a window is moved between HighDPI / LowDPI screens. */ -_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { +_SOKOL_PRIVATE void _sapp_macos_update_framebuffer_dimensions(_sapp_window_t* win) { #if defined(SOKOL_METAL) /* FIXME: hmm dpi_scale is used here with the old value, but updated further down... this looks wrong? @@ -3814,6 +3833,13 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @implementation _sapp_macos_app_delegate - (void)drawFrame { + for (int i = 0; i < _sapp.window_pool.pool.size; i++) { + const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + _sapp_macos_update_window_position(win); + } + } _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; @@ -3826,7 +3852,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( the drawableSize in the event loop causes currentRenderPassDescriptor to return a render pass descriptor with different surfaces sizes */ - _sapp_macos_update_dimensions(win); + _sapp_macos_update_framebuffer_dimensions(win); #if defined(SOKOL_METAL) [win->macos.view draw]; #else @@ -3855,7 +3881,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); - _sapp_macos_update_dimensions(win); + _sapp_macos_update_framebuffer_dimensions(win); // setup display link // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc @@ -4034,7 +4060,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( - (void)reshape { _sapp_window_t* win = _sapp_lookup_window(self.win_id); if (win) { - _sapp_macos_update_dimensions(win); + _sapp_macos_update_framebuffer_dimensions(win); } [super reshape]; } @@ -11288,6 +11314,26 @@ _SOKOL_PRIVATE int _sapp_window_height(uint32_t win_id) { } } +_SOKOL_PRIVATE int _sapp_window_posx(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->pos_x; + } + else { + return 0; + } +} + +_SOKOL_PRIVATE int _sapp_window_posy(uint32_t win_id) { + const _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + return win->pos_y; + } + else { + return 0; + } +} + _SOKOL_PRIVATE bool _sapp_window_high_dpi(uint32_t win_id) { const _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { @@ -11652,6 +11698,26 @@ SOKOL_API_IMPL float sapp_window_heightf(sapp_window window) { return (float)_sapp_window_height(window.id); } +SOKOL_API_IMPL int sapp_window_posx(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_posx(window.id); +} + +SOKOL_API_IMPL float sapp_window_posxf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_posx(window.id); +} + +SOKOL_API_IMPL int sapp_window_posy(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_posy(window.id); +} + +SOKOL_API_IMPL float sapp_window_posyf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_posy(window.id); +} + SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window) { SOKOL_ASSERT(_sapp.valid); return _sapp_window_sample_count(window.id); From 64afd39ccc8baa4b7659c869587c9a87ffa1b849 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 17 May 2021 19:51:32 +0200 Subject: [PATCH 33/49] sokol_app.h: start with window pos/size API --- sokol_app.h | 368 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 335 insertions(+), 33 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 062b45740..7cbb8c38c 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1490,6 +1490,33 @@ SOKOL_APP_API_DECL float sapp_widthf(void); SOKOL_APP_API_DECL int sapp_height(void); /* same as sapp_height(), but returns float */ SOKOL_APP_API_DECL float sapp_heightf(void); + +/* set client rect size in logical 'window system pixels' */ +SOKOL_APP_API_DECL void sapp_set_client_size(int width, int height); +/* same as sapp_set_client_size(), but with float parameters */ +SOKOL_APP_API_DECL void sapp_set_client_sizef(float width, float height); +/* get client rect width in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_client_width(void); +/* same as sapp_client_width() but returns float */ +SOKOL_APP_API_DECL float sapp_client_widthf(void); +/* get client rect height in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_client_height(void); +/* same as sapp_client_height() but returns float */ +SOKOL_APP_API_DECL float sapp_client_heightf(void); + +/* set client rect position in logical 'window system pixels' */ +SOKOL_APP_API_DECL void sapp_set_client_pos(int x, int y); +/* same as sapp_set_client_pos(), but with float parameters */ +SOKOL_APP_API_DECL void sapp_set_client_posf(float x, float y); +/* get client rect horizontal position in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_client_posx(void); +/* same as sapp_client_posx(), but returns float */ +SOKOL_APP_API_DECL float sapp_client_posxf(void); +/* get client rect vertical position in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_client_posy(void); +/* same as sapp_client_posy(), but returns float */ +SOKOL_APP_API_DECL float sapp_client_posyf(void); + /* get main window's sample count */ SOKOL_APP_API_DECL int sapp_sample_count(void); /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ @@ -1521,6 +1548,7 @@ SOKOL_APP_API_DECL sapp_window sapp_first_window(void); SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); /* test if a window handle is valid */ SOKOL_APP_API_DECL bool sapp_valid_window(sapp_window window); + /* get window's framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_window_width(sapp_window window); /* same as sapp_window_width(), but returns float */ @@ -1529,14 +1557,33 @@ SOKOL_APP_API_DECL float sapp_window_widthf(sapp_window window); SOKOL_APP_API_DECL int sapp_window_height(sapp_window window); /* same as sapp_window_height(), but returns float */ SOKOL_APP_API_DECL float sapp_window_heightf(sapp_window window); -/* get x window position */ -SOKOL_APP_API_DECL int sapp_window_posx(sapp_window window); -/* get x window position as float */ -SOKOL_APP_API_DECL float sapp_window_posxf(sapp_window window); -/* get y window position */ -SOKOL_APP_API_DECL int sapp_window_posy(sapp_window window); -/* get y window position as float */ -SOKOL_APP_API_DECL float sapp_window_posyf(sapp_window window); + +/* set window's client rect size in logical 'window system pixels' */ +SOKOL_APP_API_DECL void sapp_window_set_client_size(sapp_window window, int width, int height); +/* same as sapp_window_set_client_size(), but with float parameters */ +SOKOL_APP_API_DECL void sapp_window_set_client_sizef(sapp_window window, float width, float height); +/* get window's client rect width in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_window_client_width(sapp_window window); +/* same as sapp_window_client_width() but returns float */ +SOKOL_APP_API_DECL float sapp_window_client_widthf(sapp_window window); +/* get window's client rect height in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_window_client_height(sapp_window window); +/* same as sapp_client_height() but returns float */ +SOKOL_APP_API_DECL float sapp_window_client_heightf(sapp_window window); + +/* set window's client rect position in logical 'window system pixels' */ +SOKOL_APP_API_DECL void sapp_window_set_client_pos(sapp_window window, int x, int y); +/* same as sapp_window_set_client_pos(), but with float parameters */ +SOKOL_APP_API_DECL void sapp_window_set_client_posf(sapp_window window, float x, float y); +/* get window's client rect horizontal position in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_window_client_posx(sapp_window window); +/* same as sapp_window_client_posx(), but returns float */ +SOKOL_APP_API_DECL float sapp_window_client_posxf(sapp_window window); +/* get window's client rect vertical position in logical 'window system pixels' */ +SOKOL_APP_API_DECL int sapp_window_client_posy(sapp_window window); +/* same as sapp_window_client_posy(), but returns float */ +SOKOL_APP_API_DECL float sapp_window_client_posyf(sapp_window window); + /* get a window's sample count */ SOKOL_APP_API_DECL int sapp_window_sample_count(sapp_window window); /* returns true when high_dpi was requested for a window, and actually running in a high-dpi scenario */ @@ -2484,6 +2531,10 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void); _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_macos_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_IOS) _SOKOL_PRIVATE void _sapp_ios_init_state(void); @@ -2491,12 +2542,20 @@ _SOKOL_PRIVATE void _sapp_ios_discard_state(void); _SOKOL_PRIVATE bool _sapp_ios_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_ios_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_ios_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_ios_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_ios_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_ios_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_ios_get_window_size(_sapp_window_t* win, int* w, int* h); #elif defined(_SAPP_EMSCRIPTEN) _SOKOL_PRIVATE void _sapp_emsc_init_state(void); _SOKOL_PRIVATE void _sapp_emsc_discard_state(void); _SOKOL_PRIVATE bool _sapp_emsc_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_emsc_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_emsc_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_emsc_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_emsc_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_emsc_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_emsc_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_WIN32) _SOKOL_PRIVATE void _sapp_win32_init_state(void); @@ -2504,6 +2563,10 @@ _SOKOL_PRIVATE void _sapp_win32_discard_state(void); _SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_win32_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_win32_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_win32_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_win32_set_icon(const sapp_icon_desc* desc, int num_images); #elif defined(_SAPP_UWP) _SOKOL_PRIVATE void _sapp_uwp_init_state(void); @@ -2511,18 +2574,30 @@ _SOKOL_PRIVATE void _sapp_uwp_discard_state(void); _SOKOL_PRIVATE bool _sapp_uwp_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_uwp_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_uwp_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_uwp_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_uwp_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_uwp_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_uwp_get_window_size(_sapp_window_t* win, int* w, int* h); #elif defined(_SAPP_ANDROID) _SOKOL_PRIVATE void _sapp_android_init_state(void); _SOKOL_PRIVATE void _sapp_android_discard_state(void); _SOKOL_PRIVATE bool _sapp_android_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_android_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_android_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_android_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_android_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_android_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_android_get_window_size(_sapp_window_t* win, int* w, int* h); #elif defined(_SAPP_LINUX) _SOKOL_PRIVATE void _sapp_x11_init_state(void); _SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_set_window_pos(_sapp_window_t* win, int x, int y); +_SOKOL_PRIVATE void _sapp_x11_get_window_pos(_sapp_window_t* win, int* x, int* y); +_SOKOL_PRIVATE void _sapp_x11_set_window_size(_sapp_window_t* win, int w, int h); +_SOKOL_PRIVATE void _sapp_x11_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* desc, int num_images); #endif @@ -2715,6 +2790,78 @@ _SOKOL_PRIVATE void _sapp_platform_close_window(_sapp_window_t* win) { #endif } +_SOKOL_PRIVATE void _sapp_platform_set_window_pos(_sapp_window_t* win, int x, int y) { + #if defined(_SAPP_MACOS) + _sapp_macos_set_window_pos(win, x, y); + #elif defined(_SAPP_IOS) + _sapp_ios_set_window_pos(win, x, y); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_set_window_pos(win, x, y); + #elif defined(_SAPP_WIN32) + _sapp_win32_set_window_pos(win, x, y); + #elif defined(_SAPP_UWP) + _sapp_uwp_set_window_pos(win, x, y); + #elif defined(_SAPP_ANDROID) + _sapp_android_set_window_pos(win, x, y); + #elif defined(_SAPP_LINUX) + _sapp_x11_set_window_pos(win, x, y); + #endif +} + +_SOKOL_PRIVATE void _sapp_platform_get_window_pos(_sapp_window_t* win, int* x, int* y) { + #if defined(_SAPP_MACOS) + _sapp_macos_get_window_pos(win, x, y); + #elif defined(_SAPP_IOS) + _sapp_ios_get_window_pos(win, x, y); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_get_window_pos(win, x, y); + #elif defined(_SAPP_WIN32) + _sapp_win32_get_window_pos(win, x, y); + #elif defined(_SAPP_UWP) + _sapp_uwp_get_window_pos(win, x, y); + #elif defined(_SAPP_ANDROID) + _sapp_android_get_window_pos(win, x, y); + #elif defined(_SAPP_LINUX) + _sapp_x11_get_window_pos(win, x, y); + #endif +} + +_SOKOL_PRIVATE void _sapp_platform_set_window_size(_sapp_window_t* win, int w, int h) { + #if defined(_SAPP_MACOS) + _sapp_macos_set_window_size(win, w, h); + #elif defined(_SAPP_IOS) + _sapp_ios_set_window_size(win, w, h); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_set_window_size(win, w, h); + #elif defined(_SAPP_WIN32) + _sapp_win32_set_window_size(win, w, h); + #elif defined(_SAPP_UWP) + _sapp_uwp_set_window_size(win, w, h); + #elif defined(_SAPP_ANDROID) + _sapp_android_set_window_size(win, w, h); + #elif defined(_SAPP_LINUX) + _sapp_x11_set_window_size(win, w, h); + #endif +} + +_SOKOL_PRIVATE void _sapp_platform_get_window_size(_sapp_window_t* win, int* w, int* h) { + #if defined(_SAPP_MACOS) + _sapp_macos_get_window_size(win, w, h); + #elif defined(_SAPP_IOS) + _sapp_ios_get_window_size(win, w, h); + #elif defined(_SAPP_EMSCRIPTEN) + _sapp_emsc_get_window_size(win, w, h); + #elif defined(_SAPP_WIN32) + _sapp_win32_get_window_size(win, w, h); + #elif defined(_SAPP_UWP) + _sapp_uwp_get_window_size(win, w, h); + #elif defined(_SAPP_ANDROID) + _sapp_android_get_window_size(win, w, h); + #elif defined(_SAPP_LINUX) + _sapp_x11_get_window_size(win, w, h); + #endif +} + _SOKOL_PRIVATE void _sapp_platform_set_icon(const sapp_icon_desc* desc, int num_images) { #if defined(_SAPP_MACOS) _sapp_macos_set_icon(desc, num_images); @@ -3618,6 +3765,26 @@ _SOKOL_PRIVATE int _sapp_macos_flipy(_sapp_window_t* win, int y) { return screen_rect.size.height - y - 1; } +_SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y) { + //FIXME FIXME FIXME +} + +_SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y) { + //FIXME FIXME FIXME + *x = 0; + *y = 0; +} + +_SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h) { + //FIXME FIXME FIXME +} + +_SOKOL_PRIVATE void _sapp_macos_get_window_size(_sapp_window_t* win, int* w, int* h) { + // FIXME FIXME FIXME + *w = 1; + *h = 1; +} + _SOKOL_PRIVATE void _sapp_macos_update_window_position(_sapp_window_t* win) { const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; win->pos_x = content_rect.origin.x; @@ -3628,7 +3795,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_position(_sapp_window_t* win) { can dynamically update the DPI scaling factor when a window is moved between HighDPI / LowDPI screens. */ -_SOKOL_PRIVATE void _sapp_macos_update_framebuffer_dimensions(_sapp_window_t* win) { +_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { #if defined(SOKOL_METAL) /* FIXME: hmm dpi_scale is used here with the old value, but updated further down... this looks wrong? @@ -3833,13 +4000,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @implementation _sapp_macos_app_delegate - (void)drawFrame { - for (int i = 0; i < _sapp.window_pool.pool.size; i++) { - const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; - _sapp_window_t* win = _sapp_lookup_window(win_id); - if (win) { - _sapp_macos_update_window_position(win); - } - } _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; @@ -3852,7 +4012,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( the drawableSize in the event loop causes currentRenderPassDescriptor to return a render pass descriptor with different surfaces sizes */ - _sapp_macos_update_framebuffer_dimensions(win); + _sapp_macos_update_dimensions(win); #if defined(SOKOL_METAL) [win->macos.view draw]; #else @@ -3881,7 +4041,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); SOKOL_ASSERT(win); - _sapp_macos_update_framebuffer_dimensions(win); + _sapp_macos_update_dimensions(win); // setup display link // see: https://developer.apple.com/documentation/metal/drawable_objects/creating_a_custom_metal_view?language=objc @@ -4060,7 +4220,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( - (void)reshape { _sapp_window_t* win = _sapp_lookup_window(self.win_id); if (win) { - _sapp_macos_update_framebuffer_dimensions(win); + _sapp_macos_update_dimensions(win); } [super reshape]; } @@ -11314,20 +11474,62 @@ _SOKOL_PRIVATE int _sapp_window_height(uint32_t win_id) { } } -_SOKOL_PRIVATE int _sapp_window_posx(uint32_t win_id) { - const _sapp_window_t* win = _sapp_lookup_window(win_id); +_SOKOL_PRIVATE void _sapp_window_set_client_size(uint32_t win_id, int w, int h) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + _sapp_platform_set_window_size(win, w, h); + } +} + +_SOKOL_PRIVATE int _sapp_window_client_width(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + int w, h; + _sapp_platform_get_window_size(win, &w, &h); + return w; + } + else { + return 1; + } +} + +_SOKOL_PRIVATE int _sapp_window_client_height(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - return win->pos_x; + int w, h; + _sapp_platform_get_window_size(win, &w, &h); + return h; + } + else { + return 1; + } +} + +_SOKOL_PRIVATE void _sapp_window_set_client_pos(uint32_t win_id, int x, int y) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + _sapp_platform_set_window_pos(win, x, y); + } +} + +_SOKOL_PRIVATE int _sapp_window_client_posx(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + int x, y; + _sapp_platform_get_window_pos(win, &x, &y); + return x; } else { return 0; } } -_SOKOL_PRIVATE int _sapp_window_posy(uint32_t win_id) { - const _sapp_window_t* win = _sapp_lookup_window(win_id); +_SOKOL_PRIVATE int _sapp_window_client_posy(uint32_t win_id) { + _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - return win->pos_y; + int x, y; + _sapp_platform_get_window_pos(win, &x, &y); + return y; } else { return 0; @@ -11597,6 +11799,66 @@ SOKOL_API_IMPL float sapp_heightf(void) { return (float)_sapp_window_height(_sapp.main_window_id); } +SOKOL_API_IMPL void sapp_set_client_size(int width, int height) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_size(_sapp.main_window_id, width, height); +} + +SOKOL_API_IMPL void sapp_set_client_sizef(float width, float height) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_size(_sapp.main_window_id, (int)width, (int)height); +} + +SOKOL_API_IMPL int sapp_client_width(void) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_width(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_client_widthf(void) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_width(_sapp.main_window_id); +} + +SOKOL_API_IMPL int sapp_client_height(void) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_height(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_client_heightf(void) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_height(_sapp.main_window_id); +} + +SOKOL_API_IMPL void sapp_set_client_pos(int x, int y) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_pos(_sapp.main_window_id, x, y); +} + +SOKOL_API_IMPL void sapp_set_client_posf(float x, float y) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_pos(_sapp.main_window_id, (int)x, (int)y); +} + +SOKOL_API_IMPL int sapp_client_posx(void) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_posx(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_client_posxf(void) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_posx(_sapp.main_window_id); +} + +SOKOL_API_IMPL int sapp_client_posy(void) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_posy(_sapp.main_window_id); +} + +SOKOL_API_IMPL float sapp_client_posyf(void) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_posy(_sapp.main_window_id); +} + SOKOL_API_IMPL int sapp_sample_count(void) { SOKOL_ASSERT(_sapp.valid); return _sapp_window_sample_count(_sapp.main_window_id); @@ -11698,24 +11960,64 @@ SOKOL_API_IMPL float sapp_window_heightf(sapp_window window) { return (float)_sapp_window_height(window.id); } -SOKOL_API_IMPL int sapp_window_posx(sapp_window window) { +SOKOL_API_IMPL void sapp_window_set_client_size(sapp_window window, int width, int height) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_size(window.id, width, height); +} + +SOKOL_API_IMPL void sapp_window_set_client_sizef(sapp_window window, float width, float height) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_size(window.id, (int)width, (int)height); +} + +SOKOL_API_IMPL int sapp_window_client_width(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_width(window.id); +} + +SOKOL_API_IMPL float sapp_window_client_widthf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_width(window.id); +} + +SOKOL_API_IMPL int sapp_window_client_height(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return _sapp_window_client_height(window.id); +} + +SOKOL_API_IMPL float sapp_window_client_heightf(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + return (float)_sapp_window_client_height(window.id); +} + +SOKOL_API_IMPL void sapp_window_set_client_pos(sapp_window window, int x, int y) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_pos(window.id, x, y); +} + +SOKOL_API_IMPL void sapp_window_set_client_posf(sapp_window window, float x, float y) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_set_client_pos(window.id, (int)x, (int)y); +} + +SOKOL_API_IMPL int sapp_window_client_posx(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - return _sapp_window_posx(window.id); + return _sapp_window_client_posx(window.id); } -SOKOL_API_IMPL float sapp_window_posxf(sapp_window window) { +SOKOL_API_IMPL float sapp_window_client_posxf(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - return (float)_sapp_window_posx(window.id); + return (float)_sapp_window_client_posx(window.id); } -SOKOL_API_IMPL int sapp_window_posy(sapp_window window) { +SOKOL_API_IMPL int sapp_window_client_posy(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - return _sapp_window_posy(window.id); + return _sapp_window_client_posy(window.id); } -SOKOL_API_IMPL float sapp_window_posyf(sapp_window window) { +SOKOL_API_IMPL float sapp_window_client_posyf(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - return (float)_sapp_window_posy(window.id); + return (float)_sapp_window_client_posy(window.id); } SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window) { From c858e23c44af8b55e67f2f85bcca289e00732c03 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 23 May 2021 17:31:18 +0200 Subject: [PATCH 34/49] sokol_app.h macos: set/get window pos and size --- sokol_app.h | 66 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 7cbb8c38c..24e4620d1 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3596,9 +3596,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - NSRect window_rect = NSMakeRect(win->pos_x, win->pos_y, win->window_width, win->window_height); + const NSRect content_rect = NSMakeRect(0, 0, win->window_width, win->window_height); win->macos.window = [[_sapp_macos_window alloc] - initWithContentRect:window_rect + initWithContentRect:content_rect styleMask:style backing:NSBackingStoreBuffered defer:NO]; @@ -3676,7 +3676,12 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { [win->macos.window toggleFullScreen:NSApp]; } else { - [win->macos.window center]; + if ((win->pos_x == 0) && (win->pos_y == 0)) { + [win->macos.window center]; + } + else { + _sapp_macos_set_window_pos(win, win->pos_x, win->pos_y); + } } [win->macos.window makeKeyAndOrderFront:nil]; return true; @@ -3761,28 +3766,51 @@ _SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type t } _SOKOL_PRIVATE int _sapp_macos_flipy(_sapp_window_t* win, int y) { + SOKOL_ASSERT(win && (win->macos.window != nil)); NSRect screen_rect = win->macos.window.screen.frame; return screen_rect.size.height - y - 1; } _SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y) { - //FIXME FIXME FIXME + @autoreleasepool { + const NSRect content_rect = [win->macos.window frame]; + const NSRect dummy_rect = NSMakeRect(x, _sapp_macos_flipy(win, y + content_rect.size.height - 1), 0, 0); + const NSRect frame_rect = [win->macos.window frameRectForContentRect:dummy_rect]; + [win->macos.window setFrameOrigin:frame_rect.origin]; + } } _SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y) { - //FIXME FIXME FIXME - *x = 0; - *y = 0; + @autoreleasepool { + const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; + if (x) { + *x = content_rect.origin.x; + } + if (y) { + *y = _sapp_macos_flipy(win, content_rect.origin.y + content_rect.size.height - 1); + } + } } _SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h) { - //FIXME FIXME FIXME + @autoreleasepool { + NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; + content_rect.origin.y += content_rect.size.height - h; + content_rect.size = NSMakeSize(w, h); + [win->macos.window setFrame:[win->macos.window frameRectForContentRect:content_rect] display:YES]; + } } _SOKOL_PRIVATE void _sapp_macos_get_window_size(_sapp_window_t* win, int* w, int* h) { - // FIXME FIXME FIXME - *w = 1; - *h = 1; + @autoreleasepool { + const NSRect content_rect = [win->macos.window frame]; + if (w) { + *w = content_rect.size.width; + } + if (h) { + *h = content_rect.size.height; + } + } } _SOKOL_PRIVATE void _sapp_macos_update_window_position(_sapp_window_t* win) { @@ -11484,8 +11512,8 @@ _SOKOL_PRIVATE void _sapp_window_set_client_size(uint32_t win_id, int w, int h) _SOKOL_PRIVATE int _sapp_window_client_width(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - int w, h; - _sapp_platform_get_window_size(win, &w, &h); + int w; + _sapp_platform_get_window_size(win, &w, 0); return w; } else { @@ -11496,8 +11524,8 @@ _SOKOL_PRIVATE int _sapp_window_client_width(uint32_t win_id) { _SOKOL_PRIVATE int _sapp_window_client_height(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - int w, h; - _sapp_platform_get_window_size(win, &w, &h); + int h; + _sapp_platform_get_window_size(win, 0, &h); return h; } else { @@ -11515,8 +11543,8 @@ _SOKOL_PRIVATE void _sapp_window_set_client_pos(uint32_t win_id, int x, int y) { _SOKOL_PRIVATE int _sapp_window_client_posx(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - int x, y; - _sapp_platform_get_window_pos(win, &x, &y); + int x; + _sapp_platform_get_window_pos(win, &x, 0); return x; } else { @@ -11527,8 +11555,8 @@ _SOKOL_PRIVATE int _sapp_window_client_posx(uint32_t win_id) { _SOKOL_PRIVATE int _sapp_window_client_posy(uint32_t win_id) { _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - int x, y; - _sapp_platform_get_window_pos(win, &x, &y); + int y; + _sapp_platform_get_window_pos(win, 0, &y); return y; } else { From 786220053b30817dad1517237bfeb59236e3145f Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 24 May 2021 14:31:07 +0200 Subject: [PATCH 35/49] sokol_app.h: no_decoration flag and sapp_window_slow_index() function --- sokol_app.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 24e4620d1..f53a3eac3 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1347,6 +1347,7 @@ typedef struct sapp_window_desc { bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR + bool no_decoration; // create main window without window system decorations (title bar etc...) void* user_data; } sapp_window_desc; @@ -1396,6 +1397,7 @@ typedef struct sapp_desc { bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR + bool no_decoration; // create main window without window system decorations (title bar etc...) bool enable_dragndrop; // enable file dropping (drag'n'drop), default is false int max_dropped_files; // max number of dropped files to process (default: 1) @@ -1540,6 +1542,8 @@ SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); /* start rendering into a window */ SOKOL_APP_API_DECL void sapp_activate_window_context(sapp_window window); +/* return an array index for a window handle (to associate your own data with window handle) */ +SOKOL_APP_API_DECL int sapp_window_slot_index(sapp_window window); /* get the main window handle */ SOKOL_APP_API_DECL sapp_window sapp_main_window(void); /* start iterating over windows */ @@ -3037,6 +3041,7 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_desc_to_window_desc(const sapp_desc* desc) wdesc.fullscreen = desc->fullscreen; wdesc.alpha = desc->alpha; wdesc.user_cursor = desc->user_cursor; + wdesc.no_decoration = desc->no_decoration; wdesc.user_data = desc->user_data; return wdesc; } @@ -3591,11 +3596,13 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->framebuffer_height = win->window_height; } win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; - const NSUInteger style = - NSWindowStyleMaskTitled | - NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | - NSWindowStyleMaskResizable; + NSUInteger style = NSWindowStyleMaskMiniaturizable; + if (win->desc.no_decoration) { + style |= NSWindowStyleMaskBorderless; + } + else { + style |= NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable; + } const NSRect content_rect = NSMakeRect(0, 0, win->window_width, win->window_height); win->macos.window = [[_sapp_macos_window alloc] initWithContentRect:content_rect @@ -11942,6 +11949,14 @@ SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { // FIXME FIXME FIXME } +SOKOL_API_IMPL int sapp_window_slot_index(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + SOKOL_ASSERT(0 != _sapp_lookup_window(window.id)); + int slot_index = _sapp_slot_index(window.id); + SOKOL_ASSERT(slot_index >= 1); + return slot_index - 1; +} + SOKOL_API_IMPL sapp_window sapp_main_window(void) { SOKOL_ASSERT(_sapp.valid); return _sapp_make_window_id(_sapp.main_window_id); From bd1a6a7b82accf26d0d57e6ba762a9d7cab93251 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 25 May 2021 20:23:40 +0200 Subject: [PATCH 36/49] sokol_app.h: show/hide window wip --- sokol_app.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index f53a3eac3..7f38fd734 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1347,7 +1347,8 @@ typedef struct sapp_window_desc { bool fullscreen; // whether the window should be created in fullscreen mode bool alpha; // whether the framebuffer should have an alpha channel (ignored on some platforms) bool user_cursor; // if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR - bool no_decoration; // create main window without window system decorations (title bar etc...) + bool no_decoration; // create window without window system decorations (title bar etc...) + bool hidden; // create window in hidden state void* user_data; } sapp_window_desc; @@ -1540,6 +1541,8 @@ SOKOL_APP_API_DECL void* sapp_userdata(void); SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); /* close a window */ SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); +/* test if a window handle is valid */ +SOKOL_APP_API_DECL bool sapp_window_valid(sapp_window window); /* start rendering into a window */ SOKOL_APP_API_DECL void sapp_activate_window_context(sapp_window window); /* return an array index for a window handle (to associate your own data with window handle) */ @@ -1550,8 +1553,12 @@ SOKOL_APP_API_DECL sapp_window sapp_main_window(void); SOKOL_APP_API_DECL sapp_window sapp_first_window(void); /* continue iterating over windows, returns invalid handle when finished */ SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); -/* test if a window handle is valid */ -SOKOL_APP_API_DECL bool sapp_valid_window(sapp_window window); +/* show a hidden window */ +SOKOL_APP_API_DECL void sapp_show_window(sapp_window window); +/* hide a visible window */ +SOKOL_APP_API_DECL void sapp_hide_window(sapp_window window); +/* return true if a window is currently hidden */ +SOKOL_APP_API_DECL bool sapp_window_hidden(sapp_window window); /* get window's framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_window_width(sapp_window window); @@ -2535,6 +2542,8 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void); _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_show_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_hide_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h); @@ -2567,6 +2576,8 @@ _SOKOL_PRIVATE void _sapp_win32_discard_state(void); _SOKOL_PRIVATE bool _sapp_win32_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_show_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_hide_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_win32_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_win32_set_window_size(_sapp_window_t* win, int w, int h); @@ -2598,6 +2609,8 @@ _SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_close_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_show_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_hide_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_x11_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_x11_set_window_size(_sapp_window_t* win, int w, int h); @@ -2794,6 +2807,28 @@ _SOKOL_PRIVATE void _sapp_platform_close_window(_sapp_window_t* win) { #endif } +_SOKOL_PRIVATE void _sapp_platform_show_window(_sapp_window_t* win) { + (void)win; + #if defined(_SAPP_MACOS) + _sapp_macos_show_window(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_show_window(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_close_window(win); + #endif +} + +_SOKOL_PRIVATE void _sapp_platform_hide_window(_sapp_window_t* win) { + (void)win; + #if defined(_SAPP_MACOS) + _sapp_macos_hide_window(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_hide_window(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_hide_window(win); + #endif +} + _SOKOL_PRIVATE void _sapp_platform_set_window_pos(_sapp_window_t* win, int x, int y) { #if defined(_SAPP_MACOS) _sapp_macos_set_window_pos(win, x, y); @@ -11944,6 +11979,26 @@ SOKOL_API_IMPL void sapp_close_window(sapp_window window) { } } +SOKOL_API_IMPL void sapp_show_wndow(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + _sapp_platform_show_window(win); + } +} + +SOKOL_API_IMPL void sapp_hide_window(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + _sapp_platform_hide_window(win); + } +} + +SOKOL_API_IMPL bool sapp_window_visible(sapp_window window) { + FIXME FIXME FIXME +} + SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { SOKOL_ASSERT(_sapp.valid); // FIXME FIXME FIXME From 770583bf82ce605e3049ae38fd6bebf098a305a5 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 27 May 2021 20:22:41 +0200 Subject: [PATCH 37/49] sokol_app.h macos: add remaining multi-window functions --- sokol_app.h | 238 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 183 insertions(+), 55 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 7f38fd734..ae62ed103 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1557,8 +1557,14 @@ SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); SOKOL_APP_API_DECL void sapp_show_window(sapp_window window); /* hide a visible window */ SOKOL_APP_API_DECL void sapp_hide_window(sapp_window window); -/* return true if a window is currently hidden */ -SOKOL_APP_API_DECL bool sapp_window_hidden(sapp_window window); +/* return true if a window is currently visible */ +SOKOL_APP_API_DECL bool sapp_window_visible(sapp_window window); +/* make window focused (bring to front and get keyboard input focus) */ +SOKOL_APP_API_DECL void sapp_focus_window(sapp_window window); +/* test if window is the focus window */ +SOKOL_APP_API_DECL bool sapp_window_focused(sapp_window window); +/* test if window is minimized */ +SOKOL_APP_API_DECL bool sapp_window_minimized(sapp_window window); /* get window's framebuffer width in pixels */ SOKOL_APP_API_DECL int sapp_window_width(sapp_window window); @@ -2544,6 +2550,10 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_show_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_hide_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_macos_window_visible(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_macos_focus_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_macos_window_focused(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_macos_window_minimized(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h); @@ -2578,6 +2588,10 @@ _SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_close_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_show_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_hide_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_win32_window_visible(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_win32_focus_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_win32_window_focused(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_win32_window_minimized(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_win32_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_win32_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_win32_set_window_size(_sapp_window_t* win, int w, int h); @@ -2609,8 +2623,12 @@ _SOKOL_PRIVATE void _sapp_x11_discard_state(void); _SOKOL_PRIVATE bool _sapp_x11_create_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_close_window(_sapp_window_t* win); -_SOKOL_PRIVATE void _sapp_win32_show_window(_sapp_window_t* win); -_SOKOL_PRIVATE void _sapp_win32_hide_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_show_window(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_hide_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_x11_window_visible(_sapp_window_t* win); +_SOKOL_PRIVATE void _sapp_x11_focus_window(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_x11_window_focused(_sapp_window_t* win); +_SOKOL_PRIVATE bool _sapp_x11_window_minimized(_sapp_window_t* win); _SOKOL_PRIVATE void _sapp_x11_set_window_pos(_sapp_window_t* win, int x, int y); _SOKOL_PRIVATE void _sapp_x11_get_window_pos(_sapp_window_t* win, int* x, int* y); _SOKOL_PRIVATE void _sapp_x11_set_window_size(_sapp_window_t* win, int w, int h); @@ -2808,24 +2826,77 @@ _SOKOL_PRIVATE void _sapp_platform_close_window(_sapp_window_t* win) { } _SOKOL_PRIVATE void _sapp_platform_show_window(_sapp_window_t* win) { - (void)win; #if defined(_SAPP_MACOS) _sapp_macos_show_window(win); #elif defined(_SAPP_WIN32) _sapp_win32_show_window(win); #elif defined(_SAPP_LINUX) _sapp_x11_close_window(win); + #else + (void)win; #endif } _SOKOL_PRIVATE void _sapp_platform_hide_window(_sapp_window_t* win) { - (void)win; #if defined(_SAPP_MACOS) _sapp_macos_hide_window(win); #elif defined(_SAPP_WIN32) _sapp_win32_hide_window(win); #elif defined(_SAPP_LINUX) _sapp_x11_hide_window(win); + #else + (void)win; + #endif +} + +_SOKOL_PRIVATE bool _sapp_platform_window_visible(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + return _sapp_macos_window_visible(win); + #elif defined(_SAPP_WIN32) + return _sapp_win32_window_visible(win); + #elif defined(_SAPP_LINUX) + return _sapp_x11_window_visible(win); + #else + (void)win; + return true; + #endif +} + +_SOKOL_PRIVATE void _sapp_platform_focus_window(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + _sapp_macos_focus_window(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_focus_window(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_focus_window(win); + #else + (void)win; + #endif +} + +_SOKOL_PRIVATE bool _sapp_platform_window_focused(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + return _sapp_macos_window_focused(win); + #elif defined(_SAPP_WIN32) + return _sapp_win32_window_focused(win); + #elif defined(_SAPP_LINUX) + return _sapp_x11_window_focused(win); + #else + (void)win; + return true; + #endif +} + +_SOKOL_PRIVATE bool _sapp_platform_window_minimized(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + return _sapp_macos_window_minimized(win); + #elif defined(_SAPP_WIN32) + return _sapp_win32_window_minimized(win); + #elif defined(_SAPP_LINUX) + return _sapp_x11_window_minimized(win); + #else + (void)win; + return false; #endif } @@ -3725,7 +3796,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { _sapp_macos_set_window_pos(win, win->pos_x, win->pos_y); } } - [win->macos.window makeKeyAndOrderFront:nil]; + if (!win->desc.hidden) { + [win->macos.window makeKeyAndOrderFront:nil]; + } return true; } @@ -3739,11 +3812,41 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { } _SOKOL_PRIVATE void _sapp_macos_close_window(_sapp_window_t* win) { - SOKOL_ASSERT(win); - SOKOL_ASSERT(win->macos.window); + SOKOL_ASSERT(win && win->macos.window); [win->macos.window close]; } +_SOKOL_PRIVATE void _sapp_macos_show_window(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + [win->macos.window orderFront:nil]; +} + +_SOKOL_PRIVATE void _sapp_macos_hide_window(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + [win->macos.window orderOut:nil]; +} + +_SOKOL_PRIVATE bool _sapp_macos_window_visible(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + return [win->macos.window isVisible]; +} + +_SOKOL_PRIVATE void _sapp_macos_focus_window(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + // FIXME: see the activateIgnoringOtherApps hack in GLFW, relevant for us? + [win->macos.window makeKeyAndOrderFront:nil]; +} + +_SOKOL_PRIVATE bool _sapp_macos_window_focused(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + return [win->macos.window isKeyWindow]; +} + +_SOKOL_PRIVATE bool _sapp_macos_window_minimized(_sapp_window_t* win) { + SOKOL_ASSERT(win && win->macos.window); + return [win->macos.window isMiniaturized]; +} + /* MacOS entry function */ #if !defined(SOKOL_NO_ENTRY) int main(int argc, char* argv[]) { @@ -3814,44 +3917,36 @@ _SOKOL_PRIVATE int _sapp_macos_flipy(_sapp_window_t* win, int y) { } _SOKOL_PRIVATE void _sapp_macos_set_window_pos(_sapp_window_t* win, int x, int y) { - @autoreleasepool { - const NSRect content_rect = [win->macos.window frame]; - const NSRect dummy_rect = NSMakeRect(x, _sapp_macos_flipy(win, y + content_rect.size.height - 1), 0, 0); - const NSRect frame_rect = [win->macos.window frameRectForContentRect:dummy_rect]; - [win->macos.window setFrameOrigin:frame_rect.origin]; - } + const NSRect content_rect = [win->macos.window frame]; + const NSRect dummy_rect = NSMakeRect(x, _sapp_macos_flipy(win, y + content_rect.size.height - 1), 0, 0); + const NSRect frame_rect = [win->macos.window frameRectForContentRect:dummy_rect]; + [win->macos.window setFrameOrigin:frame_rect.origin]; } _SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* y) { - @autoreleasepool { - const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; - if (x) { - *x = content_rect.origin.x; - } - if (y) { - *y = _sapp_macos_flipy(win, content_rect.origin.y + content_rect.size.height - 1); - } + const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; + if (x) { + *x = content_rect.origin.x; + } + if (y) { + *y = _sapp_macos_flipy(win, content_rect.origin.y + content_rect.size.height - 1); } } _SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h) { - @autoreleasepool { - NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; - content_rect.origin.y += content_rect.size.height - h; - content_rect.size = NSMakeSize(w, h); - [win->macos.window setFrame:[win->macos.window frameRectForContentRect:content_rect] display:YES]; - } + NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; + content_rect.origin.y += content_rect.size.height - h; + content_rect.size = NSMakeSize(w, h); + [win->macos.window setFrame:[win->macos.window frameRectForContentRect:content_rect] display:YES]; } _SOKOL_PRIVATE void _sapp_macos_get_window_size(_sapp_window_t* win, int* w, int* h) { - @autoreleasepool { - const NSRect content_rect = [win->macos.window frame]; - if (w) { - *w = content_rect.size.width; - } - if (h) { - *h = content_rect.size.height; - } + const NSRect content_rect = [win->macos.window frame]; + if (w) { + *w = content_rect.size.width; + } + if (h) { + *h = content_rect.size.height; } } @@ -3928,27 +4023,23 @@ _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(_sapp_window_t* win) { } _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { - @autoreleasepool { - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; - [pasteboard setString:@(str) forType:NSPasteboardTypeString]; - } + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil]; + [pasteboard setString:@(str) forType:NSPasteboardTypeString]; } _SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) { SOKOL_ASSERT(_sapp.clipboard.buffer); - @autoreleasepool { - _sapp.clipboard.buffer[0] = 0; - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return _sapp.clipboard.buffer; - } - NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; - if (!str) { - return _sapp.clipboard.buffer; - } - _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + _sapp.clipboard.buffer[0] = 0; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { + return _sapp.clipboard.buffer; } + NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; + if (!str) { + return _sapp.clipboard.buffer; + } + _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); return _sapp.clipboard.buffer; } @@ -11979,7 +12070,7 @@ SOKOL_API_IMPL void sapp_close_window(sapp_window window) { } } -SOKOL_API_IMPL void sapp_show_wndow(sapp_window window) { +SOKOL_API_IMPL void sapp_show_window(sapp_window window) { SOKOL_ASSERT(_sapp.valid); _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { @@ -11996,7 +12087,44 @@ SOKOL_API_IMPL void sapp_hide_window(sapp_window window) { } SOKOL_API_IMPL bool sapp_window_visible(sapp_window window) { - FIXME FIXME FIXME + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + return _sapp_platform_window_visible(win); + } + else { + return true; + } +} + +SOKOL_API_IMPL void sapp_focus_window(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + _sapp_platform_focus_window(win); + } +} + +SOKOL_API_IMPL bool sapp_window_focused(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + return _sapp_platform_window_focused(win); + } + else { + return false; + } +} + +SOKOL_API_IMPL bool sapp_window_minimized(sapp_window window) { + SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + return _sapp_platform_window_minimized(win); + } + else { + return false; + } } SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { From 3eba4fbb13799e919dcc25f0c561fdfa2a2a8d86 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 27 May 2021 20:29:03 +0200 Subject: [PATCH 38/49] sokol_app.h macos: applicationShouldHandleReopen This application delegate method is called when the dock icon is clicked and will unminimize the main window in case multiple windows are open. --- sokol_app.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sokol_app.h b/sokol_app.h index ae62ed103..b2ed70f04 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -4227,6 +4227,18 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _SOKOL_UNUSED(notification); _sapp_discard_state(); } + +- (BOOL)applicationShouldHandleReopen:(NSApplication*)sender hasVisibleWindows:(BOOL)flag { + _SOKOL_UNUSED(sender); + _SOKOL_UNUSED(flag); + /* unminimize the main window when clicking the dock icon (which doesn't + happen automatically if the application has multiple open windows) + */ + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); + SOKOL_ASSERT(win); + [win->macos.window makeKeyAndOrderFront:nil]; + return YES; +} @end @implementation _sapp_macos_window_delegate From df8a7fd0b56a278dd72e880fde9250bba7ae8f0d Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 29 May 2021 16:53:50 +0200 Subject: [PATCH 39/49] sokol_app.h macos gl: multiwindow wip --- sokol_app.h | 57 +++++++++-------- sokol_gfx.h | 176 ++++++++++++++++++++++++++-------------------------- 2 files changed, 116 insertions(+), 117 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index b2ed70f04..cc56b136b 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3749,10 +3749,10 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8; attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24; attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8; - if (_sapp.sample_count > 1) { + if (win->desc.sample_count > 1) { attrs[i++] = NSOpenGLPFAMultisample; attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; - attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.sample_count; + attrs[i++] = NSOpenGLPFASamples; attrs[i++] = (NSOpenGLPixelFormatAttribute)_sapp.desc.sample_count; } else { attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; @@ -3761,28 +3761,21 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; SOKOL_ASSERT(glpixelformat_obj != nil); - _sapp.macos.view = [[_sapp_macos_view alloc] - initWithFrame:window_rect + win->macos.view = [[_sapp_macos_view alloc] + initWithFrame:content_rect pixelFormat:glpixelformat_obj]; _SAPP_OBJC_RELEASE(glpixelformat_obj); - [_sapp.macos.view updateTrackingAreas]; - if (_sapp.desc.high_dpi) { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:YES]; + win->macos.view.win_id = win->slot.id; + [win->macos.view updateTrackingAreas]; + if (win->desc.high_dpi) { + [win->macos.view setWantsBestResolutionOpenGLSurface:YES]; } else { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:NO]; + [win->macos.view setWantsBestResolutionOpenGLSurface:NO]; } - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; - - NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 - target:_sapp.macos.view - selector:@selector(timerFired:) - userInfo:nil - repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode]; - timer_obj = nil; + win->macos.window.contentView = win->macos.view; + [win->macos.window makeFirstResponder:win->macos.view]; #endif if (win->fullscreen) { /* on GL, this already toggles a rendered frame, so set the valid flag before */ @@ -3996,7 +3989,8 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { cur_fb_width = (int) fb_size.width; cur_fb_height = (int) fb_size.height; #else - #error "FIXME GL!" + cur_fb_width = (int) fb_rect.size.width; + cur_fb_height = (int) fb_rect.size.height; #endif const bool dim_changed = (win->framebuffer_width != cur_fb_width) || (win->framebuffer_height != cur_fb_height); @@ -4005,7 +3999,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; win->macos.view.drawableSize = drawable_size; #else - #error "FIXME GL!" + // nothing to do here? #endif if (!_sapp.first_frame) { _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); @@ -4177,7 +4171,7 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( #if defined(SOKOL_METAL) [win->macos.view draw]; #else - #error "FIXME: GL" + [[win->macos.view openGLContext] flushBuffer]; #endif } } @@ -4397,24 +4391,29 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( } [super reshape]; } -- (void)timerFired:(id)sender { - _SOKOL_UNUSED(sender); - [self setNeedsDisplay:YES]; -} - (void)prepareOpenGL { [super prepareOpenGL]; GLint swapInt = 1; - NSOpenGLContext* ctx = [_sapp.macos.view openGLContext]; - [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; - [ctx makeCurrentContext]; + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + NSOpenGLContext* ctx = [win->macos.view openGLContext]; + [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; + [ctx makeCurrentContext]; + } } #endif - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); + // FIXME? + /* #if !defined(SOKOL_METAL) - [[_sapp.macos.view openGLContext] flushBuffer]; + _sapp_window_t* win = _sapp_lookup_window(self.win_id); + if (win) { + [[win->macos.view openGLContext] flushBuffer]; + } #endif + */ } - (BOOL)isOpaque { diff --git a/sokol_gfx.h b/sokol_gfx.h index 5167b2d5a..4c042dfd3 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -5980,85 +5980,84 @@ _SOKOL_PRIVATE void _sg_gl_cache_invalidate_program(GLuint prog) { } } -_SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { - if (_sg.gl.cur_context) { - _SG_GL_CHECK_ERROR(); - #if !defined(SOKOL_GLES2) - if (!_sg.gl.gles2) { - glBindVertexArray(_sg.gl.cur_context->vao); - _SG_GL_CHECK_ERROR(); - } - #endif - memset(&_sg.gl.cache, 0, sizeof(_sg.gl.cache)); - _sg_gl_cache_clear_buffer_bindings(true); - _SG_GL_CHECK_ERROR(); - _sg_gl_cache_clear_texture_bindings(true); +_SOKOL_PRIVATE void _sg_gl_reset_state_cache(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); + _SG_GL_CHECK_ERROR(); + #if !defined(SOKOL_GLES2) + if (!_sg.gl.gles2) { + glBindVertexArray(ctx->vao); _SG_GL_CHECK_ERROR(); - for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { - _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; - attr->vb_index = -1; - attr->divisor = -1; - glDisableVertexAttribArray((GLuint)i); - _SG_GL_CHECK_ERROR(); - } - _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; - - /* shader program */ - glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); + } + #endif + memset(&_sg.gl.cache, 0, sizeof(_sg.gl.cache)); + _sg_gl_cache_clear_buffer_bindings(true); + _SG_GL_CHECK_ERROR(); + _sg_gl_cache_clear_texture_bindings(true); + _SG_GL_CHECK_ERROR(); + for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) { + _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr; + attr->vb_index = -1; + attr->divisor = -1; + glDisableVertexAttribArray((GLuint)i); _SG_GL_CHECK_ERROR(); + } + _sg.gl.cache.cur_primitive_type = GL_TRIANGLES; - /* depth and stencil state */ - _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; - _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; - _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_FALSE); - glDisable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 0, 0); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMask(0); - - /* blend state */ - _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; - _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; - _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; - glDisable(GL_BLEND); - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); - glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); + /* shader program */ + glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog); + _SG_GL_CHECK_ERROR(); - /* standalone state */ - for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { - _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; - } - _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; - _sg.gl.cache.face_winding = SG_FACEWINDING_CW; - _sg.gl.cache.sample_count = 1; - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - glDisable(GL_CULL_FACE); - glFrontFace(GL_CW); - glCullFace(GL_BACK); - glEnable(GL_SCISSOR_TEST); - glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); - glEnable(GL_DITHER); - glDisable(GL_POLYGON_OFFSET_FILL); - #if defined(SOKOL_GLCORE33) - glEnable(GL_MULTISAMPLE); - glEnable(GL_PROGRAM_POINT_SIZE); - #endif - } + /* depth and stencil state */ + _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS; + _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP; + _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP; + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_FALSE); + glDisable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0); + + /* blend state */ + _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD; + _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE; + _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO; + _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD; + glDisable(GL_BLEND); + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* standalone state */ + for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) { + _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA; + } + _sg.gl.cache.cull_mode = SG_CULLMODE_NONE; + _sg.gl.cache.face_winding = SG_FACEWINDING_CW; + _sg.gl.cache.sample_count = 1; + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glPolygonOffset(0.0f, 0.0f); + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); + glFrontFace(GL_CW); + glCullFace(GL_BACK); + glEnable(GL_SCISSOR_TEST); + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE); + glEnable(GL_DITHER); + glDisable(GL_POLYGON_OFFSET_FILL); + #if defined(SOKOL_GLCORE33) + glEnable(GL_MULTISAMPLE); + glEnable(GL_PROGRAM_POINT_SIZE); + #endif } _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { @@ -6103,15 +6102,14 @@ _SOKOL_PRIVATE void _sg_gl_discard_backend(void) { _SOKOL_PRIVATE void _sg_gl_activate_context(_sg_context_t* ctx) { SOKOL_ASSERT(_sg.gl.valid); - /* NOTE: ctx can be 0 to unset the current context */ - _sg.gl.cur_context = ctx; - _sg_gl_reset_state_cache(); + _sg_gl_reset_state_cache(ctx); } /*-- GL backend resource creation and destruction ----------------------------*/ -_SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx) { +_SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx, const sg_context_desc* desc) { SOKOL_ASSERT(ctx); SOKOL_ASSERT(0 == ctx->default_framebuffer); + _SOKOL_UNUSED(desc); _SG_GL_CHECK_ERROR(); glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer); _SG_GL_CHECK_ERROR(); @@ -6796,9 +6794,10 @@ _SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_ds_image(const _sg_pass_t* pass) { return pass->gl.ds_att.image; } -_SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { +_SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_context_t* ctx, _sg_pass_t* pass, const sg_pass_action* action, int w, int h) { /* FIXME: what if a texture used as render target is still bound, should we unbind all currently bound textures in begin pass? */ + SOKOL_ASSERT(ctx); SOKOL_ASSERT(action); SOKOL_ASSERT(!_sg.gl.in_pass); _SG_GL_CHECK_ERROR(); @@ -6824,8 +6823,7 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac } else { /* default pass */ - SOKOL_ASSERT(_sg.gl.cur_context); - glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, ctx->default_framebuffer); } glViewport(0, 0, w, h); glScissor(0, 0, w, h); @@ -6937,7 +6935,8 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac _SG_GL_CHECK_ERROR(); } -_SOKOL_PRIVATE void _sg_gl_end_pass(void) { +_SOKOL_PRIVATE void _sg_gl_end_pass(_sg_context_t* ctx) { + SOKOL_ASSERT(ctx); SOKOL_ASSERT(_sg.gl.in_pass); _SG_GL_CHECK_ERROR(); @@ -6975,8 +6974,7 @@ _SOKOL_PRIVATE void _sg_gl_end_pass(void) { _sg.gl.cur_pass_width = 0; _sg.gl.cur_pass_height = 0; - SOKOL_ASSERT(_sg.gl.cur_context); - glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, ctx->default_framebuffer); _sg.gl.in_pass = false; _SG_GL_CHECK_ERROR(); } @@ -7297,7 +7295,8 @@ _SOKOL_PRIVATE void _sg_gl_apply_bindings( _SG_GL_CHECK_ERROR(); } -_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) { +_SOKOL_PRIVATE void _sg_gl_apply_uniforms(_sg_context_t* ctx, sg_shader_stage stage_index, int ub_index, const sg_range* data) { + _SOKOL_UNUSED(ctx); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->slot.id == _sg.gl.cache.cur_pipeline_id.id); SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->slot.id == _sg.gl.cache.cur_pipeline->cmn.shader_id.id); @@ -7367,8 +7366,9 @@ _SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_inst } } -_SOKOL_PRIVATE void _sg_gl_commit(void) { +_SOKOL_PRIVATE void _sg_gl_commit(_sg_context_t* ctx) { SOKOL_ASSERT(!_sg.gl.in_pass); + _SOKOL_UNUSED(ctx); /* "soft" clear bindings (only those that are actually bound) */ _sg_gl_cache_clear_buffer_bindings(false); _sg_gl_cache_clear_texture_bindings(false); @@ -12743,7 +12743,7 @@ static inline void _sg_discard_backend(void) { static inline void _sg_reset_state_cache(_sg_context_t* ctx) { #if defined(_SOKOL_ANY_GL) - _sg_gl_reset_state_cache(); + _sg_gl_reset_state_cache(ctx); #elif defined(SOKOL_METAL) _sg_mtl_reset_state_cache(ctx); #elif defined(SOKOL_D3D11) From bb6dd746754d5b4f7bc85f39163f231a9bcd2c32 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sat, 29 May 2021 17:56:53 +0200 Subject: [PATCH 40/49] sokol_app.h macos gl: more multiwindow wip --- sokol_app.h | 61 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index cc56b136b..c700a5fdc 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1967,7 +1967,6 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #elif defined(SOKOL_GLCORE33) @interface _sapp_macos_view : NSOpenGLView @property uint32_t win_id; - - (void)timerFired:(id)sender; @end #endif // SOKOL_GLCORE33 @@ -2559,6 +2558,7 @@ _SOKOL_PRIVATE void _sapp_macos_get_window_pos(_sapp_window_t* win, int* x, int* _SOKOL_PRIVATE void _sapp_macos_set_window_size(_sapp_window_t* win, int w, int h); _SOKOL_PRIVATE void _sapp_macos_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* desc, int num_images); +_SOKOL_PRIVATE void _sapp_macos_activate_window_context(_sapp_window_t* win); #elif defined(_SAPP_IOS) _SOKOL_PRIVATE void _sapp_ios_init_state(void); _SOKOL_PRIVATE void _sapp_ios_discard_state(void); @@ -2597,6 +2597,7 @@ _SOKOL_PRIVATE void _sapp_win32_get_window_pos(_sapp_window_t* win, int* x, int* _SOKOL_PRIVATE void _sapp_win32_set_window_size(_sapp_window_t* win, int w, int h); _SOKOL_PRIVATE void _sapp_win32_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_win32_set_icon(const sapp_icon_desc* desc, int num_images); +_SOKOL_PRIVATE void _sapp_win32_activate_window_context(_sapp_window_t* win); #elif defined(_SAPP_UWP) _SOKOL_PRIVATE void _sapp_uwp_init_state(void); _SOKOL_PRIVATE void _sapp_uwp_discard_state(void); @@ -2634,6 +2635,7 @@ _SOKOL_PRIVATE void _sapp_x11_get_window_pos(_sapp_window_t* win, int* x, int* y _SOKOL_PRIVATE void _sapp_x11_set_window_size(_sapp_window_t* win, int w, int h); _SOKOL_PRIVATE void _sapp_x11_get_window_size(_sapp_window_t* win, int* w, int* h); _SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* desc, int num_images); +_SOKOL_PRIVATE void _sapp_x11_activate_window_context(_sapp_window_t* win); #endif /*=== POOL IMPLEMENTATION ====================================================*/ @@ -2972,6 +2974,18 @@ _SOKOL_PRIVATE void _sapp_platform_get_window_size(_sapp_window_t* win, int* w, #endif } +_SOKOL_PRIVATE void _sapp_platform_activate_window_context(_sapp_window_t* win) { + #if defined(_SAPP_MACOS) + _sapp_macos_activate_window_context(win); + #elif defined(_SAPP_WIN32) + _sapp_win32_activate_window_context(win); + #elif defined(_SAPP_LINUX) + _sapp_x11_activate_window_context(win); + #else + _SOKOL_UNUSED(win); + #endif +} + _SOKOL_PRIVATE void _sapp_platform_set_icon(const sapp_icon_desc* desc, int num_images) { #if defined(_SAPP_MACOS) _sapp_macos_set_icon(desc, num_images); @@ -3949,6 +3963,15 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_position(_sapp_window_t* win) { win->pos_y = _sapp_macos_flipy(win, content_rect.origin.y); } +_SOKOL_PRIVATE void _sapp_macos_activate_window_context(_sapp_window_t* win) { + #if defined(SOKOL_GLCORE33) + NSOpenGLContext* ctx = [win->macos.view openGLContext]; + [ctx makeCurrentContext]; + #else + _SOKOL_UNUSED(win); + #endif +} + /* NOTE: unlike the iOS version of this function, the macOS version can dynamically update the DPI scaling factor when a window is moved between HighDPI / LowDPI screens. @@ -3961,8 +3984,18 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { const NSRect fb_rect = [win->macos.view bounds]; win->framebuffer_width = fb_rect.size.width * win->dpi_scale; win->framebuffer_height = fb_rect.size.height * win->dpi_scale; + const CGSize fb_size = win->macos.view.drawableSize; + const int cur_fb_width = (int) fb_size.width; + const int cur_fb_height = (int) fb_size.height; + const bool dim_changed = (win->framebuffer_width != cur_fb_width) || + (win->framebuffer_height != cur_fb_height); #elif defined(SOKOL_GLCORE33) + // NOTE: on first call this will always return a Retina resolution framebuffer size const NSRect fb_rect = [win->macos.view convertRectToBacking:[win->macos.view frame]]; + const int cur_fb_width = (int) fb_rect.size.width; + const int cur_fb_height = (int) fb_rect.size.height; + const bool dim_changed = (win->framebuffer_width != cur_fb_width) || + (win->framebuffer_height != cur_fb_height); win->framebuffer_width = fb_rect.size.width; win->framebuffer_height = fb_rect.size.height; #endif @@ -3982,24 +4015,12 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { win->window_height = 1; } win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; - - int cur_fb_width, cur_fb_height; - #if defined(SOKOL_METAL) - const CGSize fb_size = win->macos.view.drawableSize; - cur_fb_width = (int) fb_size.width; - cur_fb_height = (int) fb_size.height; - #else - cur_fb_width = (int) fb_rect.size.width; - cur_fb_height = (int) fb_rect.size.height; - #endif - const bool dim_changed = (win->framebuffer_width != cur_fb_width) || - (win->framebuffer_height != cur_fb_height); if (dim_changed) { #if defined(SOKOL_METAL) CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; win->macos.view.drawableSize = drawable_size; #else - // nothing to do here? + // FIXME: nothing to do here? #endif if (!_sapp.first_frame) { _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); @@ -4155,6 +4176,10 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( @implementation _sapp_macos_app_delegate - (void)drawFrame { + #if defined(SOKOL_GLCORE33) + _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); + _sapp_macos_activate_window_context(win); + #endif _sapp_frame(); for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; @@ -12140,7 +12165,13 @@ SOKOL_API_IMPL bool sapp_window_minimized(sapp_window window) { SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { SOKOL_ASSERT(_sapp.valid); - // FIXME FIXME FIXME + _sapp_window_t* win = _sapp_lookup_window(window.id); + if (win) { + return _sapp_platform_activate_window_context(win); + } + else { + return false; + } } SOKOL_API_IMPL int sapp_window_slot_index(sapp_window window) { From 7f70b2d98631ab899a15fba3c602cd4a00b8f1be Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 30 May 2021 14:37:20 +0200 Subject: [PATCH 41/49] sokol_app.h macos gl: make multiwindow basically work (minus a memory leak) --- sokol_app.h | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index c700a5fdc..2952aaa83 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3772,14 +3772,25 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; } attrs[i++] = 0; - NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; - SOKOL_ASSERT(glpixelformat_obj != nil); + NSOpenGLPixelFormat* nsglpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + SOKOL_ASSERT(nsglpixelformat_obj != nil); + + NSOpenGLContext* shared_main_context = nil; + if (SAPP_INVALID_ID != _sapp.main_window_id) { + _sapp_window_t* main_win = _sapp_lookup_window(_sapp.main_window_id); + shared_main_context = main_win->macos.view.openGLContext; + } win->macos.view = [[_sapp_macos_view alloc] initWithFrame:content_rect - pixelFormat:glpixelformat_obj]; - _SAPP_OBJC_RELEASE(glpixelformat_obj); + pixelFormat:nsglpixelformat_obj]; win->macos.view.win_id = win->slot.id; + if (nil != shared_main_context) { + // create a new NSOpenContext which shares resources with the main window's context + win->macos.view.openGLContext = [[NSOpenGLContext alloc] initWithFormat:nsglpixelformat_obj shareContext:shared_main_context]; + SOKOL_ASSERT(nil != win->macos.view.openGLContext); + } + _SAPP_OBJC_RELEASE(nsglpixelformat_obj); [win->macos.view updateTrackingAreas]; if (win->desc.high_dpi) { [win->macos.view setWantsBestResolutionOpenGLSurface:YES]; @@ -3810,6 +3821,9 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { } _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { + +// FIXME FIXME FIXME: the GL backend currently has a ~7MB memory leak on window destruction + SOKOL_ASSERT(win); // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(win->macos.tracking_area); @@ -12167,10 +12181,7 @@ SOKOL_API_IMPL void sapp_activate_window_context(sapp_window window) { SOKOL_ASSERT(_sapp.valid); _sapp_window_t* win = _sapp_lookup_window(window.id); if (win) { - return _sapp_platform_activate_window_context(win); - } - else { - return false; + _sapp_platform_activate_window_context(win); } } From 15c95969dad8ef72bd13c2e8bdd89495a6f32bda Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Sun, 30 May 2021 14:37:58 +0200 Subject: [PATCH 42/49] sokol_gfx.h: activate default context if active context is destroyed --- sokol_gfx.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index 4c042dfd3..e885ee876 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -14836,11 +14836,15 @@ SOKOL_API_IMPL sg_context sg_make_context(const sg_context_desc* desc) { SOKOL_API_IMPL void sg_destroy_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); _sg_destroy_all_resources(&_sg.pools, ctx_id.id); + bool is_active_context = false; if (ctx_id.id == _sg.active_context.id) { _sg.active_context.id = SG_INVALID_ID; + is_active_context = true; } + bool is_default_context = false; if (ctx_id.id == _sg.default_context.id) { _sg.default_context.id = SG_INVALID_ID; + is_default_context = true; } _sg_context_t* ctx = _sg_lookup_context(&_sg.pools, ctx_id.id); if (ctx) { @@ -14849,7 +14853,11 @@ SOKOL_API_IMPL void sg_destroy_context(sg_context ctx_id) { _sg_reset_slot(&ctx->slot); _sg_pool_free_index(&_sg.pools.context_pool, _sg_slot_index(ctx_id.id)); } - _sg_activate_context(0); + if (is_active_context && !is_default_context) { + _sg_context_t* default_ctx = _sg_lookup_context(&_sg.pools, _sg.default_context.id); + SOKOL_ASSERT(default_ctx); + _sg_activate_context(default_ctx); + } } SOKOL_API_IMPL void sg_activate_context(sg_context ctx_id) { From bc64d6f2666b68729cb5f5208a8b0e29d35eba25 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Mon, 31 May 2021 19:14:22 +0200 Subject: [PATCH 43/49] sokol_app.h macos gl: fix NSOpenGLContext memory leak --- sokol_app.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 2952aaa83..965b52952 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3787,8 +3787,10 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->macos.view.win_id = win->slot.id; if (nil != shared_main_context) { // create a new NSOpenContext which shares resources with the main window's context - win->macos.view.openGLContext = [[NSOpenGLContext alloc] initWithFormat:nsglpixelformat_obj shareContext:shared_main_context]; - SOKOL_ASSERT(nil != win->macos.view.openGLContext); + NSOpenGLContext* nsgl_context = [[NSOpenGLContext alloc] initWithFormat:nsglpixelformat_obj shareContext:shared_main_context]; + SOKOL_ASSERT(nsgl_context); + win->macos.view.openGLContext = nsgl_context; + _SAPP_OBJC_RELEASE(nsgl_context); } _SAPP_OBJC_RELEASE(nsglpixelformat_obj); [win->macos.view updateTrackingAreas]; @@ -3821,9 +3823,6 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { } _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* win) { - -// FIXME FIXME FIXME: the GL backend currently has a ~7MB memory leak on window destruction - SOKOL_ASSERT(win); // NOTE: it's safe to call [release] on a nil object _SAPP_OBJC_RELEASE(win->macos.tracking_area); From b7cfef5eaea1c2f9a9728719f3061d391a4cc799 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 1 Jun 2021 19:24:05 +0200 Subject: [PATCH 44/49] sokol_app.h: intermediate code cleanup --- sokol_app.h | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 965b52952..cc20d4343 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1541,8 +1541,6 @@ SOKOL_APP_API_DECL void* sapp_userdata(void); SOKOL_APP_API_DECL sapp_window sapp_open_window(const sapp_window_desc* desc); /* close a window */ SOKOL_APP_API_DECL void sapp_close_window(sapp_window window); -/* test if a window handle is valid */ -SOKOL_APP_API_DECL bool sapp_window_valid(sapp_window window); /* start rendering into a window */ SOKOL_APP_API_DECL void sapp_activate_window_context(sapp_window window); /* return an array index for a window handle (to associate your own data with window handle) */ @@ -1553,6 +1551,8 @@ SOKOL_APP_API_DECL sapp_window sapp_main_window(void); SOKOL_APP_API_DECL sapp_window sapp_first_window(void); /* continue iterating over windows, returns invalid handle when finished */ SOKOL_APP_API_DECL sapp_window sapp_next_window(sapp_window window); +/* test if a window handle is valid */ +SOKOL_APP_API_DECL bool sapp_window_valid(sapp_window window); /* show a hidden window */ SOKOL_APP_API_DECL void sapp_show_window(sapp_window window); /* hide a visible window */ @@ -2835,7 +2835,7 @@ _SOKOL_PRIVATE void _sapp_platform_show_window(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) _sapp_x11_close_window(win); #else - (void)win; + _SOKOL_UNUSED(win); #endif } @@ -2847,7 +2847,7 @@ _SOKOL_PRIVATE void _sapp_platform_hide_window(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) _sapp_x11_hide_window(win); #else - (void)win; + _SOKOL_UNUSED(win); #endif } @@ -2859,7 +2859,7 @@ _SOKOL_PRIVATE bool _sapp_platform_window_visible(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) return _sapp_x11_window_visible(win); #else - (void)win; + _SOKOL_UNUSED(win); return true; #endif } @@ -2872,7 +2872,7 @@ _SOKOL_PRIVATE void _sapp_platform_focus_window(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) _sapp_x11_focus_window(win); #else - (void)win; + _SOKOL_UNUSED(win); #endif } @@ -2884,7 +2884,7 @@ _SOKOL_PRIVATE bool _sapp_platform_window_focused(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) return _sapp_x11_window_focused(win); #else - (void)win; + _SOKOL_UNUSED(win); return true; #endif } @@ -2897,7 +2897,7 @@ _SOKOL_PRIVATE bool _sapp_platform_window_minimized(_sapp_window_t* win) { #elif defined(_SAPP_LINUX) return _sapp_x11_window_minimized(win); #else - (void)win; + _SOKOL_UNUSED(win); return false; #endif } @@ -3424,7 +3424,7 @@ _SOKOL_PRIVATE void _sapp_setup_default_icon(void) { // initialize default_icon_desc struct uint32_t* dst = _sapp.default_icon_pixels; const uint32_t* dst_end = dst + all_num_pixels; - (void)dst_end; // silence unused warning in release mode + _SOKOL_UNUSED(dst_end); // silence unused warning in release mode for (int i = 0; i < num_icons; i++) { const int dim = (int) icon_sizes[i]; const int num_pixels = dim * dim; @@ -7438,7 +7438,7 @@ _SOKOL_PRIVATE void _sapp_win32_init_console(void) { errno_t err; err = freopen_s(&res_fp, "CON", "w", stdout); err = freopen_s(&res_fp, "CON", "w", stderr); - (void)err; + _SOKOL_UNUSED(err); } } if (_sapp.desc.win32_console_utf8) { @@ -12213,7 +12213,7 @@ SOKOL_API_IMPL sapp_window sapp_next_window(sapp_window window) { return _sapp_make_window_id(SAPP_INVALID_ID); } -SOKOL_API_IMPL bool sapp_valid_window(sapp_window window) { +SOKOL_API_IMPL bool sapp_window_valid(sapp_window window) { SOKOL_ASSERT(_sapp.valid); return 0 != _sapp_lookup_window(window.id); } @@ -12400,7 +12400,7 @@ SOKOL_API_IMPL uint32_t sapp_html5_get_dropped_file_size(int index) { } return sapp_js_dropped_file_size(index); #else - (void)index; + _SOKOL_UNUSED(index); return 0; #endif } @@ -12441,7 +12441,7 @@ SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request request->user_data); } #else - (void)request; + _SOKOL_UNUSED(request); #endif } @@ -12477,6 +12477,7 @@ SOKOL_API_IMPL const void* sapp_metal_get_window_renderpass_descriptor(sapp_wind return 0; } #else + _SOKOL_UNUSED(window); return 0; #endif } @@ -12502,6 +12503,7 @@ SOKOL_API_IMPL const void* sapp_metal_get_window_drawable(sapp_window window) { return 0; } #else + _SOKOL_UNUSED(window); return 0; #endif } @@ -12523,6 +12525,7 @@ SOKOL_API_IMPL const void* sapp_macos_get_nswindow(sapp_window window) { return 0; } #else + _SOKOL_UNUSED(win); return 0; #endif } @@ -12657,7 +12660,7 @@ SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { #if defined(_SAPP_EMSCRIPTEN) _sapp.emsc.ask_leave_site = ask; #else - (void)ask; + _SOKOL_UNUSED(ask); #endif } From ccdb7e976bceccf1a4cc144309ec47b1a71fab3b Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 1 Jun 2021 19:49:16 +0200 Subject: [PATCH 45/49] sokol_gfx.h: de-associate resources and contexts --- sokol_gfx.h | 145 +++++++++++++++++----------------------------------- 1 file changed, 48 insertions(+), 97 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index e885ee876..445009318 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -2031,7 +2031,6 @@ typedef struct sg_trace_hooks { void (*err_shader_pool_exhausted)(void* user_data); void (*err_pipeline_pool_exhausted)(void* user_data); void (*err_pass_pool_exhausted)(void* user_data); - void (*err_context_mismatch)(void* user_data); void (*err_pass_invalid)(void* user_data); void (*err_draw_invalid)(void* user_data); void (*err_bindings_invalid)(void* user_data); @@ -2060,8 +2059,7 @@ typedef struct sg_trace_hooks { */ typedef struct sg_slot_info { sg_resource_state state; /* the current state of this resource slot */ - uint32_t res_id; /* type-neutral resource if (e.g. sg_buffer.id) */ - uint32_t ctx_id; /* the context this resource belongs to */ + uint32_t res_id; /* type-neutral resource if (e.g. sg_buffer.id) */ } sg_slot_info; typedef struct sg_buffer_info { @@ -2949,7 +2947,6 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ /* resource pool slots */ typedef struct { uint32_t id; - uint32_t ctx_id; sg_resource_state state; } _sg_slot_t; @@ -13521,7 +13518,7 @@ _SOKOL_PRIVATE _sg_context_t* _sg_default_context(void) { return ctx; } -_SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { +_SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p) { /* this is a bit dumb since it loops over all pool slots to find the occupied slots, on the other hand it is only ever executed at shutdown @@ -13530,43 +13527,33 @@ _SOKOL_PRIVATE void _sg_destroy_all_resources(_sg_pools_t* p, uint32_t ctx_id) { and the resource slots not be cleared! */ for (int i = 1; i < p->buffer_pool.size; i++) { - if (p->buffers[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->buffers[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_destroy_buffer(&p->buffers[i]); - } + sg_resource_state state = p->buffers[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_buffer(&p->buffers[i]); } } for (int i = 1; i < p->image_pool.size; i++) { - if (p->images[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->images[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_destroy_image(&p->images[i]); - } + sg_resource_state state = p->images[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_image(&p->images[i]); } } for (int i = 1; i < p->shader_pool.size; i++) { - if (p->shaders[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->shaders[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_destroy_shader(&p->shaders[i]); - } + sg_resource_state state = p->shaders[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_shader(&p->shaders[i]); } } for (int i = 1; i < p->pipeline_pool.size; i++) { - if (p->pipelines[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->pipelines[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_destroy_pipeline(&p->pipelines[i]); - } + sg_resource_state state = p->pipelines[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_pipeline(&p->pipelines[i]); } } for (int i = 1; i < p->pass_pool.size; i++) { - if (p->passes[i].slot.ctx_id == ctx_id) { - sg_resource_state state = p->passes[i].slot.state; - if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { - _sg_destroy_pass(&p->passes[i]); - } + sg_resource_state state = p->passes[i].slot.state; + if ((state == SG_RESOURCESTATE_VALID) || (state == SG_RESOURCESTATE_FAILED)) { + _sg_destroy_pass(&p->passes[i]); } } } @@ -14548,7 +14535,6 @@ _SOKOL_PRIVATE void _sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc SOKOL_ASSERT(buf_id.id != SG_INVALID_ID && desc); _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); - buf->slot.ctx_id = _sg.active_context.id; if (_sg_validate_buffer_desc(desc)) { buf->slot.state = _sg_create_buffer(buf, desc); } @@ -14562,7 +14548,6 @@ _SOKOL_PRIVATE void _sg_init_image(sg_image img_id, const sg_image_desc* desc) { SOKOL_ASSERT(img_id.id != SG_INVALID_ID && desc); _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); - img->slot.ctx_id = _sg.active_context.id; if (_sg_validate_image_desc(desc)) { img->slot.state = _sg_create_image(img, desc); } @@ -14576,7 +14561,6 @@ _SOKOL_PRIVATE void _sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc SOKOL_ASSERT(shd_id.id != SG_INVALID_ID && desc); _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); - shd->slot.ctx_id = _sg.active_context.id; if (_sg_validate_shader_desc(desc)) { shd->slot.state = _sg_create_shader(shd, desc); } @@ -14590,7 +14574,6 @@ _SOKOL_PRIVATE void _sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc SOKOL_ASSERT(pip_id.id != SG_INVALID_ID && desc); _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); - pip->slot.ctx_id = _sg.active_context.id; if (_sg_validate_pipeline_desc(desc)) { _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); if (shd && (shd->slot.state == SG_RESOURCESTATE_VALID)) { @@ -14610,7 +14593,6 @@ _SOKOL_PRIVATE void _sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { SOKOL_ASSERT(pass_id.id != SG_INVALID_ID && desc); _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); - pass->slot.ctx_id = _sg.active_context.id; if (_sg_validate_pass_desc(desc)) { /* lookup pass attachment image pointers */ _sg_image_t* att_imgs[SG_MAX_COLOR_ATTACHMENTS + 1]; @@ -14644,81 +14626,61 @@ _SOKOL_PRIVATE void _sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { _SOKOL_PRIVATE bool _sg_uninit_buffer(sg_buffer buf_id) { _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); if (buf) { - if (buf->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_buffer(buf); - _sg_reset_buffer(buf); - return true; - } - else { - SOKOL_LOG("_sg_uninit_buffer: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + _sg_destroy_buffer(buf); + _sg_reset_buffer(buf); + return true; + } + else { + return false; } - return false; } _SOKOL_PRIVATE bool _sg_uninit_image(sg_image img_id) { _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); if (img) { - if (img->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_image(img); - _sg_reset_image(img); - return true; - } - else { - SOKOL_LOG("_sg_uninit_image: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + _sg_destroy_image(img); + _sg_reset_image(img); + return true; + } + else { + return false; } - return false; } _SOKOL_PRIVATE bool _sg_uninit_shader(sg_shader shd_id) { _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); if (shd) { - if (shd->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_shader(shd); - _sg_reset_shader(shd); - return true; - } - else { - SOKOL_LOG("_sg_uninit_shader: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + _sg_destroy_shader(shd); + _sg_reset_shader(shd); + return true; + } + else { + return false; } - return false; } _SOKOL_PRIVATE bool _sg_uninit_pipeline(sg_pipeline pip_id) { _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); if (pip) { - if (pip->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_pipeline(pip); - _sg_reset_pipeline(pip); - return true; - } - else { - SOKOL_LOG("_sg_uninit_pipeline: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + _sg_destroy_pipeline(pip); + _sg_reset_pipeline(pip); + return true; + } + else { + return false; } - return false; } _SOKOL_PRIVATE bool _sg_uninit_pass(sg_pass pass_id) { _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); if (pass) { - if (pass->slot.ctx_id == _sg.active_context.id) { - _sg_destroy_pass(pass); - _sg_reset_pass(pass); - return true; - } - else { - SOKOL_LOG("_sg_uninit_pass: active context mismatch (must be same as for creation)"); - _SG_TRACE_NOARGS(err_context_mismatch); - } + _sg_destroy_pass(pass); + _sg_reset_pass(pass); + return true; + } + else { + return false; } - return false; } /*== PUBLIC API FUNCTIONS ====================================================*/ @@ -14777,7 +14739,7 @@ SOKOL_API_IMPL void sg_shutdown(void) { contexts are used, the app code must take care of properly releasing them (since only the app code can switch between 3D-API contexts) */ - _sg_destroy_all_resources(&_sg.pools, _sg.default_context.id); + _sg_destroy_all_resources(&_sg.pools); _sg_destroy_context(_sg_default_context()); _sg_discard_backend(); _sg_discard_pools(&_sg.pools); @@ -14835,7 +14797,6 @@ SOKOL_API_IMPL sg_context sg_make_context(const sg_context_desc* desc) { SOKOL_API_IMPL void sg_destroy_context(sg_context ctx_id) { SOKOL_ASSERT(_sg.valid); - _sg_destroy_all_resources(&_sg.pools, ctx_id.id); bool is_active_context = false; if (ctx_id.id == _sg.active_context.id) { _sg.active_context.id = SG_INVALID_ID; @@ -15034,7 +14995,6 @@ SOKOL_API_IMPL void sg_fail_buffer(sg_buffer buf_id) { SOKOL_ASSERT(buf_id.id != SG_INVALID_ID); _sg_buffer_t* buf = _sg_lookup_buffer(&_sg.pools, buf_id.id); SOKOL_ASSERT(buf && buf->slot.state == SG_RESOURCESTATE_ALLOC); - buf->slot.ctx_id = _sg.active_context.id; buf->slot.state = SG_RESOURCESTATE_FAILED; _SG_TRACE_ARGS(fail_buffer, buf_id); } @@ -15044,7 +15004,6 @@ SOKOL_API_IMPL void sg_fail_image(sg_image img_id) { SOKOL_ASSERT(img_id.id != SG_INVALID_ID); _sg_image_t* img = _sg_lookup_image(&_sg.pools, img_id.id); SOKOL_ASSERT(img && img->slot.state == SG_RESOURCESTATE_ALLOC); - img->slot.ctx_id = _sg.active_context.id; img->slot.state = SG_RESOURCESTATE_FAILED; _SG_TRACE_ARGS(fail_image, img_id); } @@ -15054,7 +15013,6 @@ SOKOL_API_IMPL void sg_fail_shader(sg_shader shd_id) { SOKOL_ASSERT(shd_id.id != SG_INVALID_ID); _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, shd_id.id); SOKOL_ASSERT(shd && shd->slot.state == SG_RESOURCESTATE_ALLOC); - shd->slot.ctx_id = _sg.active_context.id; shd->slot.state = SG_RESOURCESTATE_FAILED; _SG_TRACE_ARGS(fail_shader, shd_id); } @@ -15064,7 +15022,6 @@ SOKOL_API_IMPL void sg_fail_pipeline(sg_pipeline pip_id) { SOKOL_ASSERT(pip_id.id != SG_INVALID_ID); _sg_pipeline_t* pip = _sg_lookup_pipeline(&_sg.pools, pip_id.id); SOKOL_ASSERT(pip && pip->slot.state == SG_RESOURCESTATE_ALLOC); - pip->slot.ctx_id = _sg.active_context.id; pip->slot.state = SG_RESOURCESTATE_FAILED; _SG_TRACE_ARGS(fail_pipeline, pip_id); } @@ -15074,7 +15031,6 @@ SOKOL_API_IMPL void sg_fail_pass(sg_pass pass_id) { SOKOL_ASSERT(pass_id.id != SG_INVALID_ID); _sg_pass_t* pass = _sg_lookup_pass(&_sg.pools, pass_id.id); SOKOL_ASSERT(pass && pass->slot.state == SG_RESOURCESTATE_ALLOC); - pass->slot.ctx_id = _sg.active_context.id; pass->slot.state = SG_RESOURCESTATE_FAILED; _SG_TRACE_ARGS(fail_pass, pass_id); } @@ -15580,7 +15536,6 @@ SOKOL_API_IMPL sg_buffer_info sg_query_buffer_info(sg_buffer buf_id) { if (buf) { info.slot.state = buf->slot.state; info.slot.res_id = buf->slot.id; - info.slot.ctx_id = buf->slot.ctx_id; info.update_frame_index = buf->cmn.update_frame_index; info.append_frame_index = buf->cmn.append_frame_index; info.append_pos = buf->cmn.append_pos; @@ -15604,7 +15559,6 @@ SOKOL_API_IMPL sg_image_info sg_query_image_info(sg_image img_id) { if (img) { info.slot.state = img->slot.state; info.slot.res_id = img->slot.id; - info.slot.ctx_id = img->slot.ctx_id; #if defined(SOKOL_D3D11) info.num_slots = 1; info.active_slot = 0; @@ -15626,7 +15580,6 @@ SOKOL_API_IMPL sg_shader_info sg_query_shader_info(sg_shader shd_id) { if (shd) { info.slot.state = shd->slot.state; info.slot.res_id = shd->slot.id; - info.slot.ctx_id = shd->slot.ctx_id; } return info; } @@ -15639,7 +15592,6 @@ SOKOL_API_IMPL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip_id) { if (pip) { info.slot.state = pip->slot.state; info.slot.res_id = pip->slot.id; - info.slot.ctx_id = pip->slot.ctx_id; } return info; } @@ -15652,7 +15604,6 @@ SOKOL_API_IMPL sg_pass_info sg_query_pass_info(sg_pass pass_id) { if (pass) { info.slot.state = pass->slot.state; info.slot.res_id = pass->slot.id; - info.slot.ctx_id = pass->slot.ctx_id; } return info; } From 847076f733161f4da1afc46a3549a336f6a3ac8e Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Tue, 1 Jun 2021 19:51:26 +0200 Subject: [PATCH 46/49] sokol_gfx_imgui.h: remove per resource context id, and context mismatch error hook --- util/sokol_gfx_imgui.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/util/sokol_gfx_imgui.h b/util/sokol_gfx_imgui.h index 861625d3a..194cabcdc 100644 --- a/util/sokol_gfx_imgui.h +++ b/util/sokol_gfx_imgui.h @@ -887,7 +887,6 @@ _SOKOL_PRIVATE const char* _sg_imgui_resourcestate_string(sg_resource_state s) { _SOKOL_PRIVATE void _sg_imgui_draw_resource_slot(const sg_slot_info* slot) { igText("ResId: %08X", slot->res_id); - igText("CtxId: %08X", slot->ctx_id); igText("State: %s", _sg_imgui_resourcestate_string(slot->state)); } @@ -2777,19 +2776,6 @@ _SOKOL_PRIVATE void _sg_imgui_err_pass_pool_exhausted(void* user_data) { } } -_SOKOL_PRIVATE void _sg_imgui_err_context_mismatch(void* user_data) { - sg_imgui_t* ctx = (sg_imgui_t*) user_data; - SOKOL_ASSERT(ctx); - sg_imgui_capture_item_t* item = _sg_imgui_capture_next_write_item(ctx); - if (item) { - item->cmd = SG_IMGUI_CMD_ERR_CONTEXT_MISMATCH; - item->color = _SG_IMGUI_COLOR_ERR; - } - if (ctx->hooks.err_context_mismatch) { - ctx->hooks.err_context_mismatch(ctx->hooks.user_data); - } -} - _SOKOL_PRIVATE void _sg_imgui_err_pass_invalid(void* user_data) { sg_imgui_t* ctx = (sg_imgui_t*) user_data; SOKOL_ASSERT(ctx); @@ -3816,7 +3802,6 @@ SOKOL_API_IMPL void sg_imgui_init(sg_imgui_t* ctx) { hooks.err_shader_pool_exhausted = _sg_imgui_err_shader_pool_exhausted; hooks.err_pipeline_pool_exhausted = _sg_imgui_err_pipeline_pool_exhausted; hooks.err_pass_pool_exhausted = _sg_imgui_err_pass_pool_exhausted; - hooks.err_context_mismatch = _sg_imgui_err_context_mismatch; hooks.err_pass_invalid = _sg_imgui_err_pass_invalid; hooks.err_draw_invalid = _sg_imgui_err_draw_invalid; hooks.err_bindings_invalid = _sg_imgui_err_bindings_invalid; From 5a1ff5b6a4cac8fd1fe76e63f1c9df01d3ae4a9e Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 3 Jun 2021 20:13:56 +0200 Subject: [PATCH 47/49] sokol_app.h GL: fix initial wrongly reported framebuffer size for non-Retina case --- sokol_app.h | 153 +++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index cc20d4343..5fbadf648 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3699,6 +3699,69 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { [NSApp run]; } +_SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type type) { + if (_sapp_events_enabled()) { + _sapp_init_event(win, type); + _sapp_call_event(&_sapp.event); + } +} + +/* NOTE: unlike the iOS version of this function, the macOS version + can dynamically update the DPI scaling factor when a window is moved + between HighDPI / LowDPI screens. +*/ +_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { + CGFloat backing_scale_factor = [win->macos.window screen].backingScaleFactor; + if (win->desc.high_dpi) { + win->dpi_scale = backing_scale_factor; + } + else { + win->dpi_scale = 1.0f; + } + const NSRect bounds = [win->macos.view bounds]; + win->window_width = bounds.size.width; + win->window_height = bounds.size.height; + #if defined(SOKOL_METAL) + win->framebuffer_width = bounds.size.width * win->dpi_scale; + win->framebuffer_height = bounds.size.height * win->dpi_scale; + const CGSize fb_size = win->macos.view.drawableSize; + const int cur_fb_width = (int) fb_size.width; + const int cur_fb_height = (int) fb_size.height; + const bool dim_changed = (win->framebuffer_width != cur_fb_width) || + (win->framebuffer_height != cur_fb_height); + #elif defined(SOKOL_GLCORE33) + const int cur_fb_width = (int) bounds.size.width * win->dpi_scale; + const int cur_fb_height = (int) bounds.size.height * win->dpi_scale; + const bool dim_changed = (win->framebuffer_width != cur_fb_width) || + (win->framebuffer_height != cur_fb_height); + win->framebuffer_width = cur_fb_width; + win->framebuffer_height = cur_fb_height; + #endif + if (win->framebuffer_width == 0) { + win->framebuffer_width = 1; + } + if (win->framebuffer_height == 0) { + win->framebuffer_height = 1; + } + if (win->window_width == 0) { + win->window_width = 1; + } + if (win->window_height == 0) { + win->window_height = 1; + } + if (dim_changed) { + #if defined(SOKOL_METAL) + CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; + win->macos.view.drawableSize = drawable_size; + #else + // FIXME: nothing to do here? + #endif + if (!_sapp.first_frame) { + _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); + } + } +} + _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { SOKOL_ASSERT(win); if (win->fullscreen) { @@ -3706,16 +3769,6 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { win->window_width = screen_rect.size.width; win->window_height = screen_rect.size.height; } - if (win->desc.high_dpi) { - // FIXME: is there something like iOS 'nativeScale' on macOS? - win->framebuffer_width = 2 * win->window_width; - win->framebuffer_height = 2 * win->window_height; - } - else { - win->framebuffer_width = win->window_width; - win->framebuffer_height = win->window_height; - } - win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; NSUInteger style = NSWindowStyleMaskMiniaturizable; if (win->desc.no_decoration) { style |= NSWindowStyleMaskBorderless; @@ -3785,6 +3838,13 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { initWithFrame:content_rect pixelFormat:nsglpixelformat_obj]; win->macos.view.win_id = win->slot.id; + [win->macos.view updateTrackingAreas]; + if (win->desc.high_dpi) { + [win->macos.view setWantsBestResolutionOpenGLSurface:YES]; + } + else { + [win->macos.view setWantsBestResolutionOpenGLSurface:NO]; + } if (nil != shared_main_context) { // create a new NSOpenContext which shares resources with the main window's context NSOpenGLContext* nsgl_context = [[NSOpenGLContext alloc] initWithFormat:nsglpixelformat_obj shareContext:shared_main_context]; @@ -3793,13 +3853,6 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { _SAPP_OBJC_RELEASE(nsgl_context); } _SAPP_OBJC_RELEASE(nsglpixelformat_obj); - [win->macos.view updateTrackingAreas]; - if (win->desc.high_dpi) { - [win->macos.view setWantsBestResolutionOpenGLSurface:YES]; - } - else { - [win->macos.view setWantsBestResolutionOpenGLSurface:NO]; - } win->macos.window.contentView = win->macos.view; [win->macos.window makeFirstResponder:win->macos.view]; @@ -3816,6 +3869,7 @@ _SOKOL_PRIVATE bool _sapp_macos_create_window(_sapp_window_t* win) { _sapp_macos_set_window_pos(win, win->pos_x, win->pos_y); } } + _sapp_macos_update_dimensions(win); if (!win->desc.hidden) { [win->macos.window makeKeyAndOrderFront:nil]; } @@ -3923,13 +3977,6 @@ _SOKOL_PRIVATE void _sapp_macos_key_event(_sapp_window_t* win, sapp_event_type t } } -_SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* win, sapp_event_type type) { - if (_sapp_events_enabled()) { - _sapp_init_event(win, type); - _sapp_call_event(&_sapp.event); - } -} - _SOKOL_PRIVATE int _sapp_macos_flipy(_sapp_window_t* win, int y) { SOKOL_ASSERT(win && (win->macos.window != nil)); NSRect screen_rect = win->macos.window.screen.frame; @@ -3985,62 +4032,6 @@ _SOKOL_PRIVATE void _sapp_macos_activate_window_context(_sapp_window_t* win) { #endif } -/* NOTE: unlike the iOS version of this function, the macOS version - can dynamically update the DPI scaling factor when a window is moved - between HighDPI / LowDPI screens. -*/ -_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* win) { - #if defined(SOKOL_METAL) - /* FIXME: hmm dpi_scale is used here with the old value, but updated - further down... this looks wrong? - */ - const NSRect fb_rect = [win->macos.view bounds]; - win->framebuffer_width = fb_rect.size.width * win->dpi_scale; - win->framebuffer_height = fb_rect.size.height * win->dpi_scale; - const CGSize fb_size = win->macos.view.drawableSize; - const int cur_fb_width = (int) fb_size.width; - const int cur_fb_height = (int) fb_size.height; - const bool dim_changed = (win->framebuffer_width != cur_fb_width) || - (win->framebuffer_height != cur_fb_height); - #elif defined(SOKOL_GLCORE33) - // NOTE: on first call this will always return a Retina resolution framebuffer size - const NSRect fb_rect = [win->macos.view convertRectToBacking:[win->macos.view frame]]; - const int cur_fb_width = (int) fb_rect.size.width; - const int cur_fb_height = (int) fb_rect.size.height; - const bool dim_changed = (win->framebuffer_width != cur_fb_width) || - (win->framebuffer_height != cur_fb_height); - win->framebuffer_width = fb_rect.size.width; - win->framebuffer_height = fb_rect.size.height; - #endif - const NSRect bounds = [win->macos.view bounds]; - win->window_width = bounds.size.width; - win->window_height = bounds.size.height; - if (win->framebuffer_width == 0) { - win->framebuffer_width = 1; - } - if (win->framebuffer_height == 0) { - win->framebuffer_height = 1; - } - if (win->window_width == 0) { - win->window_width = 1; - } - if (win->window_height == 0) { - win->window_height = 1; - } - win->dpi_scale = (float)win->framebuffer_width / (float)win->window_width; - if (dim_changed) { - #if defined(SOKOL_METAL) - CGSize drawable_size = { (CGFloat) win->framebuffer_width, (CGFloat) win->framebuffer_height }; - win->macos.view.drawableSize = drawable_size; - #else - // FIXME: nothing to do here? - #endif - if (!_sapp.first_frame) { - _sapp_macos_app_event(win, SAPP_EVENTTYPE_RESIZED); - } - } -} - _SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(_sapp_window_t* win) { /* NOTE: the _sapp.fullscreen flag is also notified by the windowDidEnterFullscreen / windowDidExitFullscreen @@ -4423,11 +4414,11 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( the correct dimensions. */ - (void)reshape { + [super reshape]; _sapp_window_t* win = _sapp_lookup_window(self.win_id); if (win) { _sapp_macos_update_dimensions(win); } - [super reshape]; } - (void)prepareOpenGL { [super prepareOpenGL]; From 3c2fa0bafb38928c44dfb2643d05e0ec240e57b5 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 3 Jun 2021 20:23:54 +0200 Subject: [PATCH 48/49] sokol_app.h metal: fix MTKView internal texture resize --- sokol_app.h | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 5fbadf648..a74ae9b52 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -4184,26 +4184,34 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); _sapp_macos_activate_window_context(win); #endif - _sapp_frame(); + /* NOTE: the MTKView drawables MUST be resized right before the dummy draw + invocation, *NOT* from within the event loop, this is because + MTKView lazily resizes some "secondary" surfaces at the start + of the draw method before drawRect callback is called. Setting + the drawableSize in the event loop causes currentRenderPassDescriptor + to return a render pass descriptor with different surfaces sizes + */ for (int i = 0; i < _sapp.window_pool.pool.size; i++) { const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; _sapp_window_t* win = _sapp_lookup_window(win_id); if (win) { - /* NOTE: the MTKView drawables MUST be resized right before the dummy draw - invocation, *NOT* from within the event loop, this is because - MTKView lazily resizes some "secondary" surfaces at the start - of the draw method before drawRect callback is called. Setting - the drawableSize in the event loop causes currentRenderPassDescriptor - to return a render pass descriptor with different surfaces sizes - */ _sapp_macos_update_dimensions(win); + // let MTKView lazily resize its framebuffer textures #if defined(SOKOL_METAL) [win->macos.view draw]; - #else - [[win->macos.view openGLContext] flushBuffer]; #endif } } + _sapp_frame(); + #if defined(SOKOL_GLCORE33) + for (int i = 0; i < _sapp.window_pool.pool.size; i++) { + const uint32_t win_id = _sapp.window_pool.windows[i].slot.id; + _sapp_window_t* win = _sapp_lookup_window(win_id); + if (win) { + [[win->macos.view openGLContext] flushBuffer]; + } + } + #endif if (_sapp.quit_requested && !_sapp.quit_ordered) { _sapp_window_t* win = _sapp_lookup_window(_sapp.main_window_id); _sapp_macos_close_window(win); @@ -4434,15 +4442,6 @@ _SOKOL_PRIVATE CVReturn _sapp_macos_displaylink_callback( - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); - // FIXME? - /* - #if !defined(SOKOL_METAL) - _sapp_window_t* win = _sapp_lookup_window(self.win_id); - if (win) { - [[win->macos.view openGLContext] flushBuffer]; - } - #endif - */ } - (BOOL)isOpaque { From 57688eb0c5d09f6149ae6a612c5b53a56e94c328 Mon Sep 17 00:00:00 2001 From: Andre Weissflog Date: Thu, 3 Jun 2021 20:58:02 +0200 Subject: [PATCH 49/49] sokol_app.h macos: fix inverted y mouse pos computation --- sokol_app.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sokol_app.h b/sokol_app.h index a74ae9b52..9ba82ee48 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -4068,9 +4068,10 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_title(_sapp_window_t* win) { _SOKOL_PRIVATE void _sapp_macos_update_mouse(_sapp_window_t* win, NSEvent* event) { if (!win->mouse.locked) { + const NSRect content_rect = [win->macos.window contentRectForFrameRect:[win->macos.window frame]]; const NSPoint mouse_pos = event.locationInWindow; float new_x = mouse_pos.x * win->dpi_scale; - float new_y = win->framebuffer_height - (mouse_pos.y * win->dpi_scale) - 1; + float new_y = content_rect.size.height - (mouse_pos.y * win->dpi_scale) - 1; /* don't update dx/dy in the very first update */ if (win->mouse.pos_valid) { win->mouse.dx = new_x - win->mouse.x;