avm1: Implement bevel filter conversions
This commit is contained in:
parent
2b48f579e6
commit
73bc637ad7
|
@ -7,7 +7,8 @@ use crate::avm1::{Activation, Error, Object, ScriptObject, TObject, Value};
|
||||||
use crate::context::GcContext;
|
use crate::context::GcContext;
|
||||||
use crate::string::{AvmString, WStr};
|
use crate::string::{AvmString, WStr};
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use swf::Color;
|
use std::ops::Deref;
|
||||||
|
use swf::{BevelFilterFlags, Color, Fixed16, Fixed8};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Collect)]
|
#[derive(Copy, Clone, Debug, Collect)]
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
|
@ -39,6 +40,28 @@ impl From<BevelFilterType> for &'static WStr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BevelFilterType {
|
||||||
|
pub fn as_flags(&self) -> BevelFilterFlags {
|
||||||
|
match self {
|
||||||
|
BevelFilterType::Inner => BevelFilterFlags::INNER_SHADOW,
|
||||||
|
BevelFilterType::Outer => BevelFilterFlags::empty(),
|
||||||
|
BevelFilterType::Full => BevelFilterFlags::ON_TOP,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BevelFilterFlags> for BevelFilterType {
|
||||||
|
fn from(value: BevelFilterFlags) -> Self {
|
||||||
|
if value.contains(BevelFilterFlags::ON_TOP) {
|
||||||
|
BevelFilterType::Full
|
||||||
|
} else if value.contains(BevelFilterFlags::INNER_SHADOW) {
|
||||||
|
BevelFilterType::Inner
|
||||||
|
} else {
|
||||||
|
BevelFilterType::Outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Collect)]
|
#[derive(Clone, Debug, Collect)]
|
||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
struct BevelFilterData {
|
struct BevelFilterData {
|
||||||
|
@ -56,6 +79,42 @@ struct BevelFilterData {
|
||||||
type_: BevelFilterType,
|
type_: BevelFilterType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&BevelFilterData> for swf::BevelFilter {
|
||||||
|
fn from(filter: &BevelFilterData) -> swf::BevelFilter {
|
||||||
|
let mut flags = BevelFilterFlags::COMPOSITE_SOURCE;
|
||||||
|
flags |= BevelFilterFlags::from_passes(filter.quality as u8);
|
||||||
|
flags |= filter.type_.as_flags();
|
||||||
|
flags.set(BevelFilterFlags::KNOCKOUT, filter.knockout);
|
||||||
|
swf::BevelFilter {
|
||||||
|
shadow_color: filter.shadow,
|
||||||
|
highlight_color: filter.highlight,
|
||||||
|
blur_x: Fixed16::from_f64(filter.blur_x),
|
||||||
|
blur_y: Fixed16::from_f64(filter.blur_y),
|
||||||
|
angle: Fixed16::from_f64(filter.angle),
|
||||||
|
distance: Fixed16::from_f64(filter.distance),
|
||||||
|
strength: Fixed8::from_f64(filter.strength()),
|
||||||
|
flags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<swf::BevelFilter> for BevelFilterData {
|
||||||
|
fn from(filter: swf::BevelFilter) -> BevelFilterData {
|
||||||
|
Self {
|
||||||
|
distance: filter.distance.into(),
|
||||||
|
angle: filter.angle.into(),
|
||||||
|
highlight: filter.highlight_color,
|
||||||
|
shadow: filter.shadow_color,
|
||||||
|
quality: filter.num_passes().into(),
|
||||||
|
strength: (filter.strength.to_f64() * 256.0) as u16,
|
||||||
|
knockout: filter.is_knockout(),
|
||||||
|
blur_x: filter.blur_x.into(),
|
||||||
|
blur_y: filter.blur_y.into(),
|
||||||
|
type_: filter.flags.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for BevelFilterData {
|
impl Default for BevelFilterData {
|
||||||
#[allow(clippy::approx_constant)]
|
#[allow(clippy::approx_constant)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -110,6 +169,10 @@ impl<'gc> BevelFilter<'gc> {
|
||||||
Ok(bevel_filter)
|
Ok(bevel_filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_filter(gc_context: MutationContext<'gc, '_>, filter: swf::BevelFilter) -> Self {
|
||||||
|
Self(GcCell::allocate(gc_context, filter.into()))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn duplicate(&self, gc_context: MutationContext<'gc, '_>) -> Self {
|
pub(crate) fn duplicate(&self, gc_context: MutationContext<'gc, '_>) -> Self {
|
||||||
Self(GcCell::allocate(gc_context, self.0.read().clone()))
|
Self(GcCell::allocate(gc_context, self.0.read().clone()))
|
||||||
}
|
}
|
||||||
|
@ -306,6 +369,10 @@ impl<'gc> BevelFilter<'gc> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn filter(&self) -> swf::BevelFilter {
|
||||||
|
self.0.read().deref().into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! bevel_filter_method {
|
macro_rules! bevel_filter_method {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use crate::avm1::activation::Activation;
|
use crate::avm1::activation::Activation;
|
||||||
use crate::avm1::error::Error;
|
use crate::avm1::error::Error;
|
||||||
|
use crate::avm1::globals::bevel_filter::BevelFilter;
|
||||||
use crate::avm1::object::NativeObject;
|
use crate::avm1::object::NativeObject;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{Attribute, Object, ScriptObject, TObject, Value};
|
use crate::avm1::{Attribute, Object, ScriptObject, TObject, Value};
|
||||||
|
@ -63,19 +64,33 @@ pub fn clone<'gc>(
|
||||||
Ok(create_instance(activation, native, proto).into())
|
Ok(create_instance(activation, native, proto).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn avm1_to_filter(_object: Object) -> Option<Filter> {
|
pub fn avm1_to_filter(object: Object) -> Option<Filter> {
|
||||||
// TODO
|
let native = object.native();
|
||||||
|
match native {
|
||||||
|
NativeObject::BevelFilter(filter) => Some(Filter::BevelFilter(filter.filter())),
|
||||||
|
|
||||||
// Invalid filters are silently dropped/ignored, no errors are thrown.
|
// Invalid filters are silently dropped/ignored, no errors are thrown.
|
||||||
None
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn filter_to_avm1<'gc>(_activation: &mut Activation<'_, 'gc>, _filter: Filter) -> Value<'gc> {
|
pub fn filter_to_avm1<'gc>(activation: &mut Activation<'_, 'gc>, filter: Filter) -> Value<'gc> {
|
||||||
// TODO
|
let (native, proto) = match filter {
|
||||||
|
Filter::BevelFilter(filter) => (
|
||||||
|
NativeObject::BevelFilter(BevelFilter::from_filter(
|
||||||
|
activation.context.gc_context,
|
||||||
|
filter,
|
||||||
|
)),
|
||||||
|
activation.context.avm1.prototypes().bevel_filter,
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
// Unrepresentable filters (eg Shader) will just return as Null.
|
||||||
|
// Not sure there's a way to even get to that state though, they can only be added in avm2.
|
||||||
|
return Value::Null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Unrepresentable filters (eg Shader) will just return as Null.
|
create_instance(activation, native, Some(proto.into())).into()
|
||||||
// Not sure there's a way to even get to that state though, they can only be added in avm2.
|
|
||||||
Value::Null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_instance<'gc>(
|
pub fn create_instance<'gc>(
|
||||||
|
|
|
@ -1,3 +1,28 @@
|
||||||
|
// test.filters[0].angle
|
||||||
|
44.999253346525
|
||||||
|
// test.filters[0].blurX
|
||||||
|
10
|
||||||
|
// test.filters[0].blurY
|
||||||
|
10
|
||||||
|
// test.filters[0].distance
|
||||||
|
10
|
||||||
|
// test.filters[0].highlightAlpha
|
||||||
|
1
|
||||||
|
// test.filters[0].highlightColor
|
||||||
|
65280
|
||||||
|
// test.filters[0].knockout
|
||||||
|
false
|
||||||
|
// test.filters[0].quality
|
||||||
|
2
|
||||||
|
// test.filters[0].shadowAlpha
|
||||||
|
1
|
||||||
|
// test.filters[0].shadowColor
|
||||||
|
255
|
||||||
|
// test.filters[0].strength
|
||||||
|
1.5
|
||||||
|
// test.filters[0].type
|
||||||
|
inner
|
||||||
|
|
||||||
// new BevelFilter
|
// new BevelFilter
|
||||||
[object Object]
|
[object Object]
|
||||||
// x.clone()
|
// x.clone()
|
||||||
|
@ -28,6 +53,33 @@ false
|
||||||
1
|
1
|
||||||
// x.type
|
// x.type
|
||||||
inner
|
inner
|
||||||
|
|
||||||
|
test.filters = [x]
|
||||||
|
// test.filters[0].angle
|
||||||
|
44.9999999772279
|
||||||
|
// test.filters[0].blurX
|
||||||
|
4
|
||||||
|
// test.filters[0].blurY
|
||||||
|
4
|
||||||
|
// test.filters[0].distance
|
||||||
|
4
|
||||||
|
// test.filters[0].highlightAlpha
|
||||||
|
1
|
||||||
|
// test.filters[0].highlightColor
|
||||||
|
16777215
|
||||||
|
// test.filters[0].knockout
|
||||||
|
false
|
||||||
|
// test.filters[0].quality
|
||||||
|
1
|
||||||
|
// test.filters[0].shadowAlpha
|
||||||
|
1
|
||||||
|
// test.filters[0].shadowColor
|
||||||
|
0
|
||||||
|
// test.filters[0].strength
|
||||||
|
1
|
||||||
|
// test.filters[0].type
|
||||||
|
inner
|
||||||
|
|
||||||
// x.angle (after set to 360)
|
// x.angle (after set to 360)
|
||||||
0
|
0
|
||||||
// x.angle (after set to 361)
|
// x.angle (after set to 361)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1 +1,4 @@
|
||||||
num_frames = 1
|
num_frames = 1
|
||||||
|
|
||||||
|
[approximations]
|
||||||
|
epsilon = 0.001
|
Loading…
Reference in New Issue