Commit Graph

176 Commits

Author SHA1 Message Date
relrelb ef79d556b4 tests: Allow trailing commas in `Matrix` unit tests 2023-04-29 22:29:37 +03:00
relrelb 3046d68da1 swf: Introduce `PointDelta`
Generally, when transforming a difference between two points, `p1`
and `p2`, with a matrix `m`, we would like the following property
to hold:

```
m * (p1 - p2) == m * p1 - m * p2
```

Unfortunately, it wasn't like this before, because matrices have a
translation component, which is non-linear. In `m * p1 - m * p2`,
the translations of `m * p1` and `m * p2` are the same and therefore
cancel out each other. However, in `m * (p1 - p2)` the translation
stays.

In order to preserve this property, introduce a new `PointDelta`
type which is not subject to translation when transformed by a matrix.

For now, the following operations are supported:

* `Point - Point -> PointDelta`
* `Point + PointDelta -> Point`
* `Point += PointDelta`
* `Point - PointDelta -> Point`
* `Point -= PointDelta`

As a consequence, the expression `position + global_to_local_matrix * mouse_delta`
in `update_drag()` now ignores translation, which fixes #817.
2023-04-29 22:29:37 +03:00
relrelb 60ffe07ae7 chore: Use `swf::Point` in many places
Convert nearly all instances of `(Twips, Twips)` (maybe besides in
`shape_utils.rs`) to `swf::Point<Twips>`.
2023-04-27 22:14:03 +03:00
Aaron Hill 962cf92223 avm2: Implement Context3D.setSamplerStateAt
This fixes pixelated backgrounds in Fancy Pants World 4 Part 3
2023-04-05 16:44:07 -07:00
Mike Welsh 792cfd82c7 avm2: Implement `Context3D.setColorMask` 2023-04-05 12:22:13 -07:00
Mike Welsh e07bde884e render: Inline `CommandList` methods 2023-04-04 13:10:45 -07:00
Mike Welsh 7779416894 render: Fix masker-in-masker rendering
Flash does not support nested mask regions and instead merges them
into a single clip region.

For example, this occurs when using a dynamic text field as a mask.
One mask layer contains the glyphs, while the second layer is the
bounds of the text field. The text field bounds end up being
ignored when the text field is used as a mask, allowing the text
outside the bounds to be visible.

Add `CommandList::maskers_in_progress` to keep track of the mask
state and discard drawing commands for inner maskers.

Fixes #9664.
2023-04-04 13:10:45 -07:00
TÖRÖK Attila 2ad43994b8 video: Don't do colorspace conversion in the video backend 2023-04-04 00:15:07 -07:00
TÖRÖK Attila 493971ab8a render: Make RenderBackend::update_texture() take a Bitmap (like register_bitmap()) 2023-04-04 00:15:07 -07:00
TÖRÖK Attila ba43b0930f render: Add Bitmap::to_rgb() 2023-04-04 00:15:07 -07:00
TÖRÖK Attila 5f94476b2a render: Add BitmapFormat::Yuv420p and BitmapFormat::Yuva420p 2023-04-04 00:15:07 -07:00
TÖRÖK Attila 322e17a5ab render: Bitmap::bytes_per_pixel() -> Bitmap::length_for_size() 2023-04-04 00:15:07 -07:00
Aaron Hill a2fa362091 wgpu: Implement double buffering for Context3D
This matches the Context3D docs. Calling 'present' swaps
the buffers.

I wasn't certain if we actually need a double-buffered depth
texture, but I included one just to be safe.
2023-04-02 19:24:23 -07:00
Aaron Hill 671ebdfa8f wgpu: Execute Context3D commands immediately
Now that most of the complicated Context3D methods have been
implemented, we can simplify the overall design. Instead of queueing
up commands and having `present` execute them in a loop, we
can execute each command immediately. The key insight is that
a `RenderPass` is only needed for `DrawTriangles`, so we don't
have to store it in `Context3D` and deal with complicated lifetime
issues.

The old behavior gave us implicit double-buffering behavior,
since nothing would get rendered until a 'present' call.
Now that a 'drawTriangles' call will immediately submit
a draw command, we need to implement actual double buffering.
This is done in the next commit.
2023-04-02 19:24:23 -07:00
Mike Welsh b62040884c core: Make `DisplayObject::global_to_local` fallible
* `global_to_local` returns `None` if the object has zero scale.
 * Adjust AVM `globalToLocal` methods to return the untransformed
   point on failure.
 * Add `DisplayObject::mouse_to_local` to handle AVM `mouseX`
   and `mouseY` coordinates. For zero scale objects, these end up
   returning values based on the twips-to-pixels scale,
   divided by 20.
2023-03-31 16:26:11 -07:00
Mike Welsh 54b7094c16 render: Make `Matrix::inverse` fallible
* Add `Matrix::determinant`.
 * Rename `Matrix::invert` to `inverse`.
 * `Matrix::inverse` return an `Option`, with `None` returned
    for non-invertible matrices.
 * AMV `Matrix::invert` duplicates the code as the behavior is
   different (works in f64 and not twips, etc.)
2023-03-31 16:26:11 -07:00
Nathan Adams c51ba098f6 render: Rename PixelRegion's (min|max)_(x|y) to (x|y)_(min|max) 2023-03-31 16:57:52 +02:00
Nathan Adams 94e5aa8f34 core: Fix calculating dirty area of BitmapData.draw() with rotation 2023-03-31 16:57:52 +02:00
Nathan Adams 78f9bb13d6 render: Fix PixelRegion::for_region_i32 for negative coordinates 2023-03-31 16:57:52 +02:00
Nathan Adams e614265c17 core: Move fill_rect from BitmapData to bitmap_data_operations, fixed a bug when using non-standard values, and added better tests for fill_rect showing the bug 2023-03-31 16:57:52 +02:00
Nathan Adams 311a165149 wgpu: Reintroduce texture promoting; only preassign buffer when the texture is frequently written/&read 2023-03-31 16:57:52 +02:00
Nathan Adams 6e859891af render: Take in dirty region in update_texture, only upload those pixels 2023-03-31 16:57:52 +02:00
Nathan Adams 137593b6a6 render: Extract (u32, u32, u32, u32) to PixelRegion 2023-03-31 16:57:52 +02:00
Nathan Adams e0bd911f2f render: Only copy a possible dirty area for bitmapdata.draw & read 2023-03-31 16:57:52 +02:00
relrelb 236a97bf31 render: Replace `ColorTransform` with `swf::ColorTransform` 2023-03-29 23:27:20 -07:00
relrelb d71617209a render: Remove `RenderBackend::register_glyph_shape`
Use just `RenderBackend::register_shape` instead.
2023-03-30 01:46:04 +03:00
Nathan Adams eb44cc5395 render: Made ShapeHandle an Arc of an internal, droppable mesh 2023-03-23 01:44:27 -07:00
Nathan Adams cc8ac4fde1 render: Remove RenderBackend::replace_shape 2023-03-23 01:44:27 -07:00
Mike Welsh 1d12fc6169 render: Fix types depending on `tessellator` feature 2023-03-22 20:30:39 +01:00
Mike Welsh 2d6d8ea0f4 core: Fix BitmapData.colorTransform
* Pixels with 0 alpha are not affected by color transforms.
 * Color channels should be clamped to the 0-255 range.
 * A color transform with only an alpha multiplier of >1 has no
   effect.
2023-03-19 09:59:13 +01:00
Nathan Adams bc9e1d7c14 swf: Rename HAS_FILL_WINDING_RULE to NON_ZERO_WINDING_RULE 2023-03-18 19:14:08 -07:00
Nathan Adams 6987c81623 render: Respect HAS_FILL_WINDING_RULE 2023-03-18 19:14:08 -07:00
Nathan Adams e7b812c2cd render: Glyphs are assumed to have HAS_FILL_WINDING_RULE 2023-03-18 19:14:08 -07:00
Aaron Hill 1e973af747 avm2: Implement Context3D.setRenderToTexture/setRenderToBackBuffer
In the process, I fixed a bug where we were clearing the depth
and stencil buffers with the incorrect value.

