core: Implement ColorTransform
This commit is contained in:
parent
328246dc10
commit
a8f7638d99
|
@ -14,6 +14,7 @@ mod array;
|
|||
pub(crate) mod boolean;
|
||||
pub(crate) mod button;
|
||||
mod color;
|
||||
mod color_transform;
|
||||
pub(crate) mod display_object;
|
||||
pub(crate) mod error;
|
||||
mod function;
|
||||
|
@ -218,6 +219,8 @@ pub fn create_globals<'gc>(
|
|||
let point_proto: Object<'gc> = point::create_proto(gc_context, object_proto, function_proto);
|
||||
let rectangle_proto: Object<'gc> =
|
||||
rectangle::create_proto(gc_context, object_proto, function_proto);
|
||||
let color_transform_proto: Object<'gc> =
|
||||
color_transform::create_proto(gc_context, object_proto, function_proto);
|
||||
|
||||
//TODO: These need to be constructors and should also set `.prototype` on each one
|
||||
let object = object::create_object_object(gc_context, object_proto, function_proto);
|
||||
|
@ -301,11 +304,22 @@ pub fn create_globals<'gc>(
|
|||
let point = point::create_point_object(gc_context, Some(point_proto), Some(function_proto));
|
||||
let rectangle =
|
||||
rectangle::create_rectangle_object(gc_context, Some(rectangle_proto), Some(function_proto));
|
||||
let color_transform = color_transform::create_color_transform_object(
|
||||
gc_context,
|
||||
Some(color_transform_proto),
|
||||
Some(function_proto),
|
||||
);
|
||||
|
||||
flash.define_value(gc_context, "geom", geom.into(), EnumSet::empty());
|
||||
geom.define_value(gc_context, "Matrix", matrix.into(), EnumSet::empty());
|
||||
geom.define_value(gc_context, "Point", point.into(), EnumSet::empty());
|
||||
geom.define_value(gc_context, "Rectangle", rectangle.into(), EnumSet::empty());
|
||||
geom.define_value(
|
||||
gc_context,
|
||||
"ColorTransform",
|
||||
color_transform.into(),
|
||||
EnumSet::empty(),
|
||||
);
|
||||
|
||||
let listeners = SystemListeners::new(gc_context, Some(array_proto));
|
||||
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
//! ColorTransform object
|
||||
|
||||
use crate::avm1::error::Error;
|
||||
use crate::avm1::function::{Executable, FunctionObject};
|
||||
use crate::avm1::return_value::ReturnValue;
|
||||
use crate::avm1::{Avm1, Object, ScriptObject, TObject, UpdateContext, Value};
|
||||
use crate::color_transform::ColorTransform;
|
||||
use enumset::EnumSet;
|
||||
use gc_arena::MutationContext;
|
||||
use std::borrow::ToOwned;
|
||||
use std::convert::Into;
|
||||
|
||||
pub fn constructor<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error<'gc>> {
|
||||
let red_multiplier = args
|
||||
.get(0)
|
||||
.unwrap_or(&Value::Number(1.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let green_multiplier = args
|
||||
.get(1)
|
||||
.unwrap_or(&Value::Number(1.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let blue_multiplier = args
|
||||
.get(2)
|
||||
.unwrap_or(&Value::Number(1.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let alpha_multiplier = args
|
||||
.get(3)
|
||||
.unwrap_or(&Value::Number(1.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let red_offset = args
|
||||
.get(4)
|
||||
.unwrap_or(&Value::Number(0.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let green_offset = args
|
||||
.get(5)
|
||||
.unwrap_or(&Value::Number(0.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let blue_offset = args
|
||||
.get(6)
|
||||
.unwrap_or(&Value::Number(0.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
let alpha_offset = args
|
||||
.get(7)
|
||||
.unwrap_or(&Value::Number(0.into()))
|
||||
.to_owned()
|
||||
.coerce_to_f64(avm, context)?;
|
||||
|
||||
let ct = ColorTransform {
|
||||
r_mult: red_multiplier as f32,
|
||||
g_mult: green_multiplier as f32,
|
||||
b_mult: blue_multiplier as f32,
|
||||
a_mult: alpha_multiplier as f32,
|
||||
r_add: red_offset as f32,
|
||||
g_add: green_offset as f32,
|
||||
b_add: blue_offset as f32,
|
||||
a_add: alpha_offset as f32,
|
||||
};
|
||||
|
||||
apply_color_transform_to_object(ct, this, avm, context)?;
|
||||
|
||||
Ok(Value::Undefined.into())
|
||||
}
|
||||
|
||||
pub fn apply_color_transform_to_object<'gc>(
|
||||
color_transform: ColorTransform,
|
||||
object: Object<'gc>,
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
) -> Result<(), Error<'gc>> {
|
||||
object.set("redMultiplier", color_transform.r_mult.into(), avm, context)?;
|
||||
object.set(
|
||||
"greenMultiplier",
|
||||
color_transform.g_mult.into(),
|
||||
avm,
|
||||
context,
|
||||
)?;
|
||||
object.set(
|
||||
"blueMultiplier",
|
||||
color_transform.b_mult.into(),
|
||||
avm,
|
||||
context,
|
||||
)?;
|
||||
object.set(
|
||||
"alphaMultiplier",
|
||||
color_transform.a_mult.into(),
|
||||
avm,
|
||||
context,
|
||||
)?;
|
||||
object.set("redOffset", color_transform.r_add.into(), avm, context)?;
|
||||
object.set("greenOffset", color_transform.g_add.into(), avm, context)?;
|
||||
object.set("blueOffset", color_transform.b_add.into(), avm, context)?;
|
||||
object.set("alphaOffset", color_transform.a_add.into(), avm, context)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn object_to_color_transform<'gc>(
|
||||
object: Object<'gc>,
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
) -> Result<ColorTransform, Error<'gc>> {
|
||||
let red_multiplier = object
|
||||
.get("redMultiplier", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let green_multiplier = object
|
||||
.get("greenMultiplier", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let blue_multiplier = object
|
||||
.get("blueMultiplier", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let alpha_multiplier = object
|
||||
.get("alphaMultiplier", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let red_offset = object
|
||||
.get("redOffset", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let green_offset = object
|
||||
.get("greenOffset", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let blue_offset = object
|
||||
.get("blueOffset", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
let alpha_offset = object
|
||||
.get("alphaOffset", avm, context)?
|
||||
.coerce_to_f64(avm, context)? as f32;
|
||||
|
||||
Ok(ColorTransform {
|
||||
r_mult: red_multiplier,
|
||||
g_mult: green_multiplier,
|
||||
b_mult: blue_multiplier,
|
||||
a_mult: alpha_multiplier,
|
||||
r_add: red_offset,
|
||||
g_add: green_offset,
|
||||
b_add: blue_offset,
|
||||
a_add: alpha_offset,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_rgb<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error<'gc>> {
|
||||
let ct = object_to_color_transform(this, avm, context)?;
|
||||
let rgb = ((ct.r_add as u32) << 16) | ((ct.g_add as u32) << 8) | (ct.b_add as u32);
|
||||
Ok(Value::Number(rgb.into()).into())
|
||||
}
|
||||
|
||||
pub fn set_rgb<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error<'gc>> {
|
||||
let new_rgb = args
|
||||
.get(0)
|
||||
.unwrap_or(&Value::Undefined)
|
||||
.coerce_to_f64(avm, context)? as u64;
|
||||
|
||||
let red = ((new_rgb >> 16) & 0xFF) as f64;
|
||||
let green = ((new_rgb >> 8) & 0xFF) as f64;
|
||||
let blue = (new_rgb & 0xFF) as f64;
|
||||
|
||||
this.set("redOffset", red.into(), avm, context)?;
|
||||
this.set("greenOffset", green.into(), avm, context)?;
|
||||
this.set("blueOffset", blue.into(), avm, context)?;
|
||||
|
||||
this.set("redMultiplier", 0.into(), avm, context)?;
|
||||
this.set("greenMultiplier", 0.into(), avm, context)?;
|
||||
this.set("blueMultiplier", 0.into(), avm, context)?;
|
||||
|
||||
Ok(Value::Undefined.into())
|
||||
}
|
||||
|
||||
pub fn create_color_transform_object<'gc>(
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
point_proto: Option<Object<'gc>>,
|
||||
fn_proto: Option<Object<'gc>>,
|
||||
) -> Object<'gc> {
|
||||
FunctionObject::function(
|
||||
gc_context,
|
||||
Executable::Native(constructor),
|
||||
fn_proto,
|
||||
point_proto,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_proto<'gc>(
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
proto: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
let mut object = ScriptObject::object(gc_context, Some(proto));
|
||||
|
||||
object.force_set_function(
|
||||
"concat",
|
||||
concat,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
Some(fn_proto),
|
||||
);
|
||||
|
||||
object.force_set_function(
|
||||
"toString",
|
||||
to_string,
|
||||
gc_context,
|
||||
EnumSet::empty(),
|
||||
Some(fn_proto),
|
||||
);
|
||||
|
||||
object.add_property(
|
||||
gc_context,
|
||||
"rgb",
|
||||
Executable::Native(get_rgb),
|
||||
Some(Executable::Native(set_rgb)),
|
||||
EnumSet::empty(),
|
||||
);
|
||||
|
||||
object.into()
|
||||
}
|
||||
|
||||
fn to_string<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error<'gc>> {
|
||||
let ct = object_to_color_transform(this, avm, context)?;
|
||||
|
||||
let formatted = format!("(redMultiplier={}, greenMultiplier={}, blueMultiplier={}, alphaMultiplier={}, redOffset={}, greenOffset={}, blueOffset={}, alphaOffset={})",
|
||||
ct.r_mult,
|
||||
ct.g_mult,
|
||||
ct.b_mult,
|
||||
ct.a_mult,
|
||||
ct.r_add,
|
||||
ct.g_add,
|
||||
ct.b_add,
|
||||
ct.a_add
|
||||
);
|
||||
|
||||
Ok(Value::String(formatted).into())
|
||||
}
|
||||
|
||||
fn concat<'gc>(
|
||||
avm: &mut Avm1<'gc>,
|
||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<ReturnValue<'gc>, Error<'gc>> {
|
||||
// Without an arg, does nothing
|
||||
if let Some(arg) = _args.get(0) {
|
||||
// If given an invalid var, return undefined
|
||||
if arg == &Value::Undefined {
|
||||
return Ok(Value::Undefined.into());
|
||||
}
|
||||
let other = arg.coerce_to_object(avm, context);
|
||||
let other_ct: ColorTransform = object_to_color_transform(other, avm, context)?;
|
||||
let this_ct: ColorTransform = object_to_color_transform(this, avm, context)?;
|
||||
|
||||
let new_ct = ColorTransform {
|
||||
r_mult: other_ct.r_mult * this_ct.r_mult,
|
||||
g_mult: other_ct.g_mult * this_ct.g_mult,
|
||||
b_mult: other_ct.b_mult * this_ct.b_mult,
|
||||
a_mult: other_ct.a_mult * this_ct.a_mult,
|
||||
r_add: (other_ct.r_add * this_ct.r_mult) + this_ct.r_add,
|
||||
g_add: (other_ct.g_add * this_ct.g_mult) + this_ct.g_add,
|
||||
b_add: (other_ct.b_add * this_ct.b_mult) + this_ct.b_add,
|
||||
a_add: (other_ct.a_add * this_ct.a_mult) + this_ct.a_add,
|
||||
};
|
||||
|
||||
// This appears to do nothing if values are out of range
|
||||
if 0.0 > new_ct.r_mult
|
||||
|| new_ct.r_mult > 1.0
|
||||
|| 0.0 > new_ct.g_mult
|
||||
|| new_ct.g_mult > 1.0
|
||||
|| 0.0 > new_ct.b_mult
|
||||
|| new_ct.b_mult > 1.0
|
||||
|| 0.0 > new_ct.a_mult
|
||||
|| new_ct.a_mult > 1.0
|
||||
|| -255.0 > new_ct.r_add
|
||||
|| new_ct.r_add > 255.0
|
||||
|| -255.0 > new_ct.g_add
|
||||
|| new_ct.g_add > 255.0
|
||||
|| -255.0 > new_ct.b_add
|
||||
|| new_ct.b_add > 255.0
|
||||
|| -255.0 > new_ct.a_add
|
||||
|| new_ct.a_add > 255.0
|
||||
{
|
||||
return Ok(Value::Undefined.into());
|
||||
}
|
||||
|
||||
|
||||
apply_color_transform_to_object(new_ct, this, avm, context)?;
|
||||
}
|
||||
|
||||
Ok(Value::Undefined.into())
|
||||
}
|
Loading…
Reference in New Issue