The stage alignment settings viewport_scale_factor should *not* be
applied to `Stage.transform.matrix`, which is only ever changed
as a result of explicit modification from ActionScript. Instead,
alignment and scaling are performed a separate step, which is
transparent to ActionScript.
I've implemented this through a new `viewport_matrix` field,
which is used during stage rendering and mouse coordinate
transformation.
This makes Stage3D instances properly scale - previously, they
would render unscaled. The linux standalone Flash Player doesn't
seem to use HiDPI mode, so I didn't realize that this was a bug
until now.
In the process of implementing this, I discovered and fixed a bug
with how we handle changing the viewport size under winit.
Calling `self.window.set_inner_size` does not immediately take
effect (at least on X11) - calling `self.window.inner_size()`
will report the old size until the next resize event.
Since build our Stage matrices from `self.window.inner_size()`
(and start running the SWF) immediately after `RuffleEvent::OnMetadata`,
we would run a few SWF frames with an incorrect viewport size. This
is visible to SWFs that have the scale mode set to "noScale", and
could break SWFs that expect the initial viewport size to be
the movie size. I've fixed this by delaying SWF execution until
we get a Resize event (if `self.window.inner_size()` does not
immediately report the size we set).
`build_output_stream` now takes in a `timeout` parameter - I've
passed in `None` to keep the current behavior.
cpal addded lots of new `SampleFormat` enum values. For now, I'm
just returning an error if we encounter any of them - a quick test
showed that desktop audio is still working on my Linux machine.
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`.
We were incorrectly skipping the call to `task.set_ready`
if `self.waiting_for_poll` was set. The `waiting_for_poll` flag
should only be used to avoid redundant messages being sent into
the event loop.
This was causing us to ignore wakeups if more than one wakup
arrived in between calls to `poll_all`.
* avm2: Implement call stack
* avm2: Class traits should have a special prefix
* avm2: Stack tracebacks should also contain error message
* avm2: Move method naming to Executable
* avm2: Handle getter and setter methods in tracebacks
* chore: Formatting
* chore: Add comments
* avm2: Make full_name write to a string, instead of creating a new one
* core: Make GcArena publicly accessible
* core: Add Deref impl for Either type
* desktop: Add AVM2 call stack to panic message
* avm2: Prefix native methods with a `/`
* chore: Appease clippy
* avm2: Check if method actually contains bytecode instead of unwrapping
* web: Add AVM2 stack trace to panic message
* chore: Formatting
* chore: Clippy
* avm2: Fix stack traces for free standing functions
* core: Remove global data from context
* core: Rename GcGlobalData to GcCallstack
* core: Introduce StaticCallstack, make GcArena private again
Co-authored-by: Adrian Wielgosik <4729533+adrian17@users.noreply.github.com>
Previously, the viewport height and width were stored in
both `Stage` and the `RenderBackend`. Any changes to the viewport
dimensions (e.g. due to window resizing) needed to be updated in both
places to keep our handling of the viewport consistent.
This PR adds a new `ViewportDimensions` type, which holds the
width, height, and scale factor. It is stored inside the
`RenderBackend` impl, and is retrieved using the newly added
method `RenderBackend.get_viewport_dimensions`. After a `Player`
has been constructed, any code that needes access to the viewport
dimensions will ultimate go through this method.
Unfortunately, `Stage` needs to use the viewport dimensions
in `build_matrices`. Therefore, any code modifying the viewport
dimensions should go through `player.set_viewport_dimensions`,
which ensures that the stage matrices are rebuilt after the render
backend is updated.
Run (almost) all event handlers regardless of whether a movie is loaded
or not. This will be useful for rendering a blank screen before a
movie has been loaded.
The resolved URL only used by `NavigatorBackend::fetch`. So simply
inline `NavigatorBackend::resolve_relative_url` into `NavigatorBackend::fetch`,
per implementation.
`core` already depends on the `instant` crate which abstracts
`std::instant::Instant` and polyfills it on Web. Use it to replace
`NavigatorBackend::time_since_launch` in order to make `NavigatorBackend`
a little smaller and more simple.
Previously there were 3 implementations of `LocaleBackend`:
`DesktopLocaleBackend`, `WebLocaleBackend` and `NullLocaleBackend`.
While `DesktopLocaleBackend`, `WebLocaleBackend` were identical,
`NullLocaleBackend` always returned a fixed date/time for tests
determinism.
Unify them in a single file, and use `cfg!(test)` and a new dedicated
`deterministic` feature to decide whether to mock date/time or not.
This should not cause any behavioral changes.
This makes `DesktopUiBackend::is_key_down` a simple one-line check.
Also unify the handling code of `ElementState::Pressed` and `ElementState::Released`,
which had a lot of common code.
Pull out the audio mixing code from desktop and add it to core.
This will allow other backends to use it (such as the web audio
backend) to get consistent audio across all platforms.
It was initialized on a separate thread since 6178dd9ef1,
as a workaround for Windows.
But now thanks to https://github.com/RustAudio/cpal/pull/597, this
is no longer needed, and cpal can be initialized on the same thread
as before.
When reading an SWF, search for FileAttributes and
SetBackgroundColor and return this along with the header data
because it's useful (in particular, the AS3 flag).
Toss out any shared objects that contain ".." in the name
to avoid accessing files outside of the Ruffle data directory.
The DiskStorageBackend also will fail any requests with a ".."
component as an extra precaution.
Fixes#3961.
Also, prefix the shared object name with # if it contains a
slash, (e.g. `#mygame/foo`). This matches Flash's directory
structure and makes it easier to transfer saved data to Ruffle.
This adds two optional parameters, --width and --height, which
allow the user to specify a desired physical window width and
height to be used. If only one of the two parameters is present,
the other will be deduced from it and the movie's aspect ratio.
If neither are present, the window's size is set to the movie's
logical size, in accordance with the behaviour before this change.
* #[derive(Collect)] should be before #[collect]
* Replace redunant `&buf[..]` with `buf`
* Changes most cases of UPPERCase to UpperCase
* Allow upper_case_acronym on most SWF types, as they are from
SWF spec/more annoying to change.
It might not succeed.
This unwrap crashes the newgrounds Meat Boy flash on desktop.
Instead, use unwrap_or_default with an empty path. This will cause
the read to fail, but it's better than crashing the whole program.
The points in an SWF sound envelope are always in 44.1KHz. The
desktop audio backend would end up using this points in the sound's
sample rate, often causing the envelope to be delayed.
Now the envelope is applied after resampling, and the positions
are scaled based on the output sample rate.
This unifies the code path for event sounds and stream sounds.
Both `AudioBackend::start_stream` and `start_sound` return a
`SoundHandle`. `stop_stream` is removed (`stop_sound` can be
used for both cases).
Also removes references to `CharacterId` from the `AudioBackend`
(instead, an increasing ID is returned to identiy streams while
loading).
Add an AudioManager struct to handle this list of actively playing
sounds. This will maintain information for each sound instance,
such as the owning display object, AVM1 object, etc.
This will allow us to implement the awkward AVM1 Sound API in a
fairly backend-agnostic way.
Basically just copied from what alacritty is doing:
530de00049/alacritty/src/main.rs
There are two functional changes:
- When launching normally, you no longer see a console window quickly flashing
- When launching via. console, the program is detached (but still logs to the console)
By default, winit limits the window size to the screen resolution.
Since some flashes are larger than this, increase the limit to an
arbitrarily-chosen larger constant.
Winit's WindowBuilder will sometimes create a window whose size is
smaller than requested. Therefore, instead of assuming the actual
window size is requested size * scaling, just check what the true
size is. (window.inner_size() also takes scaling into account.)
This fixes at least one issue where rendering would fail on Windows
with the Vulkan backend due to the incorrect size being used.
Player::set_letterbox can be used to control the letterbox behavior.
* Letterbox::Off => no letterbox (flash behavior)
* Letterbox::Fullscreen => letterbox only in fullscreen (web default)
* Letterbox::On => always letterbox (desktop default)
On desktop, don't render while the window is minimized.
In the wgpu backend, don't panic if swap chain fails to grab a
texture. Instead recreate the swap chain and bail on the current
frame.
Fixes panic when minimizing with the wgpu vulkan backend (#2065).
Add --timedemo for benchmarking, which will run the given SWF as
quickly as possible for 5000 frames or the end of the root
timeline, whichever comes first. The total duration will be output
upon completion.
sample renamed into dasp. Switch to this crate and also use the
latest git revision, which fixed some compiler errors on nightly.
Also remove unnecessary sample dependency in exporter Cargo.toml.
- removed default implementations for `play()` and `pause()` methods for AudioBackend trait
- Implemented `play()` and `pause()` methods for CPAL audio backend
- Implemented empty block for `play()` and `pause()` methods for NULL audio backend
When using ALSA, cpal was returning bogus sample rates from
`Device::supported_output_configs`, causing the audio stream to
fail to initialize.
Use `Device::default_output_config` instead.