Skip to content

Allow redrawing Lua while multiple scripts are open#4682

Open
SuuperW wants to merge 3 commits intoTASEmulators:masterfrom
SuuperW:api-drawing
Open

Allow redrawing Lua while multiple scripts are open#4682
SuuperW wants to merge 3 commits intoTASEmulators:masterfrom
SuuperW:api-drawing

Conversation

@SuuperW
Copy link
Copy Markdown
Contributor

@SuuperW SuuperW commented Apr 15, 2026

Currently if a Lua script wants to re-draw it has to do one or more of:

gui.clearGraphics("client")
gui.clearGraphics("emucore")
gui.cleartext()

and then draw it's stuff. But this clears everything drawn by other scripts as well, without giving them an opportunity to re-draw.

Having multiple Lua scripts that draw was also made difficult by the fact that some things that Lua draws weren't being cleared on each new frame. This means if any Lua script wants to clear what it drew, it must call clearGraphics which again can interfere with other scripts.

So this PR does two things:

  1. Make it so that all things drawn by the Gui API are cleared at the start of each frame. (previously it only cleared things done with DrawString, which makes no sense)
  2. Replace the various clear*** methods with an OnDraw event and a method that raises it.

A Lua script can now do something like:

function onDraw()
	gui.text(30, 50, emu.framecount())
end
gui.addDrawCallback(onDraw)

and another script can call gui.draw() to clear its drawings. The gui.draw call will end up calling the first Lua's onDraw function so that it isn't affected by the second script's wanting to clear.

We could also make it so that the Lua Console calls IGuiApi.Draw when a script is stopped. But this should happen only if the user manually stops it, since a Lua script may want to just draw once and exit, leaving the drawings on screen until the next frame.

Check if completed:

SuuperW added 3 commits April 15, 2026 03:55
…hroughout the years such that the comment accidentally got put with the wrong code and the right code doesn't exist anymore
…awings (except clear APIs, about to be deprecated)
@YoshiRulz YoshiRulz added re: Lua API/scripting Relating to EmuHawk's Lua API (not the Lua Console) re: APIHawk Relating to EmuHawk's public .NET API or to the creation of external tools labels Apr 15, 2026
Copy link
Copy Markdown
Member

@YoshiRulz YoshiRulz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this clears everything drawn by other scripts as well, without giving them an opportunity to re-draw.

Does that opportunity not come when the script yields? Scripts can clear in a event.onframestart callback then draw in a yield loop.


public void AddDrawCallback(Action callback) => _displayManager.OnDraw += callback;

public void RemoveDrawCallback(Action callback) => _displayManager.OnDraw -= callback;
Copy link
Copy Markdown
Member

@YoshiRulz YoshiRulz Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApiHawk already has a draw call batching/scoping method, WithSurface.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's completely unrelated. WithSurface(surfaceId, action) is just a wrapper for UseSurface(surfaceId); action(); UseSurface(originalSurfaceId). The new callbacks don't care about which surface is being drawn, it's just a signal to draw.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, I'm saying if you're going to limit draw calls to callbacks, use the callback which already exists and which I've been promoting for this reason.

Copy link
Copy Markdown
Contributor Author

@SuuperW SuuperW Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how WithSurface could be used in a way that is similar to AddDrawCallback.
And if you were to change how WithSurface works, that would be an API change that I think is better done while changing the name, so that existing code will fail at compile time instead of run time. (better yet, have both so existing code keeps working, at least until the old way is deprecated)

EDIT:

if you're going to limit draw calls to callbacks

This PR does not do that. Old Lua scripts should continue to work exactly as they have before.

@SuuperW
Copy link
Copy Markdown
Contributor Author

SuuperW commented Apr 15, 2026

Text written with gui.text (the one for OSD text) is not cleared in between yields, so they will build up indefinitely while paused. (a single script can of course call gui.cleartext but then that interferes with other scripts) Even if the text drawn is identical each time, this will quickly cause the client to lag while paused.

Drawing in yield instead of on frame advance also causes the Lua drawings to flicker, as the game will be rendered once without any Lua drawings before yield gets the chance to draw. You could probably get around this by drawing in the frame end callback, but then you are double-drawing or have to write extra code to avoid that. And even ignoring the flicker, writing a script this way is somewhat more difficult and not an obvious option.

Plus, drawing in a yield loop wastes a bit of CPU while paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

re: APIHawk Relating to EmuHawk's public .NET API or to the creation of external tools re: Lua API/scripting Relating to EmuHawk's Lua API (not the Lua Console)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants