render: Add Filter::DisplacementMapFilter

This commit is contained in:
Nathan Adams 2023-02-23 02:54:03 +01:00
parent f9c7303f01
commit dbe2efff00
2 changed files with 172 additions and 3 deletions

View File

@ -1,10 +1,12 @@
use crate::avm2::error::type_error;
use crate::avm2::{Activation, ArrayObject, Error, Object, TObject, Value};
use ruffle_render::filters::{
BevelFilter, BevelFilterType, BlurFilter, ColorMatrixFilter, ConvolutionFilter, Filter,
BevelFilter, BevelFilterType, BlurFilter, ColorMatrixFilter, ConvolutionFilter,
DisplacementMapFilter, DisplacementMapFilterMode, Filter,
};
use swf::Color;
use crate::avm2::error::{argument_error, type_error};
use crate::avm2::{Activation, ArrayObject, Error, Object, TObject, Value};
pub trait FilterAvm2Ext {
fn from_avm2_object<'gc>(
activation: &mut Activation<'_, 'gc>,
@ -42,6 +44,11 @@ impl FilterAvm2Ext for Filter {
return ConvolutionFilter::from_avm2_object(activation, object);
}
let displacement_map_filter = activation.avm2().classes().displacementmapfilter;
if object.is_of_type(displacement_map_filter, activation) {
return DisplacementMapFilter::from_avm2_object(activation, object);
}
Err(Error::AvmError(type_error(
activation,
&format!(
@ -60,6 +67,7 @@ impl FilterAvm2Ext for Filter {
Filter::BlurFilter(filter) => filter.as_avm2_object(activation),
Filter::ColorMatrixFilter(filter) => filter.as_avm2_object(activation),
Filter::ConvolutionFilter(filter) => filter.as_avm2_object(activation),
Filter::DisplacementMapFilter(filter) => filter.as_avm2_object(activation),
}
}
}
@ -304,3 +312,119 @@ impl FilterAvm2Ext for ConvolutionFilter {
)
}
}
impl FilterAvm2Ext for DisplacementMapFilter {
fn from_avm2_object<'gc>(
activation: &mut Activation<'_, 'gc>,
object: Object<'gc>,
) -> Result<Filter, Error<'gc>> {
let alpha = object
.get_public_property("alpha", activation)?
.coerce_to_number(activation)?;
let color = object
.get_public_property("color", activation)?
.coerce_to_u32(activation)?;
let component_x = object
.get_public_property("componentX", activation)?
.coerce_to_u32(activation)?;
let component_y = object
.get_public_property("componentY", activation)?
.coerce_to_u32(activation)?;
let map_point =
if let Value::Object(point) = object.get_public_property("mapPoint", activation)? {
(
point
.get_public_property("x", activation)?
.coerce_to_u32(activation)?,
point
.get_public_property("y", activation)?
.coerce_to_u32(activation)?,
)
} else {
(0, 0)
};
let mode = if let Value::String(mode) = object.get_public_property("mode", activation)? {
if &mode == b"clamp" {
DisplacementMapFilterMode::Clamp
} else if &mode == b"ignore" {
DisplacementMapFilterMode::Ignore
} else if &mode == b"color" {
DisplacementMapFilterMode::Color
} else if &mode == b"wrap" {
DisplacementMapFilterMode::Wrap
} else {
return Err(Error::AvmError(argument_error(
activation,
"Parameter mode must be one of the accepted values.",
2008,
)?));
}
} else {
DisplacementMapFilterMode::Wrap
};
let scale_x = object
.get_public_property("scaleX", activation)?
.coerce_to_number(activation)?;
let scale_y = object
.get_public_property("scaleY", activation)?
.coerce_to_number(activation)?;
let map_bitmap = if let Value::Object(bitmap) =
object.get_public_property("mapBitmap", activation)?
{
if let Some(bitmap) = bitmap.as_bitmap_data() {
bitmap
.write(activation.context.gc_context)
.bitmap_handle(activation.context.renderer)
} else {
return Err(Error::AvmError(type_error(
activation,
&format!("Type Coercion failed: cannot convert {bitmap:?} to flash.display.BitmapData."),
1034,
)?));
}
} else {
None
};
Ok(Filter::DisplacementMapFilter(DisplacementMapFilter {
color: Color::from_rgb(color, (alpha * 255.0) as u8),
component_x: component_x as u8,
component_y: component_y as u8,
map_bitmap,
map_point,
mode,
scale_x: scale_x as f32,
scale_y: scale_y as f32,
}))
}
fn as_avm2_object<'gc>(
&self,
activation: &mut Activation<'_, 'gc>,
) -> Result<Object<'gc>, Error<'gc>> {
let point = activation.avm2().classes().point;
let map_point = point.construct(
activation,
&[self.map_point.0.into(), self.map_point.1.into()],
)?;
let mode = match self.mode {
DisplacementMapFilterMode::Clamp => "clamp",
DisplacementMapFilterMode::Color => "color",
DisplacementMapFilterMode::Ignore => "ignore",
DisplacementMapFilterMode::Wrap => "wrap",
};
activation.avm2().classes().displacementmapfilter.construct(
activation,
&[
Value::Null, // TODO: This should be a BitmapData...
map_point.into(),
self.component_x.into(),
self.component_y.into(),
self.scale_x.into(),
self.scale_y.into(),
mode.into(),
self.color.to_rgb().into(),
(f64::from(self.color.a) / 255.0).into(),
],
)
}
}

View File

@ -1,3 +1,4 @@
use crate::bitmap::BitmapHandle;
use swf::{BevelFilterFlags, Color, Fixed16};
#[derive(Debug, Clone)]
@ -6,6 +7,7 @@ pub enum Filter {
BlurFilter(BlurFilter),
ColorMatrixFilter(ColorMatrixFilter),
ConvolutionFilter(ConvolutionFilter),
DisplacementMapFilter(DisplacementMapFilter),
}
impl Default for Filter {
@ -174,3 +176,46 @@ impl Default for ConvolutionFilter {
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DisplacementMapFilterComponent {
Alpha,
Blue,
Green,
Red,
}
#[derive(Debug, Clone, Copy)]
pub enum DisplacementMapFilterMode {
Clamp,
Color,
Ignore,
Wrap,
}
#[derive(Debug, Clone)]
pub struct DisplacementMapFilter {
pub color: Color,
pub component_x: u8,
pub component_y: u8,
pub map_bitmap: Option<BitmapHandle>,
pub map_point: (u32, u32),
pub mode: DisplacementMapFilterMode,
pub scale_x: f32,
pub scale_y: f32,
}
impl Default for DisplacementMapFilter {
fn default() -> Self {
Self {
color: Color::from_rgba(0),
component_x: 0,
component_y: 0,
map_bitmap: None,
map_point: (0, 0),
mode: DisplacementMapFilterMode::Wrap,
scale_x: 0.0,
scale_y: 0.0,
}
}
}