From 8019e9b4fbffddc4accc7410e2bc97552d05ea27 Mon Sep 17 00:00:00 2001 From: SuuperW Date: Wed, 15 Apr 2026 02:29:20 -0500 Subject: [PATCH 1/3] replace old comment; the comment and code under it got moved around throughout the years such that the comment accidentally got put with the wrong code and the right code doesn't exist anymore --- src/BizHawk.Client.EmuHawk/MainForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index fa4b8d800b5..209c165d3af 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -2935,7 +2935,7 @@ private void StepRunLoop_Core(bool force = false) _lastFastForwardingOrRewinding = isFastForwardingOrRewinding; - // client input-related duties + // Clear stuff previously drawn by gui API OSD.ClearGuiText(); CheatList.Pulse(); From b14d6be7cbca5d5d0c7b61481e42b8e32e7aca2d Mon Sep 17 00:00:00 2001 From: SuuperW Date: Wed, 15 Apr 2026 02:48:37 -0500 Subject: [PATCH 2/3] make everything that clears any gui API drawings clear all gui API drawings (except clear APIs, about to be deprecated) --- src/BizHawk.Client.Common/Api/Classes/GuiApi.cs | 2 +- .../DisplayManager/DisplayManagerBase.cs | 4 ++++ src/BizHawk.Client.Common/DisplayManager/OSDManager.cs | 2 +- src/BizHawk.Client.EmuHawk/MainForm.cs | 4 ++-- src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs | 2 -- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs b/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs index ce448247e00..c5e7dfcc340 100644 --- a/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs +++ b/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs @@ -142,7 +142,7 @@ public void AddMessage(string message, [LiteralExpected] int? duration = null) public void ClearGraphics(DisplaySurfaceID? surfaceID = null) => Get2DRenderer(surfaceID).Clear(); - public void ClearText() => _displayManager.OSD.ClearGuiText(); + public void ClearText() => _displayManager.OSD.ClearApiHawkText(); public void SetDefaultForegroundColor(Color color) => _defaultForeground = color; diff --git a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs index 5a30295c011..ac1dc96b20f 100644 --- a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs +++ b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs @@ -961,12 +961,16 @@ public I2DRenderer GetApiHawk2DRenderer(DisplaySurfaceID surfaceID) ? _apiHawkIDTo2DRenderer.GetValueOrPut(surfaceID, _ => _gl.Create2DRenderer(_imGuiResourceCache)) : throw new ArgumentOutOfRangeException(paramName: nameof(surfaceID), surfaceID, message: "invalid surface ID"); + /// + /// Clear stuff drawn by the gui API + /// public void ClearApiHawkSurfaces() { foreach (var renderer in _apiHawkIDTo2DRenderer.Values) { renderer.Clear(); } + OSD.ClearApiHawkText(); } public void DiscardApiHawkSurfaces() diff --git a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs index 1ab1aec2b0c..1a0d5ac6130 100644 --- a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs +++ b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs @@ -120,7 +120,7 @@ public void AddGuiText(string message, MessagePosition pos, Color backGround, Co }); } - public void ClearGuiText() + public void ClearApiHawkText() => _guiTextList.Clear(); private void DrawMessage(IBlitter g, UIMessage message, int yOffset) diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 209c165d3af..f926e1f23e8 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -2936,7 +2936,7 @@ private void StepRunLoop_Core(bool force = false) _lastFastForwardingOrRewinding = isFastForwardingOrRewinding; // Clear stuff previously drawn by gui API - OSD.ClearGuiText(); + DisplayManager.ClearApiHawkSurfaces(); CheatList.Pulse(); @@ -4098,7 +4098,7 @@ public bool LoadState(string path, string userFriendlyStateName, bool suppressOS return false; } - OSD.ClearGuiText(); + DisplayManager.ClearApiHawkSurfaces(); if (SavestateLoaded is not null) { StateLoadedEventArgs args = new(userFriendlyStateName); diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs index ff9ea53a77d..17f7752afd2 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/LuaConsole.cs @@ -146,7 +146,6 @@ public LuaConsole() ResetDrawSurfacePadding(); ClearFileWatches(); LuaImp?.Close(); - DisplayManager.OSD.ClearGuiText(); } else { @@ -978,7 +977,6 @@ private void RemoveScriptMenuItem_Click(object sender, EventArgs e) UpdateDialog(); DisplayManager.ClearApiHawkSurfaces(); DisplayManager.ClearApiHawkTextureCache(); - DisplayManager.OSD.ClearGuiText(); if (!_openedFiles.Any(static lf => !lf.IsSeparator)) ResetDrawSurfacePadding(); // just removed last script, reset padding } } From 8e8bd056ffde3d0564e40a162e03c726978a4bec Mon Sep 17 00:00:00 2001 From: SuuperW Date: Wed, 15 Apr 2026 03:36:23 -0500 Subject: [PATCH 3/3] replace the gui.clear methods with something more friendly to having multiple Lua scripts running at once --- .../Api/Classes/GuiApi.cs | 15 ++++++++-- .../Api/Interfaces/IGuiApi.cs | 16 ++++++++++ .../DisplayManager/DisplayManagerBase.cs | 2 ++ .../lua/NamedLuaFunction.cs | 2 ++ src/BizHawk.Client.EmuHawk/MainForm.cs | 1 + .../tools/Lua/Libraries/GuiLuaLibrary.cs | 29 +++++++++++++++++-- 6 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs b/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs index c5e7dfcc340..b9d164be73e 100644 --- a/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs +++ b/src/BizHawk.Client.Common/Api/Classes/GuiApi.cs @@ -140,9 +140,20 @@ public void DrawNew(string name, bool clear) public void AddMessage(string message, [LiteralExpected] int? duration = null) => _dialogController.AddOnScreenMessage(message, duration); - public void ClearGraphics(DisplaySurfaceID? surfaceID = null) => Get2DRenderer(surfaceID).Clear(); + public void ClearGraphics(DisplaySurfaceID? surfaceID = null) => LogCallback("the `ClearGraphics()` function has been deprecated; use `Draw()`\n"); - public void ClearText() => _displayManager.OSD.ClearApiHawkText(); + public void ClearText() => LogCallback("the `ClearText()` function has been deprecated; use `Draw()`\n"); + + public void Draw() + { + _displayManager.DiscardApiHawkSurfaces(); + _displayManager.ClearApiHawkSurfaces(); + _displayManager.OnDraw?.Invoke(); + } + + public void AddDrawCallback(Action callback) => _displayManager.OnDraw += callback; + + public void RemoveDrawCallback(Action callback) => _displayManager.OnDraw -= callback; public void SetDefaultForegroundColor(Color color) => _defaultForeground = color; diff --git a/src/BizHawk.Client.Common/Api/Interfaces/IGuiApi.cs b/src/BizHawk.Client.Common/Api/Interfaces/IGuiApi.cs index a2c3311037a..27e336ec012 100644 --- a/src/BizHawk.Client.Common/Api/Interfaces/IGuiApi.cs +++ b/src/BizHawk.Client.Common/Api/Interfaces/IGuiApi.cs @@ -33,8 +33,24 @@ public interface IGuiApi : IDisposable, IExternalApi void AddMessage(string message, int? duration = null); + [Obsolete("use Draw and AddDrawCallback instead")] void ClearGraphics(DisplaySurfaceID? surfaceID = null); + + [Obsolete("use Draw and AddDrawCallback instead")] void ClearText(); + + /// + /// Clears all prior drawings and calls any actions given to . + /// This should only be used when you want to redraw while paused. + /// + void Draw(); + + /// + /// The given action will be called before each API draw. This means after each frame and any time is called. + /// + void AddDrawCallback(Action callback); + void RemoveDrawCallback(Action callback); + void SetDefaultForegroundColor(Color color); void SetDefaultBackgroundColor(Color color); Color GetDefaultTextBackground(); diff --git a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs index ac1dc96b20f..ee5a82cf8b2 100644 --- a/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs +++ b/src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs @@ -51,6 +51,8 @@ public DisplayManagerRenderTargetProvider(Func callback) public SnowyNullVideo SnowyVP { get; private set; } + public Action/*?*/ OnDraw; + protected DisplayManagerBase( Config config, IEmulator emulator, diff --git a/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs b/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs index bf665b0b826..84d06748dfe 100644 --- a/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs +++ b/src/BizHawk.Client.Common/lua/NamedLuaFunction.cs @@ -28,6 +28,8 @@ public sealed class NamedLuaFunction : INamedLuaFunction public const string EVENT_TYPE_FUTURE = "BeforeFutureFrame"; + public const string EVENT_TYPE_DRAW = "OnDraw"; + private readonly LuaFunction _function; private readonly ILuaLibraries _luaImp; diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index f926e1f23e8..bfc8ea66a4f 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -3055,6 +3055,7 @@ private void StepRunLoop_Core(bool force = false) UpdateToolsAfter(); } } + DisplayManager.OnDraw?.Invoke(); if (newFrame) { diff --git a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs index 4c06f27caa2..fbcaf734ba5 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Lua/Libraries/GuiLuaLibrary.cs @@ -6,10 +6,12 @@ namespace BizHawk.Client.EmuHawk { - public sealed class GuiLuaLibrary : LuaLibraryBase, IDisposable + public sealed class GuiLuaLibrary : LuaLibraryBase, IDisposable, IRegisterFunctions { private DisplaySurfaceID _rememberedSurfaceID = DisplaySurfaceID.EmuCore; + public NLFAddCallback CreateAndRegisterNamedFunction { get; set; } + public GuiLuaLibrary(ILuaLibraries luaLibsImpl, ApiContainer apiContainer, Action logOutputCallback) : base(luaLibsImpl, apiContainer, logOutputCallback) {} @@ -37,15 +39,36 @@ public void DrawFinish() public void AddMessage(string message) => APIs.Gui.AddMessage(message); - [LuaMethodExample("gui.clearGraphics( );")] +#pragma warning disable CS0618 + [LuaDeprecatedMethod] [LuaMethod("clearGraphics", "clears all lua drawn graphics from the screen")] public void ClearGraphics(string surfaceName = null) => APIs.Gui.ClearGraphics(surfaceID: UseOrFallback(surfaceName)); - [LuaMethodExample("gui.cleartext( );")] + [LuaDeprecatedMethod] [LuaMethod("cleartext", "clears all text created by gui.text()")] public void ClearText() => APIs.Gui.ClearText(); +#pragma warning restore CS0618 + + [LuaMethodExample("gui.draw();")] + [LuaMethod("draw", "Clears all prior drawings and calls any functions given to gui.addDrawCallback. Use this to re-draw while paused.")] + public void Draw() + { + APIs.Gui.Draw(); + } + + [LuaMethodExample("local draw_cb_id = gui.addDrawCallback(\r\n\tfunction()\r\n\t\t-- gui.draw*** calls go here\r\n\tend);")] + [LuaMethod("addDrawCallback", "The given function will be called before each API draw. This means after each frame and any time gui.draw is called.")] + public string AddDrawCallback(LuaFunction luaf, string name = null) + { + INamedLuaFunction nlf = CreateAndRegisterNamedFunction(luaf, NamedLuaFunction.EVENT_TYPE_DRAW, ApiGroup.PROHIBITED_MID_FRAME, name); + Action callback = () => nlf.Call(); + APIs.Gui.AddDrawCallback(callback); + nlf.OnRemove += () => APIs.Gui.RemoveDrawCallback(callback); + + return nlf.GuidStr; + } [LuaMethodExample("gui.defaultForeground( 0x000000FF );")] [LuaMethod("defaultForeground", "Sets the default foreground color to use in drawing methods, white by default")]