render: Add BlendMode infrastructure and implement BlendMode.ADD
Each render backend keeps track of a stack of BlenModes, which are pushed and popped by 'core' as we render objects in the displaay tree. For now, I've just implemented BlendMode.ADD, which maps directly onto blend mode supported by each backend.
All other blend modes (besides 'NORMAL') will produce a warning when we try to render using them. This may produce a very large amount of log output, but it's simpler than emitting each warning only once, and will help to point developers in the right direction when they get otherwise inexplicable rendering issues (due to a blend mode not being implemented).
The wgpu implementation is by far the most complicated, as we need
to construct a RenderPipeline for each possible
(BlendMode, MaskState). I haven't been able to find any documentation
about the maximum supported number of (simultaneous) WebGPU render
pipelines - if this becomes an issue, we may need to register them
on-demand when a particular blend mode is requested.
Sorry if this is a bit off-topic, but: Welp, I wanted to test this on https://z0r.de/2245, as it is obviously rendering incorrectly at the moment, and I thought it was because of the missing blend modes. However, even with this PR, it appears exactly the same as before, and I don't even get any warnings about blend modes.
So, it could be simply the result of the self-overlapping, partially transparent shape being drawn on top of itself due to the tessellation. I suppose this could be solved by rendering the whole shape fully opaquely into a "layer" first, then drawing that with uniform transparency - or, what might be simpler, if possible at all, to ask lyon to remove the overlaps, and "flatten" the shape during tessellation, so it's not drawn on top of itself?
EDIT: Seems like this is a known limitation of lyon: https://nical.github.io/lyon-doc/lyon/tessellation/path_stroke/index.html#overview
So, it could be simply the result of the self-overlapping, partially transparent shape being drawn on top of itself due to the tessellation. I suppose this could be solved by rendering the whole shape fully opaquely into a "layer" first, then drawing that with uniform transparency - or, what might be simpler, if possible at all, to ask
lyonto remove the overlaps, and "flatten" the shape during tessellation, so it's not drawn on top of itself?EDIT: Seems like this is a known limitation of
lyon: https://nical.github.io/lyon-doc/lyon/tessellation/path_stroke/index.html#overview
Yep, this SWF uses 200 width transparent strokes which lyon doesn't tessellate in a nice way for us. I think we could work around it using stencil or depth to avoid overdraw when rendering these kinds of strokes.
Hooked this up for SWF PlaceObject tags, AVM1, and AVM2.
One slightly annoying thing is that I'd like to implement FromWStr for BlendMode, but the orphan rules prevent this -- could add an ruffle_wstr dep to swf, or simply add a blend_mode_to_wstr function in core somewhere.