From 572446a6cfd244ea9f0df36efe2887cf2a8a59d1 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 01/15] src/studio/configini.cpp: fix return status if pfNoValue is set In the case where pfNoValue is set and the provided section key does not exist, FGetSetRegKey() should return fTrue to indicate the operation succeeded so that the caller can check pfNoValue for the result. This is required for the switch resolution logic to work correctly when looking up the kszSwitchResolutionValue section key when it does not exist. --- src/studio/configini.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/studio/configini.cpp b/src/studio/configini.cpp index 5bee5c0a6..69a4cf504 100644 --- a/src/studio/configini.cpp +++ b/src/studio/configini.cpp @@ -220,6 +220,13 @@ bool FGetSetRegKey(PCSZ pszValueName, void *pvData, int32_t cbData, uint32_t grf grfregNew &= ~fregSetDefault; fRet = FGetSetRegKey(pszValueName, pvData, cbData, grfregNew, pfNoValue); } + else + { + /* If the caller gave us a way to differentiate a genuine registry + failure from simply not having set the value yet, do so */ + if (pfNoValue != pvNil) + fRet = fTrue; + } } if (pfNoValue) From 2d09f54a3da6c2c1195c3be7c7215c5e5c8a38f3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 02/15] kauai/src/appbsdl.cpp: use SDL_WarpMouseInWindow() in APPB::PositionCurs() If the logical renderer size is different from the window size as required for fullscreen mode, SDL_WarpMouseGlobal() does not warp the mouse correctly for the application window causing jumps when moving actors. The solution is to use SDL_WarpMouseInWindow() which will correctly take into account the logical renderer size, but this is slightly complicated in that APPB::PositionCurs() takes the position in screen coordinates. To avoid changing the APPB::PositionCurs() API which is also used for non-SDL builds, convert the screen coordinates back into window coordinates using MapPt() first before calling SDL_WarpMouseInWindow(). --- kauai/src/appbsdl.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index 79d2d80e3..feeebfa9e 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -828,9 +828,20 @@ void APPB::ShowCurs(void) ***************************************************************************/ void APPB::PositionCurs(int32_t xpScreen, int32_t ypScreen) { - AssertThis(0); + SDL_Renderer *rdr; + float flxp, flyp; + int xp, yp; + PT pt; - SDL_WarpMouseGlobal(xpScreen, ypScreen); + // Convert coordinates back from screen (global) coordinates to local (window) + // coordinates and use SDL_WarpMouseInWindow() instead of SDL_WarpMouseGlobal() + // so we can apply the logical to window coordinate transformation. + pt.xp = xpScreen; + pt.yp = ypScreen; + GOB::PgobScreen()->MapPt(&pt, cooGlobal, cooLocal); + rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); + SDL_RenderLogicalToWindow(rdr, (float)pt.xp, (float)pt.yp, &xp, &yp); + SDL_WarpMouseInWindow(vwig.hwndApp, xp, yp); if (_fFlushCursor) { From 57a3b5d34ed1f49ab9a99a7d00b2dfcedce3be53 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 03/15] kauai/src/gfxsdl.cpp: do not call SDL_RenderClear() in GPT::Flip() According to the SDL documentation SDL_RenderClear() clears the rendering target to the current paint colour. Currently this is done every time GPT::Flip() is called to update the application window causing a noticeable flicker when the application is running in fullscreen mode. Clear the rendering target just once at the time the renderer is created to avoid flickering when updating large sections in the application window. --- kauai/src/appbsdl.cpp | 3 ++- kauai/src/gfxsdl.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index feeebfa9e..4233356bd 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -118,6 +118,7 @@ bool APPB::_FInitOS(void) // Create a renderer SDL_Renderer *rdr = SDL_CreateRenderer(wnd, -1, 0); Assert(rdr != pvNil, "no renderer created from SDL_CreateRenderer"); + AssertDo(SDL_RenderClear(rdr) == 0, SDL_GetError()); vwig.hwndApp = wnd; @@ -841,7 +842,7 @@ void APPB::PositionCurs(int32_t xpScreen, int32_t ypScreen) GOB::PgobScreen()->MapPt(&pt, cooGlobal, cooLocal); rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); SDL_RenderLogicalToWindow(rdr, (float)pt.xp, (float)pt.yp, &xp, &yp); - SDL_WarpMouseInWindow(vwig.hwndApp, xp, yp); + SDL_WarpMouseInWindow((SDL_Window *)vwig.hwndApp, xp, yp); if (_fFlushCursor) { diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index fdff96b7d..f0cd39f2a 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -1105,7 +1105,6 @@ void GPT::Flip() Assert(!_fOffscreen, "drawing an offscreen GPT to the screen?"); // Paint the texture - AssertDoSDL(SDL_RenderClear(_renderer)); AssertDoSDL(SDL_RenderCopy(_renderer, _texture, NULL, NULL)); SDL_RenderPresent(_renderer); } From 9d7a3dedc5703d30bfedd289f895c13683aaa939 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 04/15] kauai/src/appbsdl.cpp: rename kd{x,y}pWindow to kd{x,y}pLogical This is to reflect that the value represents the logical application size and not the window size. --- kauai/src/appbsdl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index 4233356bd..ad5303a32 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -23,9 +23,9 @@ const uint32_t kdtsIdleTimer = 1; // FUTURE: Get this from the system const uint32_t kdtsDoubleClick = 500; -// Window size -const uint32_t kdxpWindow = 640; -const uint32_t kdypWindow = 480; +// Logical size +const uint32_t kdxpLogical = 640; +const uint32_t kdypLogical = 480; static SDL_Cursor *vpsdlcursWait = pvNil; static SDL_Cursor *vpsdlcursArrow = pvNil; @@ -108,7 +108,7 @@ bool APPB::_FInitOS(void) stnApp.GetUtf8Sz(u8szApp); int32_t xpWindow = SDL_WINDOWPOS_UNDEFINED; int32_t ypWindow = SDL_WINDOWPOS_UNDEFINED; - SDL_Window *wnd = SDL_CreateWindow(u8szApp, xpWindow, ypWindow, kdxpWindow, kdypWindow, 0); + SDL_Window *wnd = SDL_CreateWindow(u8szApp, xpWindow, ypWindow, kdxpLogical, kdypLogical, 0); Assert(wnd != pvNil, "no window returned from SDL_CreateWindow"); if (wnd == pvNil) { From d2187648fe7b38c3c1435618bfd0a5762197a3bb Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 05/15] kauai/src/appbsdl.cpp: move kd{x,y}pLogical to appb.h This is so that the logical application size can be used outside of appbsdl.cpp. --- kauai/src/appb.h | 4 ++++ kauai/src/appbsdl.cpp | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kauai/src/appb.h b/kauai/src/appb.h index 1068e660a..e7e9267a1 100644 --- a/kauai/src/appb.h +++ b/kauai/src/appb.h @@ -25,6 +25,10 @@ typedef MSG EVT; #ifdef KAUAI_SDL typedef SDL_Event EVT; + +// Logical size +const uint32_t kdxpLogical = 640; +const uint32_t kdypLogical = 480; #endif // KAUAI_SDL #ifdef MAC diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index ad5303a32..2858c965e 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -23,10 +23,6 @@ const uint32_t kdtsIdleTimer = 1; // FUTURE: Get this from the system const uint32_t kdtsDoubleClick = 500; -// Logical size -const uint32_t kdxpLogical = 640; -const uint32_t kdypLogical = 480; - static SDL_Cursor *vpsdlcursWait = pvNil; static SDL_Cursor *vpsdlcursArrow = pvNil; From b2d32ed6bf991ef8c5b55ca78c07f7fc68692b4b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 06/15] kauai/src/appbsdl.cpp: set the renderer size to kd{x,y}pLogical This ensures that the renderer size is set to the logical application size, regardless of the size of window. --- kauai/src/appbsdl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index 2858c965e..d8de1de4b 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -115,6 +115,7 @@ bool APPB::_FInitOS(void) SDL_Renderer *rdr = SDL_CreateRenderer(wnd, -1, 0); Assert(rdr != pvNil, "no renderer created from SDL_CreateRenderer"); AssertDo(SDL_RenderClear(rdr) == 0, SDL_GetError()); + AssertDo(SDL_RenderSetLogicalSize(rdr, kdxpLogical, kdypLogical) == 0, SDL_GetError()); vwig.hwndApp = wnd; From a69289d4dc5f38a3be15f437d87a0f33be78c57e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 07/15] kauai: convert window coordinates to logical coordinates When the window size is different from the logical size, it is necessary to convert any window coordinates to logical coordinates. Note that the same transformation must be applied to SDL_GetMouseState() since compared to a mouse event, the coordinates returned are always window coordinates. --- kauai/src/appbsdl.cpp | 5 +++++ kauai/src/gob.cpp | 19 +++++++++++++++++++ kauai/src/gobsdl.cpp | 7 ++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index d8de1de4b..aa1a79f3a 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -220,6 +220,11 @@ void APPB::TrackMouse(PGOB pgob, PT *ppt) { // No mouse move events: just get the current position instead int state = SDL_GetMouseState(&xp, &yp); + SDL_Renderer *rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); + float flx, fly; + SDL_RenderWindowToLogical(rdr, xp, yp, &flx, &fly); + xp = (int)flx; + yp = (int)fly; if (state & SDL_BUTTON(1)) { grfcust |= fcustMouse; diff --git a/kauai/src/gob.cpp b/kauai/src/gob.cpp index 2a6744114..74e59f363 100644 --- a/kauai/src/gob.cpp +++ b/kauai/src/gob.cpp @@ -1030,13 +1030,19 @@ KWND GOB::_HwndGetDptFromCoo(PT *pdpt, int32_t coo) ClientToScreen(hwnd, &pts); #elif defined(KAUAI_SDL) // FIXME MCA: is this correct? + SDL_Renderer *rdr; + float fxp, fyp; int xpWnd, ypWnd; PTS pts; Assert(hwnd == vwig.hwndApp, "We should only have one window"); pts = *pdpt; + rdr = SDL_GetRenderer((SDL_Window *)hwnd); SDL_GetWindowPosition((SDL_Window *)hwnd, &xpWnd, &ypWnd); + SDL_RenderWindowToLogical(rdr, xpWnd, ypWnd, &fxp, &fyp); + xpWnd = (int)fxp; + ypWnd = (int)fyp; pts.xp += xpWnd; pts.yp += ypWnd; @@ -1090,8 +1096,14 @@ PGOB GOB::PgobFromPtGlobal(int32_t xp, int32_t yp, PT *pptLocal) ScreenToClient(hwnd, &pts); #elif defined(KAUAI_SDL) PTS pts; + float fxp, fyp; int xpWnd, ypWnd; + SDL_Renderer *rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); + SDL_GetWindowPosition((SDL_Window *)vwig.hwndApp, &xpWnd, &ypWnd); + SDL_RenderWindowToLogical(rdr, xpWnd, ypWnd, &fxp, &fyp); + xpWnd = (int)fxp; + ypWnd = (int)fyp; pts.xp = xp - xpWnd; pts.yp = yp - ypWnd; @@ -1252,9 +1264,16 @@ void GOB::_SetRcCur(void) GetClientRect(pgob->_hwnd, &rcs); rc = rcs; #elif defined(KAUAI_SDL) + SDL_Renderer *rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); int dxpClient = 0, dypClient = 0; + float fxp, fyp; + SDL_GetWindowSize((SDL_Window *)pgob->_hwnd, &dxpClient, &dypClient); Assert(dxpClient > 0 && dypClient > 0, "SDL_GetWindowSize failed?"); + SDL_RenderWindowToLogical(rdr, dxpClient, dypClient, &fxp, &fyp); + dxpClient = (int)fxp; + dypClient = (int)fyp; + rc.Set(0, 0, dxpClient, dypClient); #else #error not implemented diff --git a/kauai/src/gobsdl.cpp b/kauai/src/gobsdl.cpp index be58a29c1..ce5180d2b 100644 --- a/kauai/src/gobsdl.cpp +++ b/kauai/src/gobsdl.cpp @@ -126,7 +126,12 @@ void GOB::GetPtMouse(PT *ppt, bool *pfDown) AssertThis(0); int xp = 0, yp = 0; + float fxp, fyp; + SDL_Renderer *rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); int mouseState = SDL_GetMouseState(&xp, &yp); + SDL_RenderWindowToLogical(rdr, xp, yp, &fxp, &fyp); + xp = (int)fxp; + yp = (int)fyp; if (ppt != pvNil) { @@ -194,4 +199,4 @@ bool GOB::FCreateAndAttachMdi(PSTN pstnTitle) // SDL does not support MDI RawRtn(); return fFalse; -} \ No newline at end of file +} From 9225ce34773678eb81bf152f431be92bd3b50c9a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 08/15] kauai/src/gob.cpp: return logical application size instead of window size The rectangle returned by GOB::_SetRcCur() for a GOB with a hwnd is always the logical application size, and not the window size. --- kauai/src/gob.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/kauai/src/gob.cpp b/kauai/src/gob.cpp index 74e59f363..2ed1d6624 100644 --- a/kauai/src/gob.cpp +++ b/kauai/src/gob.cpp @@ -1264,17 +1264,9 @@ void GOB::_SetRcCur(void) GetClientRect(pgob->_hwnd, &rcs); rc = rcs; #elif defined(KAUAI_SDL) - SDL_Renderer *rdr = SDL_GetRenderer((SDL_Window *)vwig.hwndApp); - int dxpClient = 0, dypClient = 0; - float fxp, fyp; - - SDL_GetWindowSize((SDL_Window *)pgob->_hwnd, &dxpClient, &dypClient); - Assert(dxpClient > 0 && dypClient > 0, "SDL_GetWindowSize failed?"); - SDL_RenderWindowToLogical(rdr, dxpClient, dypClient, &fxp, &fyp); - dxpClient = (int)fxp; - dypClient = (int)fyp; - - rc.Set(0, 0, dxpClient, dypClient); + // The rectangle is always the same as that of the logical application + // since logical coordinates are independent of window size + rc.Set(0, 0, kdxpLogical, kdypLogical); #else #error not implemented #endif From ce58f2271986385ab43f036549a8c4f3b0503206 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 09/15] kauai/src/gfxsdl.cpp: only create a renderer and texture for onscreen GPTs This is because offscreen GPTs are not bound to a window but are instead backed by a surface. --- kauai/src/gfxsdl.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index f0cd39f2a..d0ac4aca9 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -142,14 +142,22 @@ PGPT GPT::PgptNew(SDL_Window *wnd, int cbitPixel, bool fOffscreen, int dxp, int return pvNil; pgpt->_wnd = wnd; - pgpt->_renderer = SDL_GetRenderer(wnd); - Assert(pgpt->_renderer != pvNil, "no renderer"); pgpt->_fOffscreen = fOffscreen; // get drawable size if (!fOffscreen) { + pgpt->_renderer = SDL_GetRenderer(wnd); + Assert(pgpt->_renderer != pvNil, "no renderer"); + AssertDoSDL(SDL_GetRendererOutputSize(pgpt->_renderer, &dxp, &dyp)); + + // Create a texture that is used for rendering + pgpt->_texture = + SDL_CreateTexture(pgpt->_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); + Assert(pgpt->_texture, "SDL_CreateTexture failed"); + + pgpt->InvalidateTexture(); } Assert(dxp != 0, "dxp must be > 0"); Assert(dyp != 0, "dyp must be > 0"); @@ -170,13 +178,6 @@ PGPT GPT::PgptNew(SDL_Window *wnd, int cbitPixel, bool fOffscreen, int dxp, int AssertDoSDL(SDL_SetSurfacePalette(pgpt->_surface, _pal)); } - // Create a texture that is used for rendering - pgpt->_texture = - SDL_CreateTexture(pgpt->_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); - Assert(pgpt->_texture, "SDL_CreateTexture failed"); - - pgpt->InvalidateTexture(); - return pgpt; } From 527aee98494f899b65ec828db5951b3d1fc6a7a4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 10/15] kauai/src/gfxsdl.cpp: pass window width and height into GPT::PgptNew() This will allow for later moving the texture management logic out of GPT::PgptNew(). --- kauai/src/gfxsdl.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index d0ac4aca9..d888f2c3c 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -150,8 +150,6 @@ PGPT GPT::PgptNew(SDL_Window *wnd, int cbitPixel, bool fOffscreen, int dxp, int pgpt->_renderer = SDL_GetRenderer(wnd); Assert(pgpt->_renderer != pvNil, "no renderer"); - AssertDoSDL(SDL_GetRendererOutputSize(pgpt->_renderer, &dxp, &dyp)); - // Create a texture that is used for rendering pgpt->_texture = SDL_CreateTexture(pgpt->_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); @@ -188,8 +186,15 @@ PGPT GPT::PgptNewHwnd(KWND hwnd) { Assert(kwndNil != hwnd, "Null hwnd"); Assert(pvNil != ((SDL_Window *)hwnd), "Not an SDL window"); + SDL_Renderer *rdr; + int dxp, dyp; PGPT pgpt; - if (pvNil == (pgpt = PgptNew((SDL_Window *)hwnd, 32, fFalse, 0, 0))) + + rdr = SDL_GetRenderer(hwnd); + Assert(rdr != pvNil, "no renderer"); + AssertDoSDL(SDL_GetRendererOutputSize(rdr, &dxp, &dyp)); + + if (pvNil == (pgpt = PgptNew((SDL_Window *)hwnd, 32, fFalse, dxp, dyp))) { return pvNil; } From 692e1b443b89f6190a4ce342b085203f128f81e5 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 11/15] kauai/src/gfxsdl.cpp: introduce GPT::RebuildTexture() function This function will be used to reset the renderer and upload a new texture when changing window size. --- kauai/src/gfx.h | 2 ++ kauai/src/gfxsdl.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/kauai/src/gfx.h b/kauai/src/gfx.h index 090d0f23d..5623863dd 100644 --- a/kauai/src/gfx.h +++ b/kauai/src/gfx.h @@ -796,6 +796,8 @@ class GPT : public GPT_PAR void InvalidateTexture(void); // Copy contents of surface to texture void UpdateTexture(void); + // Rebuild texture e.g. due to a change in window size + void RebuildTexture(void); // Save contents of this GPT to a bitmap for debugging void DumpBitmap(STN *stnBmp); diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index d888f2c3c..8c536a498 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -293,6 +293,35 @@ void GPT::UpdateTexture() } } +void GPT::RebuildTexture(void) +{ + int dxp, dyp; + + // Free the existing texture + if (_texture != pvNil) + SDL_DestroyTexture(_texture); + + AssertDoSDL(SDL_GetRendererOutputSize(_renderer, &dxp, &dyp)); + + // Free the existing renderer + if (_renderer != pvNil) + SDL_DestroyRenderer(_renderer); + + // Create a renderer + _renderer = SDL_CreateRenderer(_wnd, -1, 0); + Assert(_renderer != pvNil, "no renderer created from SDL_CreateRenderer"); + AssertDoSDL(SDL_RenderClear(_renderer)); + AssertDoSDL(SDL_RenderSetLogicalSize(_renderer, kdxpLogical, kdypLogical)); + + // Create a new texture + _texture = + SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); + Assert(_texture, "SDL_CreateTexture failed"); + + InvalidateTexture(); + Flip(); +} + void GPT::DumpBitmap(STN *stnBmp) { U8SZ u8szFilePath; From 989eb547fae887f95374468254b2cbf94bb14543 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 12/15] kauai/src/gfxsdl.cpp: use RebuildTexture() in GOB::FAttachHwnd() Since RebuildTexture() contains all the logic to recreate an SDL texture, use it in GOB::FAttachHwnd() to avoid having duplicated logic that depends upon the GPT fOffScreen variable in GPT::PgptNew(). --- kauai/src/gfxsdl.cpp | 13 ------------- kauai/src/gobsdl.cpp | 1 + 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index 8c536a498..9604c27dd 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -144,19 +144,6 @@ PGPT GPT::PgptNew(SDL_Window *wnd, int cbitPixel, bool fOffscreen, int dxp, int pgpt->_wnd = wnd; pgpt->_fOffscreen = fOffscreen; - // get drawable size - if (!fOffscreen) - { - pgpt->_renderer = SDL_GetRenderer(wnd); - Assert(pgpt->_renderer != pvNil, "no renderer"); - - // Create a texture that is used for rendering - pgpt->_texture = - SDL_CreateTexture(pgpt->_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); - Assert(pgpt->_texture, "SDL_CreateTexture failed"); - - pgpt->InvalidateTexture(); - } Assert(dxp != 0, "dxp must be > 0"); Assert(dyp != 0, "dyp must be > 0"); diff --git a/kauai/src/gobsdl.cpp b/kauai/src/gobsdl.cpp index ce5180d2b..965b64e6b 100644 --- a/kauai/src/gobsdl.cpp +++ b/kauai/src/gobsdl.cpp @@ -54,6 +54,7 @@ bool GOB::FAttachHwnd(KWND hwnd) { if (pvNil == (_pgpt = GPT::PgptNewHwnd(hwnd))) return fFalse; + _pgpt->RebuildTexture(); _hwnd = hwnd; SetRcFromHwnd(); } From 2535a8757a09d1592ea3d78c95b88e610c64a30c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 13/15] kauai/src/gfxsdl.cpp: use logical application size for the texture and renderer Since the logical application size is fixed there is no need to query the current renderer to determine the size of the texture. Use kdxpLogical and kdypLogical directly, which also removes the need to create an initial renderer in APPB::_FInitOS(). --- kauai/src/appbsdl.cpp | 6 ------ kauai/src/gfxsdl.cpp | 14 ++------------ 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/kauai/src/appbsdl.cpp b/kauai/src/appbsdl.cpp index aa1a79f3a..119ad0151 100644 --- a/kauai/src/appbsdl.cpp +++ b/kauai/src/appbsdl.cpp @@ -111,12 +111,6 @@ bool APPB::_FInitOS(void) return fFalse; } - // Create a renderer - SDL_Renderer *rdr = SDL_CreateRenderer(wnd, -1, 0); - Assert(rdr != pvNil, "no renderer created from SDL_CreateRenderer"); - AssertDo(SDL_RenderClear(rdr) == 0, SDL_GetError()); - AssertDo(SDL_RenderSetLogicalSize(rdr, kdxpLogical, kdypLogical) == 0, SDL_GetError()); - vwig.hwndApp = wnd; // FUTURE: Turn this off when Win32 stuff is removed diff --git a/kauai/src/gfxsdl.cpp b/kauai/src/gfxsdl.cpp index 9604c27dd..a136bc909 100644 --- a/kauai/src/gfxsdl.cpp +++ b/kauai/src/gfxsdl.cpp @@ -173,15 +173,9 @@ PGPT GPT::PgptNewHwnd(KWND hwnd) { Assert(kwndNil != hwnd, "Null hwnd"); Assert(pvNil != ((SDL_Window *)hwnd), "Not an SDL window"); - SDL_Renderer *rdr; - int dxp, dyp; PGPT pgpt; - rdr = SDL_GetRenderer(hwnd); - Assert(rdr != pvNil, "no renderer"); - AssertDoSDL(SDL_GetRendererOutputSize(rdr, &dxp, &dyp)); - - if (pvNil == (pgpt = PgptNew((SDL_Window *)hwnd, 32, fFalse, dxp, dyp))) + if (pvNil == (pgpt = PgptNew((SDL_Window *)hwnd, 32, fFalse, kdxpLogical, kdypLogical))) { return pvNil; } @@ -282,14 +276,10 @@ void GPT::UpdateTexture() void GPT::RebuildTexture(void) { - int dxp, dyp; - // Free the existing texture if (_texture != pvNil) SDL_DestroyTexture(_texture); - AssertDoSDL(SDL_GetRendererOutputSize(_renderer, &dxp, &dyp)); - // Free the existing renderer if (_renderer != pvNil) SDL_DestroyRenderer(_renderer); @@ -302,7 +292,7 @@ void GPT::RebuildTexture(void) // Create a new texture _texture = - SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dxp, dyp); + SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, kdxpLogical, kdypLogical); Assert(_texture, "SDL_CreateTexture failed"); InvalidateTexture(); From 2fd8c66ca30a534aa1c5c514dfdbf5df3318f614 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 14/15] src/studio/utest.cpp: move _fMainWindowCreated check outside of defined(KAUAI_WIN32) When attempting to switch window size at startup, APP::_FInitOS() can be called early. Move the _fMainWindowCreated check outside of the defined(KAUAI_WIN32) section since it prevents APP::_FInitOS() from being called more than once in all cases. --- src/studio/utest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/studio/utest.cpp b/src/studio/utest.cpp index 507a65ade..8d244a39e 100644 --- a/src/studio/utest.cpp +++ b/src/studio/utest.cpp @@ -950,6 +950,9 @@ bool APP::_FInitOS(void) { AssertBaseThis(0); + if (_fMainWindowCreated) // If someone else called _FInitOS already, + return fTrue; // we can leave + #if defined(KAUAI_SDL) if (!(FPure(APP_PAR::_FInitOS()))) @@ -967,9 +970,6 @@ bool APP::_FInitOS(void) uint32_t dwStyle = 0; STN stnWindowTitle; - if (_fMainWindowCreated) // If someone else called _FInitOS already, - return fTrue; // we can leave - if (!FGetStnApp(idsWindowTitle, &stnWindowTitle)) return fFalse; From 53d3dcabe09fafd6ef406dacd86ec2c2c7007f5a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 25 May 2026 19:16:35 +0100 Subject: [PATCH 15/15] src/studio/utest.cpp: add support for SDL full screen mode Allow switching between windowed and full screen mode by pressing Alt-Enter. The application now works in a fixed 640x480 resolution but scales the texture to fit the current window. The current full screen mode state is saved in the config file so that 3dmovie will retain the screen mode after a restart. Note that APP::_FDisplayIs640480() and APP::_FSwitch640480() work in the opposite way that you may expect. This is because the Windows logic assumes that full sceen *is* 640x480 resolution since if the screen resolution were larger, 3D Movie Maker would configure the video controller into 640x480 mode in order to fill the screen. --- src/studio/utest.cpp | 48 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/src/studio/utest.cpp b/src/studio/utest.cpp index 8d244a39e..a46fa795c 100644 --- a/src/studio/utest.cpp +++ b/src/studio/utest.cpp @@ -939,7 +939,16 @@ bool APP::_FDisplayIs640480(void) #ifdef WIN return (GetSystemMetrics(SM_CXSCREEN) == 640 && GetSystemMetrics(SM_CYSCREEN) == 480); #else // !WIN - return fFalse; + int w, h; + + if (vwig.hwndApp == pvNil) + return fFalse; + + SDL_GetWindowSize(vwig.hwndApp, &w, &h); + + // This is actually correct, since on Windows the screen upscaling is done by switching + // the video controller into 640x480 mode to fill the screen. + return (w != kdxpLogical && h != kdypLogical); #endif // WIN } @@ -3530,8 +3539,8 @@ bool APP::_FDisplaySwitchSupported(void) // We can no longer compile for Windows platforms that do not support screen resolution changes. return fTrue; #else - // OS doesn't support res-switching - return fFalse; + // SDL does support res-switching via upscaling + return fTrue; #endif // WIN } @@ -3632,8 +3641,39 @@ bool APP::_FSwitch640480(bool fTo640480) LFail: if (0 != hLibrary) FreeLibrary(hLibrary); +#else // KAUAI_WIN32 + PGOB pgobScreen = GOB::PgobScreen(); + int32_t fSwitchRes = !_fRunInWindow; + + if (fTo640480) + { + SDL_SetWindowFullscreen((SDL_Window *)vwig.hwndApp, SDL_WINDOW_FULLSCREEN_DESKTOP); + + if (pgobScreen != pvNil) + { + PGPT pgpt = pgobScreen->Pgpt(); + + pgpt->RebuildTexture(); + } + + _fSwitchedResolution = fTrue; + } + else + { + SDL_SetWindowFullscreen((SDL_Window *)vwig.hwndApp, 0); + + if (pgobScreen != pvNil) + { + PGPT pgpt = pgobScreen->Pgpt(); + + pgpt->RebuildTexture(); + } + } + + FGetSetRegKey(kszSwitchResolutionValue, &fSwitchRes, SIZEOF(fSwitchRes), fregSetKey); + + return fTrue; #endif // KAUAI_WIN32 - return fFalse; } bool APP::_FSetRunInWindow(bool fRunInWindowNew)