core: Fix edge cases and implement rest of bevel filter

This commit is contained in:
CUB3D 2020-09-22 23:07:47 +01:00 committed by Mike Welsh
parent 2c3ee4d94b
commit 110b9ec551
7 changed files with 188 additions and 87 deletions

View File

@ -3,7 +3,7 @@
use crate::avm1::activation::Activation;
use crate::avm1::error::Error;
use crate::avm1::function::{Executable, FunctionObject};
use crate::avm1::object::bevel_filter::{BevelFilterType, BevelFilterObject};
use crate::avm1::object::bevel_filter::{BevelFilterObject, BevelFilterType};
use crate::avm1::{AvmString, Object, TObject, Value};
use enumset::EnumSet;
use gc_arena::MutationContext;
@ -15,34 +15,48 @@ pub fn constructor<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let distance = args
.get(0)
.unwrap_or(&4.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(255.0))?;
.unwrap_or(&4.0.into())
.coerce_to_f64(activation)?;
let angle = args
.get(1)
.unwrap_or(&45.0.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(360.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
};
//TODO: range
let highlight_color = args
.get(2)
.unwrap_or(&0x000000.into())
.unwrap_or(&0xFFFFFF.into())
.coerce_to_i32(activation)?;
let highlight_color_clamped = if highlight_color.is_negative() {
0x1000000 - (highlight_color.abs() % 0x1000000)
} else {
highlight_color % (0x1000000)
};
let highlight_alpha = args
.get(3)
.unwrap_or(&1.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(1.0))?;
//TODO: range
let shadow_color = args
.get(4)
.unwrap_or(&0x000000.into())
.coerce_to_i32(activation)?;
let shadow_color_clamped = if shadow_color.is_negative() {
0x1000000 - (shadow_color.abs() % 0x1000000)
} else {
shadow_color % (0x1000000)
};
let shadow_alpha = args
.get(5)
.unwrap_or(&1.into())
@ -87,10 +101,10 @@ pub fn constructor<'gc>(
let bevel_filter = this.as_bevel_filter_object().unwrap();
bevel_filter.set_distance(activation.context.gc_context, distance);
bevel_filter.set_angle(activation.context.gc_context, angle);
bevel_filter.set_highlight_color(activation.context.gc_context, highlight_color);
bevel_filter.set_angle(activation.context.gc_context, clamped_angle);
bevel_filter.set_highlight_color(activation.context.gc_context, highlight_color_clamped);
bevel_filter.set_highlight_alpha(activation.context.gc_context, highlight_alpha);
bevel_filter.set_shadow_color(activation.context.gc_context, shadow_color);
bevel_filter.set_shadow_color(activation.context.gc_context, shadow_color_clamped);
bevel_filter.set_shadow_alpha(activation.context.gc_context, shadow_alpha);
bevel_filter.set_blur_x(activation.context.gc_context, blur_x);
bevel_filter.set_blur_y(activation.context.gc_context, blur_y);
@ -102,23 +116,14 @@ pub fn constructor<'gc>(
Ok(Value::Undefined)
}
pub fn clone<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Undefined)
}
pub fn get_distance<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this.as_bevel_filter_object().unwrap().get_distance().into())
}
//TODO: check if int?
pub fn set_distance<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
@ -137,9 +142,9 @@ pub fn set_distance<'gc>(
}
pub fn get_angle<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this.as_bevel_filter_object().unwrap().get_angle().into())
}
@ -151,21 +156,26 @@ pub fn set_angle<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let angle = args
.get(0)
.unwrap_or(&45.0.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(360.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
};
this.as_bevel_filter_object()
.unwrap()
.set_angle(activation.context.gc_context, angle);
.set_angle(activation.context.gc_context, clamped_angle);
Ok(Value::Undefined)
}
pub fn get_highlight_color<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this
.as_bevel_filter_object()
@ -182,19 +192,25 @@ pub fn set_highlight_color<'gc>(
let color = args
.get(0)
.unwrap_or(&0x000000.into())
.coerce_to_i32(activation)
.map(|x| x.max(0x000000).min(0xFFFFFF))?;
.coerce_to_i32(activation)?;
let col = if color.is_negative() {
0x1000000 - (color.abs() % 0x1000000)
} else {
color % (0x1000000)
};
this.as_bevel_filter_object()
.unwrap()
.set_highlight_color(activation.context.gc_context, color);
.set_highlight_color(activation.context.gc_context, col);
Ok(Value::Undefined)}
Ok(Value::Undefined)
}
pub fn get_highlight_alpha<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this
.as_bevel_filter_object()
@ -222,9 +238,9 @@ pub fn set_highlight_alpha<'gc>(
}
pub fn get_shadow_color<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this
.as_bevel_filter_object()
@ -238,13 +254,28 @@ pub fn set_shadow_color<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let color = args
.get(0)
.unwrap_or(&0x000000.into())
.coerce_to_i32(activation)?;
let col = if color.is_negative() {
0x1000000 - (color.abs() % 0x1000000)
} else {
color % (0x1000000)
};
this.as_bevel_filter_object()
.unwrap()
.set_shadow_color(activation.context.gc_context, col);
Ok(Value::Undefined)
}
pub fn get_shadow_alpha<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this
.as_bevel_filter_object()
@ -258,13 +289,23 @@ pub fn set_shadow_alpha<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let alpha = args
.get(0)
.unwrap_or(&1.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(1.0))?;
this.as_bevel_filter_object()
.unwrap()
.set_shadow_alpha(activation.context.gc_context, alpha);
Ok(Value::Undefined)
}
pub fn get_quality<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this.as_bevel_filter_object().unwrap().get_quality().into())
}
@ -288,11 +329,11 @@ pub fn set_quality<'gc>(
}
pub fn get_strength<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Undefined)
Ok(this.as_bevel_filter_object().unwrap().get_strength().into())
}
pub fn set_strength<'gc>(
@ -300,15 +341,25 @@ pub fn set_strength<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let strength = args
.get(0)
.unwrap_or(&1.into())
.coerce_to_f64(activation)
.map(|x| x.max(0.0).min(255.0))?;
this.as_bevel_filter_object()
.unwrap()
.set_strength(activation.context.gc_context, strength);
Ok(Value::Undefined)
}
pub fn get_knockout<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(Value::Undefined)
Ok(this.as_bevel_filter_object().unwrap().get_knockout().into())
}
pub fn set_knockout<'gc>(
@ -316,13 +367,22 @@ pub fn set_knockout<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let knockout = args
.get(0)
.unwrap_or(&false.into())
.as_bool(activation.current_swf_version());
this.as_bevel_filter_object()
.unwrap()
.set_knockout(activation.context.gc_context, knockout);
Ok(Value::Undefined)
}
pub fn get_blur_x<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this.as_bevel_filter_object().unwrap().get_blur_x().into())
}
@ -346,9 +406,9 @@ pub fn set_blur_x<'gc>(
}
pub fn get_blur_y<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
Ok(this.as_bevel_filter_object().unwrap().get_blur_y().into())
}
@ -374,7 +434,7 @@ pub fn set_blur_y<'gc>(
pub fn get_type<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let type_: &str = this.as_bevel_filter_object().unwrap().get_type().into();
Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into())
@ -387,7 +447,10 @@ pub fn set_type<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let type_: BevelFilterType = args
.get(0)
.unwrap_or(&Value::String(AvmString::new(activation.context.gc_context, "full".to_string())))
.unwrap_or(&Value::String(AvmString::new(
activation.context.gc_context,
"full".to_string(),
)))
.coerce_to_string(activation)
.map(|s| s.as_str().into())?;
@ -403,9 +466,8 @@ pub fn create_proto<'gc>(
fn_proto: Object<'gc>,
) -> Object<'gc> {
let object = BevelFilterObject::empty_object(gc_context, Some(proto));
let mut script_object = object.as_script_object().unwrap();
let script_object = object.as_script_object().unwrap();
script_object.force_set_function("clone", clone, gc_context, EnumSet::empty(), Some(proto));
script_object.add_property(
gc_context,
"distance",
@ -610,5 +672,5 @@ pub fn create_proto<'gc>(
)),
EnumSet::empty(),
);
script_object.into()
object.into()
}

