Post subject: Lua function request: External drawing canvas
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
CANVASOBJECT SomeFamily.newCanvas(integer SizeX, integer SizeY, [color_spec InitialColor]) Perhaps the SomeFamily may be forms, but I don't know the best fit. The function should spawn a new window large enough to contain the drawing area (which means figuring out some way to decide how large the window itself needs to be, based on the boarder size of the scheme). The drawing area will simply be a rectangle of color InitialColor, or straight black if that parameter isn't provided. The function should return an object. Not a handle number like with form calls, an actual object that can be indexed like a table. A list of indices this object should have: CANVASOBJECT.open -- Boolean value that becomes false if window is closed CANVASOBJECT.onClose -- Starts nil; Can be assigned a function to call when window is closed CANVASOBJECT.autoClear -- Starts false; If assigned true, clears canvas every frame CANVASOBJECT.InitialColor -- Used for clearGraphics; Alpha should be ignored CANVASOBJECT:clearGraphics CANVASOBJECT:draw<various> -- I expect all related gui functions here A call to CANVASOBJECT:drawRectangle should have an effect virtually identical to the similarly named gui.drawRectangle, except that the target area would be this canvas we created earlier. Extrapolate this example with other such draw functions. If you're confused as to the use of this CANVASOBJECT, I will provide a sample code:
Language: lua

