Kode / Kha

Ultra-portable, high performance, open source multimedia framework.
http://kha.tech
zlib License
1.49k stars 173 forks source link

Image.unlock() doesn't update Image.at() results #1437

Closed RobDangerous closed 1 year ago

RobDangerous commented 1 year ago

Discussed in https://github.com/Kode/Kha/discussions/1436

Originally posted by **dewitters** October 25, 2022 I'm a happy Kha user for many years, but now I ran into a problem that I'm not able to quickly fix or work around. On the HTML5 target there is the following problem: when calling Image.lock() and Image.unlock() to update the image pixels, it all works fine visually. However, Image.at(x,y) still uses the old values. My overall intention is to replace one image from a texture atlas with another one (with lock() and unlock()), but at() still needs to work on that since I use that to detect if a user clicks on a sprite or not. I'm not well versed in WebGL (hence the use of Kha ;)), so I was hoping any of you here knows how to fix it or a workaround would also be fine. Thanks! :)
RobDangerous commented 1 year ago

Hey @dewitters, please give https://github.com/Kode/Kha/commit/5c27cd716f309c9fb34d8c851a9d394ba5c9f2f8 a try. The situation is kind of complex with all the different ways an image can be created so I'm not sure it's fixed for you yet.

dewitters commented 1 year ago

@RobDangerous having some different issues now so going to investigate further. I'll let you know when I know more. Thanks for spending time on this :+1:

RobDangerous commented 1 year ago

Okidoki. If there's more problems with it what helps me most would be a small piece of sample-code that reproduces the problem.

dewitters commented 1 year ago

I was able to make it work on my end, but I'm not sure this is the code you want.

First up the if (bytes != null) { in at() I replaced with if (bytes != null && image == null) {. This because I first do lock(), then I make a few calls to at() to copy over some pixels, and then I do unlock(). If this extra check is missing I go straight to empty bytes when calling at() before an unlock() is done.

In lock() I added a if (bytes == null) { so that bytes are not recreated every time I call lock():

if (bytes == null) {
    bytes = Bytes.alloc(formatByteSize(myFormat) * width * height);
}

And then I just removed the following in unlock():

if (!readable) {
        bytes = null;
}

I'm not sure what this readable is doing, but it's not working ;).

RobDangerous commented 1 year ago

Oh, that's not how the API should be used. Between calling lock/unlock things are in a writable-only state.

dewitters commented 1 year ago

Ok. Then final question about the "readable". How do I put my asset into a readable mode? I search the docs but couldn't find it.

RobDangerous commented 1 year ago

For images from the khafile do something ala project.addAssets('Assets/special-images/', { readable: true }); and the Image.create/from*-functions should have it as their last parameter - but it looks like that's currently only the case for Image.fromEncodedBytes. Will fix that tonight.

dewitters commented 1 year ago

Thanks! I think I can continue from here. Thanks for your help @RobDangerous, top notch work!

dewitters commented 1 year ago

I'm now caching the pixels before I lock() the image, so now it works! :smiley: You can close this issue if you want.

RobDangerous commented 1 year ago

Allrighty! The new readable-parameters are also in now.