View File

@ -2,7 +2,7 @@
use crate::avm1::activation::Activation;
use crate::avm1::error::Error;
use crate::avm1::{Object, ScriptObject, Value};
use crate::avm1::{Object, ScriptObject, TObject, Value};
use enumset::EnumSet;
use gc_arena::MutationContext;
@ -15,10 +15,57 @@ pub fn constructor<'gc>(
}
pub fn clone<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Object<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(this) = this.as_blur_filter_object() {
let proto = activation.context.avm1.prototypes.blur_filter_constructor;
let blur_x = this.get("blurX", activation)?;
let blur_y = this.get("blurY", activation)?;
let quality = this.get("quality", activation)?;
let cloned = proto.construct(activation, &[blur_x, blur_y, quality])?;
return Ok(cloned.into());
}
if let Some(this) = this.as_bevel_filter_object() {
let proto = activation.context.avm1.prototypes.bevel_filter_constructor;
let distance = this.get("distance", activation)?;
let angle = this.get("angle", activation)?;
let highlight_color = this.get("highlightColor", activation)?;
let highlight_alpha = this.get("highlightAlpha", activation)?;
let shadow_color = this.get("shadowColor", activation)?;
let shadow_alpha = this.get("shadowAlpha", 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,
highlight_color,
highlight_alpha,
shadow_color,
shadow_alpha,
blur_x,
blur_y,
strength,
quality,
type_,
knockout,
],
)?;
return Ok(cloned.into());
}
Ok(Value::Undefined)
}

