Hit-test-only masks
Basically, this is for the case where you want the hit-testing feature of masks, but don't need their graphical effect. This avoids their VRAM cost, as well as batch-breaking that results from the change in mask texture.
Furthermore, if your display object uses a bitmap you can have it sample that directly, and never load an actual mask asset.
On at least some platforms, there are performance costs when computing a loaded mask's grayscale values (future PR), but of course if you skip the load altogether you'll only pay for the bitmap, which you're already doing.
This came up while @mark-sgs and I were testing some stuff on the experimental build—since it flushed out some performance issues at scale—although this PR is independent of said build.
--
This adds two new functions:
mask = graphics.newHitTestOnlyMask( filename[, baseDir] )
mask = graphics.newHitTestOnlyMaskFromPaint( [opts] )
The first one loads from a file as usual, but has no GPU presence. The latter will pick up the display object's image or bitmap paint instead.
At the moment there are no actual opts. I thought small non-0 alphas might be a problem, so this was available for threshold tuning, but so far that hasn't been an issue.
Support for image sheets would be an obvious future improvement / need, but bitmaps are already useful.
--
Here's my test:
You can set TestMaskFromPaint to true to do a bitmap-based test, else use a mask file.
In the former case the background will blink if you touch it and not the little image. In either test you'll get a printout of the touch phase when clicking on the image.
Hello! I merged this pull request and found some weird results. It blinks when entering or leaving the screen when the image scaled up. Here is the test code: test_mask_thing.zip Here is the screen recording: https://github.com/user-attachments/assets/d010666f-2a38-49e7-babb-8028d2242d74 I test it in both MacOS and Window simulator.
@zero-meta It's been a while since I've touched this, but maybe I can take a look in a couple days. Is the scaled-up image also getting clipped too early?
Strangely, I was actually thinking about this PR, in light of #751 and #760.
I mentioned in DMs (April 10, 2023) to @Shchvova that "Apparently (this PR) has SIGBUS errors on SOME Android devices. I have a feeling it's the bool * being unaligned but was hoping to use this sanitizer to grind it out.".
This commit (not sure if any others) was an attempt to work around that, but is rather convoluted and I wonder if just memcpy()ing to onlyForHitTests (as a pointer) would have sufficed.
(Looks like that's ed674ef in the local list.)
Probably the filename encoding (earlier stuff) is also iffy. I remember trying to work around some quirk in the interface, but the details escape me, unfortunately. Possibly just not wanting to add more members to BitmapPaint for some immediately-consumed value, if it could be helped?
Anyhow, I doubt they're related to the issue in the video, but these are things I never found satisfying.
Thanks for replying! After some testing, I believe it's unnecessary to update a DisplayObject's bounds when the mask is "OnlyForHitTests". I think this is the reason why a 512x512 image, loaded into 1024x1024 by "display.newImageRect", is getting clipped too early when leaving the screen.
local fall = display.newImageRect("fallx2.png", 1024, 1024)
local mask = graphics.newHitTestOnlyMaskFromPaint()
fall:setMask(mask)
I haven't tested on enough Android devices, and haven't encountered "SIGBUS errors" yet.