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 boolean;
|
||||||
pub(crate) mod button;
|
pub(crate) mod button;
|
||||||
mod color;
|
mod color;
|
||||||
|
mod color_transform;
|
||||||
pub(crate) mod display_object;
|
pub(crate) mod display_object;
|
||||||
pub(crate) mod error;
|
pub(crate) mod error;
|
||||||
mod function;
|
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 point_proto: Object<'gc> = point::create_proto(gc_context, object_proto, function_proto);
|
||||||
let rectangle_proto: Object<'gc> =
|
let rectangle_proto: Object<'gc> =
|
||||||
rectangle::create_proto(gc_context, object_proto, function_proto);
|
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
|
//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);
|
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 point = point::create_point_object(gc_context, Some(point_proto), Some(function_proto));
|
||||||
let rectangle =
|
let rectangle =
|
||||||
rectangle::create_rectangle_object(gc_context, Some(rectangle_proto), Some(function_proto));
|
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());
|
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, "Matrix", matrix.into(), EnumSet::empty());
|
||||||
geom.define_value(gc_context, "Point", point.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, "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));
|
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