View File

@ -40,21 +40,6 @@ pub fn constructor<'gc>(
Ok(Value::Undefined)
}
pub fn clone<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let proto = activation.context.avm1.prototypes.blur_filter_constructor;
let blur_x = this.get("blurX", activation)?;
let blur_y = this.get("blurY", activation)?;
let quality = this.get("quality", activation)?;
let cloned = proto.construct(activation, &[blur_x, blur_y, quality])?;
Ok(cloned.into())
}
pub fn get_blur_x<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
@ -139,9 +124,7 @@ pub fn create_proto<'gc>(
fn_proto: Object<'gc>,
) -> Object<'gc> {
let blur_filter = BlurFilterObject::empty_object(gc_context, Some(proto));
let mut object = blur_filter.as_script_object().unwrap();
object.force_set_function("clone", clone, gc_context, EnumSet::empty(), Some(fn_proto));
let object = blur_filter.as_script_object().unwrap();
object.add_property(
gc_context,

View File

@ -47,7 +47,6 @@ pub struct BevelFilterData<'gc> {
/// The underlying script object.
base: ScriptObject<'gc>,
//TODO: is this an int
angle: f64,
blur_x: f64,
blur_y: f64,
@ -104,7 +103,7 @@ impl<'gc> BevelFilterObject<'gc> {
[set_shadow_alpha, get_shadow_alpha, shadow_alpha, f64],
[set_shadow_color, get_shadow_color, shadow_color, i32],
[set_strength, get_strength, strength, f64],
[set_type, get_type, type_, BevelFilterType], //TODO: type
[set_type, get_type, type_, BevelFilterType],
);
pub fn empty_object(gc_context: MutationContext<'gc, '_>, proto: Option<Object<'gc>>) -> Self {
@ -112,17 +111,17 @@ impl<'gc> BevelFilterObject<'gc> {
gc_context,
BevelFilterData {
base: ScriptObject::object(gc_context, proto),
angle: 45.0,
angle: 44.9999999772279,
blur_x: 4.0,
blur_y: 4.0,
distance: 4.0, // TODO: check if int
distance: 4.0,
highlight_alpha: 1.0,
highlight_color: 0xFFFFFF.into(), //TODO: int?
highlight_color: 0xFFFFFF,
knockout: false,
quality: 1, //TODO: must be int!!
quality: 1,
shadow_alpha: 1.0,
shadow_color: 0x000000.into(), //TODO: is int?
strength: 1.0, // Int?
shadow_color: 0x000000,
strength: 1.0,
type_: BevelFilterType::Inner,
},
))

View File

@ -28,6 +28,8 @@ false
1
// x.type
inner
// x.angle (after set to 360)
0
// x.angle (after set to 361)
1
// x.blurX(after set to 100)
@ -36,6 +38,8 @@ inner
100
// x.distance (after set to 1000)
1000
// x.distance (after set to 2.5)
2.5
// x.highlightAlpha (after set to 1.5)
1
// x.highlightColor (after set to 0x1000000)
@ -50,6 +54,8 @@ inner
0
// x.strength (after set to 256)
255
// x.strength (after set to 1.5)
1.5
// x.angle (after set to -1)
-1
// x.angle (after set to -366)
@ -64,6 +70,8 @@ inner
0
// x.highlightColor (after set to -1)
16777215
// x.highlightColor (after set to -10)
16777206
// x.quality(after set to 2.5)
2
// x.quality(after set to -1)
@ -72,6 +80,8 @@ inner
0
// x.shadowColor (after set to -1)
16777215
// x.shadowColor (after set to -0x11234567)
14465689
// x.strength (after set to -1)
0
// x.type (after set to "invalid")