This makes Fancy Pants World 4 Part 1 playable to completion
(though there are still some rendering issues that need
to be fixed).
2023-03-17 20:11:59 -05:00
Aaron Hill 1edcbe438d core: Avoid several BitmapData GPU -> CPU sync
We don't need to perform a sync when getting the width/height,
getting or setting the 'disposed' status, or uploading to
a Context3D texture.

The Context3D change (using `copy_texture_to_texture` instead
of relying on the CPU pixels) has the added advantage of avoiding
a validation error when our source image row length isn't aligned
to `COPY_BYTES_PER_ROW_ALIGNMENT`

This dramatically speeds up the Fancy Pants World 4 loading time
(on a branch with my XML prs merged). Without this change, my
machine spends around 10 seconds on a blank white screen after
clicking 'Play'. With this change, the time spent on that screen
is reduced to around 1-2 seconds.
2023-03-17 04:56:03 -05:00
Aaron Hill 53c6011ade render: Support more Context3D texture formats
None of these formats can currently be implemented
correctly with wgpu, so we just use Rgba8Unorm instead.

The handling of opaque compressed textures is a little
sketchy - it should work for 'normal' SWFs that upload
an opaque BitmapData, but we might need to manually
adjust the alpha values if
2023-03-16 17:40:41 -05:00
Aaron Hill acbc802c94 avm2: Fix VertexBuffer3D.uploadDataFromByteArray size calculation
We were ignoreing 'data32PerVertex'.
To make the code clearer, I've renamed the variable to
'data32_per_vertex', and made it a 'u8' (as it has a maximum of 64)
2023-03-15 19:52:09 -05:00
Aaron Hill fea885f3af render: Implement Context3DTextureFormat.BGRA using an RGBA texture
Webgl doesn't support BGRA textures, so this lets us use
Stage3D textures on the web backend. As a bonus, this speeds up
uploading an BitmapData to a Context3dTextureFormat.BGRA texture,
since we no longer need to change the format before copying.

This makes Solarmax2 playable on the web backend.
2023-03-13 13:30:15 -05:00
Nathan Adams b527054a1e
render: Make retrieve_offscreen_texture pass the raw buffer (#9936) 2023-03-13 00:00:42 +00:00
Aaron Hill de8448e00a
avm2: Implement Stage3D depth test, blend factors, and fix bugs (#9845) 2023-03-12 23:43:58 +00:00
Nathan Adams 026efe7f18 render: Moved out some Gradient fields into webgl as it's no longer needed in wgpu 2023-03-06 23:22:09 +01:00
Nathan Adams 622abe60d1 wgpu: Extract T->Color lookup from gradient shader to Mesh construction 2023-03-06 23:22:09 +01:00
relrelb 83c15b8033 render: Replace `BoundingBox` with `swf::Rectangle` 2023-03-04 21:54:23 +02:00
Aaron Hill 2748b95c86 avm2: Improve Stage3D support for textures, register types, and opcodes
This is a very large diff, but most of it comes from test files and
output.

This PR ads partial support for the following Stage3D shader features:
* Normal (square), rectangle, and cube textures
* Varying and temporary registers
* Lots of opcodes

The combination of these allows us to get a raytracing program
fully working in Ruffle. I've included it as image test.
Currently, this test is very slow (about 90 seconds on my machine),
as the code I'm using (https://github.com/saharan/OGSL) includes
its own shader language and compiler. THe raytracing demo
first compiles its own shader language to AGAL, and then starts
rendering the scene.

Limitations:
* Many opcodes are still unimplemented
* Most non-default texture options (e.g. mipmaps) are not implemented
2023-03-03 15:58:46 -06:00
Nathan Adams 545193b098 swf: Deduplicate GradientFilter again 2023-02-28 16:25:12 +01:00
Nathan Adams f79015e201 render: Use swf Filter types where possible. Gradient types had to be split into duplicate classes to allow for different trait impls based on which gradient filter type it is. 2023-02-28 16:25:12 +01:00
Nathan Adams 9224aeca5d swf: Add DropShadowFilter::hide_object(), it's the only time COMPOSITE_SOURCE is used 2023-02-28 16:25:12 +01:00
Nathan Adams b8f7c66980 core: map_point in DisplacementMapFilter is i32 not u32 2023-02-28 16:25:12 +01:00
Nathan Adams 3777210117 core: Angle from swf tag is in radians, convert it to degrees 2023-02-28 16:25:12 +01:00
Nathan Adams acc3180db7 core: Strength in filters is a f32, not u8 2023-02-28 16:25:12 +01:00
Nathan Adams 7da2a061cc swf: ColorMatrixFilter::matrix is actually f32, not Fixed16 2023-02-28 16:25:12 +01:00
Nathan Adams fc00ae8eb6 core: Load filters from PlaceObject tag 2023-02-28 16:25:12 +01:00
Nathan Adams e39fbe871d render: Add Filter::GradientGlowFilter 2023-02-28 16:25:12 +01:00
Nathan Adams bb38a7fa55 render: Add Filter::GradientBevelFilter 2023-02-28 16:25:12 +01:00
Nathan Adams c8030d047d render: Add Filter::GlowFilter 2023-02-28 16:25:12 +01:00
Nathan Adams c9656c429e render: Add Filter::DropShadowFilter 2023-02-28 16:25:12 +01:00
Nathan Adams dbe2efff00 render: Add Filter::DisplacementMapFilter 2023-02-28 16:25:12 +01:00
Nathan Adams f9c7303f01 render: Add Filter::ConvolutionFilter 2023-02-28 16:25:12 +01:00
Nathan Adams 9c1f6ea129 render: Add Filter::BevelFilter 2023-02-28 16:25:12 +01:00
Nathan Adams 5ee3a4b512 avm2: Extract out the Value -> Filter logic into a trait 2023-02-28 16:25:12 +01:00
Nathan Adams 6539262db7 render: Add Quality option to RenderBackend::render_offscreen 2023-02-22 17:36:55 +01:00
relrelb 2aaf337b6a swf: Introduce `BlurFilterFlags` 2023-02-21 16:55:13 +02:00
Nathan Adams 68761608fc desktop: Add --quality option 2023-02-06 16:08:04 +01:00
Nathan Adams b95983b492 wgpu: Hook up set_quality 2023-02-06 16:08:04 +01:00
Nathan Adams d8e924affc render: Add RenderBackend::set_quality method, and call it from core 2023-02-06 16:08:04 +01:00
Nathan Adams b270d1bbd7 render: Move StageQuality from core to render 2023-02-06 16:08:04 +01:00
Nathan Adams 3411a04cef render: Made render specific Filter enum & structs, as swf ones don't map 1:1 to potential filters 2023-02-05 18:41:43 +01:00
Nathan Adams b5a250e16f render: Changed render_offscreen to return an Option instead of an Result 2023-02-05 18:41:43 +01:00
Nathan Adams 284a58c817 avm2: Implement BitmapData.apply_filter for ColorMatrixFilter 2023-02-05 18:41:43 +01:00
Nathan Adams a3a7f79f04 render: Switch from log to tracing 2023-02-05 18:02:19 +01:00
Aaron Hill 184734267d tests: Deny unknown fields when deserializing test.toml files
This will catch typos and misplaced options when modifying tests.
2023-01-28 16:27:43 -06:00
Nathan Adams 7d234956eb tests: Move tests away from giant macro to individual test.toml files that describe the test 2023-01-27 13:53:43 +01:00
Aaron Hill e2954821ea
core: Take two - delay reading image back from render backend using `SyncHandle` (#9184)
* Take two: Delay reading image back from render backend using `SyncHandle`

This allows us to avoid blocking immediately after a `BitmapData.draw` call.
Instead, we only attempt to use the `SyncHandle` when performing an operation
that requires the CPU-side pixels (e.g. BitmapData.getPixel or BitmapData.setPixel).

In the best case, the SWF will never explicitly access the pixels of
the target BitmapData, removing the need to ever copy back the render backend
image to our BitmapData. If the SWF doesn't require access to the pixels immediately,
we can delay copying the pixels until they're actually needed, hopefully allowing
the render backend to finish processing the BitmapData.draw operation in
the backenground before we need the result.

Now that the CPU and GPU pixels can be intentionally out of sync with
each other, we need to ensure that we don't accidentally expose 'stale'
CPU-side pixels to ActionScript (which needs to remain unaware of
our internal laziness). We now use a wrapper type `BitmapDataWrapper`
to enforce that the `SyncHandle` is consumed before accessing the
underlying `BitmapData.

* core: Skip GPU->CPU sync for source and target BitmapData during draw

* Introduce DirtyState enum
2023-01-21 21:08:04 +00:00
TÖRÖK Attila ec462115ef core: nit: Use `strip_prefix` instead of `starts_with` and subslicing.
As suggested by relrelb in a review note for #8820.
2023-01-16 17:33:41 +01:00
Mike Welsh 9cd6849772 core: Append EOI marker to JPEG data when missing
Fixes #4209.
2023-01-16 03:03:28 +01:00
Mike Welsh cceb18910b core: Fix handling of invalid EOI+SOI marker in JPEG data (fix #8775)
Previously we were removing the first occurrence of the invalid
0xFFD9FFD8 byte sequence in JPEG data, but this would break the
JPEG if it happened to contain this byte sequence elsewhere (for
example, EXIF data). Instead, properly parse the JPEG markers
searching for the invalid marker sequence.

Fixes #8775.
2023-01-16 03:03:28 +01:00
Nathan Adams 9cd850d30e render: Make render_offscreen return a sync handle which can be used to get the texture at a later time 2023-01-11 16:53:33 -05:00
Nathan Adams f5a587ce61 render: Better error message when points is empty 2023-01-10 11:10:46 +01:00
Nathan Adams 5ae569983b render: Disallow unwrap() and unwrap_err() in render crate 2023-01-10 11:10:46 +01:00
Nathan Adams 85f0c9dde9 render: Replaced unwrap with expect in shape_utils 2023-01-10 11:10:46 +01:00
Nathan Adams 8f684d6943 render: Removed unwrap/panic when working with empty shapes 2023-01-10 11:10:46 +01:00
Nathan Adams 53d6fa4d8b render: Make render commands take in an actual value, not ref for immediate cloning 2023-01-10 09:39:28 +01:00
Nathan Adams a69d30bb67 render: Add debug info method to renderer backends 2023-01-05 05:51:32 +01:00
Aaron Hill 10491a1be9 core: Store data in `BitmapData` instead of `Bitmap`
This makes `Bitmap` delegate to `BitmapData` for
all of the bitmap-related information (handle, width, and height).
As a result, we now unconditionally store a `BitmapData` in `Bitmap`.

As a result, swapping the underling `BitmapData` instance will
automatically change the properties (and rendered image) of a `Bitmap`.

This required some refactoring in the render backends in order to
get access to a `BitmapHandle` through `BitmapData`.
2023-01-03 18:01:41 -07:00
Aaron Hill 172326005b Remove lifetime parameter from CommandHandler
The wgpu backend no longer needs this.
2023-01-03 04:37:28 +01:00
Nathan Adams 28768f2ad8 render: Make CommandList a struct instead of a tuple 2023-01-03 03:39:13 +01:00
Nathan Adams cb6d72b49b wgpu: Split up gradient shader based on type and repeat 2023-01-03 03:39:13 +01:00
Nathan Adams f9333e2626 wgpu: Perform command rendering recursively and chunk up blends. Blends are still not implemented, it just copies to parent. 2023-01-03 03:39:13 +01:00
Nathan Adams ded46e20e7 render: Replace PushBlendMode/PopBlendMode with Blend 2023-01-03 03:39:13 +01:00
CUB3D 1013a6a162 avm2: Button bounds_with_transform should include bounds of current state child 2022-12-18 13:32:24 -07:00
CUB3D 690191dbdf avm2: Fix SimpleButton bounds 2022-12-18 13:32:24 -07:00
Aaron Hill 1b3070ab85 core: Make `BitmapHandle` hold a trait object instead of an id
`BitmapHandle` now holds `Arc<dyn BitmapHandleImpl>`.
This allows us to move all of the per-bitmap backend data into
`BitmapHandle`, instead of holding an id to a backend-specific
hashmap.

This fixes the memory leak issue with bitmaps. Once the AVM side of a
bitmap (`Bitmap`/`BitmapData`) gets garbage-collected, the
`BitmapHandle` will get dropped, freeing all of the GPU resources
assoicated with the bitmap.
2022-12-03 19:44:44 -06:00
Aaron Hill b8745f0ff1 avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.

Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present

Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle

General implementation strategy:

A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).

Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.

The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-11-25 21:43:00 -07:00
Aaron Hill 3bef8c4fd6 render: Remove `get_bitmap_pixels` and store data in `Character::Bitmap`
We only called `get_bitmap_pixels` when creating a `BitmapData`
for an SWF-provided `Bitmap`. We now store the initial pixels
in `Character::Bitmap`, and use them to initialize a `BitmapData`
when needed.

This lets us simplify the wgpu backend, which no longer needs
to store a `Bitmap` object. In addition to saving space for
`BitmapData` objects that lack an SWF `Bitmap`, this will make
it easier to move data from `bitmap_registry` into `BitmapHandle`
itself.
2022-11-25 16:08:42 -07:00
Mark Richins d345523d02 Fix conflicts 2022-11-23 20:45:37 -07:00
Mark Richins 63a291ac4b Fix promblems caused by moving Twips 2022-11-23 20:45:37 -07:00
Aaron Hill bdadb17a95 render: Don't use BitmapHandle in tessellator
Currently, we rely on ShapeTessellator being able to get a BitmapHandle
without a RenderBackend. With the upcoming BitmapData refactor,
we will always need a RenderBackend to get a BitmapHandle, which creates
borrow-checker issues in ShapeTessellator (which is stored in a
RenderBackend).

To solve this, we split BitmapSource.bitmap into two methods -
BitmapSource.bitmap and BitmapSource.bitmap_handle. ShapeTessellator
continues to use BitmapSource.bitmap, and uses the u16 bitmap id
instead of a BitmapHandle. The BitmapSource.bitmap_handle method
is used inside each render backend to convert the id to a BitmapHandle,
avoiding borrow-checker issues.
2022-11-21 21:04:40 -07:00
Aaron Hill 45515be0a3 render: Improve support for BitmapData.draw
This PR fixes a numbe of interconnected bugs:
* We weren't consistently uploading a dirty BitmapData to the render
  backend before drawing to/from it.
* BitmapData.draw should *not* add a fill color - it should draw over
  the current contents of the BitmapData
* After drawing to a non-transparent BitmapData, we need to manually
  set the opacity back to 255 for each pixel (the drawing process
  takes transparency into account, but the opacity information is
  thrown away at the end).
2022-10-17 12:53:38 -05:00
relrelb 86ef4bd7fe core: Simplify `Bitmap` creation
Change `Bitmap::new()` to accept a `ruffle_render::bitmap::Bitmap`
directly, instead of `width`, `height` and `bitmap_handle`. As a
consequence, all `RenderBackend::register_bitmap_*` methods are no
longer necessary - we can use `ruffle_redner::utils::*` to obtain
a `ruffle_render::bitmap::Bitmap` right before calling `Bitmap::new()`.
2022-10-17 20:05:30 +03:00
relrelb e1d01b0a5e swf: Extract `Rectangle` to a separate file
And make it generic, as a first step towards making it a general-purpose
data structure for the whole codebase. Some potential replacements are:
* `BoundingBox` in `render/src/bounding_box.rs`.
* `BoxBounds` in `core/src/html/dimensions.rs`.
* Parameters to a bunch of `BitmapData` methods in
  `core/src/bitmap/bitmap_data.rs`.
2022-09-25 10:37:56 +03:00