From 8f3788fb5930dc86dc533648f54e3cee7cfbd917 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Fri, 20 Nov 2020 15:39:24 -0700 Subject: [PATCH 01/14] adds basic multi-window support for win32 platform with D3D11/GLCORE33 --- sokol_app.h | 1329 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 897 insertions(+), 432 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index aa67a2164..e78658d7f 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -903,6 +903,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; @@ -1053,7 +1054,11 @@ enum { SAPP_MODIFIER_SUPER = (1<<3) }; +/* window handle typedef - simple uint32 id handle, sokol_gfx resource style */ +typedef struct sapp_window { uint32_t id; } sapp_window; + typedef struct sapp_event { + sapp_window window; uint64_t frame_count; sapp_event_type type; sapp_keycode key_code; @@ -1075,6 +1080,24 @@ typedef struct sapp_event { int framebuffer_height; } sapp_event; +typedef struct sapp_window_desc { + int width; /* the preferred width of the window / canvas */ + int height; /* the preferred height of the window / canvas */ + int sample_count; /* MSAA sample count */ + int swap_interval; /* the preferred swap interval (ignored on some platforms) */ + 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 high_dpi; /* whether the rendering canvas is full-resolution on HighDPI displays */ + 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; /* enable clipboard access, default is false */ + int clipboard_size; /* max size of clipboard content in bytes */ + sapp_window parent_window; /* if 0, main_window is used as a parent */ +} sapp_window_desc; + typedef struct sapp_desc { void (*init_cb)(void); /* these are the user-provided callbacks without user data */ void (*frame_cb)(void); @@ -1089,21 +1112,9 @@ typedef struct sapp_desc { 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 */ - 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) */ - + // TODO: currently is a breaking change to move everything into the window struct. Probably makes sense to just expose them instead and there's a bit of a "double up" + sapp_window_desc window; /* main window configuration */ + 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 */ @@ -1111,6 +1122,8 @@ typedef struct sapp_desc { 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 gl_force_gles2; /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */ + + uint32_t window_pool_size; /* max number of simultaneous windows this app can create */ } sapp_desc; /* HTML5 specific: request and response structs for @@ -1148,15 +1161,21 @@ extern sapp_desc sokol_main(int argc, char* argv[]); /* returns true after sokol-app has been initialized */ SOKOL_API_DECL bool sapp_isvalid(void); /* returns the current framebuffer width in pixels */ -SOKOL_API_DECL int sapp_width(void); +SOKOL_API_DECL int sapp_width(sapp_window window_id); /* returns the current framebuffer height in pixels */ -SOKOL_API_DECL int sapp_height(void); +SOKOL_API_DECL int sapp_height(sapp_window window_id); +/* returns the current framebuffer width in pixels */ +SOKOL_API_DECL int sapp_window_width(sapp_window window_id); +/* returns the current framebuffer height in pixels */ +SOKOL_API_DECL int sapp_window_height(sapp_window window_id); /* get default framebuffer color pixel format */ SOKOL_API_DECL int sapp_color_format(void); /* get default framebuffer depth pixel format */ SOKOL_API_DECL int sapp_depth_format(void); /* get default framebuffer sample count */ SOKOL_API_DECL int sapp_sample_count(void); +/* get window default framebuffer sample count */ +SOKOL_API_DECL int sapp_window_sample_count(sapp_window window_id); /* returns true when high_dpi was requested and actually running in a high-dpi scenario */ SOKOL_API_DECL bool sapp_high_dpi(void); /* returns the dpi scaling factor (window pixels to framebuffer pixels) */ @@ -1165,10 +1184,14 @@ SOKOL_API_DECL float sapp_dpi_scale(void); SOKOL_API_DECL void sapp_show_keyboard(bool show); /* return true if the mobile device onscreen keyboard is currently shown */ SOKOL_API_DECL bool sapp_keyboard_shown(void); -/* query fullscreen mode */ -SOKOL_API_DECL bool sapp_is_fullscreen(void); -/* toggle fullscreen mode */ -SOKOL_API_DECL void sapp_toggle_fullscreen(void); +/* query fullscreen mode for default window */ +SOKOL_API_DECL bool sapp_is_fullscreen(); +/* toggle fullscreen mode for default window */ +SOKOL_API_DECL void sapp_toggle_fullscreen(); +/* query fullscreen mode for a window */ +SOKOL_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id); +/* toggle fullscreen mode for a window*/ +SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id); /* show or hide the mouse cursor */ SOKOL_API_DECL void sapp_show_mouse(bool show); /* show or hide the mouse cursor */ @@ -1191,16 +1214,33 @@ SOKOL_API_DECL void sapp_quit(void); SOKOL_API_DECL void sapp_consume_event(void); /* get the current frame counter (for comparison with sapp_event.frame_count) */ SOKOL_API_DECL uint64_t sapp_frame_count(void); -/* write string into clipboard */ +/* write string into main window clipboard */ SOKOL_API_DECL void sapp_set_clipboard_string(const char* str); -/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */ +/* write string into window clipboard */ +SOKOL_API_DECL void sapp_window_set_clipboard_string(sapp_window window_id, const char* str); +/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) for main window*/ SOKOL_API_DECL const char* sapp_get_clipboard_string(void); -/* set the window title (only on desktop platforms) */ -SOKOL_API_DECL void sapp_set_window_title(const char* str); +/* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) for specific window */ +SOKOL_API_DECL const char* sapp_window_get_clipboard_string(sapp_window window_id); /* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED event) */ SOKOL_API_DECL int sapp_get_num_dropped_files(void); +/* gets the total number of dropped files (after an SAPP_EVENTTYPE_FILES_DROPPED event) for a specific window */ +SOKOL_API_DECL int sapp_window_get_num_dropped_files(sapp_window window_id); /* gets the dropped file paths */ SOKOL_API_DECL const char* sapp_get_dropped_file_path(int index); +/* gets the dropped file paths for window */ +SOKOL_API_DECL const char* sapp_window_get_dropped_file_path(sapp_window window_id, int index); + +/* returns this applications default/main window */ +SOKOL_API_DECL sapp_window sapp_main_window(); +/* create a new child window */ +SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc); +/* destroy a window */ +SOKOL_API_DECL void sapp_destroy_window(sapp_window window); +/* set the window title (only on desktop platforms) */ +SOKOL_API_DECL void sapp_set_window_title(sapp_window window, const char* str); +/* make window context current */ +SOKOL_API_DECL void sapp_make_context_current(sapp_window window); /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ SOKOL_API_DECL int sapp_run(const sapp_desc* desc); @@ -1232,10 +1272,16 @@ SOKOL_API_DECL const void* sapp_d3d11_get_device(void); SOKOL_API_DECL const void* sapp_d3d11_get_device_context(void); /* D3D11: get pointer to ID3D11RenderTargetView object */ SOKOL_API_DECL const void* sapp_d3d11_get_render_target_view(void); +/* D3D11: get pointer to ID3D11RenderTargetView object */ +SOKOL_API_DECL const void* sapp_d3d11_window_get_render_target_view(sapp_window window_id); /* D3D11: get pointer to ID3D11DepthStencilView */ SOKOL_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void); -/* Win32: get the HWND window handle */ +/* D3D11: get pointer to ID3D11DepthStencilView */ +SOKOL_API_DECL const void* sapp_d3d11_window_get_depth_stencil_view(sapp_window window_id); +/* Win32: get the HWND window handle of the main window */ SOKOL_API_DECL const void* sapp_win32_get_hwnd(void); +/* Win32: get the HWND window handle of the specified window */ +SOKOL_API_DECL const void* sapp_win32_window_get_hwnd(sapp_window window_id); /* WebGPU: get WGPUDevice handle */ SOKOL_API_DECL const void* sapp_wgpu_get_device(void); @@ -1353,7 +1399,7 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #ifndef SOKOL_UNREACHABLE #define SOKOL_UNREACHABLE SOKOL_ASSERT(false) #endif -#if !defined(SOKOL_CALLOC) || !defined(SOKOL_FREE) +#if !defined(SOKOL_CALLOC) || !defined(SOKOL_MALLOC) || !defined(SOKOL_FREE) #include #endif #if !defined(SOKOL_CALLOC) @@ -1362,6 +1408,9 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #if !defined(SOKOL_FREE) #define SOKOL_FREE(p) free(p) #endif +#if !defined(SOKOL_MALLOC) + #define SOKOL_MALLOC(s) malloc(s) +#endif #ifndef SOKOL_LOG #ifdef SOKOL_DEBUG #if defined(__ANDROID__) @@ -1635,20 +1684,15 @@ typedef struct { typedef struct { ID3D11Device* device; ID3D11DeviceContext* device_context; - ID3D11Texture2D* rt; - ID3D11RenderTargetView* rtv; - ID3D11Texture2D* msaa_rt; - ID3D11RenderTargetView* msaa_rtv; - ID3D11Texture2D* ds; - ID3D11DepthStencilView* dsv; - DXGI_SWAP_CHAIN_DESC swap_chain_desc; - IDXGISwapChain* swap_chain; + IDXGIFactory* dxgi_factory; } _sapp_d3d11_t; #endif /*== WIN32 DECLARATIONS ======================================================*/ #if defined(_SAPP_WIN32) +#define _SAPP_WINDOW_PROP "SAPP_WINDOW_PROP" + #ifndef DPI_ENUMS_DECLARED typedef enum PROCESS_DPI_AWARENESS { @@ -1672,12 +1716,8 @@ typedef struct { } _sapp_win32_dpi_t; typedef struct { - HWND hwnd; - HDC dc; LONG mouse_locked_x, mouse_locked_y; bool is_win10_or_greater; - bool in_create_window; - bool iconified; bool mouse_tracked; uint8_t mouse_capture_mask; _sapp_win32_dpi_t dpi; @@ -1687,6 +1727,13 @@ typedef struct { uint8_t raw_input_data[256]; } _sapp_win32_t; +typedef struct { + HWND hwnd; + HDC dc; + bool iconified; + bool in_create_window; +} _sapp_win32_window_t; + #if defined(SOKOL_GLCORE33) #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_SUPPORT_OPENGL_ARB 0x2010 @@ -1725,7 +1772,6 @@ typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); typedef struct { HINSTANCE opengl32; - HGLRC gl_ctx; PFN_wglCreateContext CreateContext; PFN_wglDeleteContext DeleteContext; PFN_wglGetProcAddress GetProcAddress; @@ -1996,10 +2042,57 @@ typedef struct { bool pos_valid; } _sapp_mouse_t; +/* this *MUST* remain 0 */ +enum { + _SAPP_SLOT_SHIFT = 16, + _SAPP_SLOT_MASK = (1<<_SAPP_SLOT_SHIFT)-1, + _SAPP_MAX_POOL_SIZE = (1<<_SAPP_SLOT_SHIFT), +}; + +#define _SAPP_INVALID_SLOT_INDEX (0) +#define SAPP_INVALID_ID (0) + +typedef struct { + int size; + int queue_top; + uint32_t* gen_ctrs; + int* free_queue; +} _sapp_pool_t; + +typedef struct { + uint32_t id; + bool fullscreen; + int window_width; + int window_height; + int framebuffer_width; + int framebuffer_height; + int swap_interval; + int sample_count; + char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */ + wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */ + _sapp_drop_t drop; + _sapp_clipboard_t clipboard; + #if defined(_SAPP_WIN32) + _sapp_win32_window_t win32; + + #if defined(SOKOL_GLCORE33) + HGLRC gl_ctx; + #elif defined(SOKOL_D3D11) + ID3D11Texture2D* rt; + ID3D11RenderTargetView* rtv; + ID3D11Texture2D* msaa_rt; + ID3D11RenderTargetView* msaa_rtv; + ID3D11Texture2D* ds; + ID3D11DepthStencilView* dsv; + DXGI_SWAP_CHAIN_DESC swap_chain_desc; + IDXGISwapChain* swap_chain; + #endif + #endif +} _sapp_window_t; + typedef struct { sapp_desc desc; bool valid; - bool fullscreen; bool gles2_fallback; bool first_frame; bool init_called; @@ -2009,18 +2102,10 @@ typedef struct { 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; #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -2046,12 +2131,17 @@ typedef struct { _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]; + + // TODO: Desktop only? Ignore completely for html5/android/iOS? + _sapp_pool_t window_pool; + _sapp_window_t* windows; + _sapp_window_t* main_window; } _sapp_t; static _sapp_t _sapp; + /*=== OPTIONAL MINI GL LOADER FOR WIN32/WGL ==================================*/ #if defined(_SAPP_WIN32) && defined(SOKOL_GLCORE33) && !defined(SOKOL_WIN32_NO_GL_LOADER) #define __gl_h_ 1 @@ -2479,12 +2569,12 @@ _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_PRIVATE char* _sapp_dropped_file_path_ptr(_sapp_window_t* window, int index) { + SOKOL_ASSERT(window->drop.buffer); + SOKOL_ASSERT((index >= 0) && (index <= window->drop.max_files)); + int offset = index * window->drop.max_path_length; + SOKOL_ASSERT(offset < window->drop.buf_size); + return &window->drop.buffer[offset]; } /* Copy a string into a fixed size buffer with guaranteed zero- @@ -2517,74 +2607,228 @@ _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_desc_defaults(const sapp_window_desc* in_desc) { + sapp_window_desc desc = *in_desc; 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.window_title = _sapp_def(desc.window_title, "sokol_app"); + desc.fullscreen = _sapp_def(desc.fullscreen, false); + desc.high_dpi = _sapp_def(desc.high_dpi, false); 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_desc_defaults(&in_desc->window); + desc.html5_canvas_name = _sapp_def(desc.html5_canvas_name, "canvas"); + desc.window_pool_size = _sapp_def(desc.window_pool_size, 1); + return desc; +} + +/*== pool init/alloc functions ==========================*/ + +_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 */ + size_t gen_ctrs_size = sizeof(uint32_t) * pool->size; + pool->gen_ctrs = (uint32_t*) SOKOL_MALLOC(gen_ctrs_size); + SOKOL_ASSERT(pool->gen_ctrs); + memset(pool->gen_ctrs, 0, gen_ctrs_size); + /* it's not a bug to only reserve 'num' here */ + pool->free_queue = (int*) SOKOL_MALLOC(sizeof(int)*num); + 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_setup_pools(const sapp_desc* desc) { + // Sanity check that we don't expect >1 windows on anything but desktop + #if !defined(_SAPP_WIN32) && !defined(_SAPP_MACOS) && !defined(_SAPP_LINUX) + // TODO: better place for this validation? + SOKOL_ASSERT(desc->window_pool_size == 1); + #endif + + SOKOL_ASSERT(desc); + /* note: the pools here will have an additional item, since slot 0 is reserved */ + SOKOL_ASSERT((desc->window_pool_size > 0) && (desc->window_pool_size < _SAPP_MAX_POOL_SIZE)); + _sapp_init_pool(&_sapp.window_pool, desc->window_pool_size); + size_t window_pool_byte_size = sizeof(_sapp_window_t) * _sapp.window_pool.size; + _sapp.windows = (_sapp_window_t*) SOKOL_MALLOC(window_pool_byte_size); + SOKOL_ASSERT(_sapp.windows); + memset(_sapp.windows, 0, window_pool_byte_size); +} + +_SOKOL_PRIVATE void _sapp_discard_pools() { + SOKOL_FREE(_sapp.windows); + _sapp.windows = 0; + + _sapp_discard_pool(&_sapp.window_pool); +} + +/* extract slot index from 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; +} + +/* returns pointer to resource by id without matching id check */ +_SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(uint32_t window_id) { + SOKOL_ASSERT((SAPP_INVALID_ID != window_id)); + int slot_index = _sapp_slot_index(window_id); + SOKOL_ASSERT((slot_index > _SAPP_INVALID_SLOT_INDEX) && (slot_index < _sapp.window_pool.size)); + return &_sapp.windows[slot_index]; +} + +/* returns pointer to resource with matching id check, may return 0 */ +_SOKOL_PRIVATE _sapp_window_t* _sapp_lookup_window(uint32_t window_id) { + if (SAPP_INVALID_ID != window_id) { + _sapp_window_t* window = _sapp_window_at(window_id); + if (window->id == window_id) { + return window; + } + } + return 0; +} + +_SOKOL_PRIVATE sapp_window _sapp_alloc_window(void) { + _sapp_pool_t* const pool = &_sapp.window_pool; + SOKOL_ASSERT(pool->gen_ctrs && pool->free_queue); + + sapp_window window_id; + + int slot_index = _sapp_pool_alloc_index(pool); + if (_SAPP_INVALID_SLOT_INDEX != slot_index) { + SOKOL_ASSERT(_sapp.windows[slot_index].id == SAPP_INVALID_ID); + uint32_t ctr = ++pool->gen_ctrs[slot_index]; + uint32_t id = (ctr<<_SAPP_SLOT_SHIFT)|(slot_index & _SAPP_SLOT_MASK); + _sapp.windows[slot_index].id = id; + window_id.id = id; + } + else { + /* pool is exhausted */ + window_id.id = SAPP_INVALID_ID; + } + return window_id; +} + +_SOKOL_PRIVATE void _sapp_reset_window(_sapp_window_t* window) { + SOKOL_ASSERT(window); + memset(window, 0, sizeof(_sapp_window_t)); +} + +_SOKOL_PRIVATE _sapp_window_t* _sapp_init_window(sapp_window window_id, const sapp_window_desc* desc){ + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID && desc); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + + window->window_width = desc->width; + window->window_height = desc->height; + window->framebuffer_width = desc->width; + window->framebuffer_height = desc->height; + window->fullscreen = desc->fullscreen; + + _sapp_strcpy(desc->window_title, window->window_title, sizeof(window->window_title)); + // TODO: do we need the below still? Potentially if we keep a desc in the window_t + // _sapp.desc.window.window_title = _sapp.window_title; + + window->swap_interval = desc->swap_interval; + window->sample_count = desc->sample_count; + + window->drop.enabled = desc->enable_dragndrop; + if (window->drop.enabled) { + window->drop.max_files = desc->max_dropped_files; + window->drop.max_path_length = desc->max_dropped_file_path_length; + window->drop.buf_size = window->drop.max_files * window->drop.max_path_length; + window->drop.buffer = (char*) SOKOL_CALLOC(1, window->drop.buf_size); + } + + window->clipboard.enabled = desc->enable_clipboard; + if (window->clipboard.enabled) { + window->clipboard.buf_size = desc->clipboard_size; + window->clipboard.buffer = (char*) SOKOL_CALLOC(1, window->clipboard.buf_size); + } + + return window; +} + _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, _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, _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; } _SOKOL_PRIVATE void _sapp_discard_state(void) { - if (_sapp.clipboard.enabled) { - SOKOL_ASSERT(_sapp.clipboard.buffer); - SOKOL_FREE((void*)_sapp.clipboard.buffer); - } - if (_sapp.drop.enabled) { - SOKOL_ASSERT(_sapp.drop.buffer); - SOKOL_FREE((void*)_sapp.drop.buffer); - } + _sapp_discard_pools(); _SAPP_CLEAR(_sapp_t, _sapp); } -_SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) { +_SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* window, sapp_event_type type) { memset(&_sapp.event, 0, sizeof(_sapp.event)); + _sapp.event.window.id = window->id; _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.window_width = window->window_width; + _sapp.event.window_height = window->window_height; + _sapp.event.framebuffer_width = window->framebuffer_width; + _sapp.event.framebuffer_height = window->framebuffer_height; _sapp.event.mouse_x = _sapp.mouse.x; _sapp.event.mouse_y = _sapp.mouse.y; _sapp.event.mouse_dx = _sapp.mouse.dx; @@ -2605,10 +2849,10 @@ _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, _sapp.drop.buf_size); +_SOKOL_PRIVATE void _sapp_clear_drop_buffer(_sapp_window_t* window) { + if (window->drop.enabled) { + SOKOL_ASSERT(window->drop.buffer); + memset(window->drop.buffer, 0, window->drop.buf_size); } } @@ -4980,9 +5224,9 @@ _SOKOL_PRIVATE bool _sapp_win32_uwp_utf8_to_wide(const char* src, wchar_t* dst, } } -_SOKOL_PRIVATE void _sapp_win32_uwp_app_event(sapp_event_type type) { +_SOKOL_PRIVATE void _sapp_win32_uwp_app_event(_sapp_window_t* window, sapp_event_type type) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp_call_event(&_sapp.event); } } @@ -5179,32 +5423,21 @@ static inline HRESULT _sapp_dxgi_Present(IDXGISwapChain* self, UINT SyncInterval #endif } -_SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { - DXGI_SWAP_CHAIN_DESC* sc_desc = &_sapp.d3d11.swap_chain_desc; - sc_desc->BufferDesc.Width = _sapp.framebuffer_width; - sc_desc->BufferDesc.Height = _sapp.framebuffer_height; - sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - sc_desc->BufferDesc.RefreshRate.Numerator = 60; - sc_desc->BufferDesc.RefreshRate.Denominator = 1; - sc_desc->OutputWindow = _sapp.win32.hwnd; - sc_desc->Windowed = true; - if (_sapp.win32.is_win10_or_greater) { - sc_desc->BufferCount = 2; - sc_desc->SwapEffect = (DXGI_SWAP_EFFECT) _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD; - } - else { - sc_desc->BufferCount = 1; - sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - } - sc_desc->SampleDesc.Count = 1; - sc_desc->SampleDesc.Quality = 0; - sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; +static inline HRESULT _sapp_dxgi_CreateSwapChain(IDXGIFactory* self, ID3D11Device* device, DXGI_SWAP_CHAIN_DESC* sc_desc, IDXGISwapChain** swap_chain) { + #if defined(__cplusplus) + return self->CreateSwapChain(device, sc_desc, swap_chain); + #else + return self->lpVtbl->CreateSwapChain(self, (IUnknown*)device, sc_desc, swap_chain); + #endif +} + +_SOKOL_PRIVATE void _sapp_d3d11_create_device(void) { int create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if defined(SOKOL_DEBUG) create_flags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_FEATURE_LEVEL feature_level; - HRESULT hr = D3D11CreateDeviceAndSwapChain( + HRESULT hr = D3D11CreateDevice( NULL, /* pAdapter (use default) */ D3D_DRIVER_TYPE_HARDWARE, /* DriverType */ NULL, /* Software */ @@ -5212,96 +5445,133 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) { NULL, /* pFeatureLevels */ 0, /* FeatureLevels */ D3D11_SDK_VERSION, /* SDKVersion */ - sc_desc, /* pSwapChainDesc */ - &_sapp.d3d11.swap_chain, /* ppSwapChain */ &_sapp.d3d11.device, /* ppDevice */ &feature_level, /* pFeatureLevel */ &_sapp.d3d11.device_context); /* ppImmediateContext */ _SOKOL_UNUSED(hr); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.swap_chain && _sapp.d3d11.device && _sapp.d3d11.device_context); + SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.device && _sapp.d3d11.device_context); + + // We need a dxgi factory to create multiple swapchains + hr = CreateDXGIFactory(&IID_IDXGIFactory, (void**)&_sapp.d3d11.dxgi_factory); + SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.dxgi_factory); } -_SOKOL_PRIVATE void _sapp_d3d11_destroy_device_and_swapchain(void) { - _SAPP_SAFE_RELEASE(_sapp.d3d11.swap_chain); +_SOKOL_PRIVATE void _sapp_d3d11_create_swapchain(_sapp_window_t* window) { + DXGI_SWAP_CHAIN_DESC* sc_desc = &window->swap_chain_desc; + sc_desc->BufferDesc.Width = window->framebuffer_width; + sc_desc->BufferDesc.Height = window->framebuffer_height; + sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + sc_desc->BufferDesc.RefreshRate.Numerator = 60; + sc_desc->BufferDesc.RefreshRate.Denominator = 1; + sc_desc->OutputWindow = window->win32.hwnd; + sc_desc->Windowed = true; + if (_sapp.win32.is_win10_or_greater) { + sc_desc->BufferCount = 2; + sc_desc->SwapEffect = (DXGI_SWAP_EFFECT) _SAPP_DXGI_SWAP_EFFECT_FLIP_DISCARD; + } + else { + sc_desc->BufferCount = 1; + sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + } + sc_desc->SampleDesc.Count = 1; + sc_desc->SampleDesc.Quality = 0; + sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + + HRESULT hr = _sapp_dxgi_CreateSwapChain( + _sapp.d3d11.dxgi_factory, /* dxgi_factory */ + _sapp.d3d11.device, /* *pDevice */ + sc_desc, /* Swapchain Desc */ + &window->swap_chain /* ppSwapChain */ + ); + + SOKOL_ASSERT(SUCCEEDED(hr) && window->swap_chain); +} + +_SOKOL_PRIVATE void _sapp_d3d11_destroy_device() { _SAPP_SAFE_RELEASE(_sapp.d3d11.device_context); _SAPP_SAFE_RELEASE(_sapp.d3d11.device); + _SAPP_SAFE_RELEASE(_sapp.d3d11.dxgi_factory); +} + +_SOKOL_PRIVATE void _sapp_d3d11_destroy_swapchain(_sapp_window_t* window) { + _SAPP_SAFE_RELEASE(window->swap_chain); } -_SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) { - SOKOL_ASSERT(0 == _sapp.d3d11.rt); - SOKOL_ASSERT(0 == _sapp.d3d11.rtv); - SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rt); - SOKOL_ASSERT(0 == _sapp.d3d11.msaa_rtv); - SOKOL_ASSERT(0 == _sapp.d3d11.ds); - SOKOL_ASSERT(0 == _sapp.d3d11.dsv); +_SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(_sapp_window_t* window) { + SOKOL_ASSERT(0 == window->rt); + SOKOL_ASSERT(0 == window->rtv); + SOKOL_ASSERT(0 == window->msaa_rt); + SOKOL_ASSERT(0 == window->msaa_rtv); + SOKOL_ASSERT(0 == window->ds); + SOKOL_ASSERT(0 == window->dsv); HRESULT hr; /* view for the swapchain-created framebuffer */ #ifdef __cplusplus - hr = _sapp_dxgi_GetBuffer(_sapp.d3d11.swap_chain, 0, IID_ID3D11Texture2D, (void**)&_sapp.d3d11.rt); + hr = _sapp_dxgi_GetBuffer(window->swap_chain, 0, IID_ID3D11Texture2D, (void**)&window->rt); #else - hr = _sapp_dxgi_GetBuffer(_sapp.d3d11.swap_chain, 0, &IID_ID3D11Texture2D, (void**)&_sapp.d3d11.rt); + hr = _sapp_dxgi_GetBuffer(window->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&window->rt); #endif - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.rt, NULL, &_sapp.d3d11.rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->rt); + hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->rt, NULL, &window->rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->rtv); /* common desc for MSAA and depth-stencil texture */ D3D11_TEXTURE2D_DESC tex_desc; memset(&tex_desc, 0, sizeof(tex_desc)); - tex_desc.Width = _sapp.framebuffer_width; - tex_desc.Height = _sapp.framebuffer_height; + tex_desc.Width = window->framebuffer_width; + tex_desc.Height = window->framebuffer_height; tex_desc.MipLevels = 1; tex_desc.ArraySize = 1; tex_desc.Usage = D3D11_USAGE_DEFAULT; tex_desc.BindFlags = D3D11_BIND_RENDER_TARGET; - tex_desc.SampleDesc.Count = _sapp.sample_count; - tex_desc.SampleDesc.Quality = _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0; + tex_desc.SampleDesc.Count = window->sample_count; + tex_desc.SampleDesc.Quality = window->sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0; /* create MSAA texture and view if antialiasing requested */ - if (_sapp.sample_count > 1) { + if (window->sample_count > 1) { tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.msaa_rt); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.msaa_rt, NULL, &_sapp.d3d11.msaa_rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.msaa_rtv); + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->msaa_rt); + SOKOL_ASSERT(SUCCEEDED(hr) && window->msaa_rt); + hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->msaa_rt, NULL, &window->msaa_rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->msaa_rtv); } /* texture and view for the depth-stencil-surface */ tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &_sapp.d3d11.ds); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.ds); - hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)_sapp.d3d11.ds, NULL, &_sapp.d3d11.dsv); - SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.dsv); + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->ds); + SOKOL_ASSERT(SUCCEEDED(hr) && window->ds); + hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)window->ds, NULL, &window->dsv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->dsv); } -_SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(void) { - _SAPP_SAFE_RELEASE(_sapp.d3d11.rt); - _SAPP_SAFE_RELEASE(_sapp.d3d11.rtv); - _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rt); - _SAPP_SAFE_RELEASE(_sapp.d3d11.msaa_rtv); - _SAPP_SAFE_RELEASE(_sapp.d3d11.ds); - _SAPP_SAFE_RELEASE(_sapp.d3d11.dsv); +_SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(_sapp_window_t* window) { + _SAPP_SAFE_RELEASE(window->rt); + _SAPP_SAFE_RELEASE(window->rtv); + _SAPP_SAFE_RELEASE(window->msaa_rt); + _SAPP_SAFE_RELEASE(window->msaa_rtv); + _SAPP_SAFE_RELEASE(window->ds); + _SAPP_SAFE_RELEASE(window->dsv); } -_SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) { - if (_sapp.d3d11.swap_chain) { - _sapp_d3d11_destroy_default_render_target(); - _sapp_dxgi_ResizeBuffers(_sapp.d3d11.swap_chain, _sapp.d3d11.swap_chain_desc.BufferCount, _sapp.framebuffer_width, _sapp.framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); - _sapp_d3d11_create_default_render_target(); +_SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(_sapp_window_t* window) { + if (window->swap_chain) { + _sapp_d3d11_destroy_default_render_target(window); + _sapp_dxgi_ResizeBuffers(window->swap_chain, window->swap_chain_desc.BufferCount, window->framebuffer_width, window->framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + _sapp_d3d11_create_default_render_target(window); } } -_SOKOL_PRIVATE void _sapp_d3d11_present(void) { +_SOKOL_PRIVATE void _sapp_d3d11_present(_sapp_window_t* window) { /* do MSAA resolve if needed */ - if (_sapp.sample_count > 1) { - SOKOL_ASSERT(_sapp.d3d11.rt); - SOKOL_ASSERT(_sapp.d3d11.msaa_rt); - _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)_sapp.d3d11.rt, 0, (ID3D11Resource*)_sapp.d3d11.msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); + if (window->sample_count > 1) { + SOKOL_ASSERT(window->rt); + SOKOL_ASSERT(window->msaa_rt); + _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)window->rt, 0, (ID3D11Resource*)window->msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); } - _sapp_dxgi_Present(_sapp.d3d11.swap_chain, _sapp.swap_interval, 0); + _sapp_dxgi_Present(window->swap_chain, window->swap_interval, 0); } #endif /* SOKOL_D3D11 */ @@ -5422,51 +5692,60 @@ _SOKOL_PRIVATE void _sapp_wgl_load_extensions(void) { _sapp.wgl.arb_create_context_profile = _sapp_wgl_ext_supported("WGL_ARB_create_context_profile"); _sapp.wgl.ext_swap_control = _sapp_wgl_ext_supported("WGL_EXT_swap_control"); _sapp.wgl.arb_pixel_format = _sapp_wgl_ext_supported("WGL_ARB_pixel_format"); + + /* + Moved to here from _sapp_win32_run, since we need an active context for this to work. I have heard before that technically these should be loaded + on the same context as their usage, but never experienced any problems in practice. + */ + #if !defined(SOKOL_WIN32_NO_GL_LOADER) + _sapp_win32_gl_loadfuncs(); + #endif + _sapp.wgl.MakeCurrent(_sapp.wgl.msg_dc, 0); _sapp.wgl.DeleteContext(rc); } -_SOKOL_PRIVATE int _sapp_wgl_attrib(int pixel_format, int attrib) { +_SOKOL_PRIVATE int _sapp_wgl_attrib(_sapp_window_t* window, int pixel_format, int attrib) { SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); int value = 0; - if (!_sapp.wgl.GetPixelFormatAttribivARB(_sapp.win32.dc, pixel_format, 0, 1, &attrib, &value)) { + if (!_sapp.wgl.GetPixelFormatAttribivARB(window->win32.dc, pixel_format, 0, 1, &attrib, &value)) { _sapp_fail("WGL: Failed to retrieve pixel format attribute\n"); } return value; } -_SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { - SOKOL_ASSERT(_sapp.win32.dc); +_SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(_sapp_window_t* window) { + SOKOL_ASSERT(window->win32.dc); SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); const _sapp_gl_fbconfig* closest; - int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB); + int native_count = _sapp_wgl_attrib(window, 1, WGL_NUMBER_PIXEL_FORMATS_ARB); _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig)); int usable_count = 0; for (int i = 0; i < native_count; i++) { const int n = i + 1; _sapp_gl_fbconfig* u = usable_configs + usable_count; _sapp_gl_init_fbconfig(u); - if (!_sapp_wgl_attrib(n, WGL_SUPPORT_OPENGL_ARB) || !_sapp_wgl_attrib(n, WGL_DRAW_TO_WINDOW_ARB)) { + if (!_sapp_wgl_attrib(window, n, WGL_SUPPORT_OPENGL_ARB) || !_sapp_wgl_attrib(window, n, WGL_DRAW_TO_WINDOW_ARB)) { continue; } - if (_sapp_wgl_attrib(n, WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) { + if (_sapp_wgl_attrib(window, n, WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) { continue; } - if (_sapp_wgl_attrib(n, WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) { + if (_sapp_wgl_attrib(window, n, WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) { continue; } - u->red_bits = _sapp_wgl_attrib(n, WGL_RED_BITS_ARB); - u->green_bits = _sapp_wgl_attrib(n, WGL_GREEN_BITS_ARB); - u->blue_bits = _sapp_wgl_attrib(n, WGL_BLUE_BITS_ARB); - u->alpha_bits = _sapp_wgl_attrib(n, WGL_ALPHA_BITS_ARB); - u->depth_bits = _sapp_wgl_attrib(n, WGL_DEPTH_BITS_ARB); - u->stencil_bits = _sapp_wgl_attrib(n, WGL_STENCIL_BITS_ARB); - if (_sapp_wgl_attrib(n, WGL_DOUBLE_BUFFER_ARB)) { + u->red_bits = _sapp_wgl_attrib(window, n, WGL_RED_BITS_ARB); + u->green_bits = _sapp_wgl_attrib(window, n, WGL_GREEN_BITS_ARB); + u->blue_bits = _sapp_wgl_attrib(window, n, WGL_BLUE_BITS_ARB); + u->alpha_bits = _sapp_wgl_attrib(window, n, WGL_ALPHA_BITS_ARB); + u->depth_bits = _sapp_wgl_attrib(window, n, WGL_DEPTH_BITS_ARB); + u->stencil_bits = _sapp_wgl_attrib(window, n, WGL_STENCIL_BITS_ARB); + if (_sapp_wgl_attrib(window, n, WGL_DOUBLE_BUFFER_ARB)) { u->doublebuffer = true; } if (_sapp.wgl.arb_multisample) { - u->samples = _sapp_wgl_attrib(n, WGL_SAMPLES_ARB); + u->samples = _sapp_wgl_attrib(window, n, WGL_SAMPLES_ARB); } u->handle = n; usable_count++; @@ -5481,7 +5760,7 @@ _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { desired.depth_bits = 24; desired.stencil_bits = 8; desired.doublebuffer = true; - desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0; + desired.samples = window->sample_count > 1 ? window->sample_count : 0; closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count); int pixel_format = 0; if (closest) { @@ -5491,16 +5770,16 @@ _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { return pixel_format; } -_SOKOL_PRIVATE void _sapp_wgl_create_context(void) { - int pixel_format = _sapp_wgl_find_pixel_format(); +_SOKOL_PRIVATE void _sapp_wgl_create_context(_sapp_window_t* window) { + int pixel_format = _sapp_wgl_find_pixel_format(window); if (0 == pixel_format) { _sapp_fail("WGL: Didn't find matching pixel format.\n"); } PIXELFORMATDESCRIPTOR pfd; - if (!DescribePixelFormat(_sapp.win32.dc, pixel_format, sizeof(pfd), &pfd)) { + if (!DescribePixelFormat(window->win32.dc, pixel_format, sizeof(pfd), &pfd)) { _sapp_fail("WGL: Failed to retrieve PFD for selected pixel format!\n"); } - if (!SetPixelFormat(_sapp.win32.dc, pixel_format, &pfd)) { + if (!SetPixelFormat(window->win32.dc, pixel_format, &pfd)) { _sapp_fail("WGL: Failed to set selected pixel format!\n"); } if (!_sapp.wgl.arb_create_context) { @@ -5516,8 +5795,8 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(void) { WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0 }; - _sapp.wgl.gl_ctx = _sapp.wgl.CreateContextAttribsARB(_sapp.win32.dc, 0, attrs); - if (!_sapp.wgl.gl_ctx) { + window->gl_ctx = _sapp.wgl.CreateContextAttribsARB(window->win32.dc, 0, attrs); + if (!window->gl_ctx) { const DWORD err = GetLastError(); if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { _sapp_fail("WGL: Driver does not support OpenGL version 3.3\n"); @@ -5532,23 +5811,23 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(void) { _sapp_fail("WGL: Failed to create OpenGL context"); } } - _sapp.wgl.MakeCurrent(_sapp.win32.dc, _sapp.wgl.gl_ctx); + _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); if (_sapp.wgl.ext_swap_control) { /* FIXME: DwmIsCompositionEnabled() (see GLFW) */ - _sapp.wgl.SwapIntervalEXT(_sapp.swap_interval); + _sapp.wgl.SwapIntervalEXT(window->swap_interval); } } -_SOKOL_PRIVATE void _sapp_wgl_destroy_context(void) { - SOKOL_ASSERT(_sapp.wgl.gl_ctx); - _sapp.wgl.DeleteContext(_sapp.wgl.gl_ctx); - _sapp.wgl.gl_ctx = 0; +_SOKOL_PRIVATE void _sapp_wgl_destroy_context(_sapp_window_t* window) { + SOKOL_ASSERT(window->gl_ctx); + _sapp.wgl.DeleteContext(window->gl_ctx); + window->gl_ctx = 0; } -_SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) { - SOKOL_ASSERT(_sapp.win32.dc); +_SOKOL_PRIVATE void _sapp_wgl_swap_buffers(_sapp_window_t* window) { + SOKOL_ASSERT(window->win32.dc); /* FIXME: DwmIsCompositionEnabled? (see GLFW) */ - SwapBuffers(_sapp.win32.dc); + SwapBuffers(window->win32.dc); } #endif /* SOKOL_GLCORE33 */ @@ -5565,8 +5844,8 @@ _SOKOL_PRIVATE bool _sapp_win32_wide_to_utf8(const wchar_t* src, char* dst, int } } -_SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) { - HMONITOR monitor = MonitorFromWindow(_sapp.win32.hwnd, MONITOR_DEFAULTTONEAREST); +_SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(_sapp_window_t* window) { + HMONITOR monitor = MonitorFromWindow(window->win32.hwnd, MONITOR_DEFAULTTONEAREST); MONITORINFO minfo; memset(&minfo, 0, sizeof(minfo)); minfo.cbSize = sizeof(MONITORINFO); @@ -5579,11 +5858,12 @@ _SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) { DWORD win_style; RECT rect = { 0, 0, 0, 0 }; - _sapp.fullscreen = !_sapp.fullscreen; - if (!_sapp.fullscreen) { + // TODO: Update to window specific desc, we currently don't store the window desc inside the window, needed? + window->fullscreen = !window->fullscreen; + if (!window->fullscreen) { win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; - rect.right = (int) ((float)_sapp.desc.width * _sapp.win32.dpi.window_scale); - rect.bottom = (int) ((float)_sapp.desc.height * _sapp.win32.dpi.window_scale); + rect.right = (int) ((float)_sapp.desc.window.width * _sapp.win32.dpi.window_scale); + rect.bottom = (int) ((float)_sapp.desc.window.height * _sapp.win32.dpi.window_scale); } else { win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE; @@ -5593,13 +5873,13 @@ _SOKOL_PRIVATE void _sapp_win32_toggle_fullscreen(void) { AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style); int win_width = rect.right - rect.left; int win_height = rect.bottom - rect.top; - if (!_sapp.fullscreen) { + if (!window->fullscreen) { rect.left = (monitor_w - win_width) / 2; rect.top = (monitor_h - win_height) / 2; } - SetWindowLongPtr(_sapp.win32.hwnd, GWL_STYLE, win_style); - SetWindowPos(_sapp.win32.hwnd, HWND_TOP, mr.left + rect.left, mr.top + rect.top, win_width, win_height, SWP_SHOWWINDOW | SWP_FRAMECHANGED); + SetWindowLongPtr(window->win32.hwnd, GWL_STYLE, win_style); + SetWindowPos(window->win32.hwnd, HWND_TOP, mr.left + rect.left, mr.top + rect.top, win_width, win_height, SWP_SHOWWINDOW | SWP_FRAMECHANGED); } _SOKOL_PRIVATE void _sapp_win32_show_mouse(bool visible) { @@ -5607,9 +5887,10 @@ _SOKOL_PRIVATE void _sapp_win32_show_mouse(bool visible) { ShowCursor((BOOL)visible); } -_SOKOL_PRIVATE void _sapp_win32_capture_mouse(uint8_t btn_mask) { +_SOKOL_PRIVATE void _sapp_win32_capture_mouse(_sapp_window_t* window, uint8_t btn_mask) { + // TODO: window specific capture flag, what exactly happens here? Don't fully understand the code yet. if (0 == _sapp.win32.mouse_capture_mask) { - SetCapture(_sapp.win32.hwnd); + SetCapture(window->win32.hwnd); } _sapp.win32.mouse_capture_mask |= btn_mask; } @@ -5623,7 +5904,7 @@ _SOKOL_PRIVATE void _sapp_win32_release_mouse(uint8_t btn_mask) { } } -_SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { +_SOKOL_PRIVATE void _sapp_win32_lock_mouse(_sapp_window_t* window, bool lock) { if (lock == _sapp.mouse.locked) { return; } @@ -5656,10 +5937,10 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { /* enable raw input for mouse, starts sending WM_INPUT messages to WinProc (see GLFW) */ const RAWINPUTDEVICE rid = { - 0x01, // usUsagePage: HID_USAGE_PAGE_GENERIC - 0x02, // usUsage: HID_USAGE_GENERIC_MOUSE - 0, // dwFlags - _sapp.win32.hwnd // hwndTarget + 0x01, // usUsagePage: HID_USAGE_PAGE_GENERIC + 0x02, // usUsage: HID_USAGE_GENERIC_MOUSE + 0, // dwFlags + window->win32.hwnd // hwndTarget }; if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { SOKOL_LOG("RegisterRawInputDevices() failed (on mouse lock).\n"); @@ -5687,29 +5968,30 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(bool lock) { } /* updates current window and framebuffer size from the window's client rect, returns true if size has changed */ -_SOKOL_PRIVATE bool _sapp_win32_update_dimensions(void) { +_SOKOL_PRIVATE bool _sapp_win32_update_dimensions(_sapp_window_t* window) { RECT rect; - if (GetClientRect(_sapp.win32.hwnd, &rect)) { - _sapp.window_width = (int)((float)(rect.right - rect.left) / _sapp.win32.dpi.window_scale); - _sapp.window_height = (int)((float)(rect.bottom - rect.top) / _sapp.win32.dpi.window_scale); - const int fb_width = (int)((float)_sapp.window_width * _sapp.win32.dpi.content_scale); - const int fb_height = (int)((float)_sapp.window_height * _sapp.win32.dpi.content_scale); - if ((fb_width != _sapp.framebuffer_width) || (fb_height != _sapp.framebuffer_height)) { - _sapp.framebuffer_width = fb_width; - _sapp.framebuffer_height = fb_height; + if (GetClientRect(window->win32.hwnd, &rect)) { + // TODO: should dpi scale be per window? I don't even know if that's possible + window->window_width = (int)((float)(rect.right - rect.left) / _sapp.win32.dpi.window_scale); + window->window_height = (int)((float)(rect.bottom - rect.top) / _sapp.win32.dpi.window_scale); + const int fb_width = (int)((float)window->window_width * _sapp.win32.dpi.content_scale); + const int fb_height = (int)((float)window->window_height * _sapp.win32.dpi.content_scale); + if ((fb_width != window->framebuffer_width) || (fb_height != window->framebuffer_height)) { + window->framebuffer_width = fb_width; + window->framebuffer_height = fb_height; /* prevent a framebuffer size of 0 when window is minimized */ - if (_sapp.framebuffer_width == 0) { - _sapp.framebuffer_width = 1; + if (window->framebuffer_width == 0) { + window->framebuffer_width = 1; } - if (_sapp.framebuffer_height == 0) { - _sapp.framebuffer_height = 1; + if (window->framebuffer_height == 0) { + window->framebuffer_height = 1; } return true; } } else { - _sapp.window_width = _sapp.window_height = 1; - _sapp.framebuffer_width = _sapp.framebuffer_height = 1; + window->window_width = window->window_height = 1; + window->framebuffer_width = window->framebuffer_height = 1; } return false; } @@ -5731,18 +6013,18 @@ _SOKOL_PRIVATE uint32_t _sapp_win32_mods(void) { return mods; } -_SOKOL_PRIVATE void _sapp_win32_mouse_event(sapp_event_type type, sapp_mousebutton btn) { +_SOKOL_PRIVATE void _sapp_win32_mouse_event(_sapp_window_t* window, sapp_event_type type, sapp_mousebutton btn) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.modifiers = _sapp_win32_mods(); _sapp.event.mouse_button = btn; _sapp_call_event(&_sapp.event); } } -_SOKOL_PRIVATE void _sapp_win32_scroll_event(float x, float y) { +_SOKOL_PRIVATE void _sapp_win32_scroll_event(_sapp_window_t* window, float x, float y) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(window, SAPP_EVENTTYPE_MOUSE_SCROLL); _sapp.event.modifiers = _sapp_win32_mods(); _sapp.event.scroll_x = -x / 30.0f; _sapp.event.scroll_y = y / 30.0f; @@ -5750,28 +6032,28 @@ _SOKOL_PRIVATE void _sapp_win32_scroll_event(float x, float y) { } } -_SOKOL_PRIVATE void _sapp_win32_key_event(sapp_event_type type, int vk, bool repeat) { +_SOKOL_PRIVATE void _sapp_win32_key_event(_sapp_window_t* window, sapp_event_type type, int vk, bool repeat) { if (_sapp_events_enabled() && (vk < SAPP_MAX_KEYCODES)) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.modifiers = _sapp_win32_mods(); _sapp.event.key_code = _sapp.keycodes[vk]; _sapp.event.key_repeat = repeat; _sapp_call_event(&_sapp.event); /* check if a CLIPBOARD_PASTED event must be sent too */ - if (_sapp.clipboard.enabled && + if (window->clipboard.enabled && (type == SAPP_EVENTTYPE_KEY_DOWN) && (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) && (_sapp.event.key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_init_event(window, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } } } -_SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c, bool repeat) { +_SOKOL_PRIVATE void _sapp_win32_char_event(_sapp_window_t* window, uint32_t c, bool repeat) { if (_sapp_events_enabled() && (c >= 32)) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); + _sapp_init_event(window, SAPP_EVENTTYPE_CHAR); _sapp.event.modifiers = _sapp_win32_mods(); _sapp.event.char_code = c; _sapp.event.key_repeat = repeat; @@ -5779,19 +6061,19 @@ _SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c, bool repeat) { } } -_SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) { - if (!_sapp.drop.enabled) { +_SOKOL_PRIVATE void _sapp_win32_files_dropped(_sapp_window_t* window, HDROP hdrop) { + if (!window->drop.enabled) { return; } - _sapp_clear_drop_buffer(); + _sapp_clear_drop_buffer(window); bool drop_failed = false; const int count = (int) DragQueryFileW(hdrop, 0xffffffff, NULL, 0); - _sapp.drop.num_files = (count > _sapp.drop.max_files) ? _sapp.drop.max_files : count; - for (int i = 0; i < _sapp.drop.num_files; i++) { + window->drop.num_files = (count > window->drop.max_files) ? window->drop.max_files : count; + for (int i = 0; i < window->drop.num_files; i++) { const UINT num_chars = DragQueryFileW(hdrop, i, NULL, 0) + 1; WCHAR* buffer = (WCHAR*) SOKOL_CALLOC(num_chars, sizeof(WCHAR)); DragQueryFileW(hdrop, i, buffer, num_chars); - if (!_sapp_win32_wide_to_utf8(buffer, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { + if (!_sapp_win32_wide_to_utf8(buffer, _sapp_dropped_file_path_ptr(window, i), 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; } @@ -5800,41 +6082,49 @@ _SOKOL_PRIVATE void _sapp_win32_files_dropped(HDROP hdrop) { DragFinish(hdrop); if (!drop_failed) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_init_event(window, SAPP_EVENTTYPE_FILES_DROPPED); _sapp_call_event(&_sapp.event); } } else { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; + _sapp_clear_drop_buffer(window); + window->drop.num_files = 0; } } _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (!_sapp.win32.in_create_window) { + _sapp_window_t* window = (_sapp_window_t*)GetPropA(hWnd, _SAPP_WINDOW_PROP); + if (window && !window->win32.in_create_window) { switch (uMsg) { case WM_CLOSE: - /* only give user 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 change to intervene via sapp_cancel_quit() - */ - _sapp.quit_requested = true; - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - /* if user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; + if(window == _sapp.main_window){ + /* only give user 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 change to intervene via sapp_cancel_quit() + */ + _sapp.quit_requested = true; + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_QUIT_REQUESTED); + /* if user code hasn't intervened, quit the app */ + if (_sapp.quit_requested) { + _sapp.quit_ordered = true; + } + } + if (_sapp.quit_ordered) { + PostQuitMessage(0); } } - if (_sapp.quit_ordered) { - PostQuitMessage(0); + else { + // TODO: wo we want to give the user a per window opportunity to cancel closure requests? + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_WINDOW_CLOSED); + sapp_destroy_window((sapp_window){ .id = window->id }); } return 0; case WM_SYSCOMMAND: switch (wParam & 0xFFF0) { case SC_SCREENSAVE: case SC_MONITORPOWER: - if (_sapp.fullscreen) { + if (window->fullscreen) { /* disable screen saver and blanking in fullscreen mode */ return 0; } @@ -5849,47 +6139,47 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM case WM_SIZE: { const bool iconified = wParam == SIZE_MINIMIZED; - if (iconified != _sapp.win32.iconified) { - _sapp.win32.iconified = iconified; + if (iconified != window->win32.iconified) { + window->win32.iconified = iconified; if (iconified) { - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_ICONIFIED); + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_ICONIFIED); } else { - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESTORED); + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_RESTORED); } } } break; case WM_SETCURSOR: - if (_sapp.desc.user_cursor) { + if (_sapp.desc.window.user_cursor) { if (LOWORD(lParam) == HTCLIENT) { - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR); + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_UPDATE_CURSOR); return 1; } } break; case WM_LBUTTONDOWN: - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT); - _sapp_win32_capture_mouse(1<win32.hwnd; TrackMouseEvent(&tme); - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID); + _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID); } - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); + _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); } break; case WM_INPUT: @@ -5948,60 +6238,61 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM _sapp.mouse.dx = (float) raw_mouse_data->data.mouse.lLastX; _sapp.mouse.dy = (float) raw_mouse_data->data.mouse.lLastY; } - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); + _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); } break; case WM_MOUSELEAVE: if (!_sapp.mouse.locked) { _sapp.win32.mouse_tracked = false; - _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID); + _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID); } break; case WM_MOUSEWHEEL: - _sapp_win32_scroll_event(0.0f, (float)((SHORT)HIWORD(wParam))); + _sapp_win32_scroll_event(window, 0.0f, (float)((SHORT)HIWORD(wParam))); break; case WM_MOUSEHWHEEL: - _sapp_win32_scroll_event((float)((SHORT)HIWORD(wParam)), 0.0f); + _sapp_win32_scroll_event(window, (float)((SHORT)HIWORD(wParam)), 0.0f); break; case WM_CHAR: - _sapp_win32_char_event((uint32_t)wParam, !!(lParam&0x40000000)); + _sapp_win32_char_event(window, (uint32_t)wParam, !!(lParam&0x40000000)); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: - _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_DOWN, (int)(HIWORD(lParam)&0x1FF), !!(lParam&0x40000000)); + _sapp_win32_key_event(window, SAPP_EVENTTYPE_KEY_DOWN, (int)(HIWORD(lParam)&0x1FF), !!(lParam&0x40000000)); break; case WM_KEYUP: case WM_SYSKEYUP: - _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_UP, (int)(HIWORD(lParam)&0x1FF), false); + _sapp_win32_key_event(window, SAPP_EVENTTYPE_KEY_UP, (int)(HIWORD(lParam)&0x1FF), false); break; case WM_ENTERSIZEMOVE: - SetTimer(_sapp.win32.hwnd, 1, USER_TIMER_MINIMUM, NULL); + SetTimer(window->win32.hwnd, 1, USER_TIMER_MINIMUM, NULL); break; case WM_EXITSIZEMOVE: - KillTimer(_sapp.win32.hwnd, 1); + KillTimer(window->win32.hwnd, 1); break; case WM_TIMER: + // TODO: I think we may have to consider current context here, since in the run situation of update, we ensure that the main context is active _sapp_frame(); #if defined(SOKOL_D3D11) - _sapp_d3d11_present(); + _sapp_d3d11_present(window); #endif #if defined(SOKOL_GLCORE33) - _sapp_wgl_swap_buffers(); + _sapp_wgl_swap_buffers(window); #endif /* NOTE: resizing the swap-chain during resize leads to a substantial memory spike (hundreds of megabytes for a few seconds). if (_sapp_win32_update_dimensions()) { #if defined(SOKOL_D3D11) - _sapp_d3d11_resize_default_render_target(); + _sapp_d3d11_resize_default_render_target(window); #endif _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESIZED); } */ break; case WM_DROPFILES: - _sapp_win32_files_dropped((HDROP)wParam); + _sapp_win32_files_dropped(window, (HDROP)wParam); break; default: break; @@ -6010,59 +6301,53 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM return DefWindowProcW(hWnd, uMsg, wParam, lParam); } -_SOKOL_PRIVATE void _sapp_win32_create_window(void) { - WNDCLASSW wndclassw; - memset(&wndclassw, 0, sizeof(wndclassw)); - wndclassw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wndclassw.lpfnWndProc = (WNDPROC) _sapp_win32_wndproc; - wndclassw.hInstance = GetModuleHandleW(NULL); - wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclassw.hIcon = LoadIcon(NULL, IDI_WINLOGO); - wndclassw.lpszClassName = L"SOKOLAPP"; - RegisterClassW(&wndclassw); - +_SOKOL_PRIVATE void _sapp_win32_create_window(_sapp_window_t* window, const sapp_window_desc* desc) { DWORD win_style; const DWORD win_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; RECT rect = { 0, 0, 0, 0 }; - if (_sapp.fullscreen) { + if (desc->fullscreen) { win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE; rect.right = GetSystemMetrics(SM_CXSCREEN); rect.bottom = GetSystemMetrics(SM_CYSCREEN); } else { win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX; - rect.right = (int) ((float)_sapp.window_width * _sapp.win32.dpi.window_scale); - rect.bottom = (int) ((float)_sapp.window_height * _sapp.win32.dpi.window_scale); + rect.right = (int) ((float)desc->width * _sapp.win32.dpi.window_scale); + rect.bottom = (int) ((float)desc->height * _sapp.win32.dpi.window_scale); } AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style); const int win_width = rect.right - rect.left; const int win_height = rect.bottom - rect.top; - _sapp.win32.in_create_window = true; - _sapp.win32.hwnd = CreateWindowExW( - win_ex_style, /* dwExStyle */ - L"SOKOLAPP", /* lpClassName */ - _sapp.window_title_wide, /* lpWindowName */ - win_style, /* dwStyle */ - CW_USEDEFAULT, /* X */ - CW_USEDEFAULT, /* Y */ - win_width, /* nWidth */ - win_height, /* nHeight */ - NULL, /* hWndParent */ - NULL, /* hMenu */ - GetModuleHandle(NULL), /* hInstance */ - NULL); /* lParam */ - ShowWindow(_sapp.win32.hwnd, SW_SHOW); - _sapp.win32.in_create_window = false; - _sapp.win32.dc = GetDC(_sapp.win32.hwnd); - SOKOL_ASSERT(_sapp.win32.dc); - _sapp_win32_update_dimensions(); - - DragAcceptFiles(_sapp.win32.hwnd, 1); -} - -_SOKOL_PRIVATE void _sapp_win32_destroy_window(void) { - DestroyWindow(_sapp.win32.hwnd); _sapp.win32.hwnd = 0; - UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL)); + window->win32.in_create_window = true; + + _sapp_window_t* parent = _sapp_lookup_window(desc->parent_window.id); + + window->win32.hwnd = CreateWindowExW( + win_ex_style, /* dwExStyle */ + L"SOKOLAPP", /* lpClassName */ + window->window_title_wide, /* lpWindowName */ + win_style, /* dwStyle */ + CW_USEDEFAULT, /* X */ + CW_USEDEFAULT, /* Y */ + win_width, /* nWidth */ + win_height, /* nHeight */ + parent ? parent->win32.hwnd : NULL, /* hWndParent */ + NULL, /* hMenu */ + GetModuleHandle(NULL), /* hInstance */ + NULL); /* lParam */ + SetPropA(window->win32.hwnd, _SAPP_WINDOW_PROP, window); + ShowWindow(window->win32.hwnd, SW_SHOW); + window->win32.in_create_window = false; + window->win32.dc = GetDC(window->win32.hwnd); + SOKOL_ASSERT(window->win32.dc); + _sapp_win32_update_dimensions(window); + + DragAcceptFiles(window->win32.hwnd, 1); +} + +_SOKOL_PRIVATE void _sapp_win32_destroy_window(_sapp_window_t* window) { + DestroyWindow(window->win32.hwnd); + window->win32.hwnd = 0; } _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { @@ -6087,7 +6372,7 @@ _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { /* if the app didn't request HighDPI rendering, let Windows do the upscaling */ PROCESS_DPI_AWARENESS process_dpi_awareness = PROCESS_SYSTEM_DPI_AWARE; _sapp.win32.dpi.aware = true; - if (!_sapp.desc.high_dpi) { + if (!_sapp.desc.window.high_dpi) { process_dpi_awareness = PROCESS_DPI_UNAWARE; _sapp.win32.dpi.aware = false; } @@ -6111,7 +6396,7 @@ _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { else { _sapp.win32.dpi.window_scale = 1.0f; } - if (_sapp.desc.high_dpi) { + if (_sapp.desc.window.high_dpi) { _sapp.win32.dpi.content_scale = _sapp.win32.dpi.window_scale; _sapp.win32.dpi.mouse_scale = 1.0f; } @@ -6128,13 +6413,13 @@ _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) { } } -_SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { +_SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(_sapp_window_t* window, const char* str) { SOKOL_ASSERT(str); - SOKOL_ASSERT(_sapp.win32.hwnd); - SOKOL_ASSERT(_sapp.clipboard.enabled && (_sapp.clipboard.buf_size > 0)); + SOKOL_ASSERT(window->win32.hwnd); + SOKOL_ASSERT(window->clipboard.enabled && (window->clipboard.buf_size > 0)); wchar_t* wchar_buf = 0; - const int wchar_buf_size = _sapp.clipboard.buf_size * sizeof(wchar_t); + const int wchar_buf_size = window->clipboard.buf_size * sizeof(wchar_t); HANDLE object = GlobalAlloc(GMEM_MOVEABLE, wchar_buf_size); if (!object) { goto error; @@ -6148,7 +6433,7 @@ _SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { } GlobalUnlock(wchar_buf); wchar_buf = 0; - if (!OpenClipboard(_sapp.win32.hwnd)) { + if (!OpenClipboard(window->win32.hwnd)) { goto error; } EmptyClipboard(); @@ -6166,36 +6451,36 @@ _SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) { return false; } -_SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.enabled && _sapp.clipboard.buffer); - SOKOL_ASSERT(_sapp.win32.hwnd); - if (!OpenClipboard(_sapp.win32.hwnd)) { +_SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(_sapp_window_t* window) { + SOKOL_ASSERT(window->clipboard.enabled && window->clipboard.buffer); + SOKOL_ASSERT(window->win32.hwnd); + if (!OpenClipboard(window->win32.hwnd)) { /* silently ignore any errors and just return the current content of the local clipboard buffer */ - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } HANDLE object = GetClipboardData(CF_UNICODETEXT); if (!object) { CloseClipboard(); - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } const wchar_t* wchar_buf = (const wchar_t*) GlobalLock(object); if (!wchar_buf) { CloseClipboard(); - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } - if (!_sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard.buffer, _sapp.clipboard.buf_size)) { + if (!_sapp_win32_wide_to_utf8(wchar_buf, window->clipboard.buffer, window->clipboard.buf_size)) { SOKOL_LOG("sokol_app.h: clipboard string didn't fit into clipboard buffer\n"); } GlobalUnlock(object); CloseClipboard(); - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } -_SOKOL_PRIVATE void _sapp_win32_update_window_title(void) { - _sapp_win32_uwp_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); - SetWindowTextW(_sapp.win32.hwnd, _sapp.window_title_wide); +_SOKOL_PRIVATE void _sapp_win32_update_window_title(_sapp_window_t* window) { + _sapp_win32_uwp_utf8_to_wide(window->window_title, window->window_title_wide, sizeof(window->window_title_wide)); + SetWindowTextW(window->win32.hwnd, window->window_title_wide); } /* don't laugh, but this seems to be the easiest and most robust @@ -6215,23 +6500,30 @@ _SOKOL_PRIVATE bool _sapp_win32_is_win10_or_greater(void) { _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_setup_pools(desc); _sapp.win32.is_win10_or_greater = _sapp_win32_is_win10_or_greater(); _sapp_win32_uwp_init_keytable(); - _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(); + + WNDCLASSW wndclassw; + memset(&wndclassw, 0, sizeof(wndclassw)); + wndclassw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wndclassw.lpfnWndProc = (WNDPROC) _sapp_win32_wndproc; + wndclassw.hInstance = GetModuleHandleW(NULL); + wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclassw.hIcon = LoadIcon(NULL, IDI_WINLOGO); + wndclassw.lpszClassName = L"SOKOLAPP"; + RegisterClassW(&wndclassw); + #if defined(SOKOL_D3D11) - _sapp_d3d11_create_device_and_swapchain(); - _sapp_d3d11_create_default_render_target(); - #endif - #if defined(SOKOL_GLCORE33) + _sapp_d3d11_create_device(); + #elif defined(SOKOL_GLCORE33) _sapp_wgl_init(); _sapp_wgl_load_extensions(); - _sapp_wgl_create_context(); - #if !defined(SOKOL_WIN32_NO_GL_LOADER) - _sapp_win32_gl_loadfuncs(); - #endif #endif + + sapp_window main_window_id = sapp_create_window(&desc->window); + _sapp.main_window = _sapp_lookup_window(main_window_id.id); _sapp.valid = true; bool done = false; @@ -6247,37 +6539,53 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { DispatchMessage(&msg); } } + // TODO: add handle to sapp_t? + sapp_make_context_current((sapp_window){ .id = _sapp.main_window->id }); _sapp_frame(); - #if defined(SOKOL_D3D11) - _sapp_d3d11_present(); - if (IsIconic(_sapp.win32.hwnd)) { - Sleep(16 * _sapp.swap_interval); + + // TODO: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + _sapp_window_t* window = &_sapp.windows[i]; + + #if defined(SOKOL_D3D11) + _sapp_d3d11_present(window); + if (IsIconic(window->win32.hwnd)) { + Sleep(16 * window->swap_interval); + } + #elif defined(SOKOL_GLCORE33) + _sapp_wgl_swap_buffers(window); + #endif + + /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */ + if (_sapp_win32_update_dimensions(window)) { + #if defined(SOKOL_D3D11) + _sapp_d3d11_resize_default_render_target(window); + #endif + _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_RESIZED); + } } - #endif - #if defined(SOKOL_GLCORE33) - _sapp_wgl_swap_buffers(); - #endif - /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */ - if (_sapp_win32_update_dimensions()) { - #if defined(SOKOL_D3D11) - _sapp_d3d11_resize_default_render_target(); - #endif - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESIZED); - } + } + if (_sapp.quit_requested) { - PostMessage(_sapp.win32.hwnd, WM_CLOSE, 0, 0); + PostMessage(_sapp.main_window->win32.hwnd, WM_CLOSE, 0, 0); } } _sapp_call_cleanup(); + UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL)); + + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + // TODO: Is there a better way to handle this instead of creating a tmp object? + sapp_destroy_window((sapp_window){ .id=_sapp.windows[i].id }); + } + } #if defined(SOKOL_D3D11) - _sapp_d3d11_destroy_default_render_target(); - _sapp_d3d11_destroy_device_and_swapchain(); - #else - _sapp_wgl_destroy_context(); + _sapp_d3d11_destroy_device(); + #elif defined(SOKOL_GLCORE33) _sapp_wgl_shutdown(); #endif - _sapp_win32_destroy_window(); _sapp_discard_state(); } @@ -10129,6 +10437,82 @@ SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { } #endif +SOKOL_API_DECL sapp_window sapp_main_window(){ + return (sapp_window){ .id=_sapp.main_window->id }; +} + +SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ + SOKOL_ASSERT(desc); + sapp_window_desc desc_def = _sapp_window_desc_defaults(desc); + sapp_window window_id = _sapp_alloc_window(); + if(window_id.id != SAPP_INVALID_ID){ + _sapp_window_t* window = _sapp_init_window(window_id, &desc_def); + + // TODO: Deal with macOS/Linux/etc. handling + #if defined(_SAPP_WIN32) + _sapp_win32_uwp_utf8_to_wide(window->window_title, window->window_title_wide, sizeof(window->window_title_wide)); + _sapp_win32_create_window(window, desc); + + #if defined(SOKOL_D3D11) + _sapp_d3d11_create_swapchain(window); + _sapp_d3d11_create_default_render_target(window); + #elif defined(SOKOL_GLCORE33) + _sapp_wgl_create_context(window); + #endif + #endif + } + else { + _sapp_fail("windows pool exhausted!"); + } + return window_id; +} + +SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + // TODO: Deal with macOS/Linux/etc. handling + // Destroy context + #if defined(_SAPP_WIN32) + #if defined(SOKOL_D3D11) + _sapp_d3d11_destroy_default_render_target(window); + _sapp_d3d11_destroy_swapchain(window); + #elif defined(SOKOL_GLCORE33) + _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + _sapp_wgl_destroy_context(window); + #endif + + _sapp_win32_destroy_window(window); + #endif + + if (window->clipboard.enabled) { + SOKOL_ASSERT(window->clipboard.buffer); + SOKOL_FREE((void*)window->clipboard.buffer); + } + if (window->drop.enabled) { + SOKOL_ASSERT(window->drop.buffer); + SOKOL_FREE((void*)window->drop.buffer); + } + + // Add back into pool and mark as invalid resource + int slot_index = _sapp_slot_index(window_id.id); + _sapp_reset_window(window); + _sapp_pool_free_index(&_sapp.window_pool, slot_index); +} + +SOKOL_API_DECL void sapp_make_context_current(sapp_window window_id){ + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + #if defined(SOKOL_D3D11) + // Do nothing? + #elif defined(SOKOL_GLCORE33) + _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + #endif +} + SOKOL_API_IMPL bool sapp_isvalid(void) { return _sapp.valid; } @@ -10145,8 +10529,11 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) { return _sapp.frame_count; } -SOKOL_API_IMPL int sapp_width(void) { - return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1; +SOKOL_API_IMPL int sapp_width(sapp_window window_id) { + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + return (window->framebuffer_width > 0) ? window->framebuffer_width : 1; } SOKOL_API_IMPL int sapp_color_format(void) { @@ -10172,15 +10559,26 @@ SOKOL_API_IMPL int sapp_depth_format(void) { } SOKOL_API_IMPL int sapp_sample_count(void) { - return _sapp.sample_count; + return sapp_window_sample_count(sapp_main_window()); +} + +SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window_id) { + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + return window->sample_count; } -SOKOL_API_IMPL int sapp_height(void) { - return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1; +SOKOL_API_IMPL int sapp_height(sapp_window window_id) { + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + return (window->framebuffer_height > 0) ? window->framebuffer_height : 1; } SOKOL_API_IMPL bool sapp_high_dpi(void) { - return _sapp.desc.high_dpi && (_sapp.dpi_scale >= 1.5f); + // TODO: currently uses main window high_dpi flag + return _sapp.desc.window.high_dpi && (_sapp.dpi_scale >= 1.5f); } SOKOL_API_IMPL float sapp_dpi_scale(void) { @@ -10207,15 +10605,32 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { return _sapp.onscreen_keyboard_shown; } -SOKOL_API_DECL bool sapp_is_fullscreen(void) { - return _sapp.fullscreen; +SOKOL_API_DECL bool sapp_is_fullscreen() { + // TODO: fix struct literal? + return sapp_window_is_fullscreen((sapp_window){ .id=_sapp.main_window->id }); +} + +SOKOL_API_DECL void sapp_toggle_fullscreen() { + // TODO: fix struct literal? + sapp_window_toggle_fullscreen((sapp_window){ .id=_sapp.main_window->id }); +} + +SOKOL_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + return window->fullscreen; } -SOKOL_API_DECL void sapp_toggle_fullscreen(void) { +SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(_SAPP_MACOS) _sapp_macos_toggle_fullscreen(); #elif defined(_SAPP_WIN32) - _sapp_win32_toggle_fullscreen(); + // TODO: window specific toggle + _sapp_win32_toggle_fullscreen(window); #elif defined(_SAPP_UWP) _sapp_uwp_toggle_fullscreen(); #elif defined(_SAPP_LINUX) @@ -10249,7 +10664,8 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_lock_mouse(lock); #elif defined(_SAPP_WIN32) - _sapp_win32_lock_mouse(lock); + // TODO: window specific lock + _sapp_win32_lock_mouse(_sapp.main_window, lock); #elif defined(_SAPP_LINUX) _sapp_x11_lock_mouse(lock); #else @@ -10278,9 +10694,11 @@ SOKOL_API_IMPL void sapp_consume_event(void) { } /* 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_API_IMPL void sapp_window_set_clipboard_string(sapp_window window_id, const char* str) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + SOKOL_ASSERT(window->clipboard.enabled); + if (!window->clipboard.enabled) { return; } SOKOL_ASSERT(str); @@ -10289,65 +10707,90 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_set_clipboard_string(str); #elif defined(_SAPP_WIN32) - _sapp_win32_set_clipboard_string(str); + _sapp_win32_set_clipboard_string(window, str); #else /* not implemented */ #endif - _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + _sapp_strcpy(str, window->clipboard.buffer, window->clipboard.buf_size); } -SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { - SOKOL_ASSERT(_sapp.clipboard.enabled); - if (!_sapp.clipboard.enabled) { +SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) { + sapp_window_set_clipboard_string(sapp_main_window(), str); +} + +SOKOL_API_IMPL const char* sapp_window_get_clipboard_string(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + SOKOL_ASSERT(window->clipboard.enabled); + if (!window->clipboard.enabled) { return ""; } #if defined(_SAPP_MACOS) return _sapp_macos_get_clipboard_string(); #elif defined(_SAPP_EMSCRIPTEN) - return _sapp.clipboard.buffer; + return _sapp.main_window->clipboard.buffer; #elif defined(_SAPP_WIN32) - return _sapp_win32_get_clipboard_string(); + return _sapp_win32_get_clipboard_string(window); #else /* not implemented */ - return _sapp.clipboard.buffer; + return _sapp.main_window->clipboard.buffer; #endif } -SOKOL_API_IMPL void sapp_set_window_title(const char* title) { +SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { + return sapp_window_get_clipboard_string(sapp_main_window()); +} + +SOKOL_API_IMPL void sapp_set_window_title(sapp_window window_id, const char* title) { SOKOL_ASSERT(title); - _sapp_strcpy(title, _sapp.window_title, sizeof(_sapp.window_title)); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + _sapp_strcpy(title, window->window_title, sizeof(window->window_title)); #if defined(_SAPP_MACOS) _sapp_macos_update_window_title(); #elif defined(_SAPP_WIN32) - _sapp_win32_update_window_title(); + _sapp_win32_update_window_title(window); #elif defined(_SAPP_LINUX) _sapp_x11_update_window_title(); #endif } -SOKOL_API_IMPL int sapp_get_num_dropped_files(void) { - SOKOL_ASSERT(_sapp.drop.enabled); - return _sapp.drop.num_files; +SOKOL_API_IMPL int sapp_window_get_num_dropped_files(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + SOKOL_ASSERT(window->drop.enabled); + return window->drop.num_files; +} + +SOKOL_API_IMPL int sapp_get_num_dropped_files() { + return sapp_window_get_num_dropped_files((sapp_window) { .id=_sapp.main_window->id }); } 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) { + return sapp_window_get_dropped_file_path((sapp_window) { .id=_sapp.main_window->id }, index); +} + +SOKOL_API_IMPL const char* sapp_window_get_dropped_file_path(sapp_window window_id, int index) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + SOKOL_ASSERT(window->drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < window->drop.num_files)); + SOKOL_ASSERT(window->drop.buffer); + if (!window->drop.enabled) { return ""; } - if ((index < 0) || (index >= _sapp.drop.max_files)) { + if ((index < 0) || (index >= window->drop.max_files)) { return ""; } - return (const char*) _sapp_dropped_file_path_ptr(index); + return (const char*) _sapp_dropped_file_path_ptr(window, 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.main_window->drop.enabled); + SOKOL_ASSERT((index >= 0) && (index < _sapp.main_window->drop.num_files)); #if defined(_SAPP_EMSCRIPTEN) - if (!_sapp.drop.enabled) { + if (!_sapp.main_window->drop.enabled) { return 0; } return sapp_js_dropped_file_size(index); @@ -10477,33 +10920,55 @@ SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) { #endif } -SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view(void) { +SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view() { + return sapp_d3d11_window_get_render_target_view(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_d3d11_window_get_render_target_view(sapp_window window_id) { SOKOL_ASSERT(_sapp.valid); + + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(SOKOL_D3D11) - if (_sapp.d3d11.msaa_rtv) { - return _sapp.d3d11.msaa_rtv; + if (window->msaa_rtv) { + return window->msaa_rtv; } else { - return _sapp.d3d11.rtv; + return window->rtv; } #else return 0; #endif } -SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view(void) { +SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view() { + return sapp_d3d11_window_get_depth_stencil_view(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_d3d11_window_get_depth_stencil_view(sapp_window window_id) { SOKOL_ASSERT(_sapp.valid); + + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(SOKOL_D3D11) - return _sapp.d3d11.dsv; + return window->dsv; #else return 0; #endif } SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) { + return sapp_win32_window_get_hwnd(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_win32_window_get_hwnd(sapp_window window_id) { SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); #if defined(_SAPP_WIN32) - return _sapp.win32.hwnd; + return window->win32.hwnd; #else return 0; #endif From 075b1a6b69e59fdc2fcb79e774167532762bf934 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Fri, 20 Nov 2020 15:43:14 -0700 Subject: [PATCH 02/14] update html5 platform to work with multi-window changes --- sokol_app.h | 116 +++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index e78658d7f..e82286be1 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3988,10 +3988,10 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_notify_keyboard_hidden(void) { } EMSCRIPTEN_KEEPALIVE void _sapp_emsc_onpaste(const char* str) { - if (_sapp.clipboard.enabled) { - _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + if (_sapp.main_window->clipboard.enabled) { + _sapp_strcpy(str, _sapp.main_window->clipboard.buffer, _sapp.main_window->clipboard.buf_size); if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } } @@ -4003,44 +4003,44 @@ EMSCRIPTEN_KEEPALIVE int _sapp_html5_get_ask_leave_site(void) { } EMSCRIPTEN_KEEPALIVE void _sapp_emsc_begin_drop(int num) { - if (!_sapp.drop.enabled) { + if (!_sapp.main_window->drop.enabled) { return; } if (num < 0) { num = 0; } - if (num > _sapp.drop.max_files) { - num = _sapp.drop.max_files; + if (num > _sapp.main_window->drop.max_files) { + num = _sapp.main_window->drop.max_files; } - _sapp.drop.num_files = num; - _sapp_clear_drop_buffer(); + _sapp.main_window->drop.num_files = num; + _sapp_clear_drop_buffer(_sapp.main_window); } EMSCRIPTEN_KEEPALIVE void _sapp_emsc_drop(int i, const char* name) { /* NOTE: name is only the filename part, not a path */ - if (!_sapp.drop.enabled) { + if (!_sapp.main_window->drop.enabled) { return; } if (0 == name) { return; } - SOKOL_ASSERT(_sapp.drop.num_files <= _sapp.drop.max_files); - if ((i < 0) || (i >= _sapp.drop.num_files)) { + SOKOL_ASSERT(_sapp.main_window->drop.num_files <= _sapp.main_window->drop.max_files); + if ((i < 0) || (i >= _sapp.main_window->drop.num_files)) { return; } - if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) { + if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(_sapp.main_window, i), _sapp.main_window->drop.max_path_length)) { SOKOL_LOG("sokol_app.h: dropped file path too long!\n"); - _sapp.drop.num_files = 0; + _sapp.main_window->drop.num_files = 0; } } EMSCRIPTEN_KEEPALIVE void _sapp_emsc_end_drop(int x, int y) { - if (!_sapp.drop.enabled) { + if (!_sapp.main_window->drop.enabled) { return; } - if (0 == _sapp.drop.num_files) { + if (0 == _sapp.main_window->drop.num_files) { /* there was an error copying the filenames */ - _sapp_clear_drop_buffer(); + _sapp_clear_drop_buffer(_sapp.main_window); return; } @@ -4049,7 +4049,7 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_end_drop(int x, int y) { _sapp.mouse.y = (float)y * _sapp.dpi_scale; _sapp.mouse.dx = 0.0f; _sapp.mouse.dy = 0.0f; - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_FILES_DROPPED); _sapp_call_event(&_sapp.event); } } @@ -4350,28 +4350,28 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU w = ui_event->windowInnerWidth; } else { - _sapp.window_width = (int) w; + _sapp.main_window->window_width = (int) w; } if (h < 1.0) { h = ui_event->windowInnerHeight; } else { - _sapp.window_height = (int) h; + _sapp.main_window->window_height = (int) h; } - if (_sapp.desc.high_dpi) { + if (_sapp.desc.window.high_dpi) { _sapp.dpi_scale = emscripten_get_device_pixel_ratio(); } - _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale); - _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale); - SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0)); - emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); + _sapp.main_window->framebuffer_width = (int) (w * _sapp.dpi_scale); + _sapp.main_window->framebuffer_height = (int) (h * _sapp.dpi_scale); + SOKOL_ASSERT((_sapp.main_window->framebuffer_width > 0) && (_sapp.main_window->framebuffer_height > 0)); + emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.main_window->framebuffer_width, _sapp.main_window->framebuffer_height); #if defined(SOKOL_WGPU) /* on WebGPU: recreate size-dependent rendering surfaces */ _sapp_emsc_wgpu_surfaces_discard(); _sapp_emsc_wgpu_surfaces_create(); #endif if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_RESIZED); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_RESIZED); _sapp_call_event(&_sapp.event); } return true; @@ -4420,7 +4420,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseE break; } if (type != SAPP_EVENTTYPE_INVALID) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); if (emsc_event->ctrlKey) { _sapp.event.modifiers |= SAPP_MODIFIER_CTRL; } @@ -4459,7 +4459,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelE _SOKOL_UNUSED(emsc_type); _SOKOL_UNUSED(user_data); if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_MOUSE_SCROLL); if (emsc_event->mouse.ctrlKey) { _sapp.event.modifiers |= SAPP_MODIFIER_CTRL; } @@ -4510,7 +4510,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard } if (type != SAPP_EVENTTYPE_INVALID) { bool send_keyup_followup = false; - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp.event.key_repeat = emsc_event->repeat; if (emsc_event->ctrlKey) { _sapp.event.modifiers |= SAPP_MODIFIER_CTRL; @@ -4651,7 +4651,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchE break; } if (type != SAPP_EVENTTYPE_INVALID) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); if (emsc_event->ctrlKey) { _sapp.event.modifiers |= SAPP_MODIFIER_CTRL; } @@ -4798,7 +4798,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_webgl_context_cb(int emsc_type, const void* re default: type = SAPP_EVENTTYPE_INVALID; break; } if (_sapp_events_enabled() && (SAPP_EVENTTYPE_INVALID != type)) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp_call_event(&_sapp.event); } return true; @@ -4807,10 +4807,10 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_webgl_context_cb(int emsc_type, const void* re _SOKOL_PRIVATE void _sapp_emsc_webgl_init(void) { EmscriptenWebGLContextAttributes attrs; emscripten_webgl_init_context_attributes(&attrs); - attrs.alpha = _sapp.desc.alpha; + attrs.alpha = _sapp.desc.window.alpha; attrs.depth = true; attrs.stencil = true; - attrs.antialias = _sapp.sample_count > 1; + attrs.antialias = _sapp.main_window->sample_count > 1; attrs.premultipliedAlpha = _sapp.desc.html5_premultiplied_alpha; attrs.preserveDrawingBuffer = _sapp.desc.html5_preserve_drawing_buffer; attrs.enableExtensionsByDefault = true; @@ -4892,28 +4892,28 @@ _SOKOL_PRIVATE void _sapp_emsc_wgpu_surfaces_create(void) { memset(&ds_desc, 0, sizeof(ds_desc)); ds_desc.usage = WGPUTextureUsage_OutputAttachment; ds_desc.dimension = WGPUTextureDimension_2D; - ds_desc.size.width = (uint32_t) _sapp.framebuffer_width; - ds_desc.size.height = (uint32_t) _sapp.framebuffer_height; + ds_desc.size.width = (uint32_t) _sapp.main_window->framebuffer_width; + ds_desc.size.height = (uint32_t) _sapp.main_window->framebuffer_height; ds_desc.size.depth = 1; ds_desc.arrayLayerCount = 1; ds_desc.format = WGPUTextureFormat_Depth24PlusStencil8; ds_desc.mipLevelCount = 1; - ds_desc.sampleCount = _sapp.sample_count; + ds_desc.sampleCount = _sapp.main_window->sample_count; _sapp.emsc.wgpu.depth_stencil_tex = wgpuDeviceCreateTexture(_sapp.emsc.wgpu.device, &ds_desc); _sapp.emsc.wgpu.depth_stencil_view = wgpuTextureCreateView(_sapp.emsc.wgpu.depth_stencil_tex, 0); - if (_sapp.sample_count > 1) { + if (_sapp.main_window->sample_count > 1) { WGPUTextureDescriptor msaa_desc; memset(&msaa_desc, 0, sizeof(msaa_desc)); msaa_desc.usage = WGPUTextureUsage_OutputAttachment; msaa_desc.dimension = WGPUTextureDimension_2D; - msaa_desc.size.width = (uint32_t) _sapp.framebuffer_width; - msaa_desc.size.height = (uint32_t) _sapp.framebuffer_height; + msaa_desc.size.width = (uint32_t) _sapp.main_window->framebuffer_width; + msaa_desc.size.height = (uint32_t) _sapp.main_window->framebuffer_height; msaa_desc.size.depth = 1; msaa_desc.arrayLayerCount = 1; msaa_desc.format = _sapp.emsc.wgpu.render_format; msaa_desc.mipLevelCount = 1; - msaa_desc.sampleCount = _sapp.sample_count; + msaa_desc.sampleCount = _sapp.main_window->sample_count; _sapp.emsc.wgpu.msaa_tex = wgpuDeviceCreateTexture(_sapp.emsc.wgpu.device, &msaa_desc); _sapp.emsc.wgpu.msaa_view = wgpuTextureCreateView(_sapp.emsc.wgpu.msaa_tex, 0); } @@ -4963,10 +4963,10 @@ _SOKOL_PRIVATE void _sapp_emsc_register_eventhandlers(void) { emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockchange_cb); emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, _sapp_emsc_pointerlockerror_cb); sapp_js_add_beforeunload_listener(); - if (_sapp.clipboard.enabled) { + if (_sapp.main_window->clipboard.enabled) { sapp_js_add_clipboard_listener(); } - if (_sapp.drop.enabled) { + if (_sapp.main_window->drop.enabled) { sapp_js_add_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); } #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) @@ -4992,10 +4992,10 @@ _SOKOL_PRIVATE void _sapp_emsc_unregister_eventhandlers() { emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); emscripten_set_pointerlockerror_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, 0, true, 0); sapp_js_remove_beforeunload_listener(); - if (_sapp.clipboard.enabled) { + if (_sapp.main_window->clipboard.enabled) { sapp_js_remove_clipboard_listener(); } - if (_sapp.drop.enabled) { + if (_sapp.main_window->drop.enabled) { sapp_js_remove_dragndrop_listeners(&_sapp.html5_canvas_selector[1]); } #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) @@ -5036,7 +5036,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { /* quit-handling */ if (_sapp.quit_requested) { - _sapp_init_event(SAPP_EVENTTYPE_QUIT_REQUESTED); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_QUIT_REQUESTED); _sapp_call_event(&_sapp.event); if (_sapp.quit_requested) { _sapp.quit_ordered = true; @@ -5045,6 +5045,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { if (_sapp.quit_ordered) { _sapp_emsc_unregister_eventhandlers(); _sapp_call_cleanup(); + _sapp_discard_pools(); _sapp_discard_state(); return EM_FALSE; } @@ -5053,25 +5054,28 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_setup_pools(desc); sapp_js_pointer_init(&_sapp.html5_canvas_selector[1]); _sapp_emsc_keytable_init(); double w, h; if (_sapp.desc.html5_canvas_resize) { - w = (double) _sapp.desc.width; - h = (double) _sapp.desc.height; + w = (double) _sapp.desc.window.width; + h = (double) _sapp.desc.window.height; } else { emscripten_get_element_css_size(_sapp.html5_canvas_selector, &w, &h); emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, false, _sapp_emsc_size_changed); } - if (_sapp.desc.high_dpi) { + if (_sapp.desc.window.high_dpi) { _sapp.dpi_scale = emscripten_get_device_pixel_ratio(); } - _sapp.window_width = (int) w; - _sapp.window_height = (int) h; - _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale); - _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale); - emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height); + sapp_window main_window_id = sapp_create_window(&desc->window); + _sapp.main_window = _sapp_lookup_window(main_window_id.id); + _sapp.main_window->window_width = (int) w; + _sapp.main_window->window_height = (int) h; + _sapp.main_window->framebuffer_width = (int) (w * _sapp.dpi_scale); + _sapp.main_window->framebuffer_height = (int) (h * _sapp.dpi_scale); + emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.main_window->framebuffer_width, _sapp.main_window->framebuffer_height); #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3) _sapp_emsc_webgl_init(); #elif defined(SOKOL_WGPU) @@ -10801,7 +10805,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.main_window->drop.enabled); SOKOL_ASSERT(request); SOKOL_ASSERT(request->callback); SOKOL_ASSERT(request->buffer_ptr); @@ -10809,7 +10813,7 @@ SOKOL_API_IMPL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request #if defined(_SAPP_EMSCRIPTEN) const int index = request->dropped_file_index; sapp_html5_fetch_error error_code = SAPP_HTML5_FETCH_ERROR_NO_ERROR; - if ((index < 0) || (index >= _sapp.drop.num_files)) { + if ((index < 0) || (index >= _sapp.main_window->drop.num_files)) { error_code = SAPP_HTML5_FETCH_ERROR_OTHER; } if (sapp_html5_get_dropped_file_size(index) > request->buffer_size) { @@ -10986,7 +10990,7 @@ SOKOL_API_IMPL const void* sapp_wgpu_get_device(void) { SOKOL_API_IMPL const void* sapp_wgpu_get_render_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { + if (_sapp.main_window->sample_count > 1) { return (const void*) _sapp.emsc.wgpu.msaa_view; } else { @@ -11000,7 +11004,7 @@ SOKOL_API_IMPL const void* sapp_wgpu_get_render_view(void) { SOKOL_API_IMPL const void* sapp_wgpu_get_resolve_view(void) { SOKOL_ASSERT(_sapp.valid); #if defined(_SAPP_EMSCRIPTEN) && defined(SOKOL_WGPU) - if (_sapp.sample_count > 1) { + if (_sapp.main_window->sample_count > 1) { return (const void*) _sapp.emsc.wgpu.swapchain_view; } else { From b6a5ca78580529f428b385a0802a17e82d8564cf Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Fri, 20 Nov 2020 16:39:47 -0700 Subject: [PATCH 03/14] adds multi-window support for linux with GLCORE33 and moves win32 mouse to window specific struct --- sokol_app.h | 660 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 380 insertions(+), 280 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index e82286be1..a7d71bc59 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1192,14 +1192,22 @@ SOKOL_API_DECL void sapp_toggle_fullscreen(); SOKOL_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id); /* toggle fullscreen mode for a window*/ SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id); -/* show or hide the mouse cursor */ +/* show or hide the mouse cursor for the main window */ SOKOL_API_DECL void sapp_show_mouse(bool show); -/* show or hide the mouse cursor */ +/* show or hide the mouse cursor for the specified window */ +SOKOL_API_DECL void sapp_window_show_mouse(sapp_window, bool show); +/* is the mouse cursor shown or hidden for the main window */ SOKOL_API_DECL bool sapp_mouse_shown(); -/* enable/disable mouse-pointer-lock mode */ +/* is the mouse cursor shown or hidden for the specified window */ +SOKOL_API_DECL bool sapp_window_mouse_shown(sapp_window window_id); +/* enable/disable mouse-pointer-lock mode for main window */ SOKOL_API_DECL void sapp_lock_mouse(bool lock); -/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) */ +/* enable/disable mouse-pointer-lock mode for specified window */ +SOKOL_API_DECL void sapp_window_lock_mouse(sapp_window window_id, bool lock); +/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) for main window*/ SOKOL_API_DECL bool sapp_mouse_locked(void); +/* return true if in mouse-pointer-lock mode (this may toggle a few frames later) for specified window */ +SOKOL_API_DECL bool sapp_window_mouse_locked(sapp_window); /* return the userdata pointer optionally provided in sapp_desc */ SOKOL_API_DECL void* sapp_userdata(void); /* return a copy of the sapp_desc structure */ @@ -1716,9 +1724,7 @@ typedef struct { } _sapp_win32_dpi_t; typedef struct { - LONG mouse_locked_x, mouse_locked_y; bool is_win10_or_greater; - bool mouse_tracked; uint8_t mouse_capture_mask; _sapp_win32_dpi_t dpi; bool raw_input_mousepos_valid; @@ -1732,6 +1738,8 @@ typedef struct { HDC dc; bool iconified; bool in_create_window; + bool mouse_tracked; + LONG mouse_locked_x, mouse_locked_y; } _sapp_win32_window_t; #if defined(SOKOL_GLCORE33) @@ -1937,10 +1945,7 @@ typedef struct { Display* display; int screen; Window root; - Colormap colormap; - Window window; Cursor hidden_cursor; - int window_state; float dpi; unsigned char error_code; Atom UTF8_STRING; @@ -1951,18 +1956,28 @@ typedef struct { Atom NET_WM_ICON_NAME; Atom NET_WM_STATE; Atom NET_WM_STATE_FULLSCREEN; + XContext context; _sapp_xi_t xi; _sapp_xdnd_t xdnd; } _sapp_x11_t; +typedef struct { + Colormap colormap; + Window window; + int window_state; +} _sapp_x11_window_t; + +typedef struct { + GLXContext ctx; + GLXWindow window; +} _sapp_glx_window_t; + typedef struct { void* libgl; int major; int minor; int event_base; int error_base; - GLXContext ctx; - GLXWindow window; // GLX 1.3 functions PFNGLXGETFBCONFIGSPROC GetFBConfigs; @@ -2072,9 +2087,11 @@ typedef struct { wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */ _sapp_drop_t drop; _sapp_clipboard_t clipboard; + _sapp_mouse_t mouse; #if defined(_SAPP_WIN32) _sapp_win32_window_t win32; + // TODO, move into gl/d3d substructs #if defined(SOKOL_GLCORE33) HGLRC gl_ctx; #elif defined(SOKOL_D3D11) @@ -2087,6 +2104,9 @@ typedef struct { DXGI_SWAP_CHAIN_DESC swap_chain_desc; IDXGISwapChain* swap_chain; #endif + #elif defined(_SAPP_LINUX) + _sapp_x11_window_t x11; + _sapp_glx_window_t glx; #endif } _sapp_window_t; @@ -2105,7 +2125,6 @@ typedef struct { float dpi_scale; uint64_t frame_count; sapp_event event; - _sapp_mouse_t mouse; #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -2784,6 +2803,7 @@ _SOKOL_PRIVATE _sapp_window_t* _sapp_init_window(sapp_window window_id, const sa window->swap_interval = desc->swap_interval; window->sample_count = desc->sample_count; + window->mouse.shown = true; window->drop.enabled = desc->enable_dragndrop; if (window->drop.enabled) { @@ -2811,7 +2831,7 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.desc.html5_canvas_name = &_sapp.html5_canvas_selector[1]; _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; _sapp.dpi_scale = 1.0f; - _sapp.mouse.shown = true; + } _SOKOL_PRIVATE void _sapp_discard_state(void) { @@ -2829,10 +2849,10 @@ _SOKOL_PRIVATE void _sapp_init_event(_sapp_window_t* window, sapp_event_type typ _sapp.event.window_height = window->window_height; _sapp.event.framebuffer_width = window->framebuffer_width; _sapp.event.framebuffer_height = window->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.mouse_x = window->mouse.x; + _sapp.event.mouse_y = window->mouse.y; + _sapp.event.mouse_dx = window->mouse.dx; + _sapp.event.mouse_dy = window->mouse.dy; } _SOKOL_PRIVATE bool _sapp_events_enabled(void) { @@ -4598,8 +4618,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboard case SAPP_KEYCODE_LEFT_ALT: case SAPP_KEYCODE_LEFT_SUPER: case SAPP_KEYCODE_RIGHT_SHIFT: - case SAPP_KEYCODE_RIGHT_CONTROL: - case SAPP_KEYCODE_RIGHT_ALT: + case SAPP_KEYCODE_RIGHT_ALT: case SAPP_KEYCODE_RIGHT_SUPER: case SAPP_KEYCODE_MENU: /* consume the event */ @@ -5045,7 +5064,6 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { if (_sapp.quit_ordered) { _sapp_emsc_unregister_eventhandlers(); _sapp_call_cleanup(); - _sapp_discard_pools(); _sapp_discard_state(); return EM_FALSE; } @@ -5909,30 +5927,30 @@ _SOKOL_PRIVATE void _sapp_win32_release_mouse(uint8_t btn_mask) { } _SOKOL_PRIVATE void _sapp_win32_lock_mouse(_sapp_window_t* window, bool lock) { - if (lock == _sapp.mouse.locked) { + if (lock == window->mouse.locked) { return; } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; + window->mouse.dx = 0.0f; + window->mouse.dy = 0.0f; + window->mouse.locked = lock; _sapp_win32_release_mouse(0xFF); - if (_sapp.mouse.locked) { + if (window->mouse.locked) { /* store the current mouse position, so it can be restored when unlocked */ POINT pos; BOOL res = GetCursorPos(&pos); SOKOL_ASSERT(res); _SOKOL_UNUSED(res); - _sapp.win32.mouse_locked_x = pos.x; - _sapp.win32.mouse_locked_y = pos.y; + window->win32.mouse_locked_x = pos.x; + window->win32.mouse_locked_y = pos.y; /* while the mouse is locked, make the mouse cursor invisible and confine the mouse movement to a small rectangle inside our window (so that we dont miss any mouse up events) */ RECT client_rect = { - _sapp.win32.mouse_locked_x, - _sapp.win32.mouse_locked_y, - _sapp.win32.mouse_locked_x, - _sapp.win32.mouse_locked_y + window->win32.mouse_locked_x, + window->win32.mouse_locked_y, + window->win32.mouse_locked_x, + window->win32.mouse_locked_y }; ClipCursor(&client_rect); @@ -5966,7 +5984,7 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(_sapp_window_t* window, bool lock) { ShowCursor(TRUE); /* restore the 'pre-locked' mouse position */ - BOOL res = SetCursorPos(_sapp.win32.mouse_locked_x, _sapp.win32.mouse_locked_y); + BOOL res = SetCursorPos(window->win32.mouse_locked_x, window->win32.mouse_locked_y); SOKOL_ASSERT(res); _SOKOL_UNUSED(res); } } @@ -6187,19 +6205,19 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM _sapp_win32_release_mouse(1<mouse.locked) { const float new_x = (float)GET_X_LPARAM(lParam) * _sapp.win32.dpi.mouse_scale; const float new_y = (float)GET_Y_LPARAM(lParam) * _sapp.win32.dpi.mouse_scale; /* don't update dx/dy in the very first event */ - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; + if (window->mouse.pos_valid) { + window->mouse.dx = new_x - window->mouse.x; + window->mouse.dy = new_y - window->mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - if (!_sapp.win32.mouse_tracked) { - _sapp.win32.mouse_tracked = true; + window->mouse.x = new_x; + window->mouse.y = new_y; + window->mouse.pos_valid = true; + if (!window->win32.mouse_tracked) { + window->win32.mouse_tracked = true; TRACKMOUSEEVENT tme; memset(&tme, 0, sizeof(tme)); tme.cbSize = sizeof(tme); @@ -6213,7 +6231,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM break; case WM_INPUT: /* raw mouse input during mouse-lock */ - if (_sapp.mouse.locked) { + if (window->mouse.locked) { HRAWINPUT ri = (HRAWINPUT) lParam; UINT size = sizeof(_sapp.win32.raw_input_data); if (-1 == GetRawInputData(ri, RID_INPUT, &_sapp.win32.raw_input_data, &size, sizeof(RAWINPUTHEADER))) { @@ -6230,8 +6248,8 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM if (_sapp.win32.raw_input_mousepos_valid) { LONG new_x = raw_mouse_data->data.mouse.lLastX; LONG new_y = raw_mouse_data->data.mouse.lLastY; - _sapp.mouse.dx = (float) (new_x - _sapp.win32.raw_input_mousepos_x); - _sapp.mouse.dy = (float) (new_y - _sapp.win32.raw_input_mousepos_y); + window->mouse.dx = (float) (new_x - _sapp.win32.raw_input_mousepos_x); + window->mouse.dy = (float) (new_y - _sapp.win32.raw_input_mousepos_y); _sapp.win32.raw_input_mousepos_x = new_x; _sapp.win32.raw_input_mousepos_y = new_y; _sapp.win32.raw_input_mousepos_valid = true; @@ -6239,16 +6257,16 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM } else { /* mouse reports movement delta (this seems to be the common case) */ - _sapp.mouse.dx = (float) raw_mouse_data->data.mouse.lLastX; - _sapp.mouse.dy = (float) raw_mouse_data->data.mouse.lLastY; + window->mouse.dx = (float) raw_mouse_data->data.mouse.lLastX; + window->mouse.dy = (float) raw_mouse_data->data.mouse.lLastY; } _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID); } break; case WM_MOUSELEAVE: - if (!_sapp.mouse.locked) { - _sapp.win32.mouse_tracked = false; + if (!window->mouse.locked) { + window->win32.mouse_tracked = false; _sapp_win32_mouse_event(window, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID); } break; @@ -7668,7 +7686,7 @@ _SOKOL_PRIVATE bool _sapp_android_init_egl(void) { return false; } - EGLint alpha_size = _sapp.desc.alpha ? 8 : 0; + EGLint alpha_size = _sapp.desc.window.alpha ? 8 : 0; const EGLint cfg_attributes[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, @@ -7778,7 +7796,7 @@ _SOKOL_PRIVATE void _sapp_android_cleanup_egl_surface(void) { _SOKOL_PRIVATE void _sapp_android_app_event(sapp_event_type type) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); SOKOL_LOG("event_cb()"); _sapp_call_event(&_sapp.event); } @@ -7793,11 +7811,11 @@ _SOKOL_PRIVATE void _sapp_android_update_dimensions(ANativeWindow* window, bool const int32_t win_w = ANativeWindow_getWidth(window); const int32_t win_h = ANativeWindow_getHeight(window); SOKOL_ASSERT(win_w >= 0 && win_h >= 0); - const bool win_changed = (win_w != _sapp.window_width) || (win_h != _sapp.window_height); - _sapp.window_width = win_w; - _sapp.window_height = win_h; + const bool win_changed = (win_w != _sapp.main_window->window_width) || (win_h != _sapp.main_window->window_height); + _sapp.main_window->window_width = win_w; + _sapp.main_window->window_height = win_h; if (win_changed || force_update) { - if (!_sapp.desc.high_dpi) { + if (!_sapp.desc.window.high_dpi) { const int32_t buf_w = win_w / 2; const int32_t buf_h = win_h / 2; EGLint format; @@ -7819,10 +7837,10 @@ _SOKOL_PRIVATE void _sapp_android_update_dimensions(ANativeWindow* window, bool EGLBoolean egl_result_h = eglQuerySurface(_sapp.android.display, _sapp.android.surface, EGL_HEIGHT, &fb_h); SOKOL_ASSERT(egl_result_w == EGL_TRUE); SOKOL_ASSERT(egl_result_h == EGL_TRUE); - const bool fb_changed = (fb_w != _sapp.framebuffer_width) || (fb_h != _sapp.framebuffer_height); - _sapp.framebuffer_width = fb_w; - _sapp.framebuffer_height = fb_h; - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; + const bool fb_changed = (fb_w != _sapp.main_window->framebuffer_width) || (fb_h != _sapp.main_window->framebuffer_height); + _sapp.main_window->framebuffer_width = fb_w; + _sapp.main_window->framebuffer_height = fb_h; + _sapp.dpi_scale = (float)_sapp.main_window->framebuffer_width / (float)_sapp.main_window->window_width; if (win_changed || fb_changed || force_update) { if (!_sapp.first_frame) { SOKOL_LOG("SAPP_EVENTTYPE_RESIZED"); @@ -7897,7 +7915,7 @@ _SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) { return false; } int32_t idx = action_idx >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp.event.num_touches = AMotionEvent_getPointerCount(e); if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) { _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS; @@ -7905,8 +7923,8 @@ _SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) { for (int32_t i = 0; i < _sapp.event.num_touches; i++) { sapp_touchpoint* dst = &_sapp.event.touches[i]; dst->identifier = AMotionEvent_getPointerId(e, i); - dst->pos_x = (AMotionEvent_getRawX(e, i) / _sapp.window_width) * _sapp.framebuffer_width; - dst->pos_y = (AMotionEvent_getRawY(e, i) / _sapp.window_height) * _sapp.framebuffer_height; + dst->pos_x = (AMotionEvent_getRawX(e, i) / _sapp.main_window->window_width) * _sapp.main_window->framebuffer_width; + dst->pos_y = (AMotionEvent_getRawY(e, i) / _sapp.main_window->window_height) * _sapp.main_window->framebuffer_height; if (action == AMOTION_EVENT_ACTION_POINTER_DOWN || action == AMOTION_EVENT_ACTION_POINTER_UP) { @@ -9167,18 +9185,18 @@ _SOKOL_PRIVATE void _sapp_x11_init_extensions(void) { _sapp.x11.NET_WM_ICON_NAME = XInternAtom(_sapp.x11.display, "_NET_WM_ICON_NAME", False); _sapp.x11.NET_WM_STATE = XInternAtom(_sapp.x11.display, "_NET_WM_STATE", False); _sapp.x11.NET_WM_STATE_FULLSCREEN = XInternAtom(_sapp.x11.display, "_NET_WM_STATE_FULLSCREEN", False); - if (_sapp.drop.enabled) { - _sapp.x11.xdnd.XdndAware = XInternAtom(_sapp.x11.display, "XdndAware", False); - _sapp.x11.xdnd.XdndEnter = XInternAtom(_sapp.x11.display, "XdndEnter", False); - _sapp.x11.xdnd.XdndPosition = XInternAtom(_sapp.x11.display, "XdndPosition", False); - _sapp.x11.xdnd.XdndStatus = XInternAtom(_sapp.x11.display, "XdndStatus", False); - _sapp.x11.xdnd.XdndActionCopy = XInternAtom(_sapp.x11.display, "XdndActionCopy", False); - _sapp.x11.xdnd.XdndDrop = XInternAtom(_sapp.x11.display, "XdndDrop", False); - _sapp.x11.xdnd.XdndFinished = XInternAtom(_sapp.x11.display, "XdndFinished", False); - _sapp.x11.xdnd.XdndSelection = XInternAtom(_sapp.x11.display, "XdndSelection", False); - _sapp.x11.xdnd.XdndTypeList = XInternAtom(_sapp.x11.display, "XdndTypeList", False); - _sapp.x11.xdnd.text_uri_list = XInternAtom(_sapp.x11.display, "text/uri-list", False); - } + // Note: not optional anymore, since we can't predict whether a future window will enable drag and drop + _sapp.x11.xdnd.XdndAware = XInternAtom(_sapp.x11.display, "XdndAware", False); + _sapp.x11.xdnd.XdndEnter = XInternAtom(_sapp.x11.display, "XdndEnter", False); + _sapp.x11.xdnd.XdndPosition = XInternAtom(_sapp.x11.display, "XdndPosition", False); + _sapp.x11.xdnd.XdndStatus = XInternAtom(_sapp.x11.display, "XdndStatus", False); + _sapp.x11.xdnd.XdndActionCopy = XInternAtom(_sapp.x11.display, "XdndActionCopy", False); + _sapp.x11.xdnd.XdndDrop = XInternAtom(_sapp.x11.display, "XdndDrop", False); + _sapp.x11.xdnd.XdndFinished = XInternAtom(_sapp.x11.display, "XdndFinished", False); + _sapp.x11.xdnd.XdndSelection = XInternAtom(_sapp.x11.display, "XdndSelection", False); + _sapp.x11.xdnd.XdndTypeList = XInternAtom(_sapp.x11.display, "XdndTypeList", False); + _sapp.x11.xdnd.text_uri_list = XInternAtom(_sapp.x11.display, "text/uri-list", False); + /* check Xi extension for raw mouse input */ if (XQueryExtension(_sapp.x11.display, "XInputExtension", &_sapp.x11.xi.major_opcode, &_sapp.x11.xi.event_base, &_sapp.x11.xi.error_base)) { @@ -9335,7 +9353,7 @@ _SOKOL_PRIVATE int _sapp_glx_attrib(GLXFBConfig fbconfig, int attrib) { return value; } -_SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() { +_SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig(_sapp_window_t* window) { GLXFBConfig* native_configs; _sapp_gl_fbconfig* usable_configs; const _sapp_gl_fbconfig* closest; @@ -9397,7 +9415,7 @@ _SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() { desired.depth_bits = 24; desired.stencil_bits = 8; desired.doublebuffer = true; - desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0; + desired.samples = window->sample_count > 1 ? window->sample_count : 0; closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count); GLXFBConfig result = 0; if (closest) { @@ -9408,8 +9426,8 @@ _SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() { return result; } -_SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) { - GLXFBConfig native = _sapp_glx_choosefbconfig(); +_SOKOL_PRIVATE void _sapp_glx_choose_visual(_sapp_window_t* window, Visual** visual, int* depth) { + GLXFBConfig native = _sapp_glx_choosefbconfig(window); if (0 == native) { _sapp_fail("GLX: Failed to find a suitable GLXFBConfig"); } @@ -9422,8 +9440,8 @@ _SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) { XFree(result); } -_SOKOL_PRIVATE void _sapp_glx_create_context(void) { - GLXFBConfig native = _sapp_glx_choosefbconfig(); +_SOKOL_PRIVATE void _sapp_glx_create_context(_sapp_window_t* window) { + GLXFBConfig native = _sapp_glx_choosefbconfig(window); if (0 == native){ _sapp_fail("GLX: Failed to find a suitable GLXFBConfig (2)"); } @@ -9438,52 +9456,54 @@ _SOKOL_PRIVATE void _sapp_glx_create_context(void) { GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 0, 0 }; - _sapp.glx.ctx = _sapp.glx.CreateContextAttribsARB(_sapp.x11.display, native, NULL, True, attribs); - if (!_sapp.glx.ctx) { + window->glx.ctx = _sapp.glx.CreateContextAttribsARB(_sapp.x11.display, native, NULL, True, attribs); + if (!window->glx.ctx) { _sapp_fail("GLX: failed to create GL context"); } _sapp_x11_release_error_handler(); - _sapp.glx.window = _sapp.glx.CreateWindow(_sapp.x11.display, native, _sapp.x11.window, NULL); - if (!_sapp.glx.window) { + window->glx.window = _sapp.glx.CreateWindow(_sapp.x11.display, native, window->x11.window, NULL); + if (!window->glx.window) { _sapp_fail("GLX: failed to create window"); } } -_SOKOL_PRIVATE void _sapp_glx_destroy_context(void) { - if (_sapp.glx.window) { - _sapp.glx.DestroyWindow(_sapp.x11.display, _sapp.glx.window); - _sapp.glx.window = 0; +_SOKOL_PRIVATE void _sapp_glx_destroy_context(_sapp_window_t* window) { + if (window->glx.window) { + _sapp.glx.DestroyWindow(_sapp.x11.display, window->glx.window); + window->glx.window = 0; } - if (_sapp.glx.ctx) { - _sapp.glx.DestroyContext(_sapp.x11.display, _sapp.glx.ctx); - _sapp.glx.ctx = 0; + if (window->glx.ctx) { + _sapp.glx.DestroyContext(_sapp.x11.display, window->glx.ctx); + window->glx.ctx = 0; } } -_SOKOL_PRIVATE void _sapp_glx_make_current(void) { - _sapp.glx.MakeCurrent(_sapp.x11.display, _sapp.glx.window, _sapp.glx.ctx); +_SOKOL_PRIVATE void _sapp_glx_make_current(_sapp_window_t* window) { + if(!_sapp.glx.MakeCurrent(_sapp.x11.display, window->glx.window, window->glx.ctx)){ + SOKOL_LOG("Failed to make context current"); + } } -_SOKOL_PRIVATE void _sapp_glx_swap_buffers(void) { - _sapp.glx.SwapBuffers(_sapp.x11.display, _sapp.glx.window); +_SOKOL_PRIVATE void _sapp_glx_swap_buffers(_sapp_window_t* window) { + _sapp.glx.SwapBuffers(_sapp.x11.display, window->glx.window); } -_SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) { - _sapp_glx_make_current(); +_SOKOL_PRIVATE void _sapp_glx_swapinterval(_sapp_window_t* window, int interval) { + _sapp_glx_make_current(window); if (_sapp.glx.EXT_swap_control) { - _sapp.glx.SwapIntervalEXT(_sapp.x11.display, _sapp.glx.window, interval); + _sapp.glx.SwapIntervalEXT(_sapp.x11.display, window->glx.window, interval); } else if (_sapp.glx.MESA_swap_control) { _sapp.glx.SwapIntervalMESA(interval); } } -_SOKOL_PRIVATE void _sapp_x11_send_event(Atom type, int a, int b, int c, int d, int e) { +_SOKOL_PRIVATE void _sapp_x11_send_event(_sapp_window_t* window, Atom type, int a, int b, int c, int d, int e) { XEvent event; memset(&event, 0, sizeof(event)); event.type = ClientMessage; - event.xclient.window = _sapp.x11.window; + event.xclient.window = window->x11.window; event.xclient.format = 32; event.xclient.message_type = type; event.xclient.data.l[0] = a; @@ -9498,28 +9518,30 @@ _SOKOL_PRIVATE void _sapp_x11_send_event(Atom type, int a, int b, int c, int d, &event); } -_SOKOL_PRIVATE void _sapp_x11_query_window_size(void) { +_SOKOL_PRIVATE void _sapp_x11_query_window_size(_sapp_window_t* window) { XWindowAttributes attribs; - XGetWindowAttributes(_sapp.x11.display, _sapp.x11.window, &attribs); - _sapp.window_width = attribs.width; - _sapp.window_height = attribs.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; + XGetWindowAttributes(_sapp.x11.display, window->x11.window, &attribs); + window->window_width = attribs.width; + window->window_height = attribs.height; + window->framebuffer_width = window->window_width; + window->framebuffer_height = window->window_height; } -_SOKOL_PRIVATE void _sapp_x11_set_fullscreen(bool enable) { +_SOKOL_PRIVATE void _sapp_x11_set_fullscreen(_sapp_window_t* window, bool enable) { /* NOTE: this function must be called after XMapWindow (which happens in _sapp_x11_show_window()) */ if (_sapp.x11.NET_WM_STATE && _sapp.x11.NET_WM_STATE_FULLSCREEN) { if (enable) { const int _NET_WM_STATE_ADD = 1; - _sapp_x11_send_event(_sapp.x11.NET_WM_STATE, + _sapp_x11_send_event(window, + _sapp.x11.NET_WM_STATE, _NET_WM_STATE_ADD, _sapp.x11.NET_WM_STATE_FULLSCREEN, 0, 1, 0); } else { const int _NET_WM_STATE_REMOVE = 0; - _sapp_x11_send_event(_sapp.x11.NET_WM_STATE, + _sapp_x11_send_event(window, + _sapp.x11.NET_WM_STATE, _NET_WM_STATE_REMOVE, _sapp.x11.NET_WM_STATE_FULLSCREEN, 0, 1, 0); @@ -9542,29 +9564,29 @@ _SOKOL_PRIVATE void _sapp_x11_create_hidden_cursor(void) { XcursorImageDestroy(img); } -_SOKOL_PRIVATE void _sapp_x11_toggle_fullscreen(void) { - _sapp.fullscreen = !_sapp.fullscreen; - _sapp_x11_set_fullscreen(_sapp.fullscreen); - _sapp_x11_query_window_size(); +_SOKOL_PRIVATE void _sapp_x11_toggle_fullscreen(_sapp_window_t* window) { + window->fullscreen = !window->fullscreen; + _sapp_x11_set_fullscreen(window, window->fullscreen); + _sapp_x11_query_window_size(window); } -_SOKOL_PRIVATE void _sapp_x11_show_mouse(bool show) { +_SOKOL_PRIVATE void _sapp_x11_show_mouse(_sapp_window_t* window, bool show) { if (show) { - XUndefineCursor(_sapp.x11.display, _sapp.x11.window); + XUndefineCursor(_sapp.x11.display, window->x11.window); } else { - XDefineCursor(_sapp.x11.display, _sapp.x11.window, _sapp.x11.hidden_cursor); + XDefineCursor(_sapp.x11.display, window->x11.window, _sapp.x11.hidden_cursor); } } -_SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { +_SOKOL_PRIVATE void _sapp_x11_lock_mouse(_sapp_window_t* window, bool lock) { + if (lock == window->mouse.locked) { return; } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; - if (_sapp.mouse.locked) { + window->mouse.dx = 0.0f; + window->mouse.dy = 0.0f; + window->mouse.locked = lock; + if (window->mouse.locked) { if (_sapp.x11.xi.available) { XIEventMask em; unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; // XIMaskLen is a macro @@ -9575,12 +9597,12 @@ _SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) { XISelectEvents(_sapp.x11.display, _sapp.x11.root, &em, 1); } XGrabPointer(_sapp.x11.display, // display - _sapp.x11.window, // grab_window + window->x11.window, // grab_window True, // owner_events ButtonPressMask | ButtonReleaseMask | PointerMotionMask, // event_mask GrabModeAsync, // pointer_mode GrabModeAsync, // keyboard_mode - _sapp.x11.window, // confine_to + window->x11.window, // confine_to _sapp.x11.hidden_cursor, // cursor CurrentTime); // time } @@ -9593,47 +9615,68 @@ _SOKOL_PRIVATE void _sapp_x11_lock_mouse(bool lock) { em.mask = mask; XISelectEvents(_sapp.x11.display, _sapp.x11.root, &em, 1); } - XWarpPointer(_sapp.x11.display, None, _sapp.x11.window, 0, 0, 0, 0, (int) _sapp.mouse.x, _sapp.mouse.y); + XWarpPointer(_sapp.x11.display, None, window->x11.window, 0, 0, 0, 0, (int) window->mouse.x, window->mouse.y); XUngrabPointer(_sapp.x11.display, CurrentTime); } XFlush(_sapp.x11.display); } -_SOKOL_PRIVATE void _sapp_x11_update_window_title(void) { +_SOKOL_PRIVATE void _sapp_x11_update_window_title(_sapp_window_t* window) { Xutf8SetWMProperties(_sapp.x11.display, - _sapp.x11.window, - _sapp.window_title, _sapp.window_title, + window->x11.window, + window->window_title, window->window_title, NULL, 0, NULL, NULL, NULL); - XChangeProperty(_sapp.x11.display, _sapp.x11.window, + XChangeProperty(_sapp.x11.display, window->x11.window, _sapp.x11.NET_WM_NAME, _sapp.x11.UTF8_STRING, 8, PropModeReplace, - (unsigned char*)_sapp.window_title, - strlen(_sapp.window_title)); - XChangeProperty(_sapp.x11.display, _sapp.x11.window, + (unsigned char*)window->window_title, + strlen(window->window_title)); + XChangeProperty(_sapp.x11.display, window->x11.window, _sapp.x11.NET_WM_ICON_NAME, _sapp.x11.UTF8_STRING, 8, PropModeReplace, - (unsigned char*)_sapp.window_title, - strlen(_sapp.window_title)); + (unsigned char*)window->window_title, + strlen(window->window_title)); XFlush(_sapp.x11.display); } -_SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) { - _sapp.x11.colormap = XCreateColormap(_sapp.x11.display, _sapp.x11.root, visual, AllocNone); +_SOKOL_PRIVATE bool _sapp_x11_window_visible(_sapp_window_t* window) { + XWindowAttributes wa; + XGetWindowAttributes(_sapp.x11.display, window->x11.window, &wa); + return wa.map_state == IsViewable; +} + +_SOKOL_PRIVATE void _sapp_x11_show_window(_sapp_window_t* window) { + if (!_sapp_x11_window_visible(window)) { + XMapWindow(_sapp.x11.display, window->x11.window); + XRaiseWindow(_sapp.x11.display, window->x11.window); + XFlush(_sapp.x11.display); + } +} + +_SOKOL_PRIVATE void _sapp_x11_hide_window(_sapp_window_t* window) { + XUnmapWindow(_sapp.x11.display, window->x11.window); + XFlush(_sapp.x11.display); +} + +_SOKOL_PRIVATE void _sapp_x11_create_window(_sapp_window_t* window, Visual* visual, int depth) { + window->x11.window_state = NormalState; + window->x11.colormap = XCreateColormap(_sapp.x11.display, _sapp.x11.root, visual, AllocNone); XSetWindowAttributes wa; memset(&wa, 0, sizeof(wa)); const uint32_t wamask = CWBorderPixel | CWColormap | CWEventMask; - wa.colormap = _sapp.x11.colormap; + wa.colormap = window->x11.colormap; wa.border_pixel = 0; wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | FocusChangeMask | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; + _sapp_x11_grab_error_handler(); - _sapp.x11.window = XCreateWindow(_sapp.x11.display, + window->x11.window = XCreateWindow(_sapp.x11.display, _sapp.x11.root, 0, 0, - _sapp.window_width, - _sapp.window_height, + window->window_width, + window->window_height, 0, /* border width */ depth, /* color depth */ InputOutput, @@ -9641,58 +9684,50 @@ _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) { wamask, &wa); _sapp_x11_release_error_handler(); - if (!_sapp.x11.window) { + if (!window->x11.window) { _sapp_fail("X11: Failed to create window"); } Atom protocols[] = { _sapp.x11.WM_DELETE_WINDOW }; - XSetWMProtocols(_sapp.x11.display, _sapp.x11.window, protocols, 1); + XSetWMProtocols(_sapp.x11.display, window->x11.window, protocols, 1); XSizeHints* hints = XAllocSizeHints(); hints->flags |= PWinGravity; hints->win_gravity = StaticGravity; - XSetWMNormalHints(_sapp.x11.display, _sapp.x11.window, hints); + XSetWMNormalHints(_sapp.x11.display, window->x11.window, hints); XFree(hints); /* announce support for drag'n'drop */ - if (_sapp.drop.enabled) { + if (window->drop.enabled) { const Atom version = _SAPP_X11_XDND_VERSION; - XChangeProperty(_sapp.x11.display, _sapp.x11.window, _sapp.x11.xdnd.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); + XChangeProperty(_sapp.x11.display, window->x11.window, _sapp.x11.xdnd.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1); } - _sapp_x11_update_window_title(); -} + _sapp_x11_update_window_title(window); -_SOKOL_PRIVATE void _sapp_x11_destroy_window(void) { - if (_sapp.x11.window) { - XUnmapWindow(_sapp.x11.display, _sapp.x11.window); - XDestroyWindow(_sapp.x11.display, _sapp.x11.window); - _sapp.x11.window = 0; - } - if (_sapp.x11.colormap) { - XFreeColormap(_sapp.x11.display, _sapp.x11.colormap); - _sapp.x11.colormap = 0; + /* associate window XID with _sapp_window_t* for later retrieval during event processing */ + XSaveContext(_sapp.x11.display, window->x11.window,_sapp.x11.context, (XPointer) window); + + _sapp_x11_show_window(window); + if (window->fullscreen) { + _sapp_x11_set_fullscreen(window, true); } + _sapp_x11_query_window_size(window); + _sapp_glx_swapinterval(window, window->swap_interval); XFlush(_sapp.x11.display); } -_SOKOL_PRIVATE bool _sapp_x11_window_visible(void) { - XWindowAttributes wa; - XGetWindowAttributes(_sapp.x11.display, _sapp.x11.window, &wa); - return wa.map_state == IsViewable; -} - -_SOKOL_PRIVATE void _sapp_x11_show_window(void) { - if (!_sapp_x11_window_visible()) { - XMapWindow(_sapp.x11.display, _sapp.x11.window); - XRaiseWindow(_sapp.x11.display, _sapp.x11.window); - XFlush(_sapp.x11.display); +_SOKOL_PRIVATE void _sapp_x11_destroy_window(_sapp_window_t* window) { + if (window->x11.window) { + XUnmapWindow(_sapp.x11.display, window->x11.window); + XDestroyWindow(_sapp.x11.display, window->x11.window); + window->x11.window = 0; + } + if (window->x11.colormap) { + XFreeColormap(_sapp.x11.display, window->x11.colormap); + window->x11.colormap = 0; } -} - -_SOKOL_PRIVATE void _sapp_x11_hide_window(void) { - XUnmapWindow(_sapp.x11.display, _sapp.x11.window); XFlush(_sapp.x11.display); } @@ -9715,14 +9750,14 @@ _SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Window window, Atom p return itemCount; } -_SOKOL_PRIVATE int _sapp_x11_get_window_state(void) { +_SOKOL_PRIVATE int _sapp_x11_get_window_state(_sapp_window_t* window) { int result = WithdrawnState; struct { CARD32 state; Window icon; } *state = NULL; - if (_sapp_x11_get_window_property(_sapp.x11.window, _sapp.x11.WM_STATE, _sapp.x11.WM_STATE, (unsigned char**)&state) >= 2) { + if (_sapp_x11_get_window_property(window->x11.window, _sapp.x11.WM_STATE, _sapp.x11.WM_STATE, (unsigned char**)&state) >= 2) { result = state->state; } if (state) { @@ -9748,9 +9783,9 @@ _SOKOL_PRIVATE uint32_t _sapp_x11_mod(int x11_mods) { return mods; } -_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) { +_SOKOL_PRIVATE void _sapp_x11_app_event(_sapp_window_t* window, sapp_event_type type) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp_call_event(&_sapp.event); } } @@ -9764,18 +9799,18 @@ _SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event) } } -_SOKOL_PRIVATE void _sapp_x11_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mods) { +_SOKOL_PRIVATE void _sapp_x11_mouse_event(_sapp_window_t* window, sapp_event_type type, sapp_mousebutton btn, uint32_t mods) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.mouse_button = btn; _sapp.event.modifiers = mods; _sapp_call_event(&_sapp.event); } } -_SOKOL_PRIVATE void _sapp_x11_scroll_event(float x, float y, uint32_t mods) { +_SOKOL_PRIVATE void _sapp_x11_scroll_event(_sapp_window_t* window, float x, float y, uint32_t mods) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(window, SAPP_EVENTTYPE_MOUSE_SCROLL); _sapp.event.modifiers = mods; _sapp.event.scroll_x = x; _sapp.event.scroll_y = y; @@ -9783,28 +9818,28 @@ _SOKOL_PRIVATE void _sapp_x11_scroll_event(float x, float y, uint32_t mods) { } } -_SOKOL_PRIVATE void _sapp_x11_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mods) { +_SOKOL_PRIVATE void _sapp_x11_key_event(_sapp_window_t* window, sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mods) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.key_code = key; _sapp.event.key_repeat = repeat; _sapp.event.modifiers = mods; _sapp_call_event(&_sapp.event); /* check if a CLIPBOARD_PASTED event must be sent too */ - if (_sapp.clipboard.enabled && + if (window->clipboard.enabled && (type == SAPP_EVENTTYPE_KEY_DOWN) && (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) && (_sapp.event.key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_init_event(window, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } } } -_SOKOL_PRIVATE void _sapp_x11_char_event(uint32_t chr, bool repeat, uint32_t mods) { +_SOKOL_PRIVATE void _sapp_x11_char_event(_sapp_window_t* window, uint32_t chr, bool repeat, uint32_t mods) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); + _sapp_init_event(window, SAPP_EVENTTYPE_CHAR); _sapp.event.char_code = chr; _sapp.event.key_repeat = repeat; _sapp.event.modifiers = mods; @@ -9984,12 +10019,12 @@ _SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) { return -1; } -_SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { +_SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(_sapp_window_t* window, const char* src) { SOKOL_ASSERT(src); - SOKOL_ASSERT(_sapp.drop.buffer); + SOKOL_ASSERT(window->drop.buffer); - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; + _sapp_clear_drop_buffer(window); + window->drop.num_files = 0; /* src is (potentially percent-encoded) string made of one or multiple paths @@ -9998,8 +10033,8 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { bool err = false; int src_count = 0; char src_chr = 0; - char* dst_ptr = _sapp.drop.buffer; - const char* dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); // room for terminating 0 + char* dst_ptr = window->drop.buffer; + const char* dst_end_ptr = dst_ptr + (window->drop.max_path_length - 1); // room for terminating 0 while (0 != (src_chr = *src++)) { src_count++; char dst_chr = 0; @@ -10024,13 +10059,13 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { else if (src_chr == '\n') { src_chr = 0; src_count = 0; - _sapp.drop.num_files++; + window->drop.num_files++; // too many files is not an error - if (_sapp.drop.num_files >= _sapp.drop.max_files) { + if (window->drop.num_files >= window->drop.max_files) { break; } - dst_ptr = _sapp.drop.buffer + _sapp.drop.num_files * _sapp.drop.max_path_length; - dst_end_ptr = dst_ptr + (_sapp.drop.max_path_length - 1); + dst_ptr = window->drop.buffer + window->drop.num_files * window->drop.max_path_length; + dst_end_ptr = dst_ptr + (window->drop.max_path_length - 1); } else if ((src_chr == '%') && src[0] && src[1]) { // a percent-encoded byte (most like UTF-8 multibyte sequence) @@ -10054,8 +10089,8 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { } } if (err) { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; + _sapp_clear_drop_buffer(window); + window->drop.num_files = 0; return false; } else { @@ -10067,11 +10102,21 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html static bool _sapp_x11_keycodes[256]; -_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { +_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { + _sapp_window_t* window = NULL; + if (XFindContext(_sapp.x11.display, + event->xany.window, + _sapp.x11.context, + (XPointer*) &window) != 0) + { + /* This is an event for a window that has already been destroyed */ + return; + } + Bool filtered = XFilterEvent(event, None); switch (event->type) { case GenericEvent: - if (_sapp.mouse.locked && _sapp.x11.xi.available) { + if (window->mouse.locked && _sapp.x11.xi.available) { if (event->xcookie.extension == _sapp.x11.xi.major_opcode) { if (XGetEventData(_sapp.x11.display, &event->xcookie)) { if (event->xcookie.evtype == XI_RawMotion) { @@ -10079,13 +10124,13 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { if (re->valuators.mask_len) { const double* values = re->raw_values; if (XIMaskIsSet(re->valuators.mask, 0)) { - _sapp.mouse.dx = (float) *values; + window->mouse.dx = (float) *values; values++; } if (XIMaskIsSet(re->valuators.mask, 1)) { - _sapp.mouse.dy = (float) *values; + window->mouse.dy = (float) *values; } - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state)); + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state)); } } XFreeEventData(_sapp.x11.display, &event->xcookie); @@ -10095,8 +10140,8 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { break; case FocusOut: /* if focus is lost for any reason, and we're in mouse locked mode, disable mouse lock */ - if (_sapp.mouse.locked) { - _sapp_x11_lock_mouse(false); + if (window->mouse.locked) { + _sapp_x11_lock_mouse(window, false); } break; case KeyPress: @@ -10107,13 +10152,13 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { _sapp_x11_keycodes[keycode & 0xFF] = true; const uint32_t mods = _sapp_x11_mod(event->xkey.state); if (key != SAPP_KEYCODE_INVALID) { - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods); + _sapp_x11_key_event(window, SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods); } KeySym keysym; XLookupString(&event->xkey, NULL, 0, &keysym, NULL); int32_t chr = _sapp_x11_keysym_to_unicode(keysym); if (chr > 0) { - _sapp_x11_char_event((uint32_t)chr, repeat, mods); + _sapp_x11_char_event(window, (uint32_t)chr, repeat, mods); } } break; @@ -10124,7 +10169,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { _sapp_x11_keycodes[keycode & 0xFF] = false; if (key != SAPP_KEYCODE_INVALID) { const uint32_t mods = _sapp_x11_mod(event->xkey.state); - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, false, mods); + _sapp_x11_key_event(window, SAPP_EVENTTYPE_KEY_UP, key, false, mods); } } break; @@ -10133,16 +10178,16 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { const sapp_mousebutton btn = _sapp_x11_translate_button(event); const uint32_t mods = _sapp_x11_mod(event->xbutton.state); if (btn != SAPP_MOUSEBUTTON_INVALID) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods); + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods); _sapp.x11.mouse_buttons |= (1 << btn); } else { /* might be a scroll event */ switch (event->xbutton.button) { - case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break; - case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break; - case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break; - case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break; + case 4: _sapp_x11_scroll_event(window, 0.0f, 1.0f, mods); break; + case 5: _sapp_x11_scroll_event(window, 0.0f, -1.0f, mods); break; + case 6: _sapp_x11_scroll_event(window, 1.0f, 0.0f, mods); break; + case 7: _sapp_x11_scroll_event(window, -1.0f, 0.0f, mods); break; } } } @@ -10151,7 +10196,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { { const sapp_mousebutton btn = _sapp_x11_translate_button(event); if (btn != SAPP_MOUSEBUTTON_INVALID) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, _sapp_x11_mod(event->xbutton.state)); + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_UP, btn, _sapp_x11_mod(event->xbutton.state)); _sapp.x11.mouse_buttons &= ~(1 << btn); } } @@ -10159,48 +10204,48 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { case EnterNotify: /* don't send enter/leave events while mouse button held down */ if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state)); + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state)); } break; case LeaveNotify: if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state)); + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state)); } break; case MotionNotify: - if (!_sapp.mouse.locked) { + if (!window->mouse.locked) { const float new_x = (float) event->xmotion.x; const float new_y = (float) event->xmotion.y; - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; + if (window->mouse.pos_valid) { + window->mouse.dx = new_x - window->mouse.x; + window->mouse.dy = new_y - window->mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state)); + window->mouse.x = new_x; + window->mouse.y = new_y; + window->mouse.pos_valid = true; + _sapp_x11_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state)); } break; case ConfigureNotify: - if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) { - _sapp.window_width = event->xconfigure.width; - _sapp.window_height = event->xconfigure.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); + if ((event->xconfigure.width != window->window_width) || (event->xconfigure.height != window->window_height)) { + window->window_width = event->xconfigure.width; + window->window_height = event->xconfigure.height; + window->framebuffer_width = window->window_width; + window->framebuffer_height = window->window_height; + _sapp_x11_app_event(window, SAPP_EVENTTYPE_RESIZED); } break; case PropertyNotify: if (event->xproperty.state == PropertyNewValue) { if (event->xproperty.atom == _sapp.x11.WM_STATE) { - const int state = _sapp_x11_get_window_state(); - if (state != _sapp.x11.window_state) { - _sapp.x11.window_state = state; + const int state = _sapp_x11_get_window_state(window); + if (state != window->x11.window_state) { + window->x11.window_state = state; if (state == IconicState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED); + _sapp_x11_app_event(window, SAPP_EVENTTYPE_ICONIFIED); } else if (state == NormalState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED); + _sapp_x11_app_event(window, SAPP_EVENTTYPE_RESTORED); } } } @@ -10211,9 +10256,16 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { return; } if (event->xclient.message_type == _sapp.x11.WM_PROTOCOLS) { - const Atom protocol = event->xclient.data.l[0]; - if (protocol == _sapp.x11.WM_DELETE_WINDOW) { - _sapp.quit_requested = true; + /* Only quit app if main window is being closed */ + if(window == _sapp.main_window){ + const Atom protocol = event->xclient.data.l[0]; + if (protocol == _sapp.x11.WM_DELETE_WINDOW) { + _sapp.quit_requested = true; + } + } + else { + _sapp_x11_app_event(window, SAPP_EVENTTYPE_WINDOW_CLOSED); + sapp_destroy_window((sapp_window){ .id = window->id }); } } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndEnter) { @@ -10256,17 +10308,17 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { _sapp.x11.xdnd.XdndSelection, _sapp.x11.xdnd.format, _sapp.x11.xdnd.XdndSelection, - _sapp.x11.window, + window->x11.window, time); } else if (_sapp.x11.xdnd.version >= 2) { XEvent reply; memset(&reply, 0, sizeof(reply)); reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.window; + reply.xclient.window = window->x11.window; reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; reply.xclient.format = 32; - reply.xclient.data.l[0] = _sapp.x11.window; + reply.xclient.data.l[0] = window->x11.window; reply.xclient.data.l[1] = 0; // drag was rejected reply.xclient.data.l[2] = None; XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); @@ -10287,7 +10339,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { reply.xclient.window = _sapp.x11.xdnd.source; reply.xclient.message_type = _sapp.x11.xdnd.XdndStatus; reply.xclient.format = 32; - reply.xclient.data.l[0] = _sapp.x11.window; + reply.xclient.data.l[0] = window->x11.window; if (_sapp.x11.xdnd.format) { /* reply that we are ready to copy the dragged data */ reply.xclient.data.l[1] = 1; // accept with no rectangle @@ -10306,10 +10358,10 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { event->xselection.property, event->xselection.target, (unsigned char**) &data); - if (_sapp.drop.enabled && result) { - if (_sapp_x11_parse_dropped_files_list(data)) { + if (window->drop.enabled && result) { + if (_sapp_x11_parse_dropped_files_list(window, data)) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_init_event(window, SAPP_EVENTTYPE_FILES_DROPPED); _sapp_call_event(&_sapp.event); } } @@ -10318,10 +10370,10 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { XEvent reply; memset(&reply, 0, sizeof(reply)); reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.window; + reply.xclient.window = window->x11.window; reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; reply.xclient.format = 32; - reply.xclient.data.l[0] = _sapp.x11.window; + reply.xclient.data.l[0] = window->x11.window; reply.xclient.data.l[1] = result; reply.xclient.data.l[2] = _sapp.x11.xdnd.XdndActionCopy; XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); @@ -10336,7 +10388,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp.x11.window_state = NormalState; + _sapp_setup_pools(desc); XInitThreads(); XrmInitialize(); @@ -10352,21 +10404,15 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_x11_init_extensions(); _sapp_x11_create_hidden_cursor(); _sapp_glx_init(); - Visual* visual = 0; - int depth = 0; - _sapp_glx_choose_visual(&visual, &depth); - _sapp_x11_create_window(visual, depth); - _sapp_glx_create_context(); + + sapp_window main_window = sapp_create_window(&desc->window); + _sapp.main_window = _sapp_lookup_window(main_window.id); + SOKOL_ASSERT(_sapp.main_window); + _sapp.valid = true; - _sapp_x11_show_window(); - if (_sapp.fullscreen) { - _sapp_x11_set_fullscreen(true); - } - _sapp_x11_query_window_size(); - _sapp_glx_swapinterval(_sapp.swap_interval); - XFlush(_sapp.x11.display); while (!_sapp.quit_ordered) { - _sapp_glx_make_current(); + // TODO: handle all windows + _sapp_glx_make_current(_sapp.main_window); int count = XPending(_sapp.x11.display); while (count--) { XEvent event; @@ -10374,12 +10420,21 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_x11_process_event(&event); } _sapp_frame(); - _sapp_glx_swap_buffers(); + + // TODO: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + _sapp_window_t* window = &_sapp.windows[i]; + + _sapp_glx_swap_buffers(window); + } + } + XFlush(_sapp.x11.display); /* handle quit-requested, either from window or from sapp_request_quit() */ if (_sapp.quit_requested && !_sapp.quit_ordered) { /* give user code a chance to intervene */ - _sapp_x11_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); + _sapp_x11_app_event(_sapp.main_window, SAPP_EVENTTYPE_QUIT_REQUESTED); /* if user code hasn't intervened, quit the app */ if (_sapp.quit_requested) { _sapp.quit_ordered = true; @@ -10387,8 +10442,13 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { } } _sapp_call_cleanup(); - _sapp_glx_destroy_context(); - _sapp_x11_destroy_window(); + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + // TODO: Is there a better way to handle this instead of creating a tmp object? + sapp_destroy_window((sapp_window){ .id=_sapp.windows[i].id }); + } + } + XCloseDisplay(_sapp.x11.display); _sapp_discard_state(); } @@ -10463,6 +10523,12 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ #elif defined(SOKOL_GLCORE33) _sapp_wgl_create_context(window); #endif + #elif defined(_SAPP_LINUX) + Visual* visual = 0; + int depth = 0; + _sapp_glx_choose_visual(window, &visual, &depth); + _sapp_x11_create_window(window, visual, depth); + _sapp_glx_create_context(window); #endif } else { @@ -10488,6 +10554,9 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ #endif _sapp_win32_destroy_window(window); + #elif defined(_SAPP_LINUX) + _sapp_glx_destroy_context(window); + _sapp_x11_destroy_window(window); #endif if (window->clipboard.enabled) { @@ -10510,10 +10579,14 @@ SOKOL_API_DECL void sapp_make_context_current(sapp_window window_id){ _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); - #if defined(SOKOL_D3D11) - // Do nothing? - #elif defined(SOKOL_GLCORE33) - _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + #if defined(_SAPP_WIN32) + #if defined(SOKOL_D3D11) + // Do nothing? + #elif defined(SOKOL_GLCORE33) + _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + #endif + #elif defined(_SAPP_LINUX) + _sapp_glx_make_current(window); #endif } @@ -10633,36 +10706,56 @@ SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { #if defined(_SAPP_MACOS) _sapp_macos_toggle_fullscreen(); #elif defined(_SAPP_WIN32) - // TODO: window specific toggle _sapp_win32_toggle_fullscreen(window); #elif defined(_SAPP_UWP) _sapp_uwp_toggle_fullscreen(); #elif defined(_SAPP_LINUX) - _sapp_x11_toggle_fullscreen(); + _sapp_x11_toggle_fullscreen(window); #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) { - if (_sapp.mouse.shown != show) { +SOKOL_API_IMPL void sapp_window_show_mouse(sapp_window window_id, bool show) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + if (window->mouse.shown != show) { #if defined(_SAPP_MACOS) _sapp_macos_show_mouse(show); #elif defined(_SAPP_WIN32) _sapp_win32_show_mouse(show); #elif defined(_SAPP_LINUX) - _sapp_x11_show_mouse(show); + _sapp_x11_show_mouse(window, show); #elif defined(_SAPP_UWP) _sapp_uwp_show_mouse(show); #endif - _sapp.mouse.shown = show; + window->mouse.shown = show; } } +/* 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_show_mouse((sapp_window){ .id = _sapp.main_window->id }, show); +} + +SOKOL_API_IMPL bool sapp_window_mouse_shown(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + return window->mouse.shown; +} + SOKOL_API_IMPL bool sapp_mouse_shown(void) { - return _sapp.mouse.shown; + return sapp_window_mouse_shown((sapp_window){ .id = _sapp.main_window->id }); } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { + sapp_window_lock_mouse((sapp_window){ .id = _sapp.main_window->id }, lock); +} + +SOKOL_API_IMPL void sapp_window_lock_mouse(sapp_window window_id, bool lock) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(_SAPP_MACOS) _sapp_macos_lock_mouse(lock); #elif defined(_SAPP_EMSCRIPTEN) @@ -10671,14 +10764,21 @@ SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { // TODO: window specific lock _sapp_win32_lock_mouse(_sapp.main_window, lock); #elif defined(_SAPP_LINUX) - _sapp_x11_lock_mouse(lock); + _sapp_x11_lock_mouse(window, lock); #else - _sapp.mouse.locked = lock; + window->mouse.locked = lock; #endif } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - return _sapp.mouse.locked; + return sapp_window_mouse_locked((sapp_window){ .id = _sapp.main_window->id }); +} + +SOKOL_API_IMPL bool sapp_window_mouse_locked(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + + return window->mouse.locked; } SOKOL_API_IMPL void sapp_request_quit(void) { @@ -10756,7 +10856,7 @@ SOKOL_API_IMPL void sapp_set_window_title(sapp_window window_id, const char* tit #elif defined(_SAPP_WIN32) _sapp_win32_update_window_title(window); #elif defined(_SAPP_LINUX) - _sapp_x11_update_window_title(); + _sapp_x11_update_window_title(window); #endif } @@ -11037,4 +11137,4 @@ SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { _sapp.html5_ask_leave_site = ask; } -#endif /* SOKOL_IMPL */ +#endif /* SOKOL_IMPL */ \ No newline at end of file From 1e106bf72fcdc5e98a18715b988506a4f93c26b5 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Sat, 21 Nov 2020 14:30:06 -0700 Subject: [PATCH 04/14] moving d3d11 and wgl in separate structs inside window_t for consistency --- sokol_app.h | 181 +++++++++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 81 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index a7d71bc59..cd25832a9 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1694,6 +1694,18 @@ typedef struct { ID3D11DeviceContext* device_context; IDXGIFactory* dxgi_factory; } _sapp_d3d11_t; + +typedef struct { + ID3D11Texture2D* rt; + ID3D11RenderTargetView* rtv; + ID3D11Texture2D* msaa_rt; + ID3D11RenderTargetView* msaa_rtv; + ID3D11Texture2D* ds; + ID3D11DepthStencilView* dsv; + DXGI_SWAP_CHAIN_DESC swap_chain_desc; + IDXGISwapChain* swap_chain; +} _sapp_d3d11_window_t; + #endif /*== WIN32 DECLARATIONS ======================================================*/ @@ -1798,6 +1810,10 @@ typedef struct { HWND msg_hwnd; HDC msg_dc; } _sapp_wgl_t; + +typedef struct { + HGLRC gl_ctx; +} _sapp_wgl_window_t; #endif // SOKOL_GLCORE33 #endif // _SAPP_WIN32 @@ -2090,19 +2106,11 @@ typedef struct { _sapp_mouse_t mouse; #if defined(_SAPP_WIN32) _sapp_win32_window_t win32; - // TODO, move into gl/d3d substructs #if defined(SOKOL_GLCORE33) - HGLRC gl_ctx; + _sapp_wgl_window_t wgl; #elif defined(SOKOL_D3D11) - ID3D11Texture2D* rt; - ID3D11RenderTargetView* rtv; - ID3D11Texture2D* msaa_rt; - ID3D11RenderTargetView* msaa_rtv; - ID3D11Texture2D* ds; - ID3D11DepthStencilView* dsv; - DXGI_SWAP_CHAIN_DESC swap_chain_desc; - IDXGISwapChain* swap_chain; + _sapp_d3d11_window_t d3d11; #endif #elif defined(_SAPP_LINUX) _sapp_x11_window_t x11; @@ -2125,6 +2133,9 @@ typedef struct { float dpi_scale; uint64_t frame_count; sapp_event event; + _sapp_pool_t window_pool; + _sapp_window_t* windows; + _sapp_window_t* main_window; #if defined(_SAPP_MACOS) _sapp_macos_t macos; #elif defined(_SAPP_IOS) @@ -2152,11 +2163,6 @@ typedef struct { char html5_canvas_selector[_SAPP_MAX_TITLE_LENGTH]; sapp_keycode keycodes[SAPP_MAX_KEYCODES]; - - // TODO: Desktop only? Ignore completely for html5/android/iOS? - _sapp_pool_t window_pool; - _sapp_window_t* windows; - _sapp_window_t* main_window; } _sapp_t; static _sapp_t _sapp; @@ -2742,6 +2748,14 @@ _SOKOL_PRIVATE int _sapp_slot_index(uint32_t id) { return slot_index; } +/* create sapp_window handle from id */ +_SOKOL_PRIVATE sapp_window _sapp_window(uint32_t id) { + SOKOL_ASSERT(id != SAPP_INVALID_ID); + sapp_window window_id; + window_id.id = id; + return window_id; +} + /* returns pointer to resource by id without matching id check */ _SOKOL_PRIVATE _sapp_window_t* _sapp_window_at(uint32_t window_id) { SOKOL_ASSERT((SAPP_INVALID_ID != window_id)); @@ -5453,6 +5467,14 @@ static inline HRESULT _sapp_dxgi_CreateSwapChain(IDXGIFactory* self, ID3D11Devic #endif } +static inline HRESULT _sapp_dxgi_CreateDXGIFactory(IDXGIFactory** dxgi_factory) { + #if defined(__cplusplus) + return CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)dxgi_factory); + #else + return CreateDXGIFactory(&IID_IDXGIFactory, (void**)&_sapp.d3d11.dxgi_factory); + #endif +} + _SOKOL_PRIVATE void _sapp_d3d11_create_device(void) { int create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if defined(SOKOL_DEBUG) @@ -5474,12 +5496,12 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_device(void) { SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.device && _sapp.d3d11.device_context); // We need a dxgi factory to create multiple swapchains - hr = CreateDXGIFactory(&IID_IDXGIFactory, (void**)&_sapp.d3d11.dxgi_factory); + hr = _sapp_dxgi_CreateDXGIFactory(&_sapp.d3d11.dxgi_factory); SOKOL_ASSERT(SUCCEEDED(hr) && _sapp.d3d11.dxgi_factory); } _SOKOL_PRIVATE void _sapp_d3d11_create_swapchain(_sapp_window_t* window) { - DXGI_SWAP_CHAIN_DESC* sc_desc = &window->swap_chain_desc; + DXGI_SWAP_CHAIN_DESC* sc_desc = &window->d3d11.swap_chain_desc; sc_desc->BufferDesc.Width = window->framebuffer_width; sc_desc->BufferDesc.Height = window->framebuffer_height; sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; @@ -5503,10 +5525,10 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_swapchain(_sapp_window_t* window) { _sapp.d3d11.dxgi_factory, /* dxgi_factory */ _sapp.d3d11.device, /* *pDevice */ sc_desc, /* Swapchain Desc */ - &window->swap_chain /* ppSwapChain */ + &window->d3d11.swap_chain /* ppSwapChain */ ); - SOKOL_ASSERT(SUCCEEDED(hr) && window->swap_chain); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.swap_chain); } _SOKOL_PRIVATE void _sapp_d3d11_destroy_device() { @@ -5516,28 +5538,28 @@ _SOKOL_PRIVATE void _sapp_d3d11_destroy_device() { } _SOKOL_PRIVATE void _sapp_d3d11_destroy_swapchain(_sapp_window_t* window) { - _SAPP_SAFE_RELEASE(window->swap_chain); + _SAPP_SAFE_RELEASE(window->d3d11.swap_chain); } _SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(_sapp_window_t* window) { - SOKOL_ASSERT(0 == window->rt); - SOKOL_ASSERT(0 == window->rtv); - SOKOL_ASSERT(0 == window->msaa_rt); - SOKOL_ASSERT(0 == window->msaa_rtv); - SOKOL_ASSERT(0 == window->ds); - SOKOL_ASSERT(0 == window->dsv); + SOKOL_ASSERT(0 == window->d3d11.rt); + SOKOL_ASSERT(0 == window->d3d11.rtv); + SOKOL_ASSERT(0 == window->d3d11.msaa_rt); + SOKOL_ASSERT(0 == window->d3d11.msaa_rtv); + SOKOL_ASSERT(0 == window->d3d11.ds); + SOKOL_ASSERT(0 == window->d3d11.dsv); HRESULT hr; /* view for the swapchain-created framebuffer */ #ifdef __cplusplus - hr = _sapp_dxgi_GetBuffer(window->swap_chain, 0, IID_ID3D11Texture2D, (void**)&window->rt); + hr = _sapp_dxgi_GetBuffer(window->d3d11.swap_chain, 0, IID_ID3D11Texture2D, (void**)&window->d3d11.rt); #else - hr = _sapp_dxgi_GetBuffer(window->swap_chain, 0, &IID_ID3D11Texture2D, (void**)&window->rt); + hr = _sapp_dxgi_GetBuffer(window->d3d11.swap_chain, 0, &IID_ID3D11Texture2D, (void**)&window->d3d11.rt); #endif - SOKOL_ASSERT(SUCCEEDED(hr) && window->rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->rt, NULL, &window->rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && window->rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.rt); + hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->d3d11.rt, NULL, &window->d3d11.rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.rtv); /* common desc for MSAA and depth-stencil texture */ D3D11_TEXTURE2D_DESC tex_desc; @@ -5554,34 +5576,34 @@ _SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(_sapp_window_t* win /* create MSAA texture and view if antialiasing requested */ if (window->sample_count > 1) { tex_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->msaa_rt); - SOKOL_ASSERT(SUCCEEDED(hr) && window->msaa_rt); - hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->msaa_rt, NULL, &window->msaa_rtv); - SOKOL_ASSERT(SUCCEEDED(hr) && window->msaa_rtv); + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->d3d11.msaa_rt); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.msaa_rt); + hr = _sapp_d3d11_CreateRenderTargetView(_sapp.d3d11.device, (ID3D11Resource*)window->d3d11.msaa_rt, NULL, &window->d3d11.msaa_rtv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.msaa_rtv); } /* texture and view for the depth-stencil-surface */ tex_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; tex_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->ds); - SOKOL_ASSERT(SUCCEEDED(hr) && window->ds); - hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)window->ds, NULL, &window->dsv); - SOKOL_ASSERT(SUCCEEDED(hr) && window->dsv); + hr = _sapp_d3d11_CreateTexture2D(_sapp.d3d11.device, &tex_desc, NULL, &window->d3d11.ds); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.ds); + hr = _sapp_d3d11_CreateDepthStencilView(_sapp.d3d11.device, (ID3D11Resource*)window->d3d11.ds, NULL, &window->d3d11.dsv); + SOKOL_ASSERT(SUCCEEDED(hr) && window->d3d11.dsv); } _SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(_sapp_window_t* window) { - _SAPP_SAFE_RELEASE(window->rt); - _SAPP_SAFE_RELEASE(window->rtv); - _SAPP_SAFE_RELEASE(window->msaa_rt); - _SAPP_SAFE_RELEASE(window->msaa_rtv); - _SAPP_SAFE_RELEASE(window->ds); - _SAPP_SAFE_RELEASE(window->dsv); + _SAPP_SAFE_RELEASE(window->d3d11.rt); + _SAPP_SAFE_RELEASE(window->d3d11.rtv); + _SAPP_SAFE_RELEASE(window->d3d11.msaa_rt); + _SAPP_SAFE_RELEASE(window->d3d11.msaa_rtv); + _SAPP_SAFE_RELEASE(window->d3d11.ds); + _SAPP_SAFE_RELEASE(window->d3d11.dsv); } _SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(_sapp_window_t* window) { - if (window->swap_chain) { + if (window->d3d11.swap_chain) { _sapp_d3d11_destroy_default_render_target(window); - _sapp_dxgi_ResizeBuffers(window->swap_chain, window->swap_chain_desc.BufferCount, window->framebuffer_width, window->framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); + _sapp_dxgi_ResizeBuffers(window->d3d11.swap_chain, window->d3d11.swap_chain_desc.BufferCount, window->framebuffer_width, window->framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0); _sapp_d3d11_create_default_render_target(window); } } @@ -5589,11 +5611,11 @@ _SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(_sapp_window_t* win _SOKOL_PRIVATE void _sapp_d3d11_present(_sapp_window_t* window) { /* do MSAA resolve if needed */ if (window->sample_count > 1) { - SOKOL_ASSERT(window->rt); - SOKOL_ASSERT(window->msaa_rt); - _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)window->rt, 0, (ID3D11Resource*)window->msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); + SOKOL_ASSERT(window->d3d11.rt); + SOKOL_ASSERT(window->d3d11.msaa_rt); + _sapp_d3d11_ResolveSubresource(_sapp.d3d11.device_context, (ID3D11Resource*)window->d3d11.rt, 0, (ID3D11Resource*)window->d3d11.msaa_rt, 0, DXGI_FORMAT_B8G8R8A8_UNORM); } - _sapp_dxgi_Present(window->swap_chain, window->swap_interval, 0); + _sapp_dxgi_Present(window->d3d11.swap_chain, window->swap_interval, 0); } #endif /* SOKOL_D3D11 */ @@ -5817,8 +5839,8 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(_sapp_window_t* window) { WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, 0 }; - window->gl_ctx = _sapp.wgl.CreateContextAttribsARB(window->win32.dc, 0, attrs); - if (!window->gl_ctx) { + window->wgl.gl_ctx = _sapp.wgl.CreateContextAttribsARB(window->win32.dc, 0, attrs); + if (!window->wgl.gl_ctx) { const DWORD err = GetLastError(); if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { _sapp_fail("WGL: Driver does not support OpenGL version 3.3\n"); @@ -5833,7 +5855,7 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(_sapp_window_t* window) { _sapp_fail("WGL: Failed to create OpenGL context"); } } - _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + _sapp.wgl.MakeCurrent(window->win32.dc, window->wgl.gl_ctx); if (_sapp.wgl.ext_swap_control) { /* FIXME: DwmIsCompositionEnabled() (see GLFW) */ _sapp.wgl.SwapIntervalEXT(window->swap_interval); @@ -5841,9 +5863,9 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(_sapp_window_t* window) { } _SOKOL_PRIVATE void _sapp_wgl_destroy_context(_sapp_window_t* window) { - SOKOL_ASSERT(window->gl_ctx); - _sapp.wgl.DeleteContext(window->gl_ctx); - window->gl_ctx = 0; + SOKOL_ASSERT(window->wgl.gl_ctx); + _sapp.wgl.DeleteContext(window->wgl.gl_ctx); + window->wgl.gl_ctx = 0; } _SOKOL_PRIVATE void _sapp_wgl_swap_buffers(_sapp_window_t* window) { @@ -6139,7 +6161,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM else { // TODO: wo we want to give the user a per window opportunity to cancel closure requests? _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_WINDOW_CLOSED); - sapp_destroy_window((sapp_window){ .id = window->id }); + sapp_destroy_window(_sapp_window(window->id)); } return 0; case WM_SYSCOMMAND: @@ -6561,8 +6583,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { DispatchMessage(&msg); } } - // TODO: add handle to sapp_t? - sapp_make_context_current((sapp_window){ .id = _sapp.main_window->id }); + sapp_make_context_current(_sapp_window(_sapp.main_window->id)); _sapp_frame(); // TODO: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? @@ -6600,7 +6621,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { for (int i = 1; i < _sapp.window_pool.size; i++) { if(_sapp.windows[i].id != SAPP_INVALID_ID){ // TODO: Is there a better way to handle this instead of creating a tmp object? - sapp_destroy_window((sapp_window){ .id=_sapp.windows[i].id }); + sapp_destroy_window(_sapp_window(_sapp.windows[i].id)); } } #if defined(SOKOL_D3D11) @@ -6675,7 +6696,7 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _ // Helper functions _SOKOL_PRIVATE void _sapp_uwp_configure_dpi(float monitor_dpi) { _sapp.uwp.dpi.window_scale = monitor_dpi / 96.0f; - if (_sapp.desc.high_dpi) { + if (_sapp.desc.window.high_dpi) { _sapp.uwp.dpi.content_scale = _sapp.uwp.dpi.window_scale; _sapp.uwp.dpi.mouse_scale = 1.0f * _sapp.uwp.dpi.window_scale; } @@ -10549,7 +10570,7 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ _sapp_d3d11_destroy_default_render_target(window); _sapp_d3d11_destroy_swapchain(window); #elif defined(SOKOL_GLCORE33) - _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + _sapp.wgl.MakeCurrent(window->win32.dc, window->wgl.gl_ctx); _sapp_wgl_destroy_context(window); #endif @@ -10583,7 +10604,7 @@ SOKOL_API_DECL void sapp_make_context_current(sapp_window window_id){ #if defined(SOKOL_D3D11) // Do nothing? #elif defined(SOKOL_GLCORE33) - _sapp.wgl.MakeCurrent(window->win32.dc, window->gl_ctx); + _sapp.wgl.MakeCurrent(window->win32.dc, window->wgl.gl_ctx); #endif #elif defined(_SAPP_LINUX) _sapp_glx_make_current(window); @@ -10683,13 +10704,7 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { } SOKOL_API_DECL bool sapp_is_fullscreen() { - // TODO: fix struct literal? - return sapp_window_is_fullscreen((sapp_window){ .id=_sapp.main_window->id }); -} - -SOKOL_API_DECL void sapp_toggle_fullscreen() { - // TODO: fix struct literal? - sapp_window_toggle_fullscreen((sapp_window){ .id=_sapp.main_window->id }); + return sapp_window_is_fullscreen(_sapp_window(_sapp.main_window->id)); } SOKOL_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id) { @@ -10699,6 +10714,10 @@ SOKOL_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id) { return window->fullscreen; } +SOKOL_API_DECL void sapp_toggle_fullscreen() { + sapp_window_toggle_fullscreen(_sapp_window(_sapp.main_window->id)); +} + SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); @@ -10734,7 +10753,7 @@ SOKOL_API_IMPL void sapp_window_show_mouse(sapp_window window_id, bool show) { /* 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_show_mouse((sapp_window){ .id = _sapp.main_window->id }, show); + sapp_window_show_mouse(_sapp_window(_sapp.main_window->id), show); } SOKOL_API_IMPL bool sapp_window_mouse_shown(sapp_window window_id) { @@ -10745,11 +10764,11 @@ SOKOL_API_IMPL bool sapp_window_mouse_shown(sapp_window window_id) { } SOKOL_API_IMPL bool sapp_mouse_shown(void) { - return sapp_window_mouse_shown((sapp_window){ .id = _sapp.main_window->id }); + return sapp_window_mouse_shown(_sapp_window(_sapp.main_window->id)); } SOKOL_API_IMPL void sapp_lock_mouse(bool lock) { - sapp_window_lock_mouse((sapp_window){ .id = _sapp.main_window->id }, lock); + sapp_window_lock_mouse(_sapp_window(_sapp.main_window->id), lock); } SOKOL_API_IMPL void sapp_window_lock_mouse(sapp_window window_id, bool lock) { @@ -10771,7 +10790,7 @@ SOKOL_API_IMPL void sapp_window_lock_mouse(sapp_window window_id, bool lock) { } SOKOL_API_IMPL bool sapp_mouse_locked(void) { - return sapp_window_mouse_locked((sapp_window){ .id = _sapp.main_window->id }); + return sapp_window_mouse_locked(_sapp_window(_sapp.main_window->id)); } SOKOL_API_IMPL bool sapp_window_mouse_locked(sapp_window window_id) { @@ -10868,11 +10887,11 @@ SOKOL_API_IMPL int sapp_window_get_num_dropped_files(sapp_window window_id) { } SOKOL_API_IMPL int sapp_get_num_dropped_files() { - return sapp_window_get_num_dropped_files((sapp_window) { .id=_sapp.main_window->id }); + return sapp_window_get_num_dropped_files(_sapp_window(_sapp.main_window->id)); } SOKOL_API_IMPL const char* sapp_get_dropped_file_path(int index) { - return sapp_window_get_dropped_file_path((sapp_window) { .id=_sapp.main_window->id }, index); + return sapp_window_get_dropped_file_path(_sapp_window(_sapp.main_window->id), index); } SOKOL_API_IMPL const char* sapp_window_get_dropped_file_path(sapp_window window_id, int index) { @@ -11035,11 +11054,11 @@ SOKOL_API_IMPL const void* sapp_d3d11_window_get_render_target_view(sapp_window SOKOL_ASSERT(window); #if defined(SOKOL_D3D11) - if (window->msaa_rtv) { - return window->msaa_rtv; + if (window->d3d11.msaa_rtv) { + return window->d3d11.msaa_rtv; } else { - return window->rtv; + return window->d3d11.rtv; } #else return 0; @@ -11057,7 +11076,7 @@ SOKOL_API_IMPL const void* sapp_d3d11_window_get_depth_stencil_view(sapp_window SOKOL_ASSERT(window); #if defined(SOKOL_D3D11) - return window->dsv; + return window->d3d11.dsv; #else return 0; #endif From 14e89a1290dd9eb86203a0df2acadbd8d5461d3d Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Sat, 21 Nov 2020 14:30:30 -0700 Subject: [PATCH 05/14] update uwp to work with multi-window changes --- sokol_app.h | 111 ++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index cd25832a9..3130005b4 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2112,6 +2112,8 @@ typedef struct { #elif defined(SOKOL_D3D11) _sapp_d3d11_window_t d3d11; #endif + #elif defined(_SAPP_UWP) + _sapp_d3d11_window_t d3d11; #elif defined(_SAPP_LINUX) _sapp_x11_window_t x11; _sapp_glx_window_t glx; @@ -6740,7 +6742,7 @@ _SOKOL_PRIVATE uint32_t _sapp_uwp_mods(winrt::Windows::UI::Core::CoreWindow cons _SOKOL_PRIVATE void _sapp_uwp_mouse_event(sapp_event_type type, sapp_mousebutton btn, winrt::Windows::UI::Core::CoreWindow const& sender_window) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp.event.modifiers = _sapp_uwp_mods(sender_window); _sapp.event.mouse_button = btn; _sapp_call_event(&_sapp.event); @@ -6749,7 +6751,7 @@ _SOKOL_PRIVATE void _sapp_uwp_mouse_event(sapp_event_type type, sapp_mousebutton _SOKOL_PRIVATE void _sapp_uwp_scroll_event(float delta, bool horizontal, winrt::Windows::UI::Core::CoreWindow const& sender_window) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_MOUSE_SCROLL); _sapp.event.modifiers = _sapp_uwp_mods(sender_window); _sapp.event.scroll_x = horizontal ? (-delta / 30.0f) : 0.0f; _sapp.event.scroll_y = horizontal ? 0.0f : (delta / 30.0f); @@ -6806,18 +6808,18 @@ _SOKOL_PRIVATE void _sapp_uwp_key_event(sapp_event_type type, winrt::Windows::UI auto key_status = args.KeyStatus(); uint32_t ext_scan_code = key_status.ScanCode | (key_status.IsExtendedKey ? 0x100 : 0); if (_sapp_events_enabled() && (ext_scan_code < SAPP_MAX_KEYCODES)) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp.event.modifiers = _sapp_uwp_mods(sender_window); _sapp.event.key_code = _sapp.keycodes[ext_scan_code]; _sapp.event.key_repeat = type == SAPP_EVENTTYPE_KEY_UP ? false : key_status.WasKeyDown; _sapp_call_event(&_sapp.event); /* check if a CLIPBOARD_PASTED event must be sent too */ - if (_sapp.clipboard.enabled && + if (_sapp.main_window->clipboard.enabled && (type == SAPP_EVENTTYPE_KEY_DOWN) && (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) && (_sapp.event.key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } } @@ -6825,7 +6827,7 @@ _SOKOL_PRIVATE void _sapp_uwp_key_event(sapp_event_type type, winrt::Windows::UI _SOKOL_PRIVATE void _sapp_uwp_char_event(uint32_t c, bool repeat, winrt::Windows::UI::Core::CoreWindow const& sender_window) { if (_sapp_events_enabled() && (c >= 32)) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_CHAR); _sapp.event.modifiers = _sapp_uwp_mods(sender_window); _sapp.event.char_code = c; _sapp.event.key_repeat = repeat; @@ -6835,14 +6837,14 @@ _SOKOL_PRIVATE void _sapp_uwp_char_event(uint32_t c, bool repeat, winrt::Windows _SOKOL_PRIVATE void _sapp_uwp_toggle_fullscreen(void) { auto appView = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView(); - _sapp.fullscreen = appView.IsFullScreenMode(); - if (!_sapp.fullscreen) { + _sapp.main_window->fullscreen = appView.IsFullScreenMode(); + if (!_sapp.main_window->fullscreen) { appView.TryEnterFullScreenMode(); } else { appView.ExitFullScreenMode(); } - _sapp.fullscreen = appView.IsFullScreenMode(); + _sapp.main_window->fullscreen = appView.IsFullScreenMode(); } namespace {/* Empty namespace to ensure internal linkage (same as _SOKOL_PRIVATE) */ @@ -7070,12 +7072,12 @@ void DeviceResources::CreateDeviceResources() { void DeviceResources::CreateWindowSizeDependentResources() { // Cleanup Sokol Context (these are non-owning raw pointers) - _sapp.d3d11.rt = nullptr; - _sapp.d3d11.rtv = nullptr; - _sapp.d3d11.msaa_rt = nullptr; - _sapp.d3d11.msaa_rtv = nullptr; - _sapp.d3d11.ds = nullptr; - _sapp.d3d11.dsv = nullptr; + _sapp.main_window->d3d11.rt = nullptr; + _sapp.main_window->d3d11.rtv = nullptr; + _sapp.main_window->d3d11.msaa_rt = nullptr; + _sapp.main_window->d3d11.msaa_rtv = nullptr; + _sapp.main_window->d3d11.ds = nullptr; + _sapp.main_window->d3d11.dsv = nullptr; // Clear the previous window size specific context. ID3D11RenderTargetView* nullViews[] = { nullptr }; @@ -7155,8 +7157,8 @@ void DeviceResources::CreateWindowSizeDependentResources() { winrt::check_hresult(dxgiDevice->SetMaximumFrameLatency(1)); // Setup Sokol Context - winrt::check_hresult(swapChain->GetDesc(&_sapp.d3d11.swap_chain_desc)); - _sapp.d3d11.swap_chain = m_swapChain.as().detach(); + winrt::check_hresult(swapChain->GetDesc(&_sapp.main_window->d3d11.swap_chain_desc)); + _sapp.main_window->d3d11.swap_chain = m_swapChain.as().detach(); } // Set the proper orientation for the swap chain, and generate 2D and @@ -7188,7 +7190,7 @@ void DeviceResources::CreateWindowSizeDependentResources() { winrt::check_hresult(m_d3dDevice->CreateRenderTargetView1(m_d3dRenderTarget.get(), nullptr, m_d3dRenderTargetView.put())); // Create MSAA texture and view if needed - if (_sapp.sample_count > 1) { + if (_sapp.main_window->sample_count > 1) { CD3D11_TEXTURE2D_DESC1 msaaTexDesc( DXGI_FORMAT_B8G8R8A8_UNORM, lround(m_d3dRenderTargetSize.Width), @@ -7198,8 +7200,8 @@ void DeviceResources::CreateWindowSizeDependentResources() { D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, 0, // cpuAccessFlags - _sapp.sample_count, - _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 + _sapp.main_window->sample_count, + _sapp.main_window->sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 ); winrt::check_hresult(m_d3dDevice->CreateTexture2D1(&msaaTexDesc, nullptr, m_d3dMSAARenderTarget.put())); winrt::check_hresult(m_d3dDevice->CreateRenderTargetView1(m_d3dMSAARenderTarget.get(), nullptr, m_d3dMSAARenderTargetView.put())); @@ -7215,8 +7217,8 @@ void DeviceResources::CreateWindowSizeDependentResources() { D3D11_BIND_DEPTH_STENCIL, D3D11_USAGE_DEFAULT, 0, // cpuAccessFlag - _sapp.sample_count, - _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 + _sapp.main_window->sample_count, + _sapp.main_window->sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0 ); winrt::check_hresult(m_d3dDevice->CreateTexture2D1(&depthStencilDesc, nullptr, m_d3dDepthStencil.put())); @@ -7224,19 +7226,19 @@ void DeviceResources::CreateWindowSizeDependentResources() { winrt::check_hresult(m_d3dDevice->CreateDepthStencilView(m_d3dDepthStencil.get(), nullptr, m_d3dDepthStencilView.put())); // Set sokol window and framebuffer sizes - _sapp.window_width = (int) m_logicalSize.Width; - _sapp.window_height = (int) m_logicalSize.Height; - _sapp.framebuffer_width = lround(m_d3dRenderTargetSize.Width); - _sapp.framebuffer_height = lround(m_d3dRenderTargetSize.Height); + _sapp.main_window->window_width = (int) m_logicalSize.Width; + _sapp.main_window->window_height = (int) m_logicalSize.Height; + _sapp.main_window->framebuffer_width = lround(m_d3dRenderTargetSize.Width); + _sapp.main_window->framebuffer_height = lround(m_d3dRenderTargetSize.Height); // Setup Sokol Context - _sapp.d3d11.rt = m_d3dRenderTarget.as().get(); - _sapp.d3d11.rtv = m_d3dRenderTargetView.as().get(); - _sapp.d3d11.ds = m_d3dDepthStencil.as().get(); - _sapp.d3d11.dsv = m_d3dDepthStencilView.get(); - if (_sapp.sample_count > 1) { - _sapp.d3d11.msaa_rt = m_d3dMSAARenderTarget.as().get(); - _sapp.d3d11.msaa_rtv = m_d3dMSAARenderTargetView.as().get(); + _sapp.main_window->d3d11.rt = m_d3dRenderTarget.as().get(); + _sapp.main_window->d3d11.rtv = m_d3dRenderTargetView.as().get(); + _sapp.main_window->d3d11.ds = m_d3dDepthStencil.as().get(); + _sapp.main_window->d3d11.dsv = m_d3dDepthStencilView.get(); + if (_sapp.main_window->sample_count > 1) { + _sapp.main_window->d3d11.msaa_rt = m_d3dMSAARenderTarget.as().get(); + _sapp.main_window->d3d11.msaa_rtv = m_d3dMSAARenderTargetView.as().get(); } // Sokol app is now valid @@ -7363,7 +7365,7 @@ void DeviceResources::Trim() { void DeviceResources::Present() { // MSAA resolve if needed - if (_sapp.sample_count > 1) { + if (_sapp.main_window->sample_count > 1) { m_d3dContext->ResolveSubresource(m_d3dRenderTarget.get(), 0, m_d3dMSAARenderTarget.get(), 0, DXGI_FORMAT_B8G8R8A8_UNORM); m_d3dContext->DiscardView1(m_d3dMSAARenderTargetView.get(), nullptr, 0); } @@ -7537,44 +7539,44 @@ void App::OnActivated(winrt::Windows::ApplicationModel::Core::CoreApplicationVie _SOKOL_UNUSED(args); _SOKOL_UNUSED(applicationView); auto appView = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView(); - auto targetSize = winrt::Windows::Foundation::Size((float)_sapp.desc.width, (float)_sapp.desc.height); + auto targetSize = winrt::Windows::Foundation::Size((float)_sapp.desc.window.width, (float)_sapp.desc.window.height); appView.SetPreferredMinSize(targetSize); appView.TryResizeView(targetSize); // Disabling this since it can only append the title to the app name (Title - Appname). // There's no way of just setting a string to be the window title. - //appView.Title(_sapp.window_title_wide); + //appView.Title(_sapp.main_window->window_title_wide); // Run() won't start until the CoreWindow is activated. winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Activate(); - if (_sapp.desc.fullscreen) { + if (_sapp.desc.window.fullscreen) { appView.TryEnterFullScreenMode(); } - _sapp.fullscreen = appView.IsFullScreenMode(); + _sapp.main_window->fullscreen = appView.IsFullScreenMode(); } void App::OnSuspending(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::ApplicationModel::SuspendingEventArgs const& args) { _SOKOL_UNUSED(sender); _SOKOL_UNUSED(args); - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_SUSPENDED); + _sapp_win32_uwp_app_event(_sapp.main_window, SAPP_EVENTTYPE_SUSPENDED); } void App::OnResuming(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::Foundation::IInspectable const& args) { _SOKOL_UNUSED(args); _SOKOL_UNUSED(sender); - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESUMED); + _sapp_win32_uwp_app_event(_sapp.main_window, SAPP_EVENTTYPE_RESUMED); } void App::OnWindowSizeChanged(winrt::Windows::UI::Core::CoreWindow const& sender, winrt::Windows::UI::Core::WindowSizeChangedEventArgs const& args) { _SOKOL_UNUSED(args); m_deviceResources->SetLogicalSize(winrt::Windows::Foundation::Size(sender.Bounds().Width, sender.Bounds().Height)); - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESIZED); + _sapp_win32_uwp_app_event(_sapp.main_window, SAPP_EVENTTYPE_RESIZED); } void App::OnVisibilityChanged(winrt::Windows::UI::Core::CoreWindow const& sender, winrt::Windows::UI::Core::VisibilityChangedEventArgs const& args) { _SOKOL_UNUSED(sender); m_windowVisible = args.Visible(); - _sapp_win32_uwp_app_event(m_windowVisible ? SAPP_EVENTTYPE_RESTORED : SAPP_EVENTTYPE_ICONIFIED); + _sapp_win32_uwp_app_event(_sapp.main_window, m_windowVisible ? SAPP_EVENTTYPE_RESTORED : SAPP_EVENTTYPE_ICONIFIED); } void App::OnBackRequested(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Core::BackRequestedEventArgs const& args) { @@ -7622,13 +7624,13 @@ void App::OnPointerMoved(winrt::Windows::UI::Core::CoreWindow const& sender, win const float new_x = (float)(int)(position.X * _sapp.uwp.dpi.mouse_scale + 0.5f); const float new_y = (float)(int)(position.Y * _sapp.uwp.dpi.mouse_scale + 0.5f); // don't update dx/dy in the very first event - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; + if (_sapp.main_window->mouse.pos_valid) { + _sapp.main_window->mouse.dx = new_x - _sapp.main_window->mouse.x; + _sapp.main_window->mouse.dy = new_y - _sapp.main_window->mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; + _sapp.main_window->mouse.x = new_x; + _sapp.main_window->mouse.y = new_y; + _sapp.main_window->mouse.pos_valid = true; if (!_sapp.uwp.mouse_tracked) { _sapp.uwp.mouse_tracked = true; _sapp_uwp_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, sender); @@ -7648,14 +7650,14 @@ void App::OnDpiChanged(winrt::Windows::Graphics::Display::DisplayInformation con // NOTE: UNTESTED _SOKOL_UNUSED(args); m_deviceResources->SetDpi(sender.LogicalDpi()); - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESIZED); + _sapp_win32_uwp_app_event(_sapp.main_window, SAPP_EVENTTYPE_RESIZED); } void App::OnOrientationChanged(winrt::Windows::Graphics::Display::DisplayInformation const& sender, winrt::Windows::Foundation::IInspectable const& args) { // NOTE: UNTESTED _SOKOL_UNUSED(args); m_deviceResources->SetCurrentOrientation(sender.CurrentOrientation()); - _sapp_win32_uwp_app_event(SAPP_EVENTTYPE_RESIZED); + _sapp_win32_uwp_app_event(_sapp.main_window, SAPP_EVENTTYPE_RESIZED); } void App::OnDisplayContentsInvalidated(winrt::Windows::Graphics::Display::DisplayInformation const& sender, winrt::Windows::Foundation::IInspectable const& args) { @@ -7669,8 +7671,11 @@ void App::OnDisplayContentsInvalidated(winrt::Windows::Graphics::Display::Displa _SOKOL_PRIVATE void _sapp_uwp_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_setup_pools(desc); + sapp_window window_id = sapp_create_window(&desc->window); + _sapp.main_window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(_sapp.main_window); _sapp_win32_uwp_init_keytable(); - _sapp_win32_uwp_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide)); winrt::Windows::ApplicationModel::Core::CoreApplication::Run(winrt::make()); } @@ -10523,7 +10528,7 @@ SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { #endif SOKOL_API_DECL sapp_window sapp_main_window(){ - return (sapp_window){ .id=_sapp.main_window->id }; + return _sapp_window(_sapp.main_window->id); } SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ @@ -10544,6 +10549,8 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ #elif defined(SOKOL_GLCORE33) _sapp_wgl_create_context(window); #endif + #elif defined(_SAPP_UWP) + _sapp_win32_uwp_utf8_to_wide(window->window_title, window->window_title_wide, sizeof(window->window_title_wide)); #elif defined(_SAPP_LINUX) Visual* visual = 0; int depth = 0; From eec77b1dc16406df25085197d8fcd9af14941ccb Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Tue, 24 Nov 2020 21:18:06 -0700 Subject: [PATCH 06/14] adds multi-window support for macos with GLCORE33/Metal --- sokol_app.h | 543 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 343 insertions(+), 200 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 3130005b4..705045677 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1267,10 +1267,16 @@ SOKOL_API_DECL void sapp_html5_fetch_dropped_file(const sapp_html5_fetch_request SOKOL_API_DECL const void* sapp_metal_get_device(void); /* Metal: get bridged pointer to this frame's renderpass descriptor */ SOKOL_API_DECL const void* sapp_metal_get_renderpass_descriptor(void); +/* Metal: get bridged pointer to this frame's renderpass descriptor of specified window */ +SOKOL_API_DECL const void* sapp_metal_window_get_renderpass_descriptor(sapp_window window); /* Metal: get bridged pointer to current drawable */ SOKOL_API_DECL const void* sapp_metal_get_drawable(void); -/* macOS: get bridged pointer to macOS NSWindow */ +/* Metal: get bridged pointer for drawable of specified window */ +SOKOL_API_DECL const void* sapp_metal_window_get_drawable(sapp_window window); +/* macOS: get bridged pointer to macOS NSWindow for the main window */ SOKOL_API_DECL const void* sapp_macos_get_window(void); +/* macOS: get bridged pointer to macOS NSWindow for specified window */ +SOKOL_API_DECL const void* sapp_macos_window_get_window(sapp_window window_id); /* iOS: get bridged pointer to iOS UIWindow */ SOKOL_API_DECL const void* sapp_ios_get_window(void); @@ -1597,31 +1603,56 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } @interface _sapp_macos_app_delegate : NSObject @end @interface _sapp_macos_window : NSWindow +{ + struct _sapp_window_t* window; +} +- (instancetype)initWithContentRect:(NSRect)contentRect + sappWindow:(struct _sapp_window_t*)initWindow + styleMask:(NSWindowStyleMask)style + backing:(NSBackingStoreType)backingStoreType + defer:(BOOL)flag; @end @interface _sapp_macos_window_delegate : NSObject +{ + struct _sapp_window_t* window; +} +- (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow; @end #if defined(SOKOL_METAL) @interface _sapp_macos_view : MTKView + { + struct _sapp_window_t* window; + } + - (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow; @end #elif defined(SOKOL_GLCORE33) @interface _sapp_macos_view : NSOpenGLView + { + struct _sapp_window_t* window; + } + - (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow + initWithFrame:(NSRect)frameRect + pixelFormat:(NSOpenGLPixelFormat*)glPixelFormat; - (void)timerFired:(id)sender; @end #endif // SOKOL_GLCORE33 typedef struct { - uint32_t flags_changed_store; uint8_t mouse_buttons; - NSWindow* window; - NSTrackingArea* tracking_area; _sapp_macos_app_delegate* app_dlg; - _sapp_macos_window_delegate* win_dlg; - _sapp_macos_view* view; #if defined(SOKOL_METAL) id mtl_device; #endif } _sapp_macos_t; +typedef struct { + uint32_t flags_changed_store; + NSWindow* window; + NSTrackingArea* tracking_area; + _sapp_macos_window_delegate* win_dlg; + _sapp_macos_view* view; +} _sapp_macos_window_t; + #endif // _SAPP_MACOS /*== IOS DECLARATIONS ========================================================*/ @@ -2090,7 +2121,7 @@ typedef struct { int* free_queue; } _sapp_pool_t; -typedef struct { +typedef struct _sapp_window_t { uint32_t id; bool fullscreen; int window_width; @@ -2117,6 +2148,8 @@ typedef struct { #elif defined(_SAPP_LINUX) _sapp_x11_window_t x11; _sapp_glx_window_t glx; + #elif defined(_SAPP_MACOS) + _sapp_macos_window_t macos; #endif } _sapp_window_t; @@ -2847,7 +2880,6 @@ _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) { _sapp.desc.html5_canvas_name = &_sapp.html5_canvas_selector[1]; _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site; _sapp.dpi_scale = 1.0f; - } _SOKOL_PRIVATE void _sapp_discard_state(void) { @@ -3029,18 +3061,21 @@ _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); + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + _sapp_window_t* window = &_sapp.windows[i]; + sapp_destroy_window(_sapp_window(window->id)); + } + } #if defined(SOKOL_METAL) _SAPP_OBJC_RELEASE(_sapp.macos.mtl_device); - #endif - _SAPP_OBJC_RELEASE(_sapp.macos.window); + #endif } _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_setup_pools(desc); _sapp_macos_init_keytable(); [NSApplication sharedApplication]; NSApp.activationPolicy = NSApplicationActivationPolicyRegular; @@ -3078,18 +3113,18 @@ _SOKOL_PRIVATE uint32_t _sapp_macos_mod(NSEventModifierFlags f) { return m; } -_SOKOL_PRIVATE void _sapp_macos_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { +_SOKOL_PRIVATE void _sapp_macos_mouse_event(_sapp_window_t* window, sapp_event_type type, sapp_mousebutton btn, uint32_t mod) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.mouse_button = btn; _sapp.event.modifiers = mod; _sapp_call_event(&_sapp.event); } } -_SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { +_SOKOL_PRIVATE void _sapp_macos_key_event(_sapp_window_t* window, sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp.event.key_code = key; _sapp.event.key_repeat = repeat; _sapp.event.modifiers = mod; @@ -3097,54 +3132,54 @@ _SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key } } -_SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) { +_SOKOL_PRIVATE void _sapp_macos_app_event(_sapp_window_t* window, sapp_event_type type) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(window, type); _sapp_call_event(&_sapp.event); } } -_SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { +_SOKOL_PRIVATE void _sapp_macos_update_dimensions(_sapp_window_t* window) { #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 = [window->macos.view bounds]; + window->framebuffer_width = fb_rect.size.width * _sapp.dpi_scale; + window->framebuffer_height = fb_rect.size.height * _sapp.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 = [window->macos.view convertRectToBacking:[window->macos.view frame]]; + window->framebuffer_width = fb_rect.size.width; + window->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 = [window->macos.view bounds]; + window->window_width = bounds.size.width; + window->window_height = bounds.size.height; + if (window->framebuffer_width == 0) { + window->framebuffer_width = 1; } - if (_sapp.framebuffer_height == 0) { - _sapp.framebuffer_height = 1; + if (window->framebuffer_height == 0) { + window->framebuffer_height = 1; } - if (_sapp.window_width == 0) { - _sapp.window_width = 1; + if (window->window_width == 0) { + window->window_width = 1; } - if (_sapp.window_height == 0) { - _sapp.window_height = 1; + if (window->window_height == 0) { + window->window_height = 1; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width; + _sapp.dpi_scale = (float)window->framebuffer_width / (float)window->window_width; /* also make sure the MTKView drawable size is uptodate */ #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) window->framebuffer_width, (CGFloat) window->framebuffer_height }; + window->macos.view.drawableSize = drawable_size; #endif } -_SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(void) { +_SOKOL_PRIVATE void _sapp_macos_toggle_fullscreen(_sapp_window_t* window) { /* NOTE: the _sapp.fullscreen flag is also notified by the windowDidEnterFullscreen / windowDidExitFullscreen event handlers */ - _sapp.fullscreen = !_sapp.fullscreen; - [_sapp.macos.window toggleFullScreen:nil]; + window->fullscreen = !window->fullscreen; + [window->macos.window toggleFullScreen:nil]; } _SOKOL_PRIVATE void _sapp_macos_set_clipboard_string(const char* str) { @@ -3155,40 +3190,40 @@ _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_PRIVATE const char* _sapp_macos_get_clipboard_string(_sapp_window_t* window) { + SOKOL_ASSERT(window->clipboard.buffer); @autoreleasepool { - _sapp.clipboard.buffer[0] = 0; + window->clipboard.buffer[0] = 0; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; if (![[pasteboard types] containsObject:NSPasteboardTypeString]) { - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } NSString* str = [pasteboard stringForType:NSPasteboardTypeString]; if (!str) { - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } - _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size); + _sapp_strcpy([str UTF8String], window->clipboard.buffer, window->clipboard.buf_size); } - return _sapp.clipboard.buffer; + return window->clipboard.buffer; } -_SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { - [_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]]; +_SOKOL_PRIVATE void _sapp_macos_update_window_title(_sapp_window_t* window) { + [window->macos.window setTitle: [NSString stringWithUTF8String:window->window_title]]; } -_SOKOL_PRIVATE void _sapp_macos_update_mouse(void) { - if (!_sapp.mouse.locked) { - const NSPoint mouse_pos = [_sapp.macos.window mouseLocationOutsideOfEventStream]; +_SOKOL_PRIVATE void _sapp_macos_update_mouse(_sapp_window_t* window) { + if (!window->mouse.locked) { + const NSPoint mouse_pos = [window->macos.window mouseLocationOutsideOfEventStream]; float new_x = mouse_pos.x * _sapp.dpi_scale; - float new_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1; + float new_y = window->framebuffer_height - (mouse_pos.y * _sapp.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 (window->mouse.pos_valid) { + window->mouse.dx = new_x - window->mouse.x; + window->mouse.dy = new_y - window->mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; + window->mouse.x = new_x; + window->mouse.y = new_y; + window->mouse.pos_valid = true; } } @@ -3202,13 +3237,13 @@ _SOKOL_PRIVATE void _sapp_macos_show_mouse(bool visible) { } } -_SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { - if (lock == _sapp.mouse.locked) { +_SOKOL_PRIVATE void _sapp_macos_lock_mouse(_sapp_window_t* window, bool lock) { + if (lock == window->mouse.locked) { return; } - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - _sapp.mouse.locked = lock; + window->mouse.dx = 0.0f; + window->mouse.dy = 0.0f; + 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 @@ -3219,7 +3254,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 (window->mouse.locked) { [NSEvent setMouseCoalescingEnabled:NO]; CGAssociateMouseAndMouseCursorPosition(NO); CGDisplayHideCursor(kCGDirectMainDisplay); @@ -3232,61 +3267,68 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { } _SOKOL_PRIVATE void _sapp_macos_frame(void) { - _sapp_macos_update_mouse(); + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + _sapp_window_t* window = &_sapp.windows[i]; + _sapp_macos_update_mouse(window); + } + } + /* always make the main window the current context before frame() cb */ + [[_sapp.main_window->macos.view openGLContext] makeCurrentContext]; + _sapp_frame(); - if (_sapp.quit_requested || _sapp.quit_ordered) { - [_sapp.macos.window performClose:nil]; + if (_sapp.quit_requested) { + /* triggers a shouldClose event but doesn't actually close the window, see windowShouldClose */ + [_sapp.main_window->macos.window performClose:nil]; } } -@implementation _sapp_macos_app_delegate -- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { - _SOKOL_UNUSED(aNotification); - if (_sapp.fullscreen) { +_SOKOL_PRIVATE void _sapp_macos_create_window(_sapp_window_t* window, const sapp_window_desc* desc){ + if (desc->fullscreen) { NSRect screen_rect = NSScreen.mainScreen.frame; - _sapp.window_width = screen_rect.size.width; - _sapp.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; + window->window_width = screen_rect.size.width; + window->window_height = screen_rect.size.height; + if (desc->high_dpi) { + window->framebuffer_width = 2 * window->window_width; + window->framebuffer_height = 2 * window->window_height; } else { - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; + window->framebuffer_width = window->window_width; + window->framebuffer_height = window->window_height; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + _sapp.dpi_scale = (float)window->framebuffer_width / (float) 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, window->window_width, window->window_height); + window->macos.window = [[_sapp_macos_window alloc] initWithContentRect:window_rect + sappWindow:window 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; + window->macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate + window->macos.window.title = [NSString stringWithUTF8String:window->window_title]; + window->macos.window.acceptsMouseMovedEvents = YES; + window->macos.window.restorable = YES; - _sapp.macos.win_dlg = [[_sapp_macos_window_delegate alloc] init]; - _sapp.macos.window.delegate = _sapp.macos.win_dlg; + window->macos.win_dlg = [[_sapp_macos_window_delegate alloc] initWithSappWindow:window]; + window->macos.window.delegate = window->macos.win_dlg; #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 = _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; + window->macos.view = [[_sapp_macos_view alloc] initWithSappWindow:window]; + [window->macos.view updateTrackingAreas]; + window->macos.view.preferredFramesPerSecond = 60 / window->swap_interval; + window->macos.view.device = _sapp.macos.mtl_device; + window->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; + window->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; + window->macos.view.sampleCount = window->sample_count; + window->macos.view.autoResizeDrawable = false; + window->macos.window.contentView = window->macos.view; + [window->macos.window makeFirstResponder:window->macos.view]; + window->macos.view.layer.magnificationFilter = kCAFilterNearest; #elif defined(SOKOL_GLCORE33) NSOpenGLPixelFormatAttribute attrs[32]; int i = 0; @@ -3297,10 +3339,10 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8; attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24; attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8; - if (_sapp.sample_count > 1) { + if (window->sample_count > 1) { attrs[i++] = NSOpenGLPFAMultisample; attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1; - attrs[i++] = NSOpenGLPFASamples; attrs[i++] = _sapp.sample_count; + attrs[i++] = NSOpenGLPFASamples; attrs[i++] = window->sample_count; } else { attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0; @@ -3309,39 +3351,68 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { NSOpenGLPixelFormat* glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; SOKOL_ASSERT(glpixelformat_obj != nil); - _sapp.macos.view = [[_sapp_macos_view alloc] + window->macos.view = [[_sapp_macos_view alloc] + initWithSappWindow:window 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]; + [window->macos.view updateTrackingAreas]; + if (desc->high_dpi) { + [window->macos.view setWantsBestResolutionOpenGLSurface:YES]; } else { - [_sapp.macos.view setWantsBestResolutionOpenGLSurface:NO]; + [window->macos.view setWantsBestResolutionOpenGLSurface:NO]; } - _sapp.macos.window.contentView = _sapp.macos.view; - [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; + window->macos.window.contentView = window->macos.view; + [window->macos.window makeFirstResponder:window->macos.view]; NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 - target:_sapp.macos.view + target:window->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.fullscreen) { + + if (window->fullscreen) { /* on GL, this already toggles a rendered frame, so set the valid flag before */ - [_sapp.macos.window toggleFullScreen:self]; + // TODO: is the sender here required?? Set to nil (was self) + [window->macos.window toggleFullScreen:nil]; } else { - [_sapp.macos.window center]; + [window->macos.window center]; } - [_sapp.macos.window makeKeyAndOrderFront:nil]; - _sapp_macos_update_dimensions(); + [window->macos.window makeKeyAndOrderFront:nil]; + _sapp_macos_update_dimensions(window); +} + +_SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { + _SAPP_OBJC_RELEASE(window->macos.tracking_area); + _SAPP_OBJC_RELEASE(window->macos.win_dlg); + _SAPP_OBJC_RELEASE(window->macos.view); + + [window->macos.window close]; + _SAPP_OBJC_RELEASE(window->macos.window); + + /* NOTE: glfw does a NSAutoreleasePool drain at this point, should we add this? */ +} + +@implementation _sapp_macos_app_delegate +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification { + _SOKOL_UNUSED(aNotification); + + #if defined(SOKOL_METAL) + _sapp.macos.mtl_device = MTLCreateSystemDefaultDevice(); + #endif + + sapp_window window_id = sapp_create_window(&_sapp.desc.window); + _sapp.main_window = _sapp_lookup_window(window_id.id); + + // TODO: I moved a fullscreen check into create_window, which means the fullscreen event won't arrive due to + // sapp being invalid. Problematic? User knows it's a fullscreen at startup. + _sapp.valid = true; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -3358,63 +3429,85 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { @end @implementation _sapp_macos_window_delegate +- (instancetype)initWithSappWindow:(_sapp_window_t* )initWindow { + self = [super init]; + if(self != nil){ + window = initWindow; + } + + return self; +} + - (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_macos_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED); - /* user code hasn't intervened, quit the app */ - if (_sapp.quit_requested) { - _sapp.quit_ordered = true; + /* NOTE: We only give the user a chance to cancel the main window, should be changed maybe? */ + if(window == _sapp.main_window){ + /* 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_macos_app_event(window, 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; + if(_sapp.quit_ordered){ + /* close all existing windows */ + for (int i = 0; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + sapp_destroy_window(_sapp_window(_sapp.windows[i].id)); + } + } + } + return NO; } else { + _sapp_macos_app_event(window, SAPP_EVENTTYPE_WINDOW_CLOSED); + sapp_destroy_window(_sapp_window(window->id)); return NO; } } - (void)windowDidResize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_macos_update_dimensions(); + _sapp_macos_update_dimensions(window); if (!_sapp.first_frame) { - _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED); + _sapp_macos_app_event(window, SAPP_EVENTTYPE_RESIZED); } } - (void)windowDidMiniaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_ICONIFIED); + _sapp_macos_app_event(window, SAPP_EVENTTYPE_ICONIFIED); } - (void)windowDidDeminiaturize:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp_macos_app_event(SAPP_EVENTTYPE_RESTORED); + _sapp_macos_app_event(window, SAPP_EVENTTYPE_RESTORED); } - (void)windowDidEnterFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.fullscreen = true; + window->fullscreen = true; } - (void)windowDidExitFullScreen:(NSNotification*)notification { _SOKOL_UNUSED(notification); - _sapp.fullscreen = false; + window->fullscreen = false; } @end @implementation _sapp_macos_window - (instancetype)initWithContentRect:(NSRect)contentRect + sappWindow:(struct _sapp_window_t*)initWindow styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag { if (self = [super initWithContentRect:contentRect styleMask:style backing:backingStoreType defer:flag]) { + window = initWindow; [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]]; } return self; @@ -3431,12 +3524,12 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (BOOL)performDragOperation:(id)sender { 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_clear_drop_buffer(window); + window->drop.num_files = ((int)pboard.pasteboardItems.count > window->drop.max_files) ? 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 < window->drop.num_files; i++) { NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[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(window, i), 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; @@ -3444,13 +3537,13 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } if (!drop_failed) { if (_sapp_events_enabled()) { - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_init_event(window, SAPP_EVENTTYPE_FILES_DROPPED); _sapp_call_event(&_sapp.event); } } else { - _sapp_clear_drop_buffer(); - _sapp.drop.num_files = 0; + _sapp_clear_drop_buffer(window); + window->drop.num_files = 0; } return YES; } @@ -3459,7 +3552,29 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { @end @implementation _sapp_macos_view -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_METAL) +- (instancetype)initWithSappWindow:(_sapp_window_t* )initWindow +{ + self = [super init]; + if(self != nil){ + window = initWindow; + } + + return self; +} +#elif defined(SOKOL_GLCORE33) +- (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow + initWithFrame:(NSRect)frameRect + pixelFormat:(NSOpenGLPixelFormat*)glPixelFormat +{ + self = [super initWithFrame:frameRect pixelFormat:glPixelFormat]; + if(self != nil){ + window = initWindow; + } + + return self; +} + /* 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 frame size of the window is reported wrong if low-dpi rendering @@ -3470,7 +3585,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { the correct dimensions. */ - (void)reshape { - _sapp_macos_update_dimensions(); + _sapp_macos_update_dimensions(window); [super reshape]; } - (void)timerFired:(id)sender { @@ -3480,7 +3595,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { - (void)prepareOpenGL { [super prepareOpenGL]; GLint swapInt = 1; - NSOpenGLContext* ctx = [_sapp.macos.view openGLContext]; + NSOpenGLContext* ctx = [window->macos.view openGLContext]; [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; [ctx makeCurrentContext]; } @@ -3490,7 +3605,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _SOKOL_UNUSED(rect); _sapp_macos_frame(); #if !defined(SOKOL_METAL) - [[_sapp.macos.view openGLContext] flushBuffer]; + [[window->macos.view openGLContext] flushBuffer]; #endif } @@ -3504,9 +3619,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { return YES; } - (void)updateTrackingAreas { - if (_sapp.macos.tracking_area != nil) { - [self removeTrackingArea:_sapp.macos.tracking_area]; - _SAPP_OBJC_RELEASE(_sapp.macos.tracking_area); + if (window->macos.tracking_area != nil) { + [self removeTrackingArea:window->macos.tracking_area]; + _SAPP_OBJC_RELEASE(window->macos.tracking_area); } const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | @@ -3514,8 +3629,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { NSTrackingCursorUpdate | NSTrackingInVisibleRect | NSTrackingAssumeInside; - _sapp.macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; - [self addTrackingArea:_sapp.macos.tracking_area]; + window->macos.tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; + [self addTrackingArea:window->macos.tracking_area]; [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent*)event { @@ -3523,71 +3638,71 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { on Windows while SetCapture is active */ if (0 == _sapp.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } } - (void)mouseExited:(NSEvent*)event { if (0 == _sapp.macos.mouse_buttons) { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } } - (void)mouseDown:(NSEvent*)event { - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons |= (1<mouse.locked) { + window->mouse.dx = [event deltaX]; + window->mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags)); } } - (void)mouseMoved:(NSEvent*)event { - if (_sapp.mouse.locked) { - _sapp.mouse.dx = [event deltaX]; - _sapp.mouse.dy = [event deltaY]; + if (window->mouse.locked) { + window->mouse.dx = [event deltaX]; + window->mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)mouseDragged:(NSEvent*)event { - if (_sapp.mouse.locked) { - _sapp.mouse.dx = [event deltaX]; - _sapp.mouse.dy = [event deltaY]; + if (window->mouse.locked) { + window->mouse.dx = [event deltaX]; + window->mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)rightMouseDragged:(NSEvent*)event { - if (_sapp.mouse.locked) { - _sapp.mouse.dx = [event deltaX]; - _sapp.mouse.dy = [event deltaY]; + if (window->mouse.locked) { + window->mouse.dx = [event deltaX]; + window->mouse.dy = [event deltaY]; } - _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); + _sapp_macos_mouse_event(window, SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } - (void)scrollWheel:(NSEvent*)event { if (_sapp_events_enabled()) { @@ -3598,7 +3713,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { dy *= 0.1; } if ((_sapp_absf(dx) > 0.0f) || (_sapp_absf(dy) > 0.0f)) { - _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL); + _sapp_init_event(window, SAPP_EVENTTYPE_MOUSE_SCROLL); _sapp.event.modifiers = _sapp_macos_mod(event.modifierFlags); _sapp.event.scroll_x = dx; _sapp.event.scroll_y = dy; @@ -3614,14 +3729,14 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { 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(window, 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(window, 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(window, SAPP_EVENTTYPE_CHAR); _sapp.event.modifiers = mods; for (NSUInteger i = 0; i < len; i++) { const unichar codepoint = [chars characterAtIndex:i]; @@ -3634,22 +3749,22 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } } /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */ - if (_sapp.clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { - _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED); + if (window->clipboard.enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) { + _sapp_init_event(window, SAPP_EVENTTYPE_CLIPBOARD_PASTED); _sapp_call_event(&_sapp.event); } } } - (void)keyUp:(NSEvent*)event { - _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP, + _sapp_macos_key_event(window, SAPP_EVENTTYPE_KEY_UP, _sapp_translate_key(event.keyCode), event.isARepeat, _sapp_macos_mod(event.modifierFlags)); } - (void)flagsChanged:(NSEvent*)event { - const uint32_t old_f = _sapp.macos.flags_changed_store; + const uint32_t old_f = window->macos.flags_changed_store; const uint32_t new_f = event.modifierFlags; - _sapp.macos.flags_changed_store = new_f; + window->macos.flags_changed_store = new_f; sapp_keycode key_code = SAPP_KEYCODE_INVALID; bool down = false; if ((new_f ^ old_f) & NSEventModifierFlagShift) { @@ -3669,7 +3784,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { 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(window, down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP, key_code, false, _sapp_macos_mod(event.modifierFlags)); @@ -3677,8 +3792,9 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } - (void)cursorUpdate:(NSEvent*)event { _SOKOL_UNUSED(event); - if (_sapp.desc.user_cursor) { - _sapp_macos_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR); + // TODO: this needs fixing, shouldn't read from the sapp_desc + if (_sapp.desc.window.user_cursor) { + _sapp_macos_app_event(window, SAPP_EVENTTYPE_UPDATE_CURSOR); } } @end @@ -10557,6 +10673,8 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ _sapp_glx_choose_visual(window, &visual, &depth); _sapp_x11_create_window(window, visual, depth); _sapp_glx_create_context(window); + #elif defined(_SAPP_MACOS) + _sapp_macos_create_window(window, desc); #endif } else { @@ -10585,6 +10703,8 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ #elif defined(_SAPP_LINUX) _sapp_glx_destroy_context(window); _sapp_x11_destroy_window(window); + #elif defined(_SAPP_MACOS) + _sapp_macos_destroy_window(window); #endif if (window->clipboard.enabled) { @@ -10615,6 +10735,8 @@ SOKOL_API_DECL void sapp_make_context_current(sapp_window window_id){ #endif #elif defined(_SAPP_LINUX) _sapp_glx_make_current(window); + #elif defined(_SAPP_MACOS) && defined(SOKOL_GLCORE33) + [[window->macos.view openGLContext] makeCurrentContext]; #endif } @@ -10730,7 +10852,7 @@ SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { SOKOL_ASSERT(window); #if defined(_SAPP_MACOS) - _sapp_macos_toggle_fullscreen(); + _sapp_macos_toggle_fullscreen(window); #elif defined(_SAPP_WIN32) _sapp_win32_toggle_fullscreen(window); #elif defined(_SAPP_UWP) @@ -10783,7 +10905,7 @@ SOKOL_API_IMPL void sapp_window_lock_mouse(sapp_window window_id, bool lock) { SOKOL_ASSERT(window); #if defined(_SAPP_MACOS) - _sapp_macos_lock_mouse(lock); + _sapp_macos_lock_mouse(window, lock); #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_lock_mouse(lock); #elif defined(_SAPP_WIN32) @@ -10856,7 +10978,7 @@ SOKOL_API_IMPL const char* sapp_window_get_clipboard_string(sapp_window window_i return ""; } #if defined(_SAPP_MACOS) - return _sapp_macos_get_clipboard_string(); + return _sapp_macos_get_clipboard_string(window); #elif defined(_SAPP_EMSCRIPTEN) return _sapp.main_window->clipboard.buffer; #elif defined(_SAPP_WIN32) @@ -10878,7 +11000,7 @@ SOKOL_API_IMPL void sapp_set_window_title(sapp_window window_id, const char* tit _sapp_strcpy(title, window->window_title, sizeof(window->window_title)); #if defined(_SAPP_MACOS) - _sapp_macos_update_window_title(); + _sapp_macos_update_window_title(window); #elif defined(_SAPP_WIN32) _sapp_win32_update_window_title(window); #elif defined(_SAPP_LINUX) @@ -10983,12 +11105,19 @@ SOKOL_API_IMPL const void* sapp_metal_get_device(void) { } SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { + return sapp_metal_window_get_renderpass_descriptor(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_metal_window_get_renderpass_descriptor(sapp_window window_id) { SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [window->macos.view currentRenderPassDescriptor]; #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [window->ios.view currentRenderPassDescriptor]; #endif SOKOL_ASSERT(obj); return obj; @@ -10998,12 +11127,19 @@ SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) { } SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { + return sapp_metal_window_get_drawable(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_metal_window_get_drawable(sapp_window window_id) { SOKOL_ASSERT(_sapp.valid); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(SOKOL_METAL) #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) [_sapp.macos.view currentDrawable]; + const void* obj = (__bridge const void*) [window->macos.view currentDrawable]; #else - const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; + const void* obj = (__bridge const void*) [window->ios.view currentDrawable]; #endif SOKOL_ASSERT(obj); return obj; @@ -11013,8 +11149,15 @@ SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) { } SOKOL_API_IMPL const void* sapp_macos_get_window(void) { + return sapp_macos_window_get_window(sapp_main_window()); +} + +SOKOL_API_IMPL const void* sapp_macos_window_get_window(sapp_window window_id) { + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); + #if defined(_SAPP_MACOS) - const void* obj = (__bridge const void*) _sapp.macos.window; + const void* obj = (__bridge const void*) window->macos.window; SOKOL_ASSERT(obj); return obj; #else @@ -11163,4 +11306,4 @@ SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) { _sapp.html5_ask_leave_site = ask; } -#endif /* SOKOL_IMPL */ \ No newline at end of file +#endif /* SOKOL_IMPL */ From 573c0325d6c0e6755ff277f692ca2469a0aa52da Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Tue, 24 Nov 2020 21:18:49 -0700 Subject: [PATCH 07/14] update iOS to work with new multi-window changes --- sokol_app.h | 60 ++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 705045677..408510b88 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -3837,14 +3837,14 @@ int main(int argc, char* argv[]) { _SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); _sapp_call_event(&_sapp.event); } } _SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet* touches, UIEvent* event) { if (_sapp_events_enabled()) { - _sapp_init_event(type); + _sapp_init_event(_sapp.main_window, type); NSEnumerator* enumerator = event.allTouches.objectEnumerator; UITouch* ios_touch; while ((ios_touch = [enumerator nextObject])) { @@ -3865,8 +3865,8 @@ _SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet _SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) { CGRect screen_rect = UIScreen.mainScreen.bounds; - _sapp.window_width = (int) screen_rect.size.width; - _sapp.window_height = (int) screen_rect.size.height; + _sapp.main_window->window_width = (int) screen_rect.size.width; + _sapp.main_window->window_height = (int) screen_rect.size.height; int cur_fb_width, cur_fb_height; #if defined(SOKOL_METAL) const CGSize fb_size = _sapp.ios.view.drawableSize; @@ -3877,12 +3877,12 @@ _SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) { cur_fb_height = (int) _sapp.ios.view.drawableHeight; #endif const bool dim_changed = - (_sapp.framebuffer_width != cur_fb_width) || - (_sapp.framebuffer_height != cur_fb_height); - _sapp.framebuffer_width = cur_fb_width; - _sapp.framebuffer_height = cur_fb_height; - SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0)); - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + (_sapp.main_window->framebuffer_width != cur_fb_width) || + (_sapp.main_window->framebuffer_height != cur_fb_height); + _sapp.main_window->framebuffer_width = cur_fb_width; + _sapp.main_window->framebuffer_height = cur_fb_height; + SOKOL_ASSERT((_sapp.main_window->framebuffer_width > 0) && (_sapp.main_window->framebuffer_height > 0)); + _sapp.dpi_scale = (float)_sapp.main_window->framebuffer_width / (float) _sapp.main_window->window_width; if (dim_changed && !_sapp.first_frame) { _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED); } @@ -3931,26 +3931,26 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { CGRect screen_rect = UIScreen.mainScreen.bounds; _sapp.ios.window = [[UIWindow alloc] initWithFrame:screen_rect]; - _sapp.window_width = screen_rect.size.width; - _sapp.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; + _sapp.main_window->window_width = screen_rect.size.width; + _sapp.main_window->window_height = screen_rect.size.height; + if (_sapp.desc.window.high_dpi) { + _sapp.main_window->framebuffer_width = 2 * _sapp.main_window->window_width; + _sapp.main_window->framebuffer_height = 2 * _sapp.main_window->window_height; } else { - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; + _sapp.main_window->framebuffer_width = _sapp.main_window->window_width; + _sapp.main_window->framebuffer_height = _sapp.main_window->window_height; } - _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width; + _sapp.dpi_scale = (float)_sapp.main_window->framebuffer_width / (float) _sapp.main_window->window_width; #if defined(SOKOL_METAL) _sapp.ios.mtl_device = MTLCreateSystemDefaultDevice(); _sapp.ios.view = [[_sapp_ios_view alloc] init]; - _sapp.ios.view.preferredFramesPerSecond = 60 / _sapp.swap_interval; + _sapp.ios.view.preferredFramesPerSecond = 60 / _sapp.main_window->swap_interval; _sapp.ios.view.device = _sapp.ios.mtl_device; _sapp.ios.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; _sapp.ios.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; - _sapp.ios.view.sampleCount = _sapp.sample_count; - if (_sapp.desc.high_dpi) { + _sapp.ios.view.sampleCount = _sapp.main_window->sample_count; + if (_sapp.desc.window.high_dpi) { _sapp.ios.view.contentScaleFactor = 2.0; } else { @@ -3983,7 +3983,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { _sapp.ios.view.enableSetNeedsDisplay = NO; _sapp.ios.view.userInteractionEnabled = YES; _sapp.ios.view.multipleTouchEnabled = YES; - if (_sapp.desc.high_dpi) { + if (_sapp.desc.window.high_dpi) { _sapp.ios.view.contentScaleFactor = 2.0; } else { @@ -3991,7 +3991,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { } _sapp.ios.view_ctrl = [[GLKViewController alloc] init]; _sapp.ios.view_ctrl.view = _sapp.ios.view; - _sapp.ios.view_ctrl.preferredFramesPerSecond = 60 / _sapp.swap_interval; + _sapp.ios.view_ctrl.preferredFramesPerSecond = 60 / _sapp.main_window->swap_interval; _sapp.ios.window.rootViewController = _sapp.ios.view_ctrl; #endif [_sapp.ios.window makeKeyAndVisible]; @@ -4063,7 +4063,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { if (c >= 32) { /* ignore surrogates for now */ if ((c < 0xD800) || (c > 0xDFFF)) { - _sapp_init_event(SAPP_EVENTTYPE_CHAR); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_CHAR); _sapp.event.char_code = c; _sapp_call_event(&_sapp.event); } @@ -4076,10 +4076,10 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { default: break; } if (k != SAPP_KEYCODE_INVALID) { - _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_KEY_DOWN); _sapp.event.key_code = k; _sapp_call_event(&_sapp.event); - _sapp_init_event(SAPP_EVENTTYPE_KEY_UP); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_KEY_UP); _sapp.event.key_code = k; _sapp_call_event(&_sapp.event); } @@ -4088,10 +4088,10 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { } else { /* this was a backspace */ - _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_KEY_DOWN); _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE; _sapp_call_event(&_sapp.event); - _sapp_init_event(SAPP_EVENTTYPE_KEY_UP); + _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_KEY_UP); _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE; _sapp_call_event(&_sapp.event); } @@ -11117,7 +11117,7 @@ SOKOL_API_IMPL const void* sapp_metal_window_get_renderpass_descriptor(sapp_wind #if defined(_SAPP_MACOS) const void* obj = (__bridge const void*) [window->macos.view currentRenderPassDescriptor]; #else - const void* obj = (__bridge const void*) [window->ios.view currentRenderPassDescriptor]; + const void* obj = (__bridge const void*) [_sapp.ios.view currentRenderPassDescriptor]; #endif SOKOL_ASSERT(obj); return obj; @@ -11139,7 +11139,7 @@ SOKOL_API_IMPL const void* sapp_metal_window_get_drawable(sapp_window window_id) #if defined(_SAPP_MACOS) const void* obj = (__bridge const void*) [window->macos.view currentDrawable]; #else - const void* obj = (__bridge const void*) [window->ios.view currentDrawable]; + const void* obj = (__bridge const void*) [_sapp.ios.view currentDrawable]; #endif SOKOL_ASSERT(obj); return obj; From efc854fef1d77f746f6fc88705ea4ebd763f2b43 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Thu, 26 Nov 2020 12:52:25 -0700 Subject: [PATCH 08/14] some smaller multi-window clean-ups in sokol_app.h --- sokol_app.h | 107 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 408510b88..d2e670aac 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1112,8 +1112,23 @@ typedef struct sapp_desc { void (*event_userdata_cb)(const sapp_event*, void*); void (*fail_userdata_cb)(const char*, void*); - // TODO: currently is a breaking change to move everything into the window struct. Probably makes sense to just expose them instead and there's a bit of a "double up" - sapp_window_desc window; /* main window configuration */ + /* DISCUSS: this currently is an almost exact copy of sapp_window_desc, but changing this into window struct here would be a breaking change */ + int width; /* the preferred width of the window / canvas */ + int height; /* the preferred height of the window / canvas */ + int sample_count; /* MSAA sample count */ + int swap_interval; /* the preferred swap interval (ignored on some platforms) */ + 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 high_dpi; /* whether the rendering canvas is full-resolution on HighDPI displays */ + 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; /* enable clipboard access, default is false */ + int clipboard_size; /* max size of clipboard content in bytes */ + + sapp_window_desc window; 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 */ @@ -1161,12 +1176,12 @@ extern sapp_desc sokol_main(int argc, char* argv[]); /* returns true after sokol-app has been initialized */ SOKOL_API_DECL bool sapp_isvalid(void); /* returns the current framebuffer width in pixels */ -SOKOL_API_DECL int sapp_width(sapp_window window_id); -/* returns the current framebuffer height in pixels */ -SOKOL_API_DECL int sapp_height(sapp_window window_id); -/* returns the current framebuffer width in pixels */ +SOKOL_API_DECL int sapp_width(); +/* returns the current framebuffer width in pixels for specified window */ SOKOL_API_DECL int sapp_window_width(sapp_window window_id); /* returns the current framebuffer height in pixels */ +SOKOL_API_DECL int sapp_height(); +/* returns the current framebuffer height in pixels for specified window */ SOKOL_API_DECL int sapp_window_height(sapp_window window_id); /* get default framebuffer color pixel format */ SOKOL_API_DECL int sapp_color_format(void); @@ -1245,9 +1260,11 @@ SOKOL_API_DECL sapp_window sapp_main_window(); SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc); /* destroy a window */ SOKOL_API_DECL void sapp_destroy_window(sapp_window window); -/* set the window title (only on desktop platforms) */ -SOKOL_API_DECL void sapp_set_window_title(sapp_window window, const char* str); -/* make window context current */ +/* set the window title (only on desktop platforms) of main_window */ +SOKOL_API_DECL void sapp_set_window_title(const char* str); +/* set the window title (only on desktop platforms) of specified window */ +SOKOL_API_DECL void sapp_window_set_window_title(sapp_window window, const char* str); +/* make window context current TODO: make it a gl specific operation sapp_gl_make_context_current */ SOKOL_API_DECL void sapp_make_context_current(sapp_window window); /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ @@ -2684,6 +2701,23 @@ _SOKOL_PRIVATE sapp_window_desc _sapp_window_desc_defaults(const sapp_window_des _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* in_desc) { sapp_desc desc = *in_desc; + + /* for compatibility we copy these values into the window struct */ + desc.window.width = in_desc->width; + desc.window.height = in_desc->height; + desc.window.sample_count = in_desc->sample_count; + desc.window.swap_interval = in_desc->swap_interval; + desc.window.window_title = in_desc->window_title; + desc.window.fullscreen = in_desc->fullscreen; + desc.window.high_dpi = in_desc->high_dpi; + desc.window.max_dropped_files = in_desc->max_dropped_files; + desc.window.max_dropped_file_path_length = in_desc->max_dropped_file_path_length; + desc.window.clipboard_size = in_desc->clipboard_size; + desc.window.alpha = in_desc->alpha; + desc.window.enable_clipboard = in_desc->enable_clipboard; + desc.window.enable_dragndrop = in_desc->enable_dragndrop; + desc.window.user_cursor = in_desc->user_cursor; + desc.window = _sapp_window_desc_defaults(&in_desc->window); desc.html5_canvas_name = _sapp_def(desc.html5_canvas_name, "canvas"); desc.window_pool_size = _sapp_def(desc.window_pool_size, 1); @@ -2752,17 +2786,16 @@ _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_setup_pools(const sapp_desc* desc) { +_SOKOL_PRIVATE void _sapp_setup_pools() { // Sanity check that we don't expect >1 windows on anything but desktop #if !defined(_SAPP_WIN32) && !defined(_SAPP_MACOS) && !defined(_SAPP_LINUX) // TODO: better place for this validation? - SOKOL_ASSERT(desc->window_pool_size == 1); + SOKOL_ASSERT(_sapp.desc.window_pool_size == 1); #endif - SOKOL_ASSERT(desc); /* note: the pools here will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((desc->window_pool_size > 0) && (desc->window_pool_size < _SAPP_MAX_POOL_SIZE)); - _sapp_init_pool(&_sapp.window_pool, desc->window_pool_size); + SOKOL_ASSERT((_sapp.desc.window_pool_size > 0) && (_sapp.desc.window_pool_size < _SAPP_MAX_POOL_SIZE)); + _sapp_init_pool(&_sapp.window_pool, _sapp.desc.window_pool_size); size_t window_pool_byte_size = sizeof(_sapp_window_t) * _sapp.window_pool.size; _sapp.windows = (_sapp_window_t*) SOKOL_MALLOC(window_pool_byte_size); SOKOL_ASSERT(_sapp.windows); @@ -3075,7 +3108,7 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_setup_pools(desc); + _sapp_setup_pools(); _sapp_macos_init_keytable(); [NSApplication sharedApplication]; NSApp.activationPolicy = NSApplicationActivationPolicyRegular; @@ -3821,6 +3854,7 @@ _SOKOL_PRIVATE void _sapp_ios_discard_state(void) { _SOKOL_PRIVATE void _sapp_ios_run(const sapp_desc* desc) { _sapp_init_state(desc); + _sapp_setup_pools(); static int argc = 1; static char* argv[] = { (char*)"sokol_app" }; UIApplicationMain(argc, argv, nil, NSStringFromClass([_sapp_app_delegate class])); @@ -3929,6 +3963,10 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) { @implementation _sapp_app_delegate - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + + sapp_window window_id = sapp_create_window(&_sapp.desc.window); + _sapp.main_window = _sapp_lookup_window(window_id.id); + CGRect screen_rect = UIScreen.mainScreen.bounds; _sapp.ios.window = [[UIWindow alloc] initWithFrame:screen_rect]; _sapp.main_window->window_width = screen_rect.size.width; @@ -5204,7 +5242,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) { _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_setup_pools(desc); + _sapp_setup_pools(); sapp_js_pointer_init(&_sapp.html5_canvas_selector[1]); _sapp_emsc_keytable_init(); double w, h; @@ -5219,7 +5257,7 @@ _SOKOL_PRIVATE void _sapp_emsc_run(const sapp_desc* desc) { if (_sapp.desc.window.high_dpi) { _sapp.dpi_scale = emscripten_get_device_pixel_ratio(); } - sapp_window main_window_id = sapp_create_window(&desc->window); + sapp_window main_window_id = sapp_create_window(&_sapp.desc.window); _sapp.main_window = _sapp_lookup_window(main_window_id.id); _sapp.main_window->window_width = (int) w; _sapp.main_window->window_height = (int) h; @@ -6662,7 +6700,7 @@ _SOKOL_PRIVATE bool _sapp_win32_is_win10_or_greater(void) { _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_setup_pools(desc); + _sapp_setup_pools(); _sapp.win32.is_win10_or_greater = _sapp_win32_is_win10_or_greater(); _sapp_win32_uwp_init_keytable(); _sapp_win32_init_dpi(); @@ -6684,7 +6722,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_wgl_load_extensions(); #endif - sapp_window main_window_id = sapp_create_window(&desc->window); + sapp_window main_window_id = sapp_create_window(&_sapp.desc.window); _sapp.main_window = _sapp_lookup_window(main_window_id.id); _sapp.valid = true; @@ -7787,8 +7825,8 @@ void App::OnDisplayContentsInvalidated(winrt::Windows::Graphics::Display::Displa _SOKOL_PRIVATE void _sapp_uwp_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_setup_pools(desc); - sapp_window window_id = sapp_create_window(&desc->window); + _sapp_setup_pools(); + sapp_window window_id = sapp_create_window(&_sapp.desc.window); _sapp.main_window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(_sapp.main_window); _sapp_win32_uwp_init_keytable(); @@ -10530,7 +10568,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_init_state(desc); - _sapp_setup_pools(desc); + _sapp_setup_pools(); XInitThreads(); XrmInitialize(); @@ -10547,7 +10585,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp_x11_create_hidden_cursor(); _sapp_glx_init(); - sapp_window main_window = sapp_create_window(&desc->window); + sapp_window main_window = sapp_create_window(&_sapp.desc.window); _sapp.main_window = _sapp_lookup_window(main_window.id); SOKOL_ASSERT(_sapp.main_window); @@ -10654,10 +10692,9 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ if(window_id.id != SAPP_INVALID_ID){ _sapp_window_t* window = _sapp_init_window(window_id, &desc_def); - // TODO: Deal with macOS/Linux/etc. handling #if defined(_SAPP_WIN32) _sapp_win32_uwp_utf8_to_wide(window->window_title, window->window_title_wide, sizeof(window->window_title_wide)); - _sapp_win32_create_window(window, desc); + _sapp_win32_create_window(window, &desc_def); #if defined(SOKOL_D3D11) _sapp_d3d11_create_swapchain(window); @@ -10674,7 +10711,7 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ _sapp_x11_create_window(window, visual, depth); _sapp_glx_create_context(window); #elif defined(_SAPP_MACOS) - _sapp_macos_create_window(window, desc); + _sapp_macos_create_window(window, &desc_def); #endif } else { @@ -10756,7 +10793,11 @@ SOKOL_API_IMPL uint64_t sapp_frame_count(void) { return _sapp.frame_count; } -SOKOL_API_IMPL int sapp_width(sapp_window window_id) { +SOKOL_API_IMPL int sapp_width() { + return sapp_window_width(sapp_main_window()); +} + +SOKOL_API_IMPL int sapp_window_width(sapp_window window_id) { SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); @@ -10796,7 +10837,11 @@ SOKOL_API_IMPL int sapp_window_sample_count(sapp_window window_id) { return window->sample_count; } -SOKOL_API_IMPL int sapp_height(sapp_window window_id) { +SOKOL_API_IMPL int sapp_height() { + return sapp_window_height(sapp_main_window()); +} + +SOKOL_API_IMPL int sapp_window_height(sapp_window window_id) { SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); @@ -10993,7 +11038,11 @@ SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) { return sapp_window_get_clipboard_string(sapp_main_window()); } -SOKOL_API_IMPL void sapp_set_window_title(sapp_window window_id, const char* title) { +SOKOL_API_IMPL void sapp_set_window_title(const char* title) { + sapp_window_set_window_title(sapp_main_window(), title); +} + +SOKOL_API_IMPL void sapp_window_set_window_title(sapp_window window_id, const char* title) { SOKOL_ASSERT(title); _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); From 91485fc4b0689d865e706024b298633a342f8849 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Thu, 26 Nov 2020 12:53:22 -0700 Subject: [PATCH 09/14] initial multi-window support changes in sokol_glue.h and sokol_gfx.h --- sokol_gfx.h | 71 ++++++++++++++++++++++++++++++++++++---------------- sokol_glue.h | 54 ++++++++++++++++++++++++++++++++++----- 2 files changed, 97 insertions(+), 28 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index ff3715332..b439b6bc5 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -2147,6 +2147,8 @@ typedef struct sg_pass_info { */ typedef struct sg_gl_context_desc { bool force_gles2; + void (*context_make_current_userdata_cb)(void*); + void* user_data; } sg_gl_context_desc; typedef struct sg_mtl_context_desc { @@ -2205,7 +2207,7 @@ typedef struct sg_desc { } sg_desc; /* setup and misc functions */ -SOKOL_API_DECL void sg_setup(const sg_desc* desc); +SOKOL_API_DECL sg_context sg_setup(const sg_desc* desc); SOKOL_API_DECL void sg_shutdown(void); SOKOL_API_DECL bool sg_isvalid(void); SOKOL_API_DECL void sg_reset_state_cache(void); @@ -2284,7 +2286,7 @@ SOKOL_API_DECL void sg_fail_pipeline(sg_pipeline pip_id); SOKOL_API_DECL void sg_fail_pass(sg_pass pass_id); /* rendering contexts (optional) */ -SOKOL_API_DECL sg_context sg_setup_context(void); +SOKOL_API_DECL sg_context sg_setup_context(const sg_context_desc* desc); SOKOL_API_DECL void sg_activate_context(sg_context ctx_id); SOKOL_API_DECL void sg_discard_context(sg_context ctx_id); @@ -2310,7 +2312,7 @@ SOKOL_API_DECL const void* sg_mtl_render_command_encoder(void); } /* extern "C" */ /* reference-based equivalents for c++ */ -inline void sg_setup(const sg_desc& desc) { return sg_setup(&desc); } +inline sg_context sg_setup(const sg_desc& desc) { return sg_setup(&desc); } inline sg_buffer sg_make_buffer(const sg_buffer_desc& desc) { return sg_make_buffer(&desc); } inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image(&desc); } @@ -3060,6 +3062,8 @@ typedef _sg_attachment_common_t _sg_attachment_t; typedef struct { _sg_slot_t slot; + void (*context_make_current_userdata_cb)(void*); + void* user_data; #if !defined(SOKOL_GLES2) GLuint vao; #endif @@ -3111,6 +3115,7 @@ typedef struct { bool ext_anisotropic; GLint max_anisotropy; GLint max_combined_texture_image_units; + void (*make_context_current_cb)(void*); } _sg_gl_backend_t; /*== D3D11 BACKEND DECLARATIONS ==============================================*/ @@ -3203,6 +3208,11 @@ typedef _sg_attachment_common_t _sg_attachment_t; typedef struct { _sg_slot_t slot; + const void* (*render_target_view_cb)(void); + const void* (*render_target_view_userdata_cb)(void*); + const void* (*depth_stencil_view_cb)(void); + const void* (*depth_stencil_view_userdata_cb)(void*); + void* user_data; } _sg_d3d11_context_t; typedef _sg_d3d11_context_t _sg_context_t; @@ -4081,9 +4091,10 @@ _SOKOL_PRIVATE void _sg_dummy_reset_state_cache(void) { /* empty*/ } -_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_context(_sg_context_t* ctx) { +_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_context(_sg_context_t* ctx, const sg_context_desc* desc) { SOKOL_ASSERT(ctx); _SOKOL_UNUSED(ctx); + _SOKOL_UNUSED(desc); return SG_RESOURCESTATE_VALID; } @@ -5594,14 +5605,21 @@ _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 */ + if(ctx != NULL) { + ctx->context_make_current_userdata_cb(ctx->user_data); + } + _sg.gl.cur_context = ctx; _sg_gl_reset_state_cache(); } /*-- 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(desc); SOKOL_ASSERT(ctx); SOKOL_ASSERT(0 == ctx->default_framebuffer); + ctx->context_make_current_userdata_cb = desc->gl.context_make_current_userdata_cb; + ctx->user_data = desc->gl.user_data; _SG_GL_CHECK_ERROR(); glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer); _SG_GL_CHECK_ERROR(); @@ -7641,9 +7659,14 @@ _SOKOL_PRIVATE void _sg_d3d11_activate_context(_sg_context_t* ctx) { _sg_d3d11_clear_state(); } -_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_context(_sg_context_t* ctx) { +_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_context(_sg_context_t* ctx, const sg_context_desc* desc) { SOKOL_ASSERT(ctx); _SOKOL_UNUSED(ctx); + ctx->render_target_view_cb = desc->d3d11.render_target_view_cb; + ctx->render_target_view_userdata_cb = desc->d3d11.render_target_view_userdata_cb; + ctx->depth_stencil_view_cb = desc->d3d11.depth_stencil_view_cb; + ctx->depth_stencil_view_userdata_cb = desc->d3d11.depth_stencil_view_userdata_cb; + ctx->user_data = desc->d3d11.user_data; return SG_RESOURCESTATE_VALID; } @@ -8390,11 +8413,15 @@ _SOKOL_PRIVATE _sg_image_t* _sg_d3d11_pass_ds_image(const _sg_pass_t* pass) { return pass->d3d11.ds_att.image; } +// DISCUSS: Had to to forward declare this method here :/ +_SOKOL_PRIVATE _sg_context_t* _sg_lookup_context(const _sg_pools_t* p, uint32_t ctx_id); _SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { SOKOL_ASSERT(action); SOKOL_ASSERT(!_sg.d3d11.in_pass); - SOKOL_ASSERT(_sg.d3d11.rtv_cb || _sg.d3d11.rtv_userdata_cb); - SOKOL_ASSERT(_sg.d3d11.dsv_cb || _sg.d3d11.dsv_userdata_cb); + _sg_context_t* cur_context = _sg_lookup_context(&_sg.pools, _sg.active_context.id); + SOKOL_ASSERT(cur_context); + SOKOL_ASSERT(cur_context->render_target_view_cb || cur_context->render_target_view_userdata_cb); + SOKOL_ASSERT(cur_context->depth_stencil_view_cb || cur_context->depth_stencil_view_userdata_cb); _sg.d3d11.in_pass = true; _sg.d3d11.cur_width = w; _sg.d3d11.cur_height = h; @@ -8416,19 +8443,19 @@ _SOKOL_PRIVATE void _sg_d3d11_begin_pass(_sg_pass_t* pass, const sg_pass_action* _sg.d3d11.cur_pass_id.id = SG_INVALID_ID; _sg.d3d11.num_rtvs = 1; if (_sg.d3d11.rtv_cb) { - _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_cb(); + _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) cur_context->render_target_view_cb(); } else { - _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) _sg.d3d11.rtv_userdata_cb(_sg.d3d11.user_data); + _sg.d3d11.cur_rtvs[0] = (ID3D11RenderTargetView*) cur_context->render_target_view_userdata_cb(cur_context->user_data); } for (int i = 1; i < SG_MAX_COLOR_ATTACHMENTS; i++) { _sg.d3d11.cur_rtvs[i] = 0; } if (_sg.d3d11.dsv_cb) { - _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_cb(); + _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) cur_context->depth_stencil_view_cb(); } else { - _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) _sg.d3d11.dsv_userdata_cb(_sg.d3d11.user_data); + _sg.d3d11.cur_dsv = (ID3D11DepthStencilView*) cur_context->depth_stencil_view_userdata_cb(cur_context->user_data); } SOKOL_ASSERT(_sg.d3d11.cur_rtvs[0] && _sg.d3d11.cur_dsv); } @@ -12192,17 +12219,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 @@ -13992,7 +14019,7 @@ _SOKOL_PRIVATE void _sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc) { #define _SG_CLEAR(type, item) { memset(&item, 0, sizeof(item)); } #endif -SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { +SOKOL_API_IMPL sg_context sg_setup(const sg_desc* desc) { SOKOL_ASSERT(desc); SOKOL_ASSERT((desc->_start_canary == 0) && (desc->_end_canary == 0)); _SG_CLEAR(_sg_state_t, _sg); @@ -14025,7 +14052,7 @@ SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { _sg.frame_index = 1; _sg_setup_backend(&_sg.desc); _sg.valid = true; - sg_setup_context(); + return sg_setup_context(&_sg.desc.context); } SOKOL_API_IMPL void sg_shutdown(void) { @@ -14076,14 +14103,14 @@ 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_setup_context(const sg_context_desc* desc) { SOKOL_ASSERT(_sg.valid); sg_context res; int slot_index = _sg_pool_alloc_index(&_sg.pools.context_pool); 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); _sg_activate_context(ctx); } diff --git a/sokol_glue.h b/sokol_glue.h index c47892b70..e62a346a0 100644 --- a/sokol_glue.h +++ b/sokol_glue.h @@ -87,6 +87,7 @@ extern "C" { #if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED) SOKOL_API_DECL sg_context_desc sapp_sgcontext(void); +SOKOL_API_DECL sg_context_desc sapp_window_sgcontext(sapp_window window_id); #endif #ifdef __cplusplus @@ -104,26 +105,67 @@ SOKOL_API_DECL sg_context_desc sapp_sgcontext(void); #endif #if defined(SOKOL_GFX_INCLUDED) && defined(SOKOL_APP_INCLUDED) -SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) { + +// DISCUSS: Not a huge fan of doing the handle->void* casts here +_SOKOL_PRIVATE void _sapp_gl_make_context_current_cb(void* user_data) { + sapp_window window_id; + window_id.id = (uint32_t)(uintptr_t)user_data; + sapp_gl_make_context_current(window_id); +} + +_SOKOL_PRIVATE const void* _sapp_metal_window_get_renderpass_descriptor_cb(void* user_data) { + sapp_window window_id; + window_id.id = (uint32_t)(uintptr_t)user_data; + return sapp_metal_window_get_renderpass_descriptor(window_id); +} + +_SOKOL_PRIVATE const void* _sapp_metal_window_get_drawable_cb(void* user_data) { + sapp_window window_id; + window_id.id = (uint32_t)(uintptr_t)user_data; + return sapp_metal_window_get_drawable(window_id); +} + +_SOKOL_PRIVATE const void* _sapp_d3d11_window_get_render_target_view_cb(void* user_data) { + sapp_window window_id; + window_id.id = (uint32_t)(uintptr_t)user_data; + return sapp_d3d11_window_get_render_target_view(window_id); +} + +_SOKOL_PRIVATE const void* _sapp_d3d11_window_get_depth_stencil_cb(void* user_data) { + sapp_window window_id; + window_id.id = (uint32_t)(uintptr_t)user_data; + return sapp_d3d11_window_get_depth_stencil_view(window_id); +} + +SOKOL_API_IMPL sg_context_desc sapp_window_sgcontext(sapp_window window_id) { 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.sample_count = sapp_window_sample_count(window_id); desc.gl.force_gles2 = sapp_gles2(); + desc.gl.context_make_current_userdata_cb = _sapp_gl_make_context_current_cb; + desc.gl.user_data = (void*) (uintptr_t)window_id.id; desc.metal.device = sapp_metal_get_device(); - desc.metal.renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor; - desc.metal.drawable_cb = sapp_metal_get_drawable; + desc.metal.renderpass_descriptor_userdata_cb = _sapp_metal_window_get_renderpass_descriptor_cb; + desc.metal.drawable_userdata_cb = _sapp_metal_window_get_drawable_cb; + desc.metal.user_data = (void*) (uintptr_t)window_id.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.d3d11.render_target_view_userdata_cb = _sapp_d3d11_window_get_render_target_view_cb; + desc.d3d11.depth_stencil_view_userdata_cb = _sapp_d3d11_window_get_depth_stencil_cb; + desc.d3d11.user_data = (void*) (uintptr_t)window_id.id; 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; } + +SOKOL_API_IMPL sg_context_desc sapp_sgcontext(void) { + return sapp_window_sgcontext(sapp_main_window()); +} + #endif #endif /* SOKOL_IMPL */ From 53cbc27c02e1db54e4ffbab24672f7fabf01bca6 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Fri, 27 Nov 2020 15:13:32 -0700 Subject: [PATCH 10/14] more clean-ups and emsc fixes in sokol_app.h multi-window support --- sokol_app.h | 103 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index d2e670aac..327053bbb 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1264,14 +1264,17 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window); SOKOL_API_DECL void sapp_set_window_title(const char* str); /* set the window title (only on desktop platforms) of specified window */ SOKOL_API_DECL void sapp_window_set_window_title(sapp_window window, const char* str); -/* make window context current TODO: make it a gl specific operation sapp_gl_make_context_current */ -SOKOL_API_DECL void sapp_make_context_current(sapp_window window); +/* returns true if window is still valid */ +SOKOL_API_DECL bool sapp_window_isvalid(sapp_window window); + /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */ SOKOL_API_DECL int sapp_run(const sapp_desc* desc); /* GL: return true when GLES2 fallback is active (to detect fallback from GLES3) */ SOKOL_API_DECL bool sapp_gles2(void); +/* GL: make window gl context current */ +SOKOL_API_DECL void sapp_gl_make_context_current(sapp_window window); /* HTML5: enable or disable the hardwired "Leave Site?" dialog box */ SOKOL_API_DECL void sapp_html5_ask_leave_site(bool ask); @@ -2141,6 +2144,7 @@ typedef struct { typedef struct _sapp_window_t { uint32_t id; bool fullscreen; + bool user_cursor; int window_width; int window_height; int framebuffer_width; @@ -2154,7 +2158,6 @@ typedef struct _sapp_window_t { _sapp_mouse_t mouse; #if defined(_SAPP_WIN32) _sapp_win32_window_t win32; - // TODO, move into gl/d3d substructs #if defined(SOKOL_GLCORE33) _sapp_wgl_window_t wgl; #elif defined(SOKOL_D3D11) @@ -2789,7 +2792,7 @@ _SOKOL_PRIVATE void _sapp_pool_free_index(_sapp_pool_t* pool, int slot_index) { _SOKOL_PRIVATE void _sapp_setup_pools() { // Sanity check that we don't expect >1 windows on anything but desktop #if !defined(_SAPP_WIN32) && !defined(_SAPP_MACOS) && !defined(_SAPP_LINUX) - // TODO: better place for this validation? + // DISCUSS: better place for this validation? SOKOL_ASSERT(_sapp.desc.window_pool_size == 1); #endif @@ -2878,6 +2881,7 @@ _SOKOL_PRIVATE _sapp_window_t* _sapp_init_window(sapp_window window_id, const sa window->framebuffer_width = desc->width; window->framebuffer_height = desc->height; window->fullscreen = desc->fullscreen; + window->user_cursor = desc->user_cursor; _sapp_strcpy(desc->window_title, window->window_title, sizeof(window->window_title)); // TODO: do we need the below still? Potentially if we keep a desc in the window_t @@ -3824,9 +3828,8 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { } } - (void)cursorUpdate:(NSEvent*)event { - _SOKOL_UNUSED(event); - // TODO: this needs fixing, shouldn't read from the sapp_desc - if (_sapp.desc.window.user_cursor) { + _SOKOL_UNUSED(event) + if (window->user_cursor) { _sapp_macos_app_event(window, SAPP_EVENTTYPE_UPDATE_CURSOR); } } @@ -4235,10 +4238,10 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_end_drop(int x, int y) { } if (_sapp_events_enabled()) { - _sapp.mouse.x = (float)x * _sapp.dpi_scale; - _sapp.mouse.y = (float)y * _sapp.dpi_scale; - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; + _sapp.main_window->mouse.x = (float)x * _sapp.dpi_scale; + _sapp.main_window->mouse.y = (float)y * _sapp.dpi_scale; + _sapp.main_window->mouse.dx = 0.0f; + _sapp.main_window->mouse.dy = 0.0f; _sapp_init_event(_sapp.main_window, SAPP_EVENTTYPE_FILES_DROPPED); _sapp_call_event(&_sapp.event); } @@ -4457,7 +4460,7 @@ EM_JS(void, sapp_js_pointer_init, (const char* c_str_target), { _SOKOL_PRIVATE EM_BOOL _sapp_emsc_pointerlockchange_cb(int emsc_type, const EmscriptenPointerlockChangeEvent* emsc_event, void* user_data) { _SOKOL_UNUSED(emsc_type); _SOKOL_UNUSED(user_data); - _sapp.mouse.locked = emsc_event->isActive; + _sapp.main_window->mouse.locked = emsc_event->isActive; return EM_TRUE; } @@ -4465,7 +4468,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_pointerlockerror_cb(int emsc_type, const void* _SOKOL_UNUSED(emsc_type); _SOKOL_UNUSED(reserved); _SOKOL_UNUSED(user_data); - _sapp.mouse.locked = false; + _sapp.main_window->mouse.locked = false; _sapp.emsc.mouse_lock_requested = false; return true; } @@ -4569,20 +4572,20 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) { _SOKOL_UNUSED(user_data); - if (_sapp.mouse.locked) { - _sapp.mouse.dx = (float) emsc_event->movementX; - _sapp.mouse.dy = (float) emsc_event->movementY; + if (_sapp.main_window->mouse.locked) { + _sapp.main_window->mouse.dx = (float) emsc_event->movementX; + _sapp.main_window->mouse.dy = (float) emsc_event->movementY; } else { float new_x = emsc_event->targetX * _sapp.dpi_scale; float new_y = emsc_event->targetY * _sapp.dpi_scale; - if (_sapp.mouse.pos_valid) { - _sapp.mouse.dx = new_x - _sapp.mouse.x; - _sapp.mouse.dy = new_y - _sapp.mouse.y; + if (_sapp.main_window->mouse.pos_valid) { + _sapp.main_window->mouse.dx = new_x - _sapp.main_window->mouse.x; + _sapp.main_window->mouse.dy = new_y - _sapp.main_window->mouse.y; } - _sapp.mouse.x = new_x; - _sapp.mouse.y = new_y; - _sapp.mouse.pos_valid = true; + _sapp.main_window->mouse.x = new_x; + _sapp.main_window->mouse.y = new_y; + _sapp.main_window->mouse.pos_valid = true; } if (_sapp_events_enabled() && (emsc_event->button >= 0) && (emsc_event->button < SAPP_MAX_MOUSEBUTTONS)) { sapp_event_type type; @@ -6171,7 +6174,7 @@ _SOKOL_PRIVATE void _sapp_win32_lock_mouse(_sapp_window_t* window, bool lock) { _SOKOL_PRIVATE bool _sapp_win32_update_dimensions(_sapp_window_t* window) { RECT rect; if (GetClientRect(window->win32.hwnd, &rect)) { - // TODO: should dpi scale be per window? I don't even know if that's possible + // DISCUSS: should dpi scale be per window? I don't even know if that's possible window->window_width = (int)((float)(rect.right - rect.left) / _sapp.win32.dpi.window_scale); window->window_height = (int)((float)(rect.bottom - rect.top) / _sapp.win32.dpi.window_scale); const int fb_width = (int)((float)window->window_width * _sapp.win32.dpi.content_scale); @@ -6315,7 +6318,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM } } else { - // TODO: wo we want to give the user a per window opportunity to cancel closure requests? + // DISCUSS: wo we want to give the user a per window opportunity to cancel closure requests? _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_WINDOW_CLOSED); sapp_destroy_window(_sapp_window(window->id)); } @@ -6351,7 +6354,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM } break; case WM_SETCURSOR: - if (_sapp.desc.window.user_cursor) { + if (window->user_cursor) { if (LOWORD(lParam) == HTCLIENT) { _sapp_win32_uwp_app_event(window, SAPP_EVENTTYPE_UPDATE_CURSOR); return 1; @@ -6472,7 +6475,8 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM KillTimer(window->win32.hwnd, 1); break; case WM_TIMER: - // TODO: I think we may have to consider current context here, since in the run situation of update, we ensure that the main context is active + // TODO: I think we may have to consider current context here, since in the run situation of update, we ensure that the main context is active. + // This also currently pauses ALL windows, not just the one being resized. _sapp_frame(); #if defined(SOKOL_D3D11) _sapp_d3d11_present(window); @@ -6739,10 +6743,10 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { DispatchMessage(&msg); } } - sapp_make_context_current(_sapp_window(_sapp.main_window->id)); + sapp_gl_make_context_current(_sapp_window(_sapp.main_window->id)); _sapp_frame(); - // TODO: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? + // DISCUSS: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? for (int i = 1; i < _sapp.window_pool.size; i++) { if(_sapp.windows[i].id != SAPP_INVALID_ID){ _sapp_window_t* window = &_sapp.windows[i]; @@ -10591,7 +10595,6 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { _sapp.valid = true; while (!_sapp.quit_ordered) { - // TODO: handle all windows _sapp_glx_make_current(_sapp.main_window); int count = XPending(_sapp.x11.display); while (count--) { @@ -10601,7 +10604,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { } _sapp_frame(); - // TODO: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? + // DISCUSS: Not ideal, since we're checking for valid ids, but probably still better than keeping an additional linked list? for (int i = 1; i < _sapp.window_pool.size; i++) { if(_sapp.windows[i].id != SAPP_INVALID_ID){ _sapp_window_t* window = &_sapp.windows[i]; @@ -10625,7 +10628,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { for (int i = 1; i < _sapp.window_pool.size; i++) { if(_sapp.windows[i].id != SAPP_INVALID_ID){ // TODO: Is there a better way to handle this instead of creating a tmp object? - sapp_destroy_window((sapp_window){ .id=_sapp.windows[i].id }); + sapp_destroy_window(_sapp_window(_sapp.windows[i].id) }); } } @@ -10712,6 +10715,8 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ _sapp_glx_create_context(window); #elif defined(_SAPP_MACOS) _sapp_macos_create_window(window, &desc_def); + #else + _SOKOL_UNUSED(window); #endif } else { @@ -10725,7 +10730,6 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); - // TODO: Deal with macOS/Linux/etc. handling // Destroy context #if defined(_SAPP_WIN32) #if defined(SOKOL_D3D11) @@ -10759,21 +10763,21 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ _sapp_pool_free_index(&_sapp.window_pool, slot_index); } -SOKOL_API_DECL void sapp_make_context_current(sapp_window window_id){ - SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); - _sapp_window_t* window = _sapp_lookup_window(window_id.id); - SOKOL_ASSERT(window); +SOKOL_API_DECL void sapp_gl_make_context_current(sapp_window window_id){ + #if defined(SOKOL_GLCORE33) + SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); + _sapp_window_t* window = _sapp_lookup_window(window_id.id); + SOKOL_ASSERT(window); - #if defined(_SAPP_WIN32) - #if defined(SOKOL_D3D11) - // Do nothing? - #elif defined(SOKOL_GLCORE33) + #if defined(_SAPP_WIN32) _sapp.wgl.MakeCurrent(window->win32.dc, window->wgl.gl_ctx); + #elif defined(_SAPP_LINUX) + _sapp_glx_make_current(window); + #elif defined(_SAPP_MACOS) + [[window->macos.view openGLContext] makeCurrentContext]; #endif - #elif defined(_SAPP_LINUX) - _sapp_glx_make_current(window); - #elif defined(_SAPP_MACOS) && defined(SOKOL_GLCORE33) - [[window->macos.view openGLContext] makeCurrentContext]; + #else + _SOKOL_UNUSED(window_id); #endif } @@ -10781,6 +10785,11 @@ SOKOL_API_IMPL bool sapp_isvalid(void) { return _sapp.valid; } +SOKOL_API_DECL bool sapp_window_isvalid(sapp_window window) { + bool is_valid = !(window.id == SAPP_INVALID_ID) && _sapp_lookup_window(window.id); + return is_valid; +} + SOKOL_API_IMPL void* sapp_userdata(void) { return _sapp.desc.user_data; } @@ -10904,6 +10913,8 @@ SOKOL_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { _sapp_uwp_toggle_fullscreen(); #elif defined(_SAPP_LINUX) _sapp_x11_toggle_fullscreen(window); + #else + _SOKOL_UNUSED(window); #endif } @@ -10953,6 +10964,7 @@ SOKOL_API_IMPL void sapp_window_lock_mouse(sapp_window window_id, bool lock) { _sapp_macos_lock_mouse(window, lock); #elif defined(_SAPP_EMSCRIPTEN) _sapp_emsc_lock_mouse(lock); + _SOKOL_UNUSED(window); #elif defined(_SAPP_WIN32) // TODO: window specific lock _sapp_win32_lock_mouse(_sapp.main_window, lock); @@ -11171,6 +11183,7 @@ SOKOL_API_IMPL const void* sapp_metal_window_get_renderpass_descriptor(sapp_wind SOKOL_ASSERT(obj); return obj; #else + _SOKOL_UNUSED(window); return 0; #endif } @@ -11193,6 +11206,7 @@ SOKOL_API_IMPL const void* sapp_metal_window_get_drawable(sapp_window window_id) SOKOL_ASSERT(obj); return obj; #else + _SOKOL_UNUSED(window); return 0; #endif } @@ -11292,6 +11306,7 @@ SOKOL_API_IMPL const void* sapp_win32_window_get_hwnd(sapp_window window_id) { #if defined(_SAPP_WIN32) return window->win32.hwnd; #else + _SOKOL_UNUSED(window); return 0; #endif } From 5186d69abd9992b5bbf41caa5be63be26c7914ce Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Sun, 29 Nov 2020 20:41:56 -0700 Subject: [PATCH 11/14] reworked quite a bit of the macos backend -> custom NSView --- sokol_app.h | 121 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 39 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 327053bbb..adfaa3924 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1646,14 +1646,13 @@ inline int sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } - (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow; @end #elif defined(SOKOL_GLCORE33) - @interface _sapp_macos_view : NSOpenGLView + @interface _sapp_macos_view : NSView { struct _sapp_window_t* window; + NSTrackingArea* trackingArea; } - (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow - initWithFrame:(NSRect)frameRect - pixelFormat:(NSOpenGLPixelFormat*)glPixelFormat; - - (void)timerFired:(id)sender; + initWithFrame:(NSRect)frameRect; @end #endif // SOKOL_GLCORE33 @@ -1671,6 +1670,9 @@ typedef struct { NSTrackingArea* tracking_area; _sapp_macos_window_delegate* win_dlg; _sapp_macos_view* view; + #if defined(SOKOL_GLCORE33) + NSOpenGLContext* gl_ctx; + #endif } _sapp_macos_window_t; #endif // _SAPP_MACOS @@ -3110,6 +3112,22 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) { #endif } +void _sapp_macos_process_window_events(void){ + NSEvent* event; + + do { + event = [NSApp nextEventMatchingMask: NSAnyEventMask + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; + + if(event != NULL) + [NSApp sendEvent:event]; + } + while (event != NULL); +} + +_SOKOL_PRIVATE void _sapp_macos_frame(void); _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { _sapp_init_state(desc); _sapp_setup_pools(); @@ -3120,8 +3138,29 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { NSApp.delegate = _sapp.macos.app_dlg; [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; - // NOTE: [NSApp run] never returns, instead cleanup code - // must be put into applicationWillTerminate + + while(!_sapp.quit_ordered){ + _sapp_macos_frame(); + + for (int i = 1; i < _sapp.window_pool.size; i++) { + if(_sapp.windows[i].id != SAPP_INVALID_ID){ + _sapp_window_t* window = &_sapp.windows[i]; + + #if defined(SOKOL_METAL) + [window->macos.view draw]; + #else + [window->macos.gl_ctx update]; + [window->macos.gl_ctx flushBuffer]; + #endif + } + } + + _sapp_macos_process_window_events(); + } + + _sapp_call_cleanup(); + _sapp_macos_discard_state(); + _sapp_discard_state(); } /* MacOS entry function */ @@ -3311,8 +3350,10 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } } /* always make the main window the current context before frame() cb */ - [[_sapp.main_window->macos.view openGLContext] makeCurrentContext]; - + #if defined(SOKOL_GLCORE33) + [_sapp.main_window->macos.gl_ctx makeCurrentContext]; + #endif + _sapp_frame(); if (_sapp.quit_requested) { /* triggers a shouldClose event but doesn't actually close the window, see windowShouldClose */ @@ -3350,14 +3391,17 @@ _SOKOL_PRIVATE void _sapp_macos_create_window(_sapp_window_t* window, const sapp window->macos.window.releasedWhenClosed = NO; // this is necessary for proper cleanup in applicationWillTerminate window->macos.window.title = [NSString stringWithUTF8String:window->window_title]; window->macos.window.acceptsMouseMovedEvents = YES; - window->macos.window.restorable = YES; + // NOTE: The user would need to provide serialization of window manually for this to be useful. + window->macos.window.restorable = NO; window->macos.win_dlg = [[_sapp_macos_window_delegate alloc] initWithSappWindow:window]; - window->macos.window.delegate = window->macos.win_dlg; + [window->macos.window setDelegate:window->macos.win_dlg]; #if defined(SOKOL_METAL) window->macos.view = [[_sapp_macos_view alloc] initWithSappWindow:window]; [window->macos.view updateTrackingAreas]; window->macos.view.preferredFramesPerSecond = 60 / window->swap_interval; + window->macos.view.paused = true; + window->macos.view.enableSetNeedsDisplay = false; window->macos.view.device = _sapp.macos.mtl_device; window->macos.view.colorPixelFormat = MTLPixelFormatBGRA8Unorm; window->macos.view.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8; @@ -3390,9 +3434,7 @@ _SOKOL_PRIVATE void _sapp_macos_create_window(_sapp_window_t* window, const sapp window->macos.view = [[_sapp_macos_view alloc] initWithSappWindow:window - initWithFrame:window_rect - pixelFormat:glpixelformat_obj]; - _SAPP_OBJC_RELEASE(glpixelformat_obj); + initWithFrame:window_rect]; [window->macos.view updateTrackingAreas]; if (desc->high_dpi) { [window->macos.view setWantsBestResolutionOpenGLSurface:YES]; @@ -3401,16 +3443,15 @@ _SOKOL_PRIVATE void _sapp_macos_create_window(_sapp_window_t* window, const sapp [window->macos.view setWantsBestResolutionOpenGLSurface:NO]; } - window->macos.window.contentView = window->macos.view; + [window->macos.window setContentView:window->macos.view]; [window->macos.window makeFirstResponder:window->macos.view]; - NSTimer* timer_obj = [NSTimer timerWithTimeInterval:0.001 - target:window->macos.view - selector:@selector(timerFired:) - userInfo:nil - repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:timer_obj forMode:NSDefaultRunLoopMode]; - timer_obj = nil; + window->macos.gl_ctx = [[NSOpenGLContext alloc] initWithFormat:glpixelformat_obj shareContext:nil]; + SOKOL_ASSERT(window->macos.gl_ctx != nil); + + _SAPP_OBJC_RELEASE(glpixelformat_obj); + + [window->macos.gl_ctx setView:window->macos.view]; #endif if (window->fullscreen) { @@ -3429,11 +3470,14 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { _SAPP_OBJC_RELEASE(window->macos.tracking_area); _SAPP_OBJC_RELEASE(window->macos.win_dlg); _SAPP_OBJC_RELEASE(window->macos.view); + #if defined(SOKOL_GLCORE33) + _SAPP_OBJC_RELEASE(window->macos.gl_ctx); + #endif [window->macos.window close]; _SAPP_OBJC_RELEASE(window->macos.window); - /* NOTE: glfw does a NSAutoreleasePool drain at this point, should we add this? */ + /* DISCUSS: glfw does a NSAutoreleasePool drain at this point, should we add this? */ } @implementation _sapp_macos_app_delegate @@ -3450,6 +3494,8 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { // TODO: I moved a fullscreen check into create_window, which means the fullscreen event won't arrive due to // sapp being invalid. Problematic? User knows it's a fullscreen at startup. _sapp.valid = true; + + [NSApp stop:nil]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -3602,16 +3648,22 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { #elif defined(SOKOL_GLCORE33) - (instancetype)initWithSappWindow:(struct _sapp_window_t*)initWindow initWithFrame:(NSRect)frameRect - pixelFormat:(NSOpenGLPixelFormat*)glPixelFormat { - self = [super initWithFrame:frameRect pixelFormat:glPixelFormat]; + self = [super initWithFrame:frameRect]; if(self != nil){ window = initWindow; + trackingArea = nil; } return self; } +- (void)dealloc +{ + [trackingArea release]; + [super dealloc]; +} + /* 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 frame size of the window is reported wrong if low-dpi rendering @@ -3623,27 +3675,18 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { */ - (void)reshape { _sapp_macos_update_dimensions(window); - [super reshape]; -} -- (void)timerFired:(id)sender { - _SOKOL_UNUSED(sender); - [self setNeedsDisplay:YES]; } + - (void)prepareOpenGL { - [super prepareOpenGL]; GLint swapInt = 1; - NSOpenGLContext* ctx = [window->macos.view openGLContext]; - [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; - [ctx makeCurrentContext]; + [window->macos.gl_ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval]; + [window->macos.gl_ctx makeCurrentContext]; } #endif +// TODO: check if this is needed - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); - _sapp_macos_frame(); - #if !defined(SOKOL_METAL) - [[window->macos.view openGLContext] flushBuffer]; - #endif } - (BOOL)isOpaque { @@ -3828,7 +3871,7 @@ _SOKOL_PRIVATE void _sapp_macos_destroy_window(_sapp_window_t* window) { } } - (void)cursorUpdate:(NSEvent*)event { - _SOKOL_UNUSED(event) + _SOKOL_UNUSED(event); if (window->user_cursor) { _sapp_macos_app_event(window, SAPP_EVENTTYPE_UPDATE_CURSOR); } @@ -10774,7 +10817,7 @@ SOKOL_API_DECL void sapp_gl_make_context_current(sapp_window window_id){ #elif defined(_SAPP_LINUX) _sapp_glx_make_current(window); #elif defined(_SAPP_MACOS) - [[window->macos.view openGLContext] makeCurrentContext]; + [window->macos.gl_ctx makeCurrentContext]; #endif #else _SOKOL_UNUSED(window_id); From 777b510cdcabfeb407a67d11b3b526e15fa901d7 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Sun, 29 Nov 2020 20:42:35 -0700 Subject: [PATCH 12/14] updated mtl sg backend for multi-window support --- sokol_gfx.h | 58 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/sokol_gfx.h b/sokol_gfx.h index b439b6bc5..ae3132997 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -3115,7 +3115,6 @@ typedef struct { bool ext_anisotropic; GLint max_anisotropy; GLint max_combined_texture_image_units; - void (*make_context_current_cb)(void*); } _sg_gl_backend_t; /*== D3D11 BACKEND DECLARATIONS ==============================================*/ @@ -3346,6 +3345,11 @@ typedef _sg_attachment_common_t _sg_attachment_t; typedef struct { _sg_slot_t slot; + 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; } _sg_mtl_context_t; typedef _sg_mtl_context_t _sg_context_t; @@ -3367,11 +3371,6 @@ 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; uint32_t frame_index; uint32_t cur_frame_rotate_index; uint32_t ub_size; @@ -5605,7 +5604,7 @@ _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 */ - if(ctx != NULL) { + if(ctx != NULL && ctx->context_make_current_userdata_cb) { ctx->context_make_current_userdata_cb(ctx->user_data); } @@ -5620,6 +5619,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx, const SOKOL_ASSERT(0 == ctx->default_framebuffer); ctx->context_make_current_userdata_cb = desc->gl.context_make_current_userdata_cb; ctx->user_data = desc->gl.user_data; + ctx->context_make_current_userdata_cb(ctx->user_data); _SG_GL_CHECK_ERROR(); glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer); _SG_GL_CHECK_ERROR(); @@ -6329,6 +6329,8 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac glViewport(0, 0, w, h); glScissor(0, 0, w, h); + _SG_GL_CHECK_ERROR(); + /* clear color and depth-stencil attachments if needed */ bool clear_color = false; for (int i = 0; i < num_color_atts; i++) { @@ -6373,6 +6375,7 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac _sg.gl.cache.cur_pipeline = 0; _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID; } + _SG_GL_CHECK_ERROR(); bool use_mrt_clear = (0 != pass); #if defined(SOKOL_GLES2) use_mrt_clear = false; @@ -6406,6 +6409,7 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac } #if !defined SOKOL_GLES2 else { + _SG_GL_CHECK_ERROR(); SOKOL_ASSERT(pass); for (int i = 0; i < num_color_atts; i++) { if (action->colors[i].action == SG_ACTION_CLEAR) { @@ -9423,11 +9427,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.frame_index = 1; _sg.mtl.ub_size = desc->uniform_buffer_size; _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); @@ -9497,9 +9496,15 @@ _SOKOL_PRIVATE void _sg_mtl_reset_state_cache(void) { } } -_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); - _SOKOL_UNUSED(ctx); + + ctx->drawable_cb = desc->metal.drawable_cb; + ctx->drawable_userdata_cb = desc->metal.drawable_userdata_cb; + ctx->renderpass_descriptor_cb = desc->metal.renderpass_descriptor_cb; + ctx->renderpass_descriptor_userdata_cb = desc->metal.renderpass_descriptor_userdata_cb; + ctx->user_data = desc->metal.user_data; + return SG_RESOURCESTATE_VALID; } @@ -10013,12 +10018,18 @@ _SOKOL_PRIVATE _sg_image_t* _sg_mtl_pass_ds_image(const _sg_pass_t* pass) { return pass->mtl.ds_att.image; } +// DISCUSS: Had to to forward declare this method here :/ +_SOKOL_PRIVATE _sg_context_t* _sg_lookup_context(const _sg_pools_t* p, uint32_t ctx_id); _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) { SOKOL_ASSERT(action); SOKOL_ASSERT(!_sg.mtl.in_pass); SOKOL_ASSERT(_sg.mtl.cmd_queue); SOKOL_ASSERT(nil == _sg.mtl.cmd_encoder); - SOKOL_ASSERT(_sg.mtl.renderpass_descriptor_cb || _sg.mtl.renderpass_descriptor_userdata_cb); + + _sg_context_t* cur_context = _sg_lookup_context(&_sg.pools, _sg.active_context.id); + SOKOL_ASSERT(cur_context); + SOKOL_ASSERT(cur_context->renderpass_descriptor_cb || cur_context->renderpass_descriptor_userdata_cb); + _sg.mtl.in_pass = true; _sg.mtl.cur_width = w; _sg.mtl.cur_height = h; @@ -10044,11 +10055,11 @@ _SOKOL_PRIVATE void _sg_mtl_begin_pass(_sg_pass_t* pass, const sg_pass_action* a } 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 (cur_context->renderpass_descriptor_cb) { + pass_desc = (__bridge MTLRenderPassDescriptor*) cur_context->renderpass_descriptor_cb(); } else { - pass_desc = (__bridge MTLRenderPassDescriptor*) _sg.mtl.renderpass_descriptor_userdata_cb(_sg.mtl.user_data); + pass_desc = (__bridge MTLRenderPassDescriptor*) cur_context->renderpass_descriptor_userdata_cb(cur_context->user_data); } } @@ -10159,21 +10170,24 @@ _SOKOL_PRIVATE void _sg_mtl_end_pass(void) { _SOKOL_PRIVATE void _sg_mtl_commit(void) { 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); + _sg_context_t* cur_context = _sg_lookup_context(&_sg.pools, _sg.active_context.id); + SOKOL_ASSERT(cur_context); + SOKOL_ASSERT(cur_context->drawable_cb || cur_context->drawable_userdata_cb); + #if defined(_SG_TARGET_MACOS) [_sg.mtl.uniform_buffers[_sg.mtl.cur_frame_rotate_index] didModifyRange:NSMakeRange(0, _sg.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 (cur_context->drawable_cb) { + cur_drawable = (__bridge id) cur_context->drawable_cb(); } else { - cur_drawable = (__bridge id) _sg.mtl.drawable_userdata_cb(_sg.mtl.user_data); + cur_drawable = (__bridge id) cur_context->drawable_userdata_cb(cur_context->user_data); } [_sg.mtl.cmd_buffer presentDrawable:cur_drawable]; [_sg.mtl.cmd_buffer addCompletedHandler:^(id cmd_buffer) { From 87d1e5bfcf680939e9d44567ebcb75bffb3f56b3 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Sun, 29 Nov 2020 21:21:41 -0700 Subject: [PATCH 13/14] small typo fixed in sapp linux backend --- sokol_app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sokol_app.h b/sokol_app.h index adfaa3924..947039067 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -10671,7 +10671,7 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { for (int i = 1; i < _sapp.window_pool.size; i++) { if(_sapp.windows[i].id != SAPP_INVALID_ID){ // TODO: Is there a better way to handle this instead of creating a tmp object? - sapp_destroy_window(_sapp_window(_sapp.windows[i].id) }); + sapp_destroy_window(_sapp_window(_sapp.windows[i].id)); } } From f0d1e1e7ebac85e6d936255fcdc2f6876805e5e4 Mon Sep 17 00:00:00 2001 From: Stefan Bachmann Date: Mon, 30 Nov 2020 13:24:43 -0700 Subject: [PATCH 14/14] fix SOKOL_API_DECL in newly added window functions --- sokol_app.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sokol_app.h b/sokol_app.h index 0bbee91e2..5b97aaebd 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -1306,7 +1306,7 @@ SOKOL_APP_API_DECL const void* sapp_macos_get_window(void); /* macOS: get bridged pointer to macOS NSWindow for specified window */ SOKOL_APP_API_DECL const void* sapp_macos_window_get_window(sapp_window window_id); /* iOS: get bridged pointer to iOS UIWindow */ -SOKOL_APP_APP_API_DECL const void* sapp_ios_get_window(void); +SOKOL_APP_API_DECL const void* sapp_ios_get_window(void); /* D3D11: get pointer to ID3D11Device object */ SOKOL_APP_API_DECL const void* sapp_d3d11_get_device(void); @@ -10735,11 +10735,11 @@ SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) { } #endif -SOKOL_API_DECL sapp_window sapp_main_window(){ +SOKOL_APP_IMPL sapp_window sapp_main_window(){ return _sapp_window(_sapp.main_window->id); } -SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ +SOKOL_API_IMPL sapp_window sapp_create_window(const sapp_window_desc* desc){ SOKOL_ASSERT(desc); sapp_window_desc desc_def = _sapp_window_desc_defaults(desc); sapp_window window_id = _sapp_alloc_window(); @@ -10776,7 +10776,7 @@ SOKOL_API_DECL sapp_window sapp_create_window(const sapp_window_desc* desc){ return window_id; } -SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ +SOKOL_API_IMPL void sapp_destroy_window(sapp_window window_id){ SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); @@ -10814,7 +10814,7 @@ SOKOL_API_DECL void sapp_destroy_window(sapp_window window_id){ _sapp_pool_free_index(&_sapp.window_pool, slot_index); } -SOKOL_API_DECL void sapp_gl_make_context_current(sapp_window window_id){ +SOKOL_API_IMPL void sapp_gl_make_context_current(sapp_window window_id){ #if defined(SOKOL_GLCORE33) SOKOL_ASSERT(window_id.id != SAPP_INVALID_ID); _sapp_window_t* window = _sapp_lookup_window(window_id.id); @@ -10836,7 +10836,7 @@ SOKOL_API_IMPL bool sapp_isvalid(void) { return _sapp.valid; } -SOKOL_API_DECL bool sapp_window_isvalid(sapp_window window) { +SOKOL_API_IMPL bool sapp_window_isvalid(sapp_window window) { bool is_valid = !(window.id == SAPP_INVALID_ID) && _sapp_lookup_window(window.id); return is_valid; } @@ -10937,22 +10937,22 @@ SOKOL_API_IMPL bool sapp_keyboard_shown(void) { return _sapp.onscreen_keyboard_shown; } -SOKOL_APP_API_DECL bool sapp_is_fullscreen() { +SOKOL_API_IMPL bool sapp_is_fullscreen() { return sapp_window_is_fullscreen(_sapp_window(_sapp.main_window->id)); } -SOKOL_APP_API_DECL bool sapp_window_is_fullscreen(sapp_window window_id) { +SOKOL_API_IMPL bool sapp_window_is_fullscreen(sapp_window window_id) { _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window); return window->fullscreen; } -SOKOL_APP_API_DECL void sapp_toggle_fullscreen() { +SOKOL_API_IMPL void sapp_toggle_fullscreen() { sapp_window_toggle_fullscreen(_sapp_window(_sapp.main_window->id)); } -SOKOL_APP_API_DECL void sapp_window_toggle_fullscreen(sapp_window window_id) { +SOKOL_API_IMPL void sapp_window_toggle_fullscreen(sapp_window window_id) { _sapp_window_t* window = _sapp_lookup_window(window_id.id); SOKOL_ASSERT(window);