render: Add Filter::GradientBevelFilter
This commit is contained in:
parent
c8030d047d
commit
bb38a7fa55
|
@ -1,8 +1,9 @@
|
|||
use ruffle_render::filters::{
|
||||
BevelFilter, BevelFilterType, BlurFilter, ColorMatrixFilter, ConvolutionFilter,
|
||||
DisplacementMapFilter, DisplacementMapFilterMode, DropShadowFilter, Filter, GlowFilter,
|
||||
GradientBevelFilter,
|
||||
};
|
||||
use swf::Color;
|
||||
use swf::{Color, GradientRecord};
|
||||
|
||||
use crate::avm2::error::{argument_error, type_error};
|
||||
use crate::avm2::{Activation, ArrayObject, Error, Object, TObject, Value};
|
||||
|
@ -59,6 +60,11 @@ impl FilterAvm2Ext for Filter {
|
|||
return GlowFilter::from_avm2_object(activation, object);
|
||||
}
|
||||
|
||||
let gradient_bevel_filter = activation.avm2().classes().gradientbevelfilter;
|
||||
if object.is_of_type(gradient_bevel_filter, activation) {
|
||||
return GradientBevelFilter::from_avm2_object(activation, object);
|
||||
}
|
||||
|
||||
Err(Error::AvmError(type_error(
|
||||
activation,
|
||||
&format!(
|
||||
|
@ -80,6 +86,7 @@ impl FilterAvm2Ext for Filter {
|
|||
Filter::DisplacementMapFilter(filter) => filter.as_avm2_object(activation),
|
||||
Filter::DropShadowFilter(filter) => filter.as_avm2_object(activation),
|
||||
Filter::GlowFilter(filter) => filter.as_avm2_object(activation),
|
||||
Filter::GradientBevelFilter(filter) => filter.as_avm2_object(activation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -575,3 +582,144 @@ impl FilterAvm2Ext for GlowFilter {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterAvm2Ext for GradientBevelFilter {
|
||||
fn from_avm2_object<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
object: Object<'gc>,
|
||||
) -> Result<Filter, Error<'gc>> {
|
||||
let mut colors = vec![];
|
||||
let angle = object
|
||||
.get_public_property("angle", activation)?
|
||||
.coerce_to_number(activation)?;
|
||||
let blur_x = object
|
||||
.get_public_property("blurX", activation)?
|
||||
.coerce_to_number(activation)?;
|
||||
let blur_y = object
|
||||
.get_public_property("blurY", activation)?
|
||||
.coerce_to_number(activation)?;
|
||||
let distance = object
|
||||
.get_public_property("distance", activation)?
|
||||
.coerce_to_number(activation)?;
|
||||
let knockout = object
|
||||
.get_public_property("knockout", activation)?
|
||||
.coerce_to_boolean();
|
||||
let quality = object
|
||||
.get_public_property("quality", activation)?
|
||||
.coerce_to_u32(activation)?;
|
||||
let strength = object
|
||||
.get_public_property("strength", activation)?
|
||||
.coerce_to_u32(activation)?;
|
||||
let bevel_type = object
|
||||
.get_public_property("type", activation)?
|
||||
.coerce_to_string(activation)?;
|
||||
if let Some(colors_object) = object
|
||||
.get_public_property("colors", activation)?
|
||||
.as_object()
|
||||
{
|
||||
if let Some(colors_array) = colors_object.as_array_storage() {
|
||||
if let Some(alphas_object) = object
|
||||
.get_public_property("alphas", activation)?
|
||||
.as_object()
|
||||
{
|
||||
if let Some(alphas_array) = alphas_object.as_array_storage() {
|
||||
if let Some(ratios_object) = object
|
||||
.get_public_property("ratios", activation)?
|
||||
.as_object()
|
||||
{
|
||||
if let Some(ratios_array) = ratios_object.as_array_storage() {
|
||||
// Flash only keeps the elements from any array until the lowest index in each array
|
||||
for i in 0..ratios_array
|
||||
.length()
|
||||
.min(alphas_array.length())
|
||||
.min(colors_array.length())
|
||||
as usize
|
||||
{
|
||||
let color = colors_array
|
||||
.get(i)
|
||||
.expect("Length was already checked at this point")
|
||||
.coerce_to_u32(activation)?;
|
||||
let alpha = colors_array
|
||||
.get(i)
|
||||
.expect("Length was already checked at this point")
|
||||
.coerce_to_number(activation)?
|
||||
as f32;
|
||||
let ratio = colors_array
|
||||
.get(i)
|
||||
.expect("Length was already checked at this point")
|
||||
.coerce_to_u32(activation)?;
|
||||
colors.push(GradientRecord {
|
||||
ratio: ratio.clamp(0, 255) as u8,
|
||||
color: Color::from_rgb(color, (alpha * 255.0) as u8),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Filter::GradientBevelFilter(GradientBevelFilter {
|
||||
colors,
|
||||
blur_x: blur_x as f32,
|
||||
blur_y: blur_y as f32,
|
||||
angle: angle as f32,
|
||||
distance: distance as f32,
|
||||
strength: strength.clamp(0, 255) as u8,
|
||||
bevel_type: if &bevel_type == b"inner" {
|
||||
BevelFilterType::Inner
|
||||
} else if &bevel_type == b"outer" {
|
||||
BevelFilterType::Outer
|
||||
} else {
|
||||
BevelFilterType::Full
|
||||
},
|
||||
knockout,
|
||||
quality: quality.clamp(1, 15) as u8,
|
||||
}))
|
||||
}
|
||||
|
||||
fn as_avm2_object<'gc>(
|
||||
&self,
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
) -> Result<Object<'gc>, Error<'gc>> {
|
||||
let colors = ArrayObject::from_storage(
|
||||
activation,
|
||||
self.colors
|
||||
.iter()
|
||||
.map(|v| Value::from(v.color.to_rgb()))
|
||||
.collect(),
|
||||
)?;
|
||||
let alphas = ArrayObject::from_storage(
|
||||
activation,
|
||||
self.colors
|
||||
.iter()
|
||||
.map(|v| Value::from(f64::from(v.color.a) / 255.0))
|
||||
.collect(),
|
||||
)?;
|
||||
let ratios = ArrayObject::from_storage(
|
||||
activation,
|
||||
self.colors.iter().map(|v| Value::from(v.ratio)).collect(),
|
||||
)?;
|
||||
activation.avm2().classes().gradientbevelfilter.construct(
|
||||
activation,
|
||||
&[
|
||||
self.distance.into(),
|
||||
self.angle.into(),
|
||||
colors.into(),
|
||||
alphas.into(),
|
||||
ratios.into(),
|
||||
self.blur_x.into(),
|
||||
self.blur_y.into(),
|
||||
self.strength.into(),
|
||||
self.quality.into(),
|
||||
match self.bevel_type {
|
||||
BevelFilterType::Inner => "inner",
|
||||
BevelFilterType::Outer => "outer",
|
||||
BevelFilterType::Full => "full",
|
||||
}
|
||||
.into(),
|
||||
self.knockout.into(),
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::bitmap::BitmapHandle;
|
||||
use swf::{BevelFilterFlags, Color, Fixed16};
|
||||
use swf::{BevelFilterFlags, Color, Fixed16, GradientFilterFlags, GradientRecord};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Filter {
|
||||
|
@ -10,6 +10,7 @@ pub enum Filter {
|
|||
DisplacementMapFilter(DisplacementMapFilter),
|
||||
DropShadowFilter(DropShadowFilter),
|
||||
GlowFilter(GlowFilter),
|
||||
GradientBevelFilter(GradientBevelFilter),
|
||||
}
|
||||
|
||||
impl Default for Filter {
|
||||
|
@ -314,3 +315,55 @@ impl Default for GlowFilter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GradientBevelFilter {
|
||||
pub colors: Vec<GradientRecord>,
|
||||
pub blur_x: f32,
|
||||
pub blur_y: f32,
|
||||
pub angle: f32,
|
||||
pub distance: f32,
|
||||
pub strength: u8,
|
||||
pub bevel_type: BevelFilterType,
|
||||
pub knockout: bool,
|
||||
pub quality: u8,
|
||||
}
|
||||
|
||||
impl From<swf::GradientFilter> for GradientBevelFilter {
|
||||
fn from(value: swf::GradientFilter) -> Self {
|
||||
let quality = value.num_passes();
|
||||
Self {
|
||||
colors: value.colors,
|
||||
blur_x: value.blur_x.to_f32(),
|
||||
blur_y: value.blur_y.to_f32(),
|
||||
angle: value.angle.to_f32(),
|
||||
distance: value.distance.to_f32(),
|
||||
strength: (value.strength.to_f32() * 255.0) as u8,
|
||||
bevel_type: if value.flags.contains(GradientFilterFlags::ON_TOP) {
|
||||
BevelFilterType::Full
|
||||
} else if value.flags.contains(GradientFilterFlags::INNER_SHADOW) {
|
||||
BevelFilterType::Inner
|
||||
} else {
|
||||
BevelFilterType::Outer
|
||||
},
|
||||
knockout: value.flags.contains(GradientFilterFlags::KNOCKOUT),
|
||||
quality,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GradientBevelFilter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
colors: vec![],
|
||||
blur_x: 4.0,
|
||||
blur_y: 4.0,
|
||||
angle: 45.0,
|
||||
distance: 4.0,
|
||||
strength: 1,
|
||||
bevel_type: BevelFilterType::Inner,
|
||||
knockout: false,
|
||||
quality: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue