core: Matrix translation is in twips

This commit is contained in:
Mike Welsh 2020-02-18 11:39:53 -08:00
parent c4c02260fb
commit 223edb9bc1
12 changed files with 217 additions and 193 deletions

View File

@ -85,7 +85,7 @@ pub fn text_width<'gc>(
{
let metrics = etext.measure_text(context);
return Ok(metrics.0.into());
return Ok(metrics.0.to_pixels().into());
}
Ok(Value::Undefined.into())
@ -103,7 +103,7 @@ pub fn text_height<'gc>(
{
let metrics = etext.measure_text(context);
return Ok(metrics.1.into());
return Ok(metrics.1.to_pixels().into());
}
Ok(Value::Undefined.into())

View File

@ -142,18 +142,18 @@ impl<'gc> DisplayObjectBase<'gc> {
self.transform.color_transform = *color_transform;
}
fn x(&self) -> f64 {
f64::from(self.transform.matrix.tx) / Twips::TWIPS_PER_PIXEL
self.transform.matrix.tx.to_pixels()
}
fn set_x(&mut self, value: f64) {
self.set_transformed_by_script(true);
self.transform.matrix.tx = (value * Twips::TWIPS_PER_PIXEL) as f32
self.transform.matrix.tx = Twips::from_pixels(value)
}
fn y(&self) -> f64 {
f64::from(self.transform.matrix.ty) / Twips::TWIPS_PER_PIXEL
self.transform.matrix.ty.to_pixels()
}
fn set_y(&mut self, value: f64) {
self.set_transformed_by_script(true);
self.transform.matrix.ty = (value * Twips::TWIPS_PER_PIXEL) as f32
self.transform.matrix.ty = Twips::from_pixels(value)
}
/// Caches the scale and rotation factors for this display object, if necessary.

View File

