render: Move StageQuality from core to render

This commit is contained in:
Nathan Adams 2023-02-03 15:03:28 +01:00
parent 00c7e8f634
commit b270d1bbd7
11 changed files with 142 additions and 130 deletions

1
Cargo.lock generated
View File

@ -3569,6 +3569,7 @@ dependencies = [
"jpeg-decoder",
"lyon",
"png",
"ruffle_wstr",
"serde",
"smallvec",
"swf",

View File

@ -2045,7 +2045,7 @@ impl<'a, 'gc> Activation<'a, 'gc> {
}
fn action_toggle_quality(&mut self) -> Result<FrameControl<'gc>, Error<'gc>> {
use crate::display_object::StageQuality;
use ruffle_render::quality::StageQuality;
// Toggle between `Low` and `High`/`Best` quality.
// This op remembers whether the stage quality was `Best` or higher, so we have to maintain
// the bitmap downsampling flag to ensure we toggle back to the proper quality.

View File

@ -668,7 +668,7 @@ fn high_quality<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: DisplayObject<'gc>,
) -> Value<'gc> {
use crate::display_object::StageQuality;
use ruffle_render::quality::StageQuality;
let quality = match activation.context.stage.quality() {
StageQuality::Best => 2,
StageQuality::High => 1,
@ -682,7 +682,7 @@ fn set_high_quality<'gc>(
_this: DisplayObject<'gc>,
val: Value<'gc>,
) -> Result<(), Error<'gc>> {
use crate::display_object::StageQuality;
use ruffle_render::quality::StageQuality;
let val = val.coerce_to_f64(activation)?;
if !val.is_nan() {
// 0 -> Low, 1 -> High, 2 -> Best, but with some odd rules for non-integers.

View File

@ -3,8 +3,9 @@
use crate::avm2::Multiname;
use crate::avm2::{Activation, Error, Namespace, Object, TObject, Value};
use crate::avm2_stub_getter;
use crate::display_object::{StageQuality, TDisplayObject};
use crate::display_object::TDisplayObject;
use crate::prelude::{ColorTransform, DisplayObject, Matrix, Twips};
use ruffle_render::quality::StageQuality;
use swf::Fixed8;
fn get_display_object<'gc>(

View File

@ -50,7 +50,7 @@ pub use loader_display::LoaderDisplay;
pub use morph_shape::{MorphShape, MorphShapeStatic};
pub use movie_clip::{MovieClip, Scene};
use ruffle_render::commands::CommandHandler;
pub use stage::{Stage, StageAlign, StageDisplayState, StageQuality, StageScaleMode, WindowMode};
pub use stage::{Stage, StageAlign, StageDisplayState, StageScaleMode, WindowMode};
pub use text::Text;
pub use video::Video;

View File

@ -26,6 +26,7 @@ use bitflags::bitflags;
use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_render::backend::ViewportDimensions;
use ruffle_render::commands::CommandHandler;
use ruffle_render::quality::StageQuality;
use std::cell::{Ref, RefMut};
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
@ -1022,127 +1023,6 @@ impl FromWStr for StageAlign {
}
}
/// The quality setting of the `Stage`.
///
/// In the Flash Player, this settings affects anti-aliasing and bitmap smoothing.
/// These settings currently have no effect in Ruffle, but the active setting is still stored.
/// [StageQuality in the AS3 Reference](https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/StageQuality.html)
#[derive(Default, Clone, Collect, Copy, Debug, Eq, PartialEq)]
#[collect(require_static)]
pub enum StageQuality {
/// No anti-aliasing, and bitmaps are never smoothed.
Low,
/// 2x anti-aliasing.
Medium,
/// 4x anti-aliasing.
#[default]
High,
/// 4x anti-aliasing with high quality downsampling.
/// Bitmaps will use high quality downsampling when scaled down.
/// Despite the name, this is not the best quality setting as 8x8 and 16x16 modes were added to
/// Flash Player 11.3.
Best,
/// 8x anti-aliasing.
/// Bitmaps will use high quality downsampling when scaled down.
High8x8,
/// 8x anti-aliasing done in linear sRGB space.
/// Bitmaps will use high quality downsampling when scaled down.
High8x8Linear,
/// 16x anti-aliasing.
/// Bitmaps will use high quality downsampling when scaled down.
High16x16,
/// 16x anti-aliasing done in linear sRGB space.
/// Bitmaps will use high quality downsampling when scaled down.
High16x16Linear,
}
impl StageQuality {
/// Returns the string representing the quality setting as returned by AVM1 `_quality` and
/// AVM2 `Stage.quality`.
pub fn into_avm_str(self) -> &'static str {
// Flash Player always returns quality in uppercase, despite the AVM2 `StageQuality` being
// lowercase.
match self {
StageQuality::Low => "LOW",
StageQuality::Medium => "MEDIUM",
StageQuality::High => "HIGH",
StageQuality::Best => "BEST",
// The linear sRGB quality settings are not returned even if they are active.
StageQuality::High8x8 | StageQuality::High8x8Linear => "8X8",
StageQuality::High16x16 | StageQuality::High16x16Linear => "16X16",
}
}
}
impl Display for StageQuality {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
// Match string values returned by AS.
let s = match *self {
StageQuality::Low => "low",
StageQuality::Medium => "medium",
StageQuality::High => "high",
StageQuality::Best => "best",
StageQuality::High8x8 => "8x8",
StageQuality::High8x8Linear => "8x8linear",
StageQuality::High16x16 => "16x16",
StageQuality::High16x16Linear => "16x16linear",
};
f.write_str(s)
}
}
impl FromStr for StageQuality {
type Err = ParseEnumError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let quality = match s.to_ascii_lowercase().as_str() {
"low" => StageQuality::Low,
"medium" => StageQuality::Medium,
"high" => StageQuality::High,
"best" => StageQuality::Best,
"8x8" => StageQuality::High8x8,
"8x8linear" => StageQuality::High8x8Linear,
"16x16" => StageQuality::High16x16,
"16x16linear" => StageQuality::High16x16Linear,
_ => return Err(ParseEnumError),
};
Ok(quality)
}
}
impl FromWStr for StageQuality {
type Err = ParseEnumError;
fn from_wstr(s: &WStr) -> Result<Self, Self::Err> {
if s.eq_ignore_case(WStr::from_units(b"low")) {
Ok(StageQuality::Low)
} else if s.eq_ignore_case(WStr::from_units(b"medium")) {
Ok(StageQuality::Medium)
} else if s.eq_ignore_case(WStr::from_units(b"high")) {
Ok(StageQuality::High)
} else if s.eq_ignore_case(WStr::from_units(b"best")) {
Ok(StageQuality::Best)
} else if s.eq_ignore_case(WStr::from_units(b"8x8")) {
Ok(StageQuality::High8x8)
} else if s.eq_ignore_case(WStr::from_units(b"8x8linear")) {
Ok(StageQuality::High8x8Linear)
} else if s.eq_ignore_case(WStr::from_units(b"16x16")) {
Ok(StageQuality::High16x16)
} else if s.eq_ignore_case(WStr::from_units(b"16x16linear")) {
Ok(StageQuality::High16x16Linear)
} else {
Err(ParseEnumError)
}
}
}
/// The window mode of the Ruffle player.
///
/// This setting controls how the Ruffle container is layered and rendered with other content on

View File

@ -14,6 +14,7 @@ use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_render::bitmap::BitmapInfo;
use ruffle_render::bounding_box::BoundingBox;
use ruffle_render::commands::CommandHandler;
use ruffle_render::quality::StageQuality;
use ruffle_video::error::Error;
use ruffle_video::frame::EncodedFrame;
use ruffle_video::VideoStreamHandle;
@ -23,8 +24,6 @@ use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
use swf::{CharacterId, DefineVideoStream, VideoFrame};
use super::StageQuality;
/// A Video display object is a high-level interface to a video player.
///
/// Video data may be embedded within a variety of container formats, including

View File

@ -22,8 +22,8 @@ use crate::context_menu::{
BuiltInItemFlags, ContextMenuCallback, ContextMenuItem, ContextMenuState,
};
use crate::display_object::{
EditText, InteractiveObject, MovieClip, Stage, StageAlign, StageDisplayState, StageQuality,
StageScaleMode, TInteractiveObject, WindowMode,
EditText, InteractiveObject, MovieClip, Stage, StageAlign, StageDisplayState, StageScaleMode,
TInteractiveObject, WindowMode,
};
use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode, MouseButton, PlayerEvent};
use crate::external::Value as ExternalValue;
@ -46,6 +46,7 @@ use instant::Instant;
use rand::{rngs::SmallRng, SeedableRng};
use ruffle_render::backend::{null::NullRenderer, RenderBackend, ViewportDimensions};
use ruffle_render::commands::CommandList;
use ruffle_render::quality::StageQuality;
use ruffle_render::transform::TransformStack;
use ruffle_video::backend::VideoBackend;
use std::cell::RefCell;

View File

@ -8,6 +8,7 @@ repository.workspace = true
version.workspace = true
[dependencies]
ruffle_wstr = { path = "../wstr" }
swf = { path = "../swf"}
tracing = "0.1.37"
gif = "0.12.0"

View File

@ -12,5 +12,6 @@ pub mod transform;
pub mod utils;
pub mod commands;
pub mod quality;
#[cfg(feature = "tessellator")]
pub mod tessellator;

128
render/src/quality.rs Normal file
View File

@ -0,0 +1,128 @@
use gc_arena::Collect;
use ruffle_wstr::{FromWStr, WStr};
use std::fmt;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
/// The quality setting of the `Stage`.
///
/// In the Flash Player, this settings affects anti-aliasing and bitmap smoothing.
/// These settings currently have no effect in Ruffle, but the active setting is still stored.
/// [StageQuality in the AS3 Reference](https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/StageQuality.html)
#[derive(Default, Clone, Collect, Copy, Debug, Eq, PartialEq)]
#[collect(require_static)]
pub enum StageQuality {
/// No anti-aliasing, and bitmaps are never smoothed.
Low,
/// 2x anti-aliasing.
Medium,
/// 4x anti-aliasing.
#[default]
High,
/// 4x anti-aliasing with high quality downsampling.
/// Bitmaps will use high quality downsampling when scaled down.
/// Despite the name, this is not the best quality setting as 8x8 and 16x16 modes were added to
/// Flash Player 11.3.
Best,
/// 8x anti-aliasing.
/// Bitmaps will use high quality downsampling when scaled down.
High8x8,
/// 8x anti-aliasing done in linear sRGB space.
/// Bitmaps will use high quality downsampling when scaled down.
High8x8Linear,
/// 16x anti-aliasing.
/// Bitmaps will use high quality downsampling when scaled down.
High16x16,
/// 16x anti-aliasing done in linear sRGB space.
/// Bitmaps will use high quality downsampling when scaled down.
High16x16Linear,
}
impl StageQuality {
/// Returns the string representing the quality setting as returned by AVM1 `_quality` and
/// AVM2 `Stage.quality`.
pub fn into_avm_str(self) -> &'static str {
// Flash Player always returns quality in uppercase, despite the AVM2 `StageQuality` being
// lowercase.
match self {
StageQuality::Low => "LOW",
StageQuality::Medium => "MEDIUM",
StageQuality::High => "HIGH",
StageQuality::Best => "BEST",
// The linear sRGB quality settings are not returned even if they are active.
StageQuality::High8x8 | StageQuality::High8x8Linear => "8X8",
StageQuality::High16x16 | StageQuality::High16x16Linear => "16X16",
}
}
}
impl Display for StageQuality {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
// Match string values returned by AS.
let s = match *self {
StageQuality::Low => "low",
StageQuality::Medium => "medium",
StageQuality::High => "high",
StageQuality::Best => "best",
StageQuality::High8x8 => "8x8",
StageQuality::High8x8Linear => "8x8linear",
StageQuality::High16x16 => "16x16",
StageQuality::High16x16Linear => "16x16linear",
};
f.write_str(s)
}
}
pub struct StageQualityError;
impl FromStr for StageQuality {
type Err = StageQualityError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let quality = match s.to_ascii_lowercase().as_str() {
"low" => StageQuality::Low,
"medium" => StageQuality::Medium,
"high" => StageQuality::High,
"best" => StageQuality::Best,
"8x8" => StageQuality::High8x8,
"8x8linear" => StageQuality::High8x8Linear,
"16x16" => StageQuality::High16x16,
"16x16linear" => StageQuality::High16x16Linear,
_ => return Err(StageQualityError),
};
Ok(quality)
}
}
impl FromWStr for StageQuality {
type Err = StageQualityError;
fn from_wstr(s: &WStr) -> Result<Self, Self::Err> {
if s.eq_ignore_case(WStr::from_units(b"low")) {
Ok(StageQuality::Low)
} else if s.eq_ignore_case(WStr::from_units(b"medium")) {
Ok(StageQuality::Medium)
} else if s.eq_ignore_case(WStr::from_units(b"high")) {
Ok(StageQuality::High)
} else if s.eq_ignore_case(WStr::from_units(b"best")) {
Ok(StageQuality::Best)
} else if s.eq_ignore_case(WStr::from_units(b"8x8")) {
Ok(StageQuality::High8x8)
} else if s.eq_ignore_case(WStr::from_units(b"8x8linear")) {
Ok(StageQuality::High8x8Linear)
} else if s.eq_ignore_case(WStr::from_units(b"16x16")) {
Ok(StageQuality::High16x16)
} else if s.eq_ignore_case(WStr::from_units(b"16x16linear")) {
Ok(StageQuality::High16x16Linear)
} else {
Err(StageQualityError)
}
}
}