Page 1 of 1
SetAlwaysRedrawEntireCanvas()
Posted: Sat Oct 19, 2024 4:39 pm
by ColinP
Has anyone tried using the new VoltageCanvas method SetAlwaysRedrawEntireCanvas() introduced in VM 2.9.2?
My hope was that this might address the inefficiencies I highlighted in the following post...
viewtopic.php?p=14111&hilit=invalidate#p14111
But when I call SetAlwaysRedrawEntireCanvas( true ) on a canvas it turns the canvas into a black rectangle.
Re: SetAlwaysRedrawEntireCanvas()
Posted: Sun Oct 20, 2024 3:52 am
by Aarnville
I haven't tried it but I did note that it had been added. About two years ago I shelved a couple of projects because the canvas was causing me so much grief. The amount of time it was taking up was just too much so I had a crisis meeting with my team (aka myself) and the entire team agreed that we should move on to developing more enjoyable modules. Your post has done nothing to persuade me to revisit that shelf. In the case of VM Module development, when the going gets tough, I change tack!
Re: SetAlwaysRedrawEntireCanvas()
Posted: Sun Oct 20, 2024 11:09 am
by ColinP
You are a wiser person than I. Unfortunately as a combination of bloody-mindedness and having already invested so much time in trying to bend VM to my will I've continued down the VoltageCanvas rabbit hole.
In Adroit Custom I need to be able to bypass the standard components to dynamically render to the entire module in a flexible and thread-safe manner.
So I've encapsulated or replaced virtually all of CA's code to build an idealized/simulated "to the metal" interface where almost all rendering is to a standard Java BufferedImage that has dimensions that are twice the width and height of the module (so that zooming doesn't result in pixelation).
The "hidden" implementation behind this uses two VoltageCanvas objects, one small one at the top of the module that ignores mouse notifications so that a module can be dragged around and will pop-up the standard context menu in response to a right click and a larger canvas below that accepts mouse notifications so that my replacements for VoltageComponents can operate
Getting this to work wasn't easy. Unfortunately, invalidation doesn't behave as one would expect. If several invalidations occur rapidly then instead of a union of the clip rectangle being built or all invalidations being eventually returned as discrete repaint events, some information is simply discarded by VM's event handling - resulting in parts of the display being corrupted. This means I have to try and coalesce repaint notifications and then blit the entire buffer to the canvases. Various levels of caching mean that this generally works at acceptable levels of performance but in certain situations the UI thread overloads. Fortunately, this doesn't seem to impact the main ProcessSample() thread so even though graphical animation can stall the audio keeps working.
But VoltageCanvas is a gift that keeps on giving. In VM 2.9.2 VoltageCanvas SetWantsMouseNotifications( false ) no longer works so now all mouse events are always absorbed by the canvas. This means that it's no longer possible to drag a module or launch the context menu if a module is entirely covered with one or more canvases.
Thankfully, the bug doesn't surface with a VoltageImage object. However you can't invalidate VoltageImage objects nor get a graphical context for them. So to workaround this problem I have a VoltageImage object that ignores mouse events behind (in the Z-order) an invisible VoltageCanvas object that absorbs all mouse events (but only when it's visible). On beginning a virtual invalidation I make the invisible canvas visible and invalidate it. Then in the repaint notification handler I copy the area from the idealized BufferedImage mentioned earlier to the canvas via its graphical context (this avoids flicker), copy the same area to another BufferedImage, convert this into the memory image of a PNG file, then tell the VoltageImage object to use the PNG data as the first and only frame of its "animation" (so that the VoltageImage looks identical to the canvas), then importantly I make the canvas object invisible again so that subsequent mouse events are no longer absorbed by the canvas but transmitted via the VoltageImage object to the VoltageModule code so that dragging and the context menu work again. It's incredibly inefficient but only applies to the small area at the top of the module so I can get away with it.