@ -226,9 +226,9 @@ impl<'gc> EditText<'gc> {
transform.color_transform.a_mult = f32::from(color.a) / 255.0;
if let Some(layout) = &static_data.text.layout {
transform.matrix.tx += layout.left_margin.get() as f32;
transform.matrix.tx += layout.indent.get() as f32;
transform.matrix.ty -= layout.leading.get() as f32;
transform.matrix.tx += layout.left_margin;
transform.matrix.tx += layout.indent;
transform.matrix.ty -= layout.leading;
}
transform
@ -239,31 +239,31 @@ impl<'gc> EditText<'gc> {
///
/// This function takes the current font size and the transform to adjust,
/// and returns the adjusted transform.
pub fn newline(self, height: f32, mut transform: Transform) -> Transform {
pub fn newline(self, height: Twips, mut transform: Transform) -> Transform {
let edit_text = self.0.read();
let static_data = &edit_text.static_data;
transform.matrix.tx = 0.0;
transform.matrix.ty += height * Twips::TWIPS_PER_PIXEL as f32;
transform.matrix.tx = Twips::new(0);
transform.matrix.ty += height;
if let Some(layout) = &static_data.text.layout {
transform.matrix.tx += layout.left_margin.get() as f32;
transform.matrix.tx += layout.indent.get() as f32;
transform.matrix.ty += layout.leading.get() as f32;
transform.matrix.tx += layout.left_margin;
transform.matrix.tx += layout.indent;
transform.matrix.ty += layout.leading;
}
transform
}
pub fn line_width(self) -> f32 {
pub fn line_width(self) -> Twips {
let edit_text = self.0.read();
let static_data = &edit_text.static_data;
let mut base_width = self.width() as f32;
let mut base_width = Twips::from_pixels(self.width());
if let Some(layout) = &static_data.text.layout {
base_width -= layout.left_margin.to_pixels() as f32;
base_width -= layout.indent.to_pixels() as f32;
base_width -= layout.right_margin.to_pixels() as f32;
base_width -= layout.left_margin;
base_width -= layout.indent;
base_width -= layout.right_margin;
}
base_width
@ -311,8 +311,7 @@ impl<'gc> EditText<'gc> {
let height = static_data
.text
.height
.map(|v| v.to_pixels() as f32)
.unwrap_or_else(|| font.scale());
.unwrap_or_else(|| Twips::from_pixels(font.scale().into()));
for natural_line in edit_text.text.split('\n') {
if break_base != 0 {
@ -364,14 +363,14 @@ impl<'gc> EditText<'gc> {
/// Measure the width and height of the `EditText`'s current text load.
///
/// The returned tuple should be interpreted as width, then height.
pub fn measure_text(self, context: &mut UpdateContext<'_, 'gc, '_>) -> (f32, f32) {
pub fn measure_text(self, context: &mut UpdateContext<'_, 'gc, '_>) -> (Twips, Twips) {
let breakpoints = self.line_breaks_cached(context.gc_context, context.library);
let edit_text = self.0.read();
let static_data = &edit_text.static_data;
let font_id = static_data.text.font_id.unwrap_or(0);
let mut size: (f32, f32) = (0.0, 0.0);
let mut size: (Twips, Twips) = Default::default();
if let Some(font) = context
.library
@ -399,15 +398,14 @@ impl<'gc> EditText<'gc> {
let height = static_data
.text
.height
.map(|v| v.to_pixels() as f32)
.unwrap_or_else(|| font.scale());
.unwrap_or_else(|| Twips::from_pixels(font.scale().into()));
for chunk in chunks {
let chunk_size = font.measure(chunk, height);
size.0 = size.0.max(chunk_size.0);
if let Some(layout) = &static_data.text.layout {
size.1 += layout.leading.to_pixels() as f32;
size.1 += layout.leading;
}
size.1 += chunk_size.1;
}
@ -490,8 +488,7 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
let height = static_data
.text
.height
.map(|v| v.to_pixels() as f32)
.unwrap_or_else(|| font.scale());
.unwrap_or_else(|| Twips::from_pixels(font.scale().into()));
let breakpoints = edit_text
.cached_break_points

View File

@ -71,25 +71,25 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
a: 0,
};
let mut font_id = 0;
let mut height = 0.0;
let mut height = Twips::new(0);
let mut transform: Transform = Default::default();
for block in &tf.static_data.text_blocks {
if let Some(x) = block.x_offset {
transform.matrix.tx = x.get() as f32;
transform.matrix.tx = x;
}
if let Some(y) = block.y_offset {
transform.matrix.ty = y.get() as f32;
transform.matrix.ty = y;
}
color = block.color.as_ref().unwrap_or(&color).clone();
font_id = block.font_id.unwrap_or(font_id);
height = block.height.map(|h| h.get() as f32).unwrap_or(height);
height = block.height.unwrap_or(height);
if let Some(font) = context
.library
.library_for_movie(self.movie().unwrap())
.unwrap()
.get_font(font_id)
{
let scale = height / font.scale();
let scale = (height.get() as f32) / font.scale();
transform.matrix.a = scale;
transform.matrix.d = scale;
transform.color_transform.r_mult = f32::from(color.r) / 255.0;
@ -103,7 +103,7 @@ impl<'gc> TDisplayObject<'gc> for Text<'gc> {
.renderer
.render_shape(glyph.shape, context.transform_stack.transform());
context.transform_stack.pop();
transform.matrix.tx += c.advance as f32;
transform.matrix.tx += Twips::new(c.advance);
}
}
}

View File

@ -132,13 +132,13 @@ impl<'gc> Font<'gc> {
self,
text: &str,
mut transform: Transform,
height: f32,
height: Twips,
mut glyph_func: FGlyph,
) where
FGlyph: FnMut(&Transform, &Glyph),
{
transform.matrix.ty += height * Twips::TWIPS_PER_PIXEL as f32;
let scale = (height * Twips::TWIPS_PER_PIXEL as f32) / self.scale();
transform.matrix.ty += height;
let scale = height.get() as f32 / self.scale();
transform.matrix.a = scale;
transform.matrix.d = scale;
@ -148,26 +148,24 @@ impl<'gc> Font<'gc> {
if let Some(glyph) = self.get_glyph_for_char(c) {
glyph_func(&transform, &glyph);
// Step horizontally.
let mut advance = f32::from(glyph.advance);
let mut advance = Twips::new(glyph.advance);
if has_kerning_info {
advance += self
.get_kerning_offset(c, chars.peek().cloned().unwrap_or('\0'))
.get() as f32;
advance += self.get_kerning_offset(c, chars.peek().cloned().unwrap_or('\0'));
}
transform.matrix.tx += advance * scale;
transform.matrix.tx += Twips::new((advance.get() as f32 * scale) as i32);
}
}
}
/// Measure a particular string's metrics (width and height).
pub fn measure(self, text: &str, height: f32) -> (f32, f32) {
let mut size = (0.0, 0.0);
pub fn measure(self, text: &str, height: Twips) -> (Twips, Twips) {
let mut size = (Twips::new(0), Twips::new(0));
self.evaluate(text, Default::default(), height, |transform, _glyph| {
let tx = transform.matrix.tx / Twips::TWIPS_PER_PIXEL as f32;
let ty = transform.matrix.ty / Twips::TWIPS_PER_PIXEL as f32;
size.0 = f32::max(size.0, tx);
size.1 = f32::max(size.1, ty);
let tx = transform.matrix.tx;
let ty = transform.matrix.ty;
size.0 = std::cmp::max(size.0, tx);
size.1 = std::cmp::max(size.1, ty);
});
size
@ -178,7 +176,7 @@ impl<'gc> Font<'gc> {
///
/// This function assumes only `" "` is valid whitespace to split words on,
/// and will not attempt to break words that are longer than `width`.
pub fn split_wrapped_lines(self, text: &str, height: f32, width: f32) -> Vec<usize> {
pub fn split_wrapped_lines(self, text: &str, height: Twips, width: Twips) -> Vec<usize> {
let mut result = vec![];
let mut current_width = width;
let mut current_word = &text[0..0];

View File

@ -6,20 +6,30 @@ pub struct Matrix {
pub b: f32,
pub c: f32,
pub d: f32,
pub tx: f32,
pub ty: f32,
pub tx: Twips,
pub ty: Twips,
}
impl Matrix {
pub fn invert(&mut self) {
let (tx, ty) = (self.tx.get() as f32, self.ty.get() as f32);
let det = self.a * self.d - self.b * self.c;
let a = self.d / det;
let b = self.b / -det;
let c = self.c / -det;
let d = self.a / det;
let tx = (self.d * self.tx - self.c * self.ty) / -det;
let ty = (self.b * self.tx - self.a * self.ty) / det;
*self = Matrix { a, b, c, d, tx, ty };
let (out_tx, out_ty) = (
round_to_i32((self.d * tx - self.c * ty) / -det),
round_to_i32((self.b * tx - self.a * ty) / det),
);
*self = Matrix {
a,
b,
c,
d,
tx: Twips::new(out_tx),
ty: Twips::new(out_ty),
};
}
}
@ -30,8 +40,8 @@ impl From<swf::Matrix> for Matrix {
b: matrix.rotate_skew_0,
c: matrix.rotate_skew_1,
d: matrix.scale_y,
tx: matrix.translate_x.get() as f32,
ty: matrix.translate_y.get() as f32,
tx: matrix.translate_x,
ty: matrix.translate_y,
}
}
}
@ -39,13 +49,18 @@ impl From<swf::Matrix> for Matrix {
impl std::ops::Mul for Matrix {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
let (rhs_tx, rhs_ty) = (rhs.tx.get() as f32, rhs.ty.get() as f32);
let (out_tx, out_ty) = (
round_to_i32(self.a * rhs_tx + self.c * rhs_ty).wrapping_add(self.tx.get()),
round_to_i32(self.b * rhs_tx + self.d * rhs_ty).wrapping_add(self.ty.get()),
);
Matrix {
a: self.a * rhs.a + self.c * rhs.b,
b: self.b * rhs.a + self.d * rhs.b,
c: self.a * rhs.c + self.c * rhs.d,
d: self.b * rhs.c + self.d * rhs.d,
tx: self.a * rhs.tx + self.c * rhs.ty + self.tx,
ty: self.b * rhs.tx + self.d * rhs.ty + self.ty,
tx: Twips::new(out_tx),
ty: Twips::new(out_ty),
}
}
}
@ -54,9 +69,9 @@ impl std::ops::Mul<(Twips, Twips)> for Matrix {
type Output = (Twips, Twips);
fn mul(self, (x, y): (Twips, Twips)) -> (Twips, Twips) {
let (x, y) = (x.get() as f32, y.get() as f32);
let out_x = self.a * x + self.c * y + self.tx;
let out_y = self.b * x + self.d * y + self.ty;
(Twips::new(out_x as i32), Twips::new(out_y as i32))
let out_x = round_to_i32(self.a * x + self.c * y).wrapping_add(self.tx.get());
let out_y = round_to_i32(self.b * x + self.d * y).wrapping_add(self.ty.get());
(Twips::new(out_x), Twips::new(out_y))
}
}
@ -65,23 +80,28 @@ impl std::default::Default for Matrix {
Matrix {
a: 1.0,
c: 0.0,
tx: 0.0,
tx: Twips::new(0),
b: 0.0,
d: 1.0,
ty: 0.0,
ty: Twips::new(0),
}
}
}
impl std::ops::MulAssign for Matrix {
fn mul_assign(&mut self, rhs: Self) {
let (rhs_tx, rhs_ty) = (rhs.tx.get() as f32, rhs.ty.get() as f32);
let (out_tx, out_ty) = (
round_to_i32(self.a * rhs_tx + self.c * rhs_ty) + self.tx.get(),
round_to_i32(self.b * rhs_tx + self.d * rhs_ty) + self.ty.get(),
);
*self = Matrix {
a: self.a * rhs.a + self.c * rhs.b,
b: self.b * rhs.a + self.d * rhs.b,
c: self.a * rhs.c + self.c * rhs.d,
d: self.b * rhs.c + self.d * rhs.d,
tx: self.a * rhs.tx + self.c * rhs.ty + self.tx,
ty: self.b * rhs.tx + self.d * rhs.ty + self.ty,
tx: Twips::new(out_tx),
ty: Twips::new(out_ty),
}
}
}
@ -129,18 +149,18 @@ mod tests {
}
impl AbsDiffEq for Matrix {
type Epsilon = <f32 as AbsDiffEq>::Epsilon;
type Epsilon = (<f32 as AbsDiffEq>::Epsilon, <i32 as AbsDiffEq>::Epsilon);
fn default_epsilon() -> Self::Epsilon {
f32::default_epsilon()
(f32::default_epsilon(), i32::default_epsilon())
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.a.abs_diff_eq(&other.a, epsilon)
&& self.b.abs_diff_eq(&other.b, epsilon)
&& self.c.abs_diff_eq(&other.c, epsilon)
&& self.d.abs_diff_eq(&other.d, epsilon)
&& self.tx.abs_diff_eq(&other.tx, epsilon)
&& self.ty.abs_diff_eq(&other.ty, epsilon)
self.a.abs_diff_eq(&other.a, epsilon.0)
&& self.b.abs_diff_eq(&other.b, epsilon.0)
&& self.c.abs_diff_eq(&other.c, epsilon.0)
&& self.d.abs_diff_eq(&other.d, epsilon.0)
&& self.tx.get().abs_diff_eq(&other.tx.get(), epsilon.1)
&& self.ty.get().abs_diff_eq(&other.ty.get(), epsilon.1)
}
}
@ -150,12 +170,12 @@ mod tests {
}
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.a.ulps_eq(&other.a, epsilon, max_ulps)
&& self.b.ulps_eq(&other.b, epsilon, max_ulps)
&& self.c.ulps_eq(&other.c, epsilon, max_ulps)
&& self.d.ulps_eq(&other.d, epsilon, max_ulps)
&& self.tx.ulps_eq(&other.tx, epsilon, max_ulps)
&& self.ty.ulps_eq(&other.ty, epsilon, max_ulps)
self.a.ulps_eq(&other.a, epsilon.0, max_ulps)
&& self.b.ulps_eq(&other.b, epsilon.0, max_ulps)
&& self.c.ulps_eq(&other.c, epsilon.0, max_ulps)
&& self.d.ulps_eq(&other.d, epsilon.0, max_ulps)
&& self.tx == other.tx
&& self.ty == other.ty
}
}
@ -172,72 +192,72 @@ mod tests {
Matrix {
a: 1.0,
c: 4.0,
tx: 7.0,
tx: Twips::from_pixels(7.0),
b: 2.0,
d: 5.0,
ty: 2.0
ty: Twips::from_pixels(2.0)
},
Matrix {
a: -1.666_666_6,
c: 1.333_333_3,
tx: 9.0,
tx: Twips::from_pixels(9.0),
b: 0.666_666_6,
d: -0.333_333_3,
ty: -4.0
ty: Twips::from_pixels(-4.0)
}
),
(
Matrix {
a: -1.0,
c: -4.0,
tx: -7.0,
tx: Twips::from_pixels(-7.0),
b: -2.0,
d: -5.0,
ty: -2.0
ty: Twips::from_pixels(-2.0)
},
Matrix {
a: 1.666_666_6,
c: -1.333_333_3,
tx: 9.0,
tx: Twips::from_pixels(9.0),
b: -0.666_666_6,
d: 0.333_333_3,
ty: -4.0
ty: Twips::from_pixels(-4.0)
}
),
(
Matrix {
a: 1.5,
c: 1.2,
tx: 1.0,
tx: Twips::from_pixels(1.0),
b: -2.7,
d: 3.4,
ty: -2.4
ty: Twips::from_pixels(-2.4)
},
Matrix {
a: 0.407_673_9,
c: -0.143_884_9,
tx: -0.752_997_6,
tx: Twips::from_pixels(-0.752_997_6),
b: 0.323_741,
d: 0.179_856_1,
ty: 0.107_913_67
ty: Twips::from_pixels(0.107_913_67)
}
),
(
Matrix {
a: -2.0,
c: 0.0,
tx: 10.0,
tx: Twips::from_pixels(10.0),
b: 0.0,
d: -1.0,
ty: 5.0
ty: Twips::from_pixels(5.0)
},
Matrix {
a: -0.5,
c: 0.0,
tx: 5.0,
tx: Twips::from_pixels(5.0),
b: 0.0,
d: -1.0,
ty: 5.0
ty: Twips::from_pixels(5.0)
}
)
);
@ -251,37 +271,37 @@ mod tests {
Matrix {
a: 1.0,
c: 4.0,
tx: 7.0,
tx: Twips::from_pixels(7.0),
b: 2.0,
d: 5.0,
ty: 2.0
ty: Twips::from_pixels(2.0)
},
Matrix {
a: 1.0,
c: 4.0,
tx: 7.0,
tx: Twips::from_pixels(7.0),
b: 2.0,
d: 5.0,
ty: 2.0
ty: Twips::from_pixels(2.0)
}
),
(
Matrix {
a: 1.0,
c: 4.0,
tx: 7.0,
tx: Twips::from_pixels(7.0),
b: 2.0,
d: 5.0,
ty: 2.0
ty: Twips::from_pixels(2.0)
},
Matrix::default(),
Matrix {
a: 1.0,
c: 4.0,
tx: 7.0,
tx: Twips::from_pixels(7.0),
b: 2.0,
d: 5.0,
ty: 2.0
ty: Twips::from_pixels(2.0)
}
)
);
@ -293,130 +313,130 @@ mod tests {
Matrix {
a: 6.0,
c: 4.0,
tx: 2.0,
tx: Twips::new(2),
b: 5.0,
d: 3.0,
ty: 1.0
ty: Twips::new(1)
},
Matrix {
a: 1.0,
c: 3.0,
tx: 5.0,
tx: Twips::new(5),
b: 2.0,
d: 4.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 14.0,
c: 34.0,
tx: 56.0,
tx: Twips::new(56),
b: 11.0,
d: 27.0,
ty: 44.0
ty: Twips::new(44)
}
),
(
Matrix {
a: 1.0,
c: 3.0,
tx: 5.0,
tx: Twips::new(5),
b: 2.0,
d: 4.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 6.0,
c: 4.0,
tx: 2.0,
tx: Twips::new(2),
b: 5.0,
d: 3.0,
ty: 1.0
ty: Twips::new(1)
},
Matrix {
a: 21.0,
c: 13.0,
tx: 10.0,
tx: Twips::new(10),
b: 32.0,
d: 20.0,
ty: 14.0
ty: Twips::new(14)
}
),
(
Matrix {
a: 1.0,
c: 2.0,
tx: 3.0,
tx: Twips::new(3),
b: 4.0,
d: 5.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 6.0,
c: 5.0,
tx: 4.0,
tx: Twips::new(4),
b: 3.0,
d: 2.0,
ty: 1.0
ty: Twips::new(1)
},
Matrix {
a: 12.0,
c: 9.0,
tx: 9.0,
tx: Twips::new(9),
b: 39.0,
d: 30.0,
ty: 27.0
ty: Twips::new(27)
}
),
(
Matrix {
a: 6.0,
c: 5.0,
tx: 4.0,
tx: Twips::new(4),
b: 3.0,
d: 2.0,
ty: 1.0
ty: Twips::new(1)
},
Matrix {
a: 1.0,
c: 2.0,
tx: 3.0,
tx: Twips::new(3),
b: 4.0,
d: 5.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 26.0,
c: 37.0,
tx: 52.0,
tx: Twips::new(52),
b: 11.0,
d: 16.0,
ty: 22.0
ty: Twips::new(22)
}
),
(
Matrix {
a: 1.0,
c: 2.0,
tx: 3.0,
tx: Twips::new(3),
b: 4.0,
d: 5.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 1.0,
c: 2.0,
tx: 3.0,
tx: Twips::new(3),
b: 4.0,
d: 5.0,
ty: 6.0
ty: Twips::new(6)
},
Matrix {
a: 9.0,
c: 12.0,
tx: 18.0,
tx: Twips::new(18),
b: 24.0,
d: 33.0,
ty: 48.0
ty: Twips::new(48)
}
)
);
@ -453,10 +473,10 @@ mod tests {
Matrix {
a: 1.0,
c: 0.0,
tx: 10.0,
tx: Twips::new(10),
b: 0.0,
d: 1.0,
ty: 5.0
ty: Twips::new(5)
},
(Twips::new(0), Twips::new(0)),
(Twips::new(10), Twips::new(5))
@ -465,25 +485,13 @@ mod tests {
Matrix {
a: 1.0,
c: 0.0,
tx: -200.0,
tx: Twips::new(-200),
b: 0.0,
d: 1.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(50), Twips::new(20)),
(Twips::new(-150), Twips::new(20))
),
(
Matrix {
a: 1.0,
c: 0.0,
tx: 1.125,
b: 0.0,
d: 1.0,
ty: 1.925
},
(Twips::new(0), Twips::new(0)),
(Twips::new(1), Twips::new(1))
)
);
@ -494,10 +502,10 @@ mod tests {
Matrix {
a: 3.0,
c: 0.0,
tx: 0.0,
tx: Twips::new(0),
b: 0.0,
d: 3.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(0), Twips::new(0)),
(Twips::new(0), Twips::new(0))
@ -506,10 +514,10 @@ mod tests {
Matrix {
a: 3.0,
c: 0.0,
tx: 0.0,
tx: Twips::new(0),
b: 0.0,
d: 3.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(10), Twips::new(10)),
(Twips::new(30), Twips::new(30))
@ -518,10 +526,10 @@ mod tests {
Matrix {
a: 0.6,
c: 0.0,
tx: 0.0,
tx: Twips::new(0),
b: 0.0,
d: 0.2,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(5), Twips::new(10)),
(Twips::new(3), Twips::new(2))
@ -530,10 +538,10 @@ mod tests {
Matrix {
a: 0.5,
c: 0.0,
tx: 0.0,
tx: Twips::new(0),
b: 0.0,
d: 0.5,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(5), Twips::new(5)),
(Twips::new(2), Twips::new(2))
@ -547,10 +555,10 @@ mod tests {
Matrix {
a: 0.0,
c: -1.0,
tx: 0.0,
tx: Twips::new(0),
b: 1.0,
d: 0.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(10), Twips::new(0)),
(Twips::new(0), Twips::new(10))
@ -559,10 +567,10 @@ mod tests {
Matrix {
a: 0.0,
c: -1.0,
tx: 0.0,
tx: Twips::new(0),
b: 1.0,
d: 0.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(0), Twips::new(10)),
(Twips::new(-10), Twips::new(0))
@ -571,10 +579,10 @@ mod tests {
Matrix {
a: 0.0,
c: 1.0,
tx: 0.0,
tx: Twips::new(0),
b: -1.0,
d: 0.0,
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(10), Twips::new(10)),
(Twips::new(10), Twips::new(-10))
@ -583,22 +591,22 @@ mod tests {
Matrix {
a: f32::cos(std::f32::consts::FRAC_PI_4),
c: f32::sin(std::f32::consts::FRAC_PI_4),
tx: 0.0,
tx: Twips::new(0),
b: -f32::sin(std::f32::consts::FRAC_PI_4),
d: f32::cos(std::f32::consts::FRAC_PI_4),
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(100), Twips::new(0)),
(Twips::new(70), Twips::new(-70))
(Twips::new(71), Twips::new(-71))
),
(
Matrix {
a: f32::cos(std::f32::consts::FRAC_PI_4),
c: f32::sin(std::f32::consts::FRAC_PI_4),
tx: 0.0,
tx: Twips::new(0),
b: -f32::sin(std::f32::consts::FRAC_PI_4),
d: f32::cos(std::f32::consts::FRAC_PI_4),
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(100), Twips::new(100)),
(Twips::new(141), Twips::new(0))
@ -613,10 +621,10 @@ mod tests {
Matrix {
a: 3.0 * f32::cos(std::f32::consts::FRAC_PI_4),
c: 3.0 * f32::sin(std::f32::consts::FRAC_PI_4),
tx: 0.0,
tx: Twips::new(0),
b: 3.0 * -f32::sin(std::f32::consts::FRAC_PI_4),
d: 3.0 * f32::cos(std::f32::consts::FRAC_PI_4),
ty: 0.0
ty: Twips::new(0)
},
(Twips::new(100), Twips::new(100)),
(Twips::new(424), Twips::new(0))
@ -626,10 +634,10 @@ mod tests {
Matrix {
a: 3.0 * f32::cos(std::f32::consts::FRAC_PI_4),
c: 3.0 * f32::sin(std::f32::consts::FRAC_PI_4),
tx: -5.0,
tx: Twips::new(-5),
b: 3.0 * -f32::sin(std::f32::consts::FRAC_PI_4),
d: 3.0 * f32::cos(std::f32::consts::FRAC_PI_4),
ty: 5.0
ty: Twips::new(5)
},
(Twips::new(100), Twips::new(100)),
(Twips::new(419), Twips::new(5))
@ -639,10 +647,10 @@ mod tests {
Matrix {
a: f32::cos(std::f32::consts::FRAC_PI_4),
c: f32::sin(std::f32::consts::FRAC_PI_4),
tx: -5.0,
tx: Twips::new(-5),
b: -f32::sin(std::f32::consts::FRAC_PI_4),
d: f32::cos(std::f32::consts::FRAC_PI_4),
ty: 5.0
ty: Twips::new(5)
},
(Twips::new(100), Twips::new(100)),
(Twips::new(136), Twips::new(5))
@ -652,13 +660,38 @@ mod tests {
Matrix {
a: f32::cos(std::f32::consts::FRAC_PI_4),
c: f32::sin(std::f32::consts::FRAC_PI_4),
tx: 0.0,
tx: Twips::new(0),
b: -f32::sin(std::f32::consts::FRAC_PI_4),
d: f32::cos(std::f32::consts::FRAC_PI_4),
ty: 10.0 * f32::sin(std::f32::consts::FRAC_PI_4)
ty: Twips::new((10.0 * f32::sin(std::f32::consts::FRAC_PI_4)) as i32)
},
(Twips::new(105), Twips::new(95)),
(Twips::new(141), Twips::new(0))
)
);
}
/// Implements the IEEE-754 "Round to nearest, ties to even" rounding rule.
/// (e.g., both 1.5 and 2.5 will round to 2).
/// This is the rounding method used by Flash for the above transforms.
/// Although this is easy to do on most architectures, Rust provides no standard
/// way to round in this manner (`f32::round` always rounds away from zero).
/// For more info and the below code snippet, see: https://github.com/rust-lang/rust/issues/55107
/// This also clamps out-of-range values and NaN to `i32::MIN`.
/// TODO: Investigate using SSE/wasm intrinsics for this.
fn round_to_i32(f: f32) -> i32 {
if f.is_finite() {
let a = f.abs();
if f < 2_147_483_648.0_f32 {
let k = 1.0 / std::f32::EPSILON;
let out = if a < k { ((a + k) - k).copysign(f) } else { f };
out as i32
} else {
// Out-of-range clamps to MIN.
std::i32::MIN
}
} else {
// NAN/Infinity goes to 0.
0
}
}

View File

@ -728,8 +728,8 @@ impl Player {
b: 0.0,
c: 0.0,
d: scale,
tx: margin_width * 20.0,
ty: margin_height * 20.0,
tx: Twips::from_pixels(margin_width.into()),
ty: Twips::from_pixels(margin_height.into()),
};
self.inverse_view_matrix = self.view_matrix;
self.inverse_view_matrix.invert();

View File

@ -181,10 +181,10 @@ swf_tests! {
// Eventually we can hopefully make some of these match exactly (see #193).
// Some will probably always need to be approx. (if they rely on trig functions, etc.)
swf_tests_approx! {
(local_to_global, "avm1/local_to_global", 1, 0.4),
(local_to_global, "avm1/local_to_global", 1, 0.051),
(stage_object_properties, "avm1/stage_object_properties", 4, 0.051),
(stage_object_properties_swf6, "avm1/stage_object_properties_swf6", 4, 0.051),
(movieclip_getbounds, "avm1/movieclip_getbounds", 1, 0.1),
(movieclip_getbounds, "avm1/movieclip_getbounds", 1, 0.051),
}
#[test]

View File

@ -710,8 +710,8 @@ impl RenderBackend for GliumRenderBackend {
[transform.matrix.c, transform.matrix.d, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[
transform.matrix.tx / 20.0,
transform.matrix.ty / 20.0,
transform.matrix.tx.to_pixels() as f32,
transform.matrix.ty.to_pixels() as f32,
0.0,
1.0,
],

View File

@ -305,8 +305,8 @@ impl WebCanvasRenderBackend {
matrix.b.into(),
matrix.c.into(),
matrix.d.into(),
f64::from(matrix.tx) / 20.0,
f64::from(matrix.ty) / 20.0,
matrix.tx.to_pixels(),
matrix.ty.to_pixels(),
)
.unwrap();
}
@ -774,8 +774,8 @@ fn swf_shape_to_svg(
let shift = Matrix {
a: 32768.0 / width,
d: 32768.0 / height,
tx: -16384.0,
ty: -16384.0,
tx: swf::Twips::new(-16384),
ty: swf::Twips::new(-16384),
..Default::default()
};
let gradient_matrix = matrix * shift;
@ -821,8 +821,6 @@ fn swf_shape_to_svg(
let shift = Matrix {
a: 32768.0,
d: 32768.0,
tx: 0.0,
ty: 0.0,
..Default::default()
};
let gradient_matrix = matrix * shift;
@ -874,8 +872,6 @@ fn swf_shape_to_svg(
let shift = Matrix {
a: 32768.0,
d: 32768.0,
tx: 0.0,
ty: 0.0,
..Default::default()
};
let gradient_matrix = matrix * shift;
@ -1219,8 +1215,8 @@ fn swf_shape_to_canvas_commands(
matrix.set_b(a.b);
matrix.set_c(a.c);
matrix.set_d(a.d);
matrix.set_e(a.tx);
matrix.set_f(a.ty);
matrix.set_e(a.tx.get() as f32);
matrix.set_f(a.ty.get() as f32);
bitmap_pattern.set_transform(&matrix);