ID:2697628
 
Resolved
If an object was transformed using anything but translation matrices, and then used as a render source for an alpha mask filter, the filter positioned the mask incorrectly.
BYOND Version:514.1557
Operating System:Windows 10 Home 64-bit
Web Browser:Firefox 78.0
Applies to:Dream Seeker
Status: Resolved (514.1558)

This issue has been resolved.
Descriptive Problem Summary:
When using a render target consisting of an atom with KEEP_TOGETHER set and transformed overlays as the render source for an alpha mask filter, the filter is centered in the wrong location.

Numbered Steps to Reproduce Problem:

1. Apply non-identity transforms to one or more images
2. Add those images as overlays to an atom with KEEP_TOGETHER set in appearance_flags
3. Set render_target as a non-empty string for that atom
4. Apply an alpha mask filter using the render_target value set for the aforementioned atom as the render_source for the filter

Code Snippet (if applicable) to Reproduce Problem:
/*
Tweaks to make to this code before compiling:
- slate, offset_filter, and not_offset_filter should be placed on turfs where they are all visible
- overlay, offset_filter, and not_offset_filter should each have an icon and icon_state. For ease of noticing the problem, offset_filter and not_offset_filter should use the same icon/icon_state
- slate does not need an icon or icon_state
*/

var/obj/slate = new()
slate.icon = null
slate.icon_state = null
slate.appearance_flags = KEEP_TOGETHER
slate.render_target = "*foo"
var/image/overlay = image()
var/matrix/overlay_transform = overlay.transform
overlay_transform.Scale(2, 0.5)
overlay_transform.Turn(45)
overlay_transform.Translate(16, 16)
overlay.transform = overlay_transform
slate.overlays += overlay
var/obj/offset_filter = new()
offset_filter.icon = null
offset_filter.icon_state = null
offset_filter.filters += filter(type="alpha", render_source = "*foo", flags = MASK_INVERSE) //MASK_INVERSE is set to make noticing the problem easier.
var/obj/not_offset_filter = new()
not_offset_filter.icon = null
not_offset_filter.icon_state = null
not_offset_filter.filters += filter(type="layer", render_source = "*foo")


Expected Results:
The area masked by the alpha mask filter on the first object should be the same as the area covered by the layering filter on the second object.

Actual Results:
The alpha mask filter is offset, causing the alpha mask filter to mask a different area than the one covered by the layering filter.

When does the problem NOT occur?
- When the render source has no overlays.
- When no transform has been applied to any of the render source's overlays.

Workarounds:
Theoretically, it should be possibly to calculate how much the alpha mask is offset in each dimension and use the calculated value to accordingly adjust the x and y values of the filter, but I have not been able to identify a formula that accounts for the offset in all cases.

Versions tested:
I originally ran into this problem on 513.1542, but I tried switching to 154.1557 to see if the problem was incidentally fixed as part of the general alpha mask filter fixes. As you can tell by the specified version, it wasn't.
I'm gonna need a test project for this to make sure I'm on the same page.
Here's a zip with a demo project I whipped up to demonstrate the issue. https://drive.google.com/file/d/ 1_82pgbUrLDEbLlmxx4SjXbhdaD7v00FU/view?usp=sharing

UPDATE: After some experimentation, I discovered that the issue is not limited to transformed overlays on render targets. The problem manifests even if the render target has no overlays, but has a non-identity transform applied to it.

Expected result is for the alpha mask filter and the layering filter to move identically, but the observed result is the alpha mask filter moving around chaotically.

Link to updated demo project: https://drive.google.com/file/d/ 1SeIGTUWMyyOXDq8DLrJtewsDWpr1qVMJ/view?usp=sharing
Lummox JR resolved issue with message:
If an object was transformed using anything but translation matrices, and then used as a render source for an alpha mask filter, the filter positioned the mask incorrectly.