local MyCanvas = SomeFamily.newCanvas(200,200) MyCanvas.autoClear = true while MyCanvas.open do MyCanvas:drawText(0,0,"Hello World") MyCanvas:drawBox(10,30,190,190,0xFFFFFFFF,0xFF0000FF) MyCanvas:drawText(12,32,memory.read_s8(0x0080)) emu.frameadvance() end
In case it is necessary for those who don't know lua syntax, SomeTable:FunctionCall(x,y,z) is the same as SomeTable.FunctionCall(SomeTable,x,y,z) -- Note the colon or period. This will allow a way for the attached function to identify the object in question. Although, generating a new function that "already knows" when spawning multiple canvas objects would mean we don't need the colon, but it might be best to have the identifier. If such a function already exists, please point me to such function, since I missed it while looking through the functions list.
mz
Emulator Coder, Player (79)
Joined: 10/26/2007
Posts: 693
Yes, I would love to have something like this. I've been wanting to modify emulators to add canvas with sizes bigger than the native resolutions, for example for doing things similar to Atlas Videos, but in real time. If I had more screen state for games like Metroid II, I think I would enjoy them more. My idea was just to have a simple function like ResizeCanvas(width, height) that one would put at the start of the script, but your idea would work too for this (provided that you can hide the main window or put the new canvas in full screen.) There are a lot of things that one could do to improve old games with Lua if emulators had more screen space. :D
You're just fucking stupid, everyone hates you, sorry to tell you the truth. no one likes you, you're someone pretentious and TASes only to be on speed game, but don't have any hope, you won't get there.
Pokota
He/Him
Joined: 2/5/2014
Posts: 779
I can get behind this idea for the reasons stated already. I'd love to be able to do a self-updating party stats block for Pokemon games (like as seen in the alternate encode for the current Fire Red run, as well as in recent visits to TPP) but there just isn't enough screen real estate to do it sanely.
Adventures in Lua When did I get a vest?
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
lsnes has gui.<class>_gap(number gap) (more specifically, gui.left_gap, gui.right_gap, gui.top_gap, and gui.bottom_gap) that can be experimented with. A replication of this set of functions is another useful request, but a separate one. The gap functions add some extra drawing space off to the specified side. I have a write-up of it somewhere in this tutorial. (I really need to get back into playing with lsnes lua some more, one of these days) lsnes also allows one to pick a custom font by selecting a file. Generate a font file that matches what the game uses, and you can use a style consistent with the game, too! I could always post a topic of my complaints with lua as implemented in BizHawk, with all my criticisms as well, and I'm considering posting my write-up for gui.drawText. There's a bit of work that can be done to make it closer to the ideal stuff I see, I would say.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
Just so you know, I think all that lua stuff is very nearly half-assed to just to get the bulk of the needs out of the way and crudely compatible with several other older emulators which predate lsnes innovations. A document written up from the point of view of criticising the "design" won't make any sense and maybe won't even be read. Write it up from the point of view of actually designing it as heres-how-it-should-ideally-be. In other words, none of the stuff is "designed" the way it is because anyone particularly wants it that way, it's how it is because that's what was easiest and we have a million other things to do and there is an ordering to the technical dependencies for superior lua drawing which must be satisfied or else effort is wasted. So you might write 1000 things to which the reply to all of them is "of COURSE, eventually"
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
As an alternative idea, you could try to play around with the iup module. I believe they have some module for canvas drawing in an external window. http://webserver2.tecgraf.puc-rio.br/iup/ http://webserver2.tecgraf.puc-rio.br/iup/en/download_tips.html (canvas is CD) http://webserver2.tecgraf.puc-rio.br/iup/en/elem/iupcanvas.html http://webserver2.tecgraf.puc-rio.br/cd/ I managed to run some of these lib a while ago in both FCEU and PCSX-rr. Though, a special workaround is required in order to load the iup module. If I remember right, this involved loading a dll at the start of the luascript, but in the end it worked just fine. Yet, I doubt it works well with bizhawk(well.. at the moment), since this workaround did only work with a LuaEngine base like fceu, but I guess it's still worth investigating.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
zeromus: Fair enough. BizHawk is mostly trying to advance in getting the best in emulation into a single TASing platform (my impressions), which left various features underdeveloped as of this time. There's a lot of things about BizHawk's lua that frustrates me, as even the emulua in non-lsnes emulators seem to be superior in a few aspects than BizHawk. I'll downsize my complaints: Why the distinction of signed/unsigned memory writes? Why isn't the complete memory map (BUS?) the default memory region? Why does gui.drawText have no background color? There probably isn't need to go into detail as of this moment, unless someone is actively rewriting the lua implementation, but it feels like I need some trial and error workaround just to have consistently readable text displayed. In any case, lua's a mess, you got the point, my complaints aren't going to speed things up, so just wait, or if I have the time, see if I can fix it myself. Apologies for any annoyance, I do rather want to stay quiet until work elsewhere is finished and there is time set aside to work on the lua back end. Just that I believe an idea I have will more likely remain existing if I post it somewhere public rather than keeping it with me until I forgot it completely.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
1. I think it's for orthogonality with signed/unsigned memory reads, which is an imperative issue. Is there a scenario where it actually matters? As far as I can tell, if it ever matters, then that may be a bug. 2. Because you cant always get what you want as the default, and some other people think other defaults are better 3. because nobody asked hard enough for it and/or maybe it isn't easy in GDI+ I'm not seeing a mess here, but I'm not saying there isnt one. Your complaints serve to get specific issues fixed. Your general complaints that it's a mess accomplish nothing. I dont think anybody put their stamp on it and said BEST LUA EVAR. DONE.
Pokota
He/Him
Joined: 2/5/2014
Posts: 779
I would say leave the signed/unsigned writes in place for those who want them - even though the game won't see the difference, I want to say it's easier to spot bad input if we know to expect a small negative and get someone trying to put in a large positive instead.
Adventures in Lua When did I get a vest?
Editor, Expert player (2073)
Joined: 6/15/2005
Posts: 3282
Pokota wrote:
I can get behind this idea for the reasons stated already. I'd love to be able to do a self-updating party stats block for Pokemon games (like as seen in the alternate encode for the current Fire Red run, as well as in recent visits to TPP) but there just isn't enough screen real estate to do it sanely.
I've been playing around with Lua lately so I'll share my thoughts. From the standpoint of just getting the information necessary to do a TAS, there is no need for an elaborate setup; having the information in clear-cut text is all that is needed. In fact, the function gui.text is perfectly capable of writing text outside the canvas, limited only by the emulator's window, and it is even neater than gui.drawText since it uses the OSD font and doesn't rely on graphical hacks to be drawn on the canvas. From the standpoint of making actual display encodes for the audience, then a definable canvas feature would definitely be welcome; however, you can still make display encodes without it. First, video dump the movie itself, and then draw as much as you can put on the canvas itself (to start, you can draw a black box over the canvas) and dump the movie again with Capture OSD checked. Repeat until you have everything you need for the display encode; then put it all together using Avisynth. By the way, video dumping with Capture OSD dumps exactly what is shown in the BizHawk window (OSD messages and everything including window resolution). So, don't resize the window during dumping. You can't minimize the window either, since minimizing the window or resizing it to width or height 0 causes video dumping to crash.
FatRatKnight wrote:
Why the distinction of signed/unsigned memory writes?
Out of pragmatism, most likely. I just want to point out that the important part of coding is how things are understood and used, as long as our understanding of them is correct. And as far as I tested, the memory.write functions all work the way we understand them. That being said, you can use the unsigned memory writes to write signed integers (or any integers for that matter) if you wish, and it will simply take mod 2^8 (or 2^16, 2^24, 2^32) if you are outside its stated range. I warn though that it is very easy to fall into Lua pitfalls if you rely on going outside of stated ranges too much. For example, numbers above 0xFFFFFFFF can never be represented in Lua using 0x notation; Lua will without fail set it back to 0xFFFFFFFF. Also, even if you don't do that, Lua will corrupt integers greater than 2^53, since every number in Lua is stored as a 64-bit double float (this means for example that bit.byteswap_64 is inherently flawed). On that note, I recommend not playing with numbers greater than 0xFFFFFFFF in absolute value, because Lua itself seems to have a hard time beyond the 32-bit level and things don't work as expected. For example, string.format, while useful for stuff like displaying hex and zero filling (such as string.format("%08X",number) ), has problems if numbers are too large.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
zeromus: I said "it's a mess" specifically because I do not wish to get into details right now. If you prefer, I can post my full write-up for gui.drawText, and that does get into specific issues I crash into, or I can further explain the details of one of the three questions I fired off (which I'm already doing now for one of them, later in this post). After that, we can come to a discussion on the specific points and ask whether anyone else has similar feelings.
FractalFusion wrote:
FatRatKnight wrote:
Why the distinction of signed/unsigned memory writes?
Out of pragmatism, most likely. I just want to point out that the important part of coding is how things are understood and used, as long as our understanding of them is correct. And as far as I tested, the memory.write functions all work the way we understand them.
The existence of separate signed/unsigned memory.write functions was enough to confuse me as to their meaning. In fact, my initial belief would be that they would throw a lua error should you go out of range, in order to give a proper distinction between the two sets of functions. I now see this initial belief has me off track. If there is no difference between the two sets, other than name, then by splitting off two sets, an unintended meaning gets injected into something that can already handle the full scope of possible numbers. Without explicitly stating signed or unsigned, and simply having a merged name that indicates neither, this would be more likely to pass the message that this function can handle numbers of any range. I don't know how correct I am in this line of thinking, but I do know I was mislead myself, and am curious how others may have reacted to the "trap" I came across.
FractalFusion wrote:
For example, numbers above 0xFFFFFFFF can never be represented in Lua using 0x notation; Lua will without fail set it back to 0xFFFFFFFF. [...]
lsnes lua is capable of going higher. It's less of a limitation of lua as a language, and more down to implementation. I will note that 0xFFFFFFFF is the limit that most emu lua implementations have, but 0x100000000 should work as intended in lsnes. I'm aware of double-precision floating point limitations, as well. I have crashed into them trying to calculate RNG values, and decided the solution was to split up the 32-bit*32-bit calculations into a pair of 16-bit*32-bit calculations. I've also noted in several instances where bit functions like bit.band would return 0x80000000 as a negative value. In praise of BizHawk, I must state, I'm getting back a positive value with such a large value, so no complaints in that instance. In one case I recall (VBA?), memory.readdword would actually return a signed value, something advertised as something only memory.readdwordsigned should do. In fact, memory.readdwordunsigned still returned a signed value. That lua just refused to have functions that dealt with anything other than 32-bit signed values. The straight math operators still treated those numbers as double-precision floating point just fine, but once a function was involved, 32-bit signed was your limit.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
lsnes uses a newer lua. it may be a limitation of lua as a language (version). if you run into actual bugs in _bizhawk_ and not vba, let us know.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
Then I am mistaken, again. The number limitation of older lua versions would be news to me. I have no actual bugs to report as of this time. I see there isn't a need to redesign the lua at this time, as there are other issues to work on, and the lua does work. I may be upset about some things myself, but the lua can still display information. I do get frustrated with it, then pass time elsewhere until my frustrations go away, which slows down the rate I code things up for TASing purposes. Perhaps I became rather vocal about it due to this process, but I need to focus more on workarounds I have available. I'm happy to continue any discussion with anyone, though. Any information worked out can still be referenced in the future.
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
Ok, I did a couple of trial and error with IUP and the result look pretty good so far: Demo Basically this is a minimap using x,y position. How to run it? Currently, my script can be downloaded on GitHub Extract all the dll and dk_canvas.lua in your bizhawk folder*. Start a game(e.g. Donkey Kong(JU) for GB). Obviously, you may experiment some lag if try to listen the music, this is due to Lua lacking a multithread feature. So I get around this issue with a timer to schedule the task using the best way that I figured. The script run well, enjoy. You can read the script here(further modification may come later). *You can also get the dll on sourceforge. edit: Fixed release link
Post subject: Re: Lua function request: External drawing canvas
Player (146)
Joined: 7/16/2009
Posts: 686
FatRatKnight wrote:
The function should return an object. Not a handle number like with form calls, an actual object that can be indexed like a table.
I understand that this might be more convenient, but is that really such a hard demand for you? Otherwise, implementing some functionality for the form-component PictureBox would make most of what you want to do possible.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
I don't know enough details about PictureBox, but as far as I know, it takes an image rather than something that can be drawn on. I'm probably incorrect here, so I'll request the details you may know of how one should deal with PictureBox. It's not a hard requirement that it must be an object, but as long as its possible to have an external canvas of some sort, and a usable interface to work with it, my only complaint would be I'm using a handle number rather than an object, which is small compared to having no access to an external drawing surface. I'm suggesting what is ideal for me, which isn't necessarily something that must absolutely be this, so I'd like to know if there are some details that are very difficult to implement. Keep in mind I'm requesting a set of functions that can draw on it like the main window already has, and differentiating between a handle number or a position number to overload the current gui functions is unwieldy, to say the least. A copy of gui functions would also add to the difficulty of maintaining them later.
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
FatRatKnight wrote:
I need to focus more on workarounds I have available.
Maybe I missed something, but what about using a third party library in Lua? (*) That being said, I'm sure it would a lot more convenient to get everything packaged in Bizhawk out of the box, but I'll rather see the dev refactor what need to be changed(or working on the other platform core), before building new stuff on a somewhat unstable and undocumented base(yet innovative). Well at least, that's my impression when reading what zeromus said.
Editor, Skilled player (1202)
Joined: 9/27/2008
Posts: 1085
I, uh... Completely missed that post. third party lua extensions seem like an interesting possibility. Does get the workload off of the devs while still getting something somewhat close. Your sample is appreciated, as well. ... I don't have much specifics to really say, since I still haven't explore the links you've shown, as I was off doing other things, but once I get the time to look at what you did, I may have more to say. I believe a reply now should give comfort of acknowledgement, at least.
Joined: 1/26/2009
Posts: 558
Location: Canada - Québec
Thank you, I was actually surprise to get iup working on bizhawk. At this point, I don't see why the script wouldn't work on other emulator as well. Also, look like I didn't really bother to explain what's happening in the script or adding any meaningful comments, but basically you'll notice the key idea is to get some sort of "refresh" while being single-threaded. So using simple enter/exit of `MainLoopLevel` function continually in the timer does the job. Any action that may require some sort refresh should called in `idle_cb`. Thought, if you want to call frameadvance(), I'll suggest to put it in the timer. Now, there's other alternative idea which could be worth exploring if you dislike the iup api or any other reason. For instance, you could give the love2d library a try. I saw an interesting post about the ability to run the lib from a console, so maybe it's possible to run some function from an emulator and do a similar sync/refresh setup, but that's yet an another subject to investigation for those interested.
Site Admin, Skilled player (1254)
Joined: 4/17/2010
Posts: 11478
Location: Lake Char­gogg­a­gogg­man­chaugg­a­gogg­chau­bun­a­gung­a­maugg
Warning: When making decisions, I try to collect as much data as possible before actually deciding. I try to abstract away and see the principles behind real world events and people's opinions. I try to generalize them and turn into something clear and reusable. I hate depending on unpredictable and having to make lottery guesses. Any problem can be solved by systems thinking and acting.
Editor, Emulator Coder
Joined: 8/7/2008
Posts: 1156
Yeah, it's possible that if someone hooks up the lua, the canvas extension will automatically work. However, it's tricky, and I can't promise it will be bug-free or even kept in the long run, if it's too problematical. Basically in r9262 I changed it to work like the r9261 notes suggested: the emulator output is extended by the specified padding (using what color????) before proceeding further into the display pipeline, which is in turn before lua gets access to it. So then lua has some (what color?????) space to draw on. What color???? is probably black, but I don't know. Let's see how it works first.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
zeromus wrote:
What color???? is probably black
Just... make it an option? (if possible)