haxeui / haxeui-kha

The Kha backend of the HaxeUI framework -
http://haxeui.org
MIT License
45 stars 16 forks source link

flickering button texture #51

Closed sh-dave closed 3 years ago

sh-dave commented 3 years ago

See the sample code here: https://github.com/sh-dave/haxeui-kha-testsuite/blob/master/src/kenneyButtonFlicker/Main.hx

Expected Behavior

Current Behavior

Steps to Reproduce (for bugs)

  1. Clone the haxeui-kha-testsuite and open in vscode with the Kha Extension Pack installed
  2. Edit the khafile.js and uncomment the line // suite.addParameter('--main kenneyButtonFlicker.Main'); to pull in the proper Main function, comment out any other that might be active.

Media

link

Your Environment

ianharrigan commented 3 years ago

This is an interesting one, i can defo reproduce... any thoughts / hints on how i might get around this? All im doing in the backend is g.drawScaledSubImage and the image should be loaded and available - so im not sure why there is a flicker at all...

ianharrigan commented 3 years ago

So this is really confusing, i just tried (to test) to create an Image and draw the parts to that:

                    var img:Image = Image.create(Std.int(w), Std.int(h));
                    for (i in 0...srcRects.length) {
                        var srcRect = new Rectangle(srcRects[i].left + trc.left,
                                                    srcRects[i].top + trc.top,
                                                    srcRects[i].width,
                                                    srcRects[i].height);
                        var dstRect = dstRects[i];
                        /*
                        g.drawScaledSubImage(imageInfo.data, srcRect.left, srcRect.top, srcRect.width, srcRect.height,
                                                             x + dstRect.left, y + dstRect.top, dstRect.width, dstRect.height);
                                                             */
                        img.g2.drawScaledSubImage(imageInfo.data, srcRect.left, srcRect.top, srcRect.width, srcRect.height,
                                                             x + dstRect.left, y + dstRect.top, dstRect.width, dstRect.height);
                    }

Whats strange is i never use that img later, but it still appears! I would have expected it to not appear, so maybe this is a hint of whats going on? Ie, creating the Image shows it?? Im a little confused to be honest.

sh-dave commented 3 years ago

In your example, you should create the image via Image.createRenderTarget(). You're also missing the begin/end around the img.g2.drawScaledSubImage() call.

var img: Image = Image.createRenderTarget(Std.int(w), Std.int(h));
img.g2.begin();

for loop...

img.g2.end()
ianharrigan commented 3 years ago

I've tried these:

                    var img:Image = Image.createRenderTarget(Std.int(w), Std.int(h));
                    //img.g2.begin();                                     
                    for (i in 0...srcRects.length) {
                        var srcRect = new Rectangle(srcRects[i].left + trc.left,
                                                    srcRects[i].top + trc.top,
                                                    srcRects[i].width,
                                                    srcRects[i].height);
                        var dstRect = dstRects[i];
                        /*
                        g.drawScaledSubImage(imageInfo.data, srcRect.left, srcRect.top, srcRect.width, srcRect.height,
                                                             x + dstRect.left, y + dstRect.top, dstRect.width, dstRect.height);
                                                             */
                        img.g2.begin(); 
                        img.g2.drawScaledSubImage(imageInfo.data, srcRect.left, srcRect.top, srcRect.width, srcRect.height,
                                                             x + dstRect.left, y + dstRect.top, dstRect.width, dstRect.height);
                        img.g2.end();                                     
                    }
                    //img.g2.end();                                     

But i keep getting "End before you begin"

sh-dave commented 3 years ago

I think the problem might be in the async logic in StyleHelper.hx. You expect the getImage() callback to return immediately, but that won't happen for unloaded resources.

if (style.backgroundImage != null) {
        // i added a trace here
    Toolkit.assets.getImage(style.backgroundImage, function(imageInfo:ImageInfo) {
        ...
                // i added a trace
                var rects:Slice9Rects = Slice9.buildRects(w, h, trc.width, trc.height, slice);
                ...
    });
}

I added some traces to verify (the number is the frame the function is called).

kenneyButtonFlicker/Main.hx:30: 48
haxe/ui/backend/kha/StyleHelper.hx:78: 48
haxe/ui/backend/kha/StyleHelper.hx:114: 48
kenneyButtonFlicker/Main.hx:30: 49
haxe/ui/backend/kha/StyleHelper.hx:78: 49
haxe/ui/backend/kha/StyleHelper.hx:114: 49
haxe/ui/components/Button.hx:404: 49
kenneyButtonFlicker/Main.hx:30: 50
haxe/ui/backend/kha/StyleHelper.hx:78: 50
haxe/ui/ToolkitAssets.hx:87: 50
haxe/ui/backend/AssetsImpl.hx:47: 50
haxe/ui/backend/AssetsImpl.hx:68: 50
kha/Image.hx:94: 50
kha/Image.hx:96: 50
haxe/ui/backend/AssetsImpl.hx:70: 50
haxe/ui/backend/AssetsImpl.hx:50: 50
haxe/ui/backend/kha/StyleHelper.hx:114: 50
kenneyButtonFlicker/Main.hx:30: 51
haxe/ui/backend/kha/StyleHelper.hx:78: 51
haxe/ui/backend/kha/StyleHelper.hx:114: 51
kenneyButtonFlicker/Main.hx:30: 52
haxe/ui/backend/kha/StyleHelper.hx:78: 52
haxe/ui/backend/kha/StyleHelper.hx:114: 52
kenneyButtonFlicker/Main.hx:30: 53
haxe/ui/backend/kha/StyleHelper.hx:78: 53
haxe/ui/backend/kha/StyleHelper.hx:114: 53
kenneyButtonFlicker/Main.hx:30: 54
ianharrigan commented 3 years ago

OK, so that should be fixed now... feels a little icky / hacky... lemme know what you think...

Cheers, Ian

sh-dave commented 3 years ago

I've seen way worse hacks :smiley: