diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index a5ff57ca6..ad9053e9a 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -34,6 +34,7 @@ mod external_interface; mod function; mod glow_filter; pub mod gradient_bevel_filter; +pub mod gradient_glow_filter; mod key; mod load_vars; mod math; @@ -503,6 +504,8 @@ pub struct SystemPrototypes<'gc> { pub convolution_filter_constructor: Object<'gc>, pub gradient_bevel_filter: Object<'gc>, pub gradient_bevel_filter_constructor: Object<'gc>, + pub gradient_glow_filter: Object<'gc>, + pub gradient_glow_filter_constructor: Object<'gc>, pub date: Object<'gc>, pub bitmap_data: Object<'gc>, pub bitmap_data_constructor: Object<'gc>, @@ -780,6 +783,16 @@ pub fn create_globals<'gc>( gradient_bevel_filter_proto, ); + //TODO: are there any differnces + let gradient_glow_filter_proto = + gradient_glow_filter::create_proto(gc_context, bitmap_filter_proto, function_proto); + let gradient_glow_filter = FunctionObject::constructor( + gc_context, + Executable::Native(gradient_glow_filter::constructor), + Some(function_proto), + gradient_glow_filter_proto, + ); + filters.define_value( gc_context, "BitmapFilter", @@ -835,6 +848,12 @@ pub fn create_globals<'gc>( gradient_bevel_filter.into(), EnumSet::empty(), ); + filters.define_value( + gc_context, + "GradientGlowFilter", + gradient_glow_filter.into(), + EnumSet::empty(), + ); let bitmap_data_proto = bitmap_data::create_proto(gc_context, object_proto, function_proto); let bitmap_data = @@ -1157,6 +1176,8 @@ pub fn create_globals<'gc>( convolution_filter_constructor: convolution_filter, gradient_bevel_filter: gradient_bevel_filter_proto, gradient_bevel_filter_constructor: gradient_bevel_filter, + gradient_glow_filter: gradient_glow_filter_proto, + gradient_glow_filter_constructor: gradient_glow_filter, date: date_proto, bitmap_data: bitmap_data_proto, bitmap_data_constructor: bitmap_data, diff --git a/core/src/avm1/globals/bitmap_filter.rs b/core/src/avm1/globals/bitmap_filter.rs index 0ad9b6a11..bdd996c67 100644 --- a/core/src/avm1/globals/bitmap_filter.rs +++ b/core/src/avm1/globals/bitmap_filter.rs @@ -234,6 +234,36 @@ pub fn clone<'gc>( return Ok(cloned.into()); } + if let Some(this) = this.as_gradient_glow_filter_object() { + let proto = activation + .context + .avm1 + .prototypes + .gradient_glow_filter_constructor; + + let distance = this.get("distance", activation)?; + let angle = this.get("angle", activation)?; + let colors = this.get("colors", activation)?; + let alphas = this.get("alphas", activation)?; + let ratios = this.get("ratios", activation)?; + let blur_x = this.get("blurX", activation)?; + let blur_y = this.get("blurY", activation)?; + let strength = this.get("strength", activation)?; + let quality = this.get("quality", activation)?; + let type_ = this.get("type", activation)?; + let knockout = this.get("knockout", activation)?; + + let cloned = proto.construct( + activation, + &[ + distance, angle, colors, alphas, ratios, blur_x, blur_y, strength, quality, type_, + knockout, + ], + )?; + + return Ok(cloned.into()); + } + Ok(Value::Undefined) } diff --git a/core/src/avm1/globals/blur_filter.rs b/core/src/avm1/globals/blur_filter.rs index 6d113642d..422bd3c11 100644 --- a/core/src/avm1/globals/blur_filter.rs +++ b/core/src/avm1/globals/blur_filter.rs @@ -26,7 +26,7 @@ pub fn blur_x<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(filter) = this.as_blur_filter_object() { - return Ok(filter.blur_x().into()) + return Ok(filter.blur_x().into()); } Ok(Value::Undefined) @@ -56,7 +56,7 @@ pub fn get_blur_y<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(filter) = this.as_blur_filter_object() { - return Ok(filter.blur_y().into()) + return Ok(filter.blur_y().into()); } Ok(Value::Undefined) @@ -86,7 +86,7 @@ pub fn get_quality<'gc>( _args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(filter) = this.as_blur_filter_object() { - return Ok(filter.quality().into()) + return Ok(filter.quality().into()); } Ok(Value::Undefined) diff --git a/core/src/avm1/globals/gradient_bevel_filter.rs b/core/src/avm1/globals/gradient_bevel_filter.rs index e312f3359..17440d0c9 100644 --- a/core/src/avm1/globals/gradient_bevel_filter.rs +++ b/core/src/avm1/globals/gradient_bevel_filter.rs @@ -29,8 +29,6 @@ pub fn constructor<'gc>( Ok(Value::Undefined) } -// todo: check floats / types etcss - pub fn distance<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, @@ -195,7 +193,12 @@ pub fn set_alphas<'gc>( let mut arr = Vec::with_capacity(arr_len); for index in 0..arr_len { - arr.push(obj.array_element(index).coerce_to_f64(activation)?.max(0.0).min(1.0)); + arr.push( + obj.array_element(index) + .coerce_to_f64(activation)? + .max(0.0) + .min(1.0), + ); } let colors = filter.colors().into_iter().take(arr_len).collect(); @@ -247,10 +250,14 @@ pub fn set_ratios<'gc>( let mut arr = Vec::with_capacity(arr_len); for index in 0..arr_len { - arr.push(obj.array_element(index).coerce_to_i32(activation)?.max(0).min(255) as u8); + arr.push( + obj.array_element(index) + .coerce_to_i32(activation)? + .max(0) + .min(255) as u8, + ); } - let colors = filter.colors().into_iter().take(arr_len).collect(); filter.set_colors(activation.context.gc_context, colors); @@ -384,13 +391,13 @@ pub fn set_quality<'gc>( Ok(Value::Undefined) } -pub fn type_<'gc>( +pub fn get_type<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(filter) = this.as_gradient_bevel_filter_object() { - let type_: &str = filter.type_().into(); + let type_: &str = filter.get_type().into(); return Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into()); } @@ -622,7 +629,7 @@ pub fn create_proto<'gc>( "type", FunctionObject::function( gc_context, - Executable::Native(type_), + Executable::Native(get_type), Some(fn_proto), fn_proto, ), diff --git a/core/src/avm1/globals/gradient_glow_filter.rs b/core/src/avm1/globals/gradient_glow_filter.rs new file mode 100644 index 000000000..ac1e130d1 --- /dev/null +++ b/core/src/avm1/globals/gradient_glow_filter.rs @@ -0,0 +1,664 @@ +//! flash.filter.GradientGlowFilter object + +use crate::avm1::activation::Activation; +use crate::avm1::error::Error; +use crate::avm1::function::{Executable, FunctionObject}; +use crate::avm1::object::bevel_filter::BevelFilterType; +use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject; +use crate::avm1::{AvmString, Object, ScriptObject, TObject, Value}; +use enumset::EnumSet; +use gc_arena::MutationContext; + +pub fn constructor<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + set_distance(activation, this, args.get(0..1).unwrap_or_default())?; + set_angle(activation, this, args.get(1..2).unwrap_or_default())?; + set_colors(activation, this, args.get(2..3).unwrap_or_default())?; + set_alphas(activation, this, args.get(3..4).unwrap_or_default())?; + set_ratios(activation, this, args.get(4..5).unwrap_or_default())?; + set_blur_x(activation, this, args.get(5..6).unwrap_or_default())?; + set_blur_y(activation, this, args.get(6..7).unwrap_or_default())?; + set_strength(activation, this, args.get(7..8).unwrap_or_default())?; + set_quality(activation, this, args.get(8..9).unwrap_or_default())?; + set_type(activation, this, args.get(9..10).unwrap_or_default())?; + set_knockout(activation, this, args.get(10..11).unwrap_or_default())?; + + Ok(Value::Undefined) +} + +pub fn distance<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.distance().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_distance<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let distance = args + .get(0) + .unwrap_or(&4.0.into()) + .coerce_to_f64(activation)?; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_distance(activation.context.gc_context, distance); + } + + Ok(Value::Undefined) +} + +pub fn angle<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.angle().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_angle<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let angle = args + .get(0) + .unwrap_or(&44.9999999772279.into()) + .coerce_to_f64(activation)?; + + let clamped_angle = if angle.is_sign_negative() { + -(angle.abs() % 360.0) + } else { + angle % 360.0 + }; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_angle(activation.context.gc_context, clamped_angle); + } + + Ok(Value::Undefined) +} + +pub fn colors<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let array = ScriptObject::array( + activation.context.gc_context, + Some(activation.context.avm1.prototypes.array), + ); + + let arr = filter.colors(); + + for (index, item) in arr.iter().copied().enumerate() { + array.set_array_element(index, item.into(), activation.context.gc_context); + } + + return Ok(array.into()); + } + + Ok(Value::Undefined) +} + +pub fn set_colors<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let colors = args.get(0).unwrap_or(&Value::Undefined); + + if let Value::Object(obj) = colors { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let arr_len = obj.length(); + let mut colors_arr = Vec::with_capacity(arr_len); + + let old_alphas = filter.alphas(); + let mut alphas_arr = Vec::with_capacity(arr_len); + + for index in 0..arr_len { + let col = obj.array_element(index).coerce_to_u32(activation)?; + + let alpha = if let Some(alpha) = old_alphas.get(index) { + *alpha + } else if col >> 24 == 0 { + 0.0 + } else { + 255.0 / (col >> 24) as f64 + }; + + colors_arr.push(col & 0xFFFFFF); + alphas_arr.push(alpha); + } + + filter.set_colors(activation.context.gc_context, colors_arr); + filter.set_alphas(activation.context.gc_context, alphas_arr); + + let ratios = filter.ratios().into_iter().take(arr_len).collect(); + filter.set_ratios(activation.context.gc_context, ratios); + } + } + + Ok(Value::Undefined) +} + +pub fn alphas<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let array = ScriptObject::array( + activation.context.gc_context, + Some(activation.context.avm1.prototypes.array), + ); + + let arr = filter.alphas(); + + for (index, item) in arr.iter().copied().enumerate() { + array.set_array_element(index, item.into(), activation.context.gc_context); + } + + return Ok(array.into()); + } + + Ok(Value::Undefined) +} + +pub fn set_alphas<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let alphas = args.get(0).unwrap_or(&Value::Undefined); + + if let Value::Object(obj) = alphas { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let arr_len = obj.length().min(filter.colors().len()); + let mut arr = Vec::with_capacity(arr_len); + + for index in 0..arr_len { + arr.push( + obj.array_element(index) + .coerce_to_f64(activation)? + .max(0.0) + .min(1.0), + ); + } + + let colors = filter.colors().into_iter().take(arr_len).collect(); + filter.set_colors(activation.context.gc_context, colors); + + let ratios = filter.ratios().into_iter().take(arr_len).collect(); + filter.set_ratios(activation.context.gc_context, ratios); + + filter.set_alphas(activation.context.gc_context, arr); + } + } + + Ok(Value::Undefined) +} + +pub fn ratios<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let array = ScriptObject::array( + activation.context.gc_context, + Some(activation.context.avm1.prototypes.array), + ); + + let arr = filter.ratios(); + + for (index, item) in arr.iter().copied().enumerate() { + array.set_array_element(index, item.into(), activation.context.gc_context); + } + + return Ok(array.into()); + } + + Ok(Value::Undefined) +} + +pub fn set_ratios<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let ratios = args.get(0).unwrap_or(&Value::Undefined); + + if let Value::Object(obj) = ratios { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let arr_len = obj.length().min(filter.colors().len()); + let mut arr = Vec::with_capacity(arr_len); + + for index in 0..arr_len { + arr.push( + obj.array_element(index) + .coerce_to_i32(activation)? + .max(0) + .min(255) as u8, + ); + } + + let colors = filter.colors().into_iter().take(arr_len).collect(); + filter.set_colors(activation.context.gc_context, colors); + + let alphas = filter.alphas().into_iter().take(arr_len).collect(); + filter.set_alphas(activation.context.gc_context, alphas); + + filter.set_ratios(activation.context.gc_context, arr); + } + } + + Ok(Value::Undefined) +} + +pub fn blur_x<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.blur_x().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_blur_x<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let blur_x = args + .get(0) + .unwrap_or(&4.0.into()) + .coerce_to_f64(activation) + .map(|x| x.max(0.0).min(255.0))?; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_blur_x(activation.context.gc_context, blur_x); + } + + Ok(Value::Undefined) +} + +pub fn blur_y<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.blur_y().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_blur_y<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let blur_y = args + .get(0) + .unwrap_or(&4.0.into()) + .coerce_to_f64(activation) + .map(|x| x.max(0.0).min(255.0))?; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_blur_y(activation.context.gc_context, blur_y); + } + + Ok(Value::Undefined) +} + +pub fn strength<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.strength().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_strength<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let strength = args + .get(0) + .unwrap_or(&1.0.into()) + .coerce_to_f64(activation) + .map(|x| x.max(0.0).min(255.0))?; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_strength(activation.context.gc_context, strength); + } + + Ok(Value::Undefined) +} + +pub fn quality<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.quality().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_quality<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let quality = args + .get(0) + .unwrap_or(&1.0.into()) + .coerce_to_i32(activation) + .map(|x| x.max(0).min(15))?; + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_quality(activation.context.gc_context, quality); + } + + Ok(Value::Undefined) +} + +pub fn get_type<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(filter) = this.as_gradient_glow_filter_object() { + let type_: &str = filter.get_type().into(); + return Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into()); + } + + Ok(Value::Undefined) +} + +pub fn set_type<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let type_: BevelFilterType = args + .get(0) + .unwrap_or(&Value::String(AvmString::new( + activation.context.gc_context, + "inner".to_string(), + ))) + .coerce_to_string(activation) + .map(|s| s.as_str().into())?; + + if let Some(filter) = this.as_gradient_glow_filter_object() { + filter.set_type(activation.context.gc_context, type_); + } + + Ok(Value::Undefined) +} + +pub fn knockout<'gc>( + _activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + _args: &[Value<'gc>], +) -> Result, Error<'gc>> { + if let Some(object) = this.as_gradient_glow_filter_object() { + return Ok(object.knockout().into()); + } + + Ok(Value::Undefined) +} + +pub fn set_knockout<'gc>( + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, + args: &[Value<'gc>], +) -> Result, Error<'gc>> { + let knockout = args + .get(0) + .unwrap_or(&false.into()) + .as_bool(activation.current_swf_version()); + + if let Some(object) = this.as_gradient_glow_filter_object() { + object.set_knockout(activation.context.gc_context, knockout); + } + + Ok(Value::Undefined) +} + +pub fn create_proto<'gc>( + gc_context: MutationContext<'gc, '_>, + proto: Object<'gc>, + fn_proto: Object<'gc>, +) -> Object<'gc> { + let color_matrix_filter = GradientGlowFilterObject::empty_object(gc_context, Some(proto)); + let object = color_matrix_filter.as_script_object().unwrap(); + + object.add_property( + gc_context, + "distance", + FunctionObject::function( + gc_context, + Executable::Native(distance), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_distance), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "angle", + FunctionObject::function( + gc_context, + Executable::Native(angle), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_angle), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "colors", + FunctionObject::function( + gc_context, + Executable::Native(colors), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_colors), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "alphas", + FunctionObject::function( + gc_context, + Executable::Native(alphas), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_alphas), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "ratios", + FunctionObject::function( + gc_context, + Executable::Native(ratios), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_ratios), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "blurX", + FunctionObject::function( + gc_context, + Executable::Native(blur_x), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_blur_x), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "blurY", + FunctionObject::function( + gc_context, + Executable::Native(blur_y), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_blur_y), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "strength", + FunctionObject::function( + gc_context, + Executable::Native(strength), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_strength), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "quality", + FunctionObject::function( + gc_context, + Executable::Native(quality), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_quality), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "type", + FunctionObject::function( + gc_context, + Executable::Native(get_type), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_type), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + object.add_property( + gc_context, + "knockout", + FunctionObject::function( + gc_context, + Executable::Native(knockout), + Some(fn_proto), + fn_proto, + ), + Some(FunctionObject::function( + gc_context, + Executable::Native(set_knockout), + Some(fn_proto), + fn_proto, + )), + EnumSet::empty(), + ); + + color_matrix_filter.into() +} diff --git a/core/src/avm1/object.rs b/core/src/avm1/object.rs index afe80b229..13c83edea 100644 --- a/core/src/avm1/object.rs +++ b/core/src/avm1/object.rs @@ -19,6 +19,7 @@ use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject; use crate::avm1::object::drop_shadow_filter::DropShadowFilterObject; use crate::avm1::object::glow_filter::GlowFilterObject; use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject; +use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject; use crate::avm1::object::transform_object::TransformObject; use crate::avm1::object::xml_attributes_object::XMLAttributesObject; use crate::avm1::object::xml_idmap_object::XMLIDMapObject; @@ -45,6 +46,7 @@ pub mod displacement_map_filter; pub mod drop_shadow_filter; pub mod glow_filter; pub mod gradient_bevel_filter; +pub mod gradient_glow_filter; pub mod script_object; pub mod shared_object; pub mod sound_object; @@ -82,6 +84,7 @@ pub mod xml_object; DisplacementMapFilterObject(DisplacementMapFilterObject<'gc>), ConvolutionFilterObject(ConvolutionFilterObject<'gc>), GradientBevelFilterObject(GradientBevelFilterObject<'gc>), + GradientGlowFilterObject(GradientGlowFilterObject<'gc>), DateObject(DateObject<'gc>), BitmapData(BitmapDataObject<'gc>), } @@ -500,6 +503,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy None } + /// Get the underlying `GradientGlowFilterObject`, if it exists + fn as_gradient_glow_filter_object(&self) -> Option> { + None + } + /// Get the underlying `BitmapDataObject`, if it exists fn as_bitmap_data_object(&self) -> Option> { None diff --git a/core/src/avm1/object/gradient_bevel_filter.rs b/core/src/avm1/object/gradient_bevel_filter.rs index edb2bb17f..7c16d3a98 100644 --- a/core/src/avm1/object/gradient_bevel_filter.rs +++ b/core/src/avm1/object/gradient_bevel_filter.rs @@ -53,18 +53,14 @@ impl fmt::Debug for GradientBevelFilterObject<'_> { impl<'gc> GradientBevelFilterObject<'gc> { add_field_accessors!( - [set_angle, angle, angle, f64], - [set_blur_x, blur_x, blur_x, f64], - [set_blur_y, blur_y, blur_y, f64], - [set_distance, distance, distance, f64], - [set_knockout, knockout, knockout, bool], - [set_quality, quality, quality, i32], - [set_strength, strength, strength, f64], - [set_type, type_, type_, BevelFilterType], - ); - - //TODO: combine with above - add_field_accessors!( + [angle, f64, set => set_angle, get => angle], + [blur_x, f64, set => set_blur_x, get => blur_x], + [blur_y, f64, set => set_blur_y, get => blur_y], + [distance, f64, set => set_distance, get => distance], + [knockout, bool, set => set_knockout, get => knockout], + [quality, i32, set => set_quality, get => quality], + [strength, f64, set => set_strength, get => strength], + [type_, BevelFilterType, set => set_type, get => get_type], [alphas, Vec, set => set_alphas], [colors, Vec, set => set_colors], [ratios, Vec, set => set_ratios], diff --git a/core/src/avm1/object/gradient_glow_filter.rs b/core/src/avm1/object/gradient_glow_filter.rs new file mode 100644 index 000000000..4d2745481 --- /dev/null +++ b/core/src/avm1/object/gradient_glow_filter.rs @@ -0,0 +1,136 @@ +use crate::add_field_accessors; +use crate::avm1::error::Error; +use crate::avm1::{Object, ScriptObject, TObject, Value}; +use crate::impl_custom_object_without_set; +use gc_arena::{Collect, GcCell, MutationContext}; + +use crate::avm1::activation::Activation; +use crate::avm1::object::bevel_filter::BevelFilterType; +use std::fmt; + +/// A GradientGlowFilter +#[derive(Clone, Copy, Collect)] +#[collect(no_drop)] +pub struct GradientGlowFilterObject<'gc>(GcCell<'gc, GradientGlowFilterData<'gc>>); + +#[derive(Clone, Collect)] +#[collect(no_drop)] +pub struct GradientGlowFilterData<'gc> { + /// The underlying script object. + base: ScriptObject<'gc>, + + alphas: Vec, + angle: f64, + blur_x: f64, + blur_y: f64, + colors: Vec, + distance: f64, + knockout: bool, + quality: i32, + ratios: Vec, + strength: f64, + type_: BevelFilterType, +} + +impl fmt::Debug for GradientGlowFilterObject<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let this = self.0.read(); + f.debug_struct("GradientGlowFilter") + .field("alphas", &this.alphas) + .field("angle", &this.angle) + .field("blurX", &this.blur_x) + .field("blurY", &this.blur_y) + .field("colors", &this.colors) + .field("distance", &this.distance) + .field("knockout", &this.knockout) + .field("quality", &this.quality) + .field("ratios", &this.ratios) + .field("strength", &this.strength) + .field("type_", &this.type_) + .finish() + } +} + +impl<'gc> GradientGlowFilterObject<'gc> { + add_field_accessors!( + [angle, f64, set => set_angle, get => angle], + [blur_x, f64, set => set_blur_x, get => blur_x], + [blur_y, f64, set => set_blur_y, get => blur_y], + [distance, f64, set => set_distance, get => distance], + [knockout, bool, set => set_knockout, get => knockout], + [quality, i32, set => set_quality, get => quality], + [strength, f64, set => set_strength, get => strength], + [type_, BevelFilterType, set => set_type, get => get_type], + [alphas, Vec, set => set_alphas], + [colors, Vec, set => set_colors], + [ratios, Vec, set => set_ratios], + ); + + pub fn alphas(&self) -> Vec { + self.0.read().alphas.clone() + } + + pub fn colors(&self) -> Vec { + self.0.read().colors.clone() + } + + pub fn ratios(&self) -> Vec { + self.0.read().ratios.clone() + } + + pub fn empty_object(gc_context: MutationContext<'gc, '_>, proto: Option>) -> Self { + GradientGlowFilterObject(GcCell::allocate( + gc_context, + GradientGlowFilterData { + base: ScriptObject::object(gc_context, proto), + alphas: vec![], + angle: 0.0, + blur_x: 0.0, + blur_y: 0.0, + colors: vec![], + distance: 0.0, + knockout: false, + quality: 0, + ratios: vec![], + strength: 0.0, + type_: BevelFilterType::Inner, + }, + )) + } +} + +impl<'gc> TObject<'gc> for GradientGlowFilterObject<'gc> { + impl_custom_object_without_set!(base); + + fn set( + &self, + name: &str, + value: Value<'gc>, + activation: &mut Activation<'_, 'gc, '_>, + ) -> Result<(), Error<'gc>> { + let base = self.0.read().base; + base.internal_set( + name, + value, + activation, + (*self).into(), + Some(activation.context.avm1.prototypes.gradient_glow_filter), + ) + } + + fn as_gradient_glow_filter_object(&self) -> Option> { + Some(*self) + } + + fn create_bare_object( + &self, + activation: &mut Activation<'_, 'gc, '_>, + _this: Object<'gc>, + ) -> Result, Error<'gc>> { + Ok(GradientGlowFilterObject::empty_object( + activation.context.gc_context, + Some(activation.context.avm1.prototypes.gradient_glow_filter), + ) + .into()) + } +} diff --git a/core/tests/regression_tests.rs b/core/tests/regression_tests.rs index c8b712368..e510d1a4a 100644 --- a/core/tests/regression_tests.rs +++ b/core/tests/regression_tests.rs @@ -304,6 +304,7 @@ swf_tests! { (displacement_map_filter, "avm1/displacement_map_filter", 1), (convolution_filter, "avm1/convolution_filter", 1), (gradient_bevel_filter, "avm1/gradient_bevel_filter", 1), + (gradient_glow_filter, "avm1/gradient_glow_filter", 1), (bitmap_data, "avm1/bitmap_data", 1), (array_call_method, "avm1/array_call_method", 1), (as3_hello_world, "avm2/hello_world", 1), diff --git a/core/tests/swfs/avm1/gradient_glow_filter/output.txt b/core/tests/swfs/avm1/gradient_glow_filter/output.txt index e69de29bb..7d92e9753 100644 --- a/core/tests/swfs/avm1/gradient_glow_filter/output.txt +++ b/core/tests/swfs/avm1/gradient_glow_filter/output.txt @@ -0,0 +1,188 @@ +// new GradientGlowFilter +[object Object] +// x.clone() +[object Object] +// x.clone() == x +false +// x.alphas + +// x.angle +44.9999999772279 +// x.blurX +4 +// x.blurY +4 +// x.colors + +// x.distance +4 +// x.knockout +false +// x.quality +1 +// x.ratios + +// x.strength +1 +// x.type +inner +// x.alphas + +// x.colors + +// x.ratios + +// x.alphas +0 +// x.colors +0 +// x.ratios +0 +// x.alphas +1 +// x.colors +1 +// x.ratios +0 +// x.alphas +1 +// x.colors +1 +// x.ratios +0 +// x.alphas + +// x.colors + +// x.ratios + +// x.alphas +1 +// x.colors +65535 +// x.ratios +1 +// x.alphas +0.4 +// x.colors +65535 +// x.ratios +1 +// x.alphas +0 +// x.colors +65535 +// x.ratios +1 +// x.alphas +0.4 +// x.colors +65535 +// x.ratios +1 +// x.alphas +0.4 +// x.colors +65535 +// x.ratios +1 +// x.alphas +1 +// x.colors +16777215 +// x.ratios +255 +// x.alphas +0 +// x.colors +1 +// x.ratios +0 +// x.alphas (after set to null) +0.4 +// x.colors (after set to null) +65535 +// x.ratios (after set to null) +1 +// x.angle (after set to 1000) +280 +// x.blurX (after set to 1000) +255 +// x.blurY (after set to 1000) +4 +// x.distance (after set to 1000) +1000 +// x.quality (after set to 1000) +15 +// x.strength (after set to 1000) +255 +// x.type (after set to null) +full +// x.angle (after set to -1000) +-280 +// x.blurX (after set to -1000) +0 +// x.blurY (after set to -1000) +4 +// x.distance (after set to -1000) +-1000 +// x.quality (after set to -1000) +0 +// x.strength (after set to -1000) +0 +// x.angle (after set to 1.5) +1.5 +// x.blurX (after set to 1.5) +1.5 +// x.blurY (after set to 1.5) +4 +// x.distance (after set to 1.5) +1.5 +// x.quality (after set to 1.5) +1 +// x.strength (after set to 1.5) +0 +// oob_over.alphas + +// oob_over.angle +280 +// oob_over.blurX +255 +// oob_over.blurY +255 +// oob_over.colors + +// oob_over.distance +1000 +// oob_over.knockout +false +// oob_over.quality +15 +// oob_over.ratios + +// oob_over.strength +255 +// oob_over.type +full +// oob_under.alphas + +// oob_under.angle +-280 +// oob_under.blurX +0 +// oob_under.blurY +0 +// oob_under.colors + +// oob_under.distance +-1000 +// oob_under.knockout +false +// oob_under.quality +0 +// oob_under.ratios + +// oob_under.strength +0 +// oob_under.type +full diff --git a/core/tests/swfs/avm1/gradient_glow_filter/test.fla b/core/tests/swfs/avm1/gradient_glow_filter/test.fla new file mode 100644 index 000000000..e5e4ac694 Binary files /dev/null and b/core/tests/swfs/avm1/gradient_glow_filter/test.fla differ diff --git a/core/tests/swfs/avm1/gradient_glow_filter/test.swf b/core/tests/swfs/avm1/gradient_glow_filter/test.swf new file mode 100644 index 000000000..7ebd5ecb7 Binary files /dev/null and b/core/tests/swfs/avm1/gradient_glow_filter/test.swf differ