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).
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.
D.O.s removed by the timeline may only be removed from the depth list
(if they were manipulated by AS3 scripts), but their unload method
would still be called, which is wrong.
This is linked to the legacy DisplayObject::Text, which can
only be created by Flash CS6 (but is allowed in AVM2 swfs).
The 'StaticText' class cannot be constructed from ActionScript.
To support this, I've added support for native initializers to
playerglobal. This allows us to throw an exception in the
ActionScript constructor in Test.as, and do nothing in the native
intiializer (so that we can construct it from a DisplayObject).
I've left StaticText.text unimplemented for now, since it will require
dealing with Glyphs
Co-authored-by: kmeisthax <dcrkid@yahoo.com>
This is done by:
- using the global constant pool instead of a fresh empty one:
- OK, as no call-site is directly executing arbitrary bytecode that
could care about the contents of the constant pool.
- pre-allocating the global scope object in the `Avm1` context
- using the global scope directly instead of allocating a local scope:
- OK, because no call-site is directly defining locals on the
returned Activation's scope.
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.
`tag_length` isn't really necessary since each tag is read using
a dedicated `swf::Reader`, which keeps track of the tag boundary
internally.
As a result, `tag_len` can be avoided passed around many times in
`movie_clip.rs`.
The call to `super_init` will initialize a `DisplayObject` (if unset)
in the `Sprite` constructor, using exactly the same logic that we're
attempting to use. The code in `MovieClip` is unreachable, and can
be deleted.
The desktop player now takes a `--spoof-url` argument, which overrides
the movie URL provided to ActionScript. This does not affect non-root
movies loaded through `Loader`.
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).
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()`.
`NaN` and large numbers are actually treated like `i32::MIN`. As described
in https://github.com/ruffle-rs/ruffle/issues/7772#issuecomment-1235977709,
Flash (at least 7+) fails to convert `i32::MIN` to a string due to a bug.
Since `i32::MIN` has no `i32` positive counterpart, digits extracted using
modulo are actually negative and characters before ASCII `'0'` are selected.
Flash 6- somehow return just `0` in those cases. This was Ruffle's behavior
up until this commit. This commit matches Ruffle behavior to latest Flash
Player, as we usually prefer. A `TODO` is still there in case we ever add
player version emulation.
These methods were incorrectly treating the argument as a local name,
instead of a qualified name. Additionally, 'getDefinition' now throws
an AVM error.
Previously, we would display an empty string for the method name.
We can now store a `&'static str` again in `NativeMethod`,
instead of needing a `Cow`
Instead of propagating the underlying compression library errors.
Also, make `ByteArray.deflate` and `ByteArray.inflate` pure-ActionScript
methods that call into the native `ByteArray.compress` and `ByteArray.uncompress`
native methods, respectively.
Since `serde-wasm-bindgen` doesn't support `#[serde(default)]` (https://github.com/cloudflare/serde-wasm-bindgen/issues/20),
we no longer able to deserialize a partial `Config` object. As a solution,
take care to pass a full object from the TypeScript side.
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`.
Now that we have a custom `Error` enum, this is very straightforwawrd.
I've converted `getDefinitionByName` return an AVM error, since this
is commonly used by games to test for a class.
Main changes:
* Merge `ColorTransformParams` into `ColorTransformObject`, as it's only relevant for AVM1.
* Make `BitmapData::color_transform` work with a generic `ColorTransform`, which uses fixed-point
arithmetic.
Note that Ruffle still calculates color transforms slightly different from Flash. This is probably
caused by inaccuracy of the current `ColorTransformObject` to `ColorTransform` conversion and/or the
`ColorTransform` application logic itself. Since this requires further research, it'll be fixed in a
future PR.
While doing this I also noticed that we were incorrectly producing AmfValue::Integer if our
target AMF version is AMF0. This is incorrect because AMF0 is based on AS2, which does not
recognise Integer as a valid type, and therefore must be represented with Number instead.
This prevents the root from being constructed until we know its `SymbolClass`, and is roughly equivalent to delaying the work until `ShowFrame`. (We don't actually run any work on `ShowFrame` in our current movieclip impl.)