From 794dd55038c13d8f9daa77a50278eef8a9179f23 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 1 Apr 2020 17:20:32 -0700 Subject: [PATCH] Add some implicit conversions between scalars and vectors where appropriate --- c/src/lib.rs | 2 +- canvas/src/lib.rs | 25 +++-- content/src/dilation.rs | 4 +- content/src/outline.rs | 2 +- content/src/segment.rs | 4 +- content/src/stroke.rs | 14 +-- demo/common/src/camera.rs | 8 +- demo/common/src/lib.rs | 40 +++----- demo/common/src/window.rs | 7 +- demo/magicleap/src/lib.rs | 2 +- examples/canvas_glutin_minimal/src/main.rs | 2 +- examples/canvas_moire/src/main.rs | 12 +-- examples/canvas_nanovg/src/main.rs | 82 +++++++-------- examples/swf_basic/src/main.rs | 9 +- export/src/lib.rs | 8 +- geometry/src/line_segment.rs | 46 +++++---- geometry/src/rect.rs | 40 +++++--- geometry/src/transform2d.rs | 31 ++---- geometry/src/transform3d.rs | 4 +- geometry/src/vector.rs | 112 ++++++++++++++++----- renderer/src/allocator.rs | 9 +- renderer/src/builder.rs | 8 +- renderer/src/paint.rs | 16 ++- renderer/src/scene.rs | 2 +- renderer/src/tiles.rs | 2 +- swf/src/lib.rs | 2 +- 26 files changed, 268 insertions(+), 225 deletions(-) diff --git a/c/src/lib.rs b/c/src/lib.rs index e6a62734..00788670 100644 --- a/c/src/lib.rs +++ b/c/src/lib.rs @@ -341,7 +341,7 @@ pub unsafe extern "C" fn PFCanvasSetLineDashOffset(canvas: PFCanvasRef, new_offs pub unsafe extern "C" fn PFCanvasSetFontByPostScriptName(canvas: PFCanvasRef, postscript_name: *const c_char, postscript_name_len: usize) { - (*canvas).set_font_by_postscript_name(to_rust_string(&postscript_name, postscript_name_len)) + (*canvas).set_font(to_rust_string(&postscript_name, postscript_name_len)) } #[no_mangle] diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index a92a19ab..710f5d45 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -23,7 +23,7 @@ use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::rect::RectF; use pathfinder_geometry::transform2d::Transform2F; -use pathfinder_geometry::vector::{Vector2F, vec2f}; +use pathfinder_geometry::vector::{IntoVector2F, Vector2F, vec2f}; use pathfinder_renderer::paint::{Paint, PaintId}; use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, RenderTarget, Scene}; use std::borrow::Cow; @@ -550,7 +550,7 @@ impl Path2D { start_angle: f32, end_angle: f32, direction: ArcDirection) { - let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center); + let transform = Transform2F::from_scale(radius).translate(center); self.current_contour.push_arc(&transform, start_angle, end_angle, direction); } @@ -562,12 +562,10 @@ impl Path2D { let (vu0, vu1) = (v0.normalize(), v1.normalize()); let hypot = radius / f32::sqrt(0.5 * (1.0 - vu0.dot(vu1))); let bisector = vu0 + vu1; - let center = ctrl + bisector.scale(hypot / bisector.length()); + let center = ctrl + bisector * (hypot / bisector.length()); - let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center); - - let chord = LineSegment2F::new(vu0.yx().scale_xy(vec2f(-1.0, 1.0)), - vu1.yx().scale_xy(vec2f( 1.0, -1.0))); + let transform = Transform2F::from_scale(radius).translate(center); + let chord = LineSegment2F::new(vu0.yx() * vec2f(-1.0, 1.0), vu1.yx() * vec2f( 1.0, -1.0)); // FIXME(pcwalton): Is clockwise direction correct? self.current_contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW); @@ -582,12 +580,13 @@ impl Path2D { self.current_contour.close(); } - pub fn ellipse(&mut self, - center: Vector2F, - axes: Vector2F, - rotation: f32, - start_angle: f32, - end_angle: f32) { + pub fn ellipse(&mut self, + center: Vector2F, + axes: A, + rotation: f32, + start_angle: f32, + end_angle: f32) + where A: IntoVector2F { self.flush_current_contour(); let transform = Transform2F::from_scale(axes).rotate(rotation).translate(center); diff --git a/content/src/dilation.rs b/content/src/dilation.rs index d543fd77..9e39f699 100644 --- a/content/src/dilation.rs +++ b/content/src/dilation.rs @@ -33,7 +33,7 @@ impl<'a> ContourDilator<'a> { pub fn dilate(&mut self) { // Determine orientation. - let scale = self.amount.scale_xy(match self.orientation { + let scale = self.amount * (match self.orientation { Orientation::Ccw => vec2f( 1.0, -1.0), Orientation::Cw => vec2f(-1.0, 1.0), }); @@ -86,7 +86,7 @@ impl<'a> ContourDilator<'a> { let scaled_bisector = if bisector_length == 0.0 { Vector2F::zero() } else { - bisector.scale_xy(scale).scale(1.0 / bisector_length) + bisector * scale * (1.0 / bisector_length) }; let new_position = position - scaled_bisector; diff --git a/content/src/outline.rs b/content/src/outline.rs index e2953743..69813fed 100644 --- a/content/src/outline.rs +++ b/content/src/outline.rs @@ -420,7 +420,7 @@ impl Contour { direction: ArcDirection) { let mut direction_transform = Transform2F::default(); if direction == ArcDirection::CCW { - chord = chord.scale_xy(vec2f(1.0, -1.0)); + chord *= vec2f(1.0, -1.0); direction_transform = Transform2F::from_scale(vec2f(1.0, -1.0)); } diff --git a/content/src/segment.rs b/content/src/segment.rs index c2115cbf..3c607f79 100644 --- a/content/src/segment.rs +++ b/content/src/segment.rs @@ -103,7 +103,7 @@ impl Segment { let p0 = Vector2F::splat(SQRT_2 * 0.5); let p1 = vec2f(-SQRT_2 / 6.0 + 4.0 / 3.0, 7.0 * SQRT_2 / 6.0 - 4.0 / 3.0); let flip = vec2f(1.0, -1.0); - let (p2, p3) = (p1.scale_xy(flip), p0.scale_xy(flip)); + let (p2, p3) = (p1 * flip, p0 * flip); Segment::cubic(LineSegment2F::new(p3, p0), LineSegment2F::new(p2, p1)) } @@ -150,7 +150,7 @@ impl Segment { let mut new_segment = *self; let p1_2 = self.ctrl.from() + self.ctrl.from(); new_segment.ctrl = LineSegment2F::new(self.baseline.from() + p1_2, - p1_2 + self.baseline.to()).scale(1.0 / 3.0); + p1_2 + self.baseline.to()) * (1.0 / 3.0); new_segment.kind = SegmentKind::Cubic; new_segment } diff --git a/content/src/stroke.rs b/content/src/stroke.rs index fe1ac17e..385fbecf 100644 --- a/content/src/stroke.rs +++ b/content/src/stroke.rs @@ -16,7 +16,7 @@ use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::rect::RectF; use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::util::EPSILON; -use pathfinder_geometry::vector::Vector2F; +use pathfinder_geometry::vector::{Vector2F, vec2f}; use std::f32; const TOLERANCE: f32 = 0.01; @@ -139,10 +139,10 @@ impl<'a> OutlineStrokeToFill<'a> { LineCap::Butt => unreachable!(), LineCap::Square => { - let offset = gradient.scale(width * 0.5); + let offset = gradient * (width * 0.5); let p2 = p1 + offset; - let p3 = p2 + gradient.yx().scale_xy(Vector2F::new(-width, width)); + let p3 = p2 + gradient.yx() * vec2f(-width, width); let p4 = p3 - offset; contour.push_endpoint(p2); @@ -151,9 +151,9 @@ impl<'a> OutlineStrokeToFill<'a> { } LineCap::Round => { - let scale = Vector2F::splat(width * 0.5); - let offset = gradient.yx().scale_xy(Vector2F::new(-1.0, 1.0)); - let translation = p1 + offset.scale(width * 0.5); + let scale = width * 0.5; + let offset = gradient.yx() * vec2f(-1.0, 1.0); + let translation = p1 + offset * (width * 0.5); let transform = Transform2F::from_scale(scale).translate(translation); let chord = LineSegment2F::new(-offset, offset); contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW); @@ -395,7 +395,7 @@ impl Contour { } } LineJoin::Round => { - let scale = Vector2F::splat(distance.abs()); + let scale = distance.abs(); let transform = Transform2F::from_scale(scale).translate(join_point); let chord_from = (prev_tangent.to() - join_point).normalize(); let chord_to = (next_tangent.to() - join_point).normalize(); diff --git a/demo/common/src/camera.rs b/demo/common/src/camera.rs index 888abe48..35cf7619 100644 --- a/demo/common/src/camera.rs +++ b/demo/common/src/camera.rs @@ -53,10 +53,10 @@ impl Camera { } fn new_2d(view_box: RectF, viewport_size: Vector2I) -> Camera { - let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 - * scale_factor_for_view_box(view_box); - let origin = viewport_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5); - Camera::TwoD(Transform2F::from_uniform_scale(scale).translate(origin)) + let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 * + scale_factor_for_view_box(view_box); + let origin = viewport_size.to_f32() * 0.5 - view_box.size() * (scale * 0.5); + Camera::TwoD(Transform2F::from_scale(scale).translate(origin)) } fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera { diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 74eec271..d230c347 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -255,8 +255,7 @@ impl DemoApp where W: Window { transform: self.render_transform.clone().unwrap(), dilation: if self.ui_model.stem_darkening_effect_enabled { let font_size = APPROX_FONT_SIZE * self.window_size.backing_scale_factor; - let (x, y) = (STEM_DARKENING_FACTORS[0], STEM_DARKENING_FACTORS[1]); - vec2f(x, y).scale(font_size) + vec2f(STEM_DARKENING_FACTORS[0], STEM_DARKENING_FACTORS[1]) * font_size } else { Vector2F::zero() }, @@ -290,15 +289,8 @@ impl DemoApp where W: Window { } Event::MouseMoved(new_position) if self.mouselook_enabled => { let mouse_position = self.process_mouse_position(new_position); - if let Camera::ThreeD { - ref mut modelview_transform, - .. - } = self.camera - { - let rotation = mouse_position - .relative - .to_f32() - .scale(MOUSELOOK_ROTATION_SPEED); + if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera { + let rotation = mouse_position.relative.to_f32() * MOUSELOOK_ROTATION_SPEED; modelview_transform.yaw += rotation.x(); modelview_transform.pitch += rotation.y(); self.dirty = true; @@ -312,19 +304,15 @@ impl DemoApp where W: Window { Event::Zoom(d_dist, position) => { if let Camera::TwoD(ref mut transform) = self.camera { let backing_scale_factor = self.window_size.backing_scale_factor; - let position = position.to_f32().scale(backing_scale_factor); + let position = position.to_f32() * backing_scale_factor; let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D; *transform = transform.translate(-position) - .uniform_scale(scale_delta) + .scale(scale_delta) .translate(position); } } Event::Look { pitch, yaw } => { - if let Camera::ThreeD { - ref mut modelview_transform, - .. - } = self.camera - { + if let Camera::ThreeD { ref mut modelview_transform, .. } = self.camera { modelview_transform.pitch += pitch; modelview_transform.yaw += yaw; } @@ -470,7 +458,7 @@ impl DemoApp where W: Window { } fn process_mouse_position(&mut self, new_position: Vector2I) -> MousePosition { - let absolute = new_position.scale(self.window_size.backing_scale_factor as i32); + let absolute = new_position * self.window_size.backing_scale_factor as i32; let relative = absolute - self.last_mouse_position; self.last_mouse_position = absolute; MousePosition { absolute, relative } @@ -487,10 +475,8 @@ impl DemoApp where W: Window { self.renderer.debug_ui_presenter.ui_presenter.event_queue.push(*ui_event); } - self.renderer.debug_ui_presenter.ui_presenter.mouse_position = self - .last_mouse_position - .to_f32() - .scale(self.window_size.backing_scale_factor); + self.renderer.debug_ui_presenter.ui_presenter.mouse_position = + self.last_mouse_position.to_f32() * self.window_size.backing_scale_factor; let mut ui_action = UIAction::None; if self.options.ui == UIVisibility::All { @@ -605,7 +591,7 @@ impl DemoApp where W: Window { } UIAction::ZoomIn => { if let Camera::TwoD(ref mut transform) = self.camera { - let scale = Vector2F::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D); + let scale = 1.0 + CAMERA_ZOOM_AMOUNT_2D; let center = center_of_window(&self.window_size); *transform = transform.translate(-center).scale(scale).translate(center); self.dirty = true; @@ -613,7 +599,7 @@ impl DemoApp where W: Window { } UIAction::ZoomOut => { if let Camera::TwoD(ref mut transform) = self.camera { - let scale = Vector2F::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D); + let scale = 1.0 - CAMERA_ZOOM_AMOUNT_2D; let center = center_of_window(&self.window_size); *transform = transform.translate(-center).scale(scale).translate(center); self.dirty = true; @@ -779,7 +765,7 @@ fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, effects: Option _ => vec2i(1, 1), }; let name = "Text".to_owned(); - let render_target = RenderTarget::new(viewport_size.scale_xy(scale), name); + let render_target = RenderTarget::new(viewport_size * scale, name); Some(scene.push_render_target(render_target)) } }; @@ -794,7 +780,7 @@ fn build_svg_tree(tree: &Tree, viewport_size: Vector2I, effects: Option } fn center_of_window(window_size: &WindowSize) -> Vector2F { - window_size.device_size().to_f32().scale(0.5) + window_size.device_size().to_f32() * 0.5 } fn get_svg_building_message(built_svg: &BuiltSVG) -> String { diff --git a/demo/common/src/window.rs b/demo/common/src/window.rs index c7a44f1e..2fd45ebd 100644 --- a/demo/common/src/window.rs +++ b/demo/common/src/window.rs @@ -10,9 +10,9 @@ //! A minimal cross-platform windowing layer. -use pathfinder_geometry::vector::Vector2I; use pathfinder_geometry::rect::RectI; use pathfinder_geometry::transform3d::{Perspective, Transform4F}; +use pathfinder_geometry::vector::Vector2I; use pathfinder_resources::ResourceLoader; use rayon::ThreadPoolBuilder; use std::path::PathBuf; @@ -90,10 +90,7 @@ pub struct WindowSize { impl WindowSize { #[inline] pub fn device_size(&self) -> Vector2I { - self.logical_size - .to_f32() - .scale(self.backing_scale_factor) - .to_i32() + (self.logical_size.to_f32() * self.backing_scale_factor).to_i32() } } diff --git a/demo/magicleap/src/lib.rs b/demo/magicleap/src/lib.rs index 5d6c08f6..fdfc1065 100644 --- a/demo/magicleap/src/lib.rs +++ b/demo/magicleap/src/lib.rs @@ -218,7 +218,7 @@ pub unsafe extern "C" fn magicleap_pathfinder_render(pf: *mut c_void, options: * let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 / f32::max(svg.scene.bounds().size().x(), svg.scene.bounds().size().y()); let transform = Transform2F::from_translation(svg.scene.bounds().size().scale(-0.5)) - .post_mul(&Transform2F::from_scale(Vector2F::splat(scale))) + .post_mul(&Transform2F::from_scale(scale)) .post_mul(&Transform2F::from_translation(viewport_size.to_f32().scale(0.5))); let render_options = RenderOptions { diff --git a/examples/canvas_glutin_minimal/src/main.rs b/examples/canvas_glutin_minimal/src/main.rs index d5f364cb..26562504 100644 --- a/examples/canvas_glutin_minimal/src/main.rs +++ b/examples/canvas_glutin_minimal/src/main.rs @@ -18,7 +18,7 @@ use glutin::window::WindowBuilder; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D}; use pathfinder_color::ColorF; use pathfinder_geometry::rect::RectF; -use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i}; +use pathfinder_geometry::vector::{vec2f, vec2i}; use pathfinder_gl::{GLDevice, GLVersion}; use pathfinder_resources::fs::FilesystemResourceLoader; use pathfinder_renderer::concurrent::rayon::RayonExecutor; diff --git a/examples/canvas_moire/src/main.rs b/examples/canvas_moire/src/main.rs index ef7343e0..15683de5 100644 --- a/examples/canvas_moire/src/main.rs +++ b/examples/canvas_moire/src/main.rs @@ -119,9 +119,9 @@ impl MoireRenderer { let foreground_color = self.colors.sample(color_time + 0.5); // Calculate outer and inner circle centers (circle and Leminscate of Gerono respectively). - let window_center = self.window_size.to_f32().scale(0.5); - let outer_center = window_center + vec2f(sin_time, cos_time).scale(OUTER_RADIUS); - let inner_center = window_center + vec2f(1.0, sin_time).scale(cos_time * INNER_RADIUS); + let window_center = self.window_size.to_f32() * 0.5; + let outer_center = window_center + vec2f(sin_time, cos_time) * OUTER_RADIUS; + let inner_center = window_center + vec2f(1.0, sin_time) * (cos_time * INNER_RADIUS); // Clear to background color. self.renderer.set_options(RendererOptions { background_color: Some(background_color) }); @@ -144,12 +144,12 @@ impl MoireRenderer { self.frame += 1; } - fn draw_circles(&self, canvas: &mut CanvasRenderingContext2D, center: Vector2F) { - let center = center.scale(self.device_pixel_ratio); + fn draw_circles(&self, canvas: &mut CanvasRenderingContext2D, mut center: Vector2F) { + center *= self.device_pixel_ratio; for index in 0..CIRCLE_COUNT { let radius = (index + 1) as f32 * CIRCLE_SPACING * self.device_pixel_ratio; let mut path = Path2D::new(); - path.ellipse(center, Vector2F::splat(radius), 0.0, 0.0, PI * 2.0); + path.ellipse(center, radius, 0.0, 0.0, PI * 2.0); canvas.stroke_path(path); } } diff --git a/examples/canvas_nanovg/src/main.rs b/examples/canvas_nanovg/src/main.rs index eb1bf340..632677a2 100644 --- a/examples/canvas_nanovg/src/main.rs +++ b/examples/canvas_nanovg/src/main.rs @@ -66,8 +66,7 @@ fn render_demo(canvas: &mut CanvasRenderingContext2D, time); draw_paragraph(canvas, RectF::new(vec2f(window_size.x() - 450.0, 50.0), vec2f(150.0, 100.0))); draw_graph(canvas, - RectF::new(window_size.scale_xy(vec2f(0.0, 0.5)), - window_size.scale_xy(vec2f(1.0, 0.5))), + RectF::new(window_size * vec2f(0.0, 0.5), window_size * vec2f(1.0, 0.5)), time); draw_color_wheel(canvas, RectF::new(window_size - vec2f(300.0, 300.0), vec2f(250.0, 250.0)), @@ -130,7 +129,7 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, rect: RectF, mouse_position: Vector2F, time: f32) { - let eyes_radii = rect.size().scale_xy(vec2f(0.23, 0.5)); + let eyes_radii = rect.size() * vec2f(0.23, 0.5); let eyes_left_position = rect.origin() + eyes_radii; let eyes_right_position = rect.origin() + vec2f(rect.width() - eyes_radii.x(), eyes_radii.y()); let eyes_center = f32::min(eyes_radii.x(), eyes_radii.y()) * 0.5; @@ -138,7 +137,7 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, let mut gradient = Gradient::linear( LineSegment2F::new(vec2f(0.0, rect.height() * 0.5), - rect.size().scale_xy(vec2f(0.1, 1.0))) + rect.origin()); + rect.size() * vec2f(0.1, 1.0)) + rect.origin()); gradient.add_color_stop(rgbau(0, 0, 0, 32), 0.0); gradient.add_color_stop(rgbau(0, 0, 0, 16), 1.0); let mut path = Path2D::new(); @@ -147,9 +146,9 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, canvas.set_fill_style(gradient); canvas.fill_path(path, FillRule::Winding); - let mut gradient = Gradient::linear( - LineSegment2F::new(vec2f(0.0, rect.height() * 0.25), - rect.size().scale_xy(vec2f(0.1, 1.0))) + rect.origin()); + let mut gradient = + Gradient::linear(LineSegment2F::new(vec2f(0.0, rect.height() * 0.25), + rect.size() * vec2f(0.1, 1.0)) + rect.origin()); gradient.add_color_stop(rgbu(220, 220, 220), 0.0); gradient.add_color_stop(rgbu(128, 128, 128), 1.0); let mut path = Path2D::new(); @@ -158,12 +157,12 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, canvas.set_fill_style(gradient); canvas.fill_path(path, FillRule::Winding); - let mut delta = (mouse_position - eyes_right_position) / eyes_radii.scale(10.0); + let mut delta = (mouse_position - eyes_right_position) / (eyes_radii * 10.0); let distance = delta.length(); if distance > 1.0 { - delta = delta.scale(1.0 / distance); + delta *= 1.0 / distance; } - delta = delta.scale_xy(eyes_radii).scale_xy(vec2f(0.4, 0.5)); + delta *= eyes_radii * vec2f(0.4, 0.5); let mut path = Path2D::new(); path.ellipse(eyes_left_position + delta + vec2f(0.0, eyes_radii.y() * 0.25 * (1.0 - blink)), vec2f(eyes_center, eyes_center * blink), @@ -178,7 +177,7 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, canvas.set_fill_style(rgbu(32, 32, 32)); canvas.fill_path(path, FillRule::Winding); - let gloss_position = eyes_left_position - eyes_radii.scale_xy(vec2f(0.25, 0.5)); + let gloss_position = eyes_left_position - eyes_radii * vec2f(0.25, 0.5); let gloss_radii = F32x2::new(0.1, 0.75) * F32x2::splat(eyes_radii.x()); let mut gloss = Gradient::radial(gloss_position, gloss_radii); gloss.add_color_stop(rgbau(255, 255, 255, 128), 0.0); @@ -188,7 +187,7 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D, path.ellipse(eyes_left_position, eyes_radii, 0.0, 0.0, PI_2); canvas.fill_path(path, FillRule::Winding); - let gloss_position = eyes_right_position - eyes_radii.scale_xy(vec2f(0.25, 0.5)); + let gloss_position = eyes_right_position - eyes_radii * vec2f(0.25, 0.5); let mut gloss = Gradient::radial(gloss_position, gloss_radii); gloss.add_color_stop(rgbau(255, 255, 255, 128), 0.0); gloss.add_color_stop(rgbau(255, 255, 255, 0), 1.0); @@ -263,7 +262,7 @@ fn draw_graph(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f32) { let sample_points: ArrayVec<[Vector2F; 6]> = samples.iter() .enumerate() .map(|(index, &sample)| { - rect.origin() + vec2f(index as f32, sample).scale_xy(sample_scale) + rect.origin() + vec2f(index as f32, sample) * sample_scale }).collect(); // Draw graph background. @@ -336,7 +335,7 @@ fn draw_color_wheel(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f3 let line = LineSegment2F::new(vec2f(f32::cos(start_angle), f32::sin(start_angle)), vec2f(f32::cos(end_angle), f32::sin(end_angle))); let scale = util::lerp(inner_radius, outer_radius, 0.5); - let mut gradient = Gradient::linear(line.scale(scale) + center); + let mut gradient = Gradient::linear(line * scale + center); let start_color = ColorF::from_hsl(start_angle, 1.0, 0.55).to_u8(); let end_color = ColorF::from_hsl(end_angle, 1.0, 0.55).to_u8(); gradient.add_color_stop(start_color, 0.0); @@ -353,8 +352,8 @@ fn draw_color_wheel(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f3 canvas.set_stroke_style(rgbau(0, 0, 0, 64)); canvas.set_line_width(1.0); let mut path = Path2D::new(); - path.ellipse(center, Vector2F::splat(inner_radius - 0.5), 0.0, 0.0, PI_2); - path.ellipse(center, Vector2F::splat(outer_radius + 0.5), 0.0, 0.0, PI_2); + path.ellipse(center, inner_radius - 0.5, 0.0, 0.0, PI_2); + path.ellipse(center, outer_radius + 0.5, 0.0, 0.0, PI_2); canvas.stroke_path(path); // Prepare to draw the selector. @@ -374,9 +373,8 @@ fn draw_color_wheel(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f3 // Draw center triangle. let triangle_radius = inner_radius - 6.0; let triangle_vertex_a = vec2f(triangle_radius, 0.0); - let triangle_vertex_b = vec2f(FRAC_PI_2_3.cos(), FRAC_PI_2_3.sin()).scale(triangle_radius); - let triangle_vertex_c = vec2f((-FRAC_PI_2_3).cos(), - (-FRAC_PI_2_3).sin()).scale(triangle_radius); + let triangle_vertex_b = vec2f(FRAC_PI_2_3.cos(), FRAC_PI_2_3.sin()) * triangle_radius; + let triangle_vertex_c = vec2f((-FRAC_PI_2_3).cos(), (-FRAC_PI_2_3).sin()) * triangle_radius; let mut gradient_0 = Gradient::linear_from_points(triangle_vertex_a, triangle_vertex_b); gradient_0.add_color_stop(ColorF::from_hsl(hue, 1.0, 0.5).to_u8(), 0.0); gradient_0.add_color_stop(ColorU::white(), 1.0); @@ -398,9 +396,8 @@ fn draw_color_wheel(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f3 canvas.stroke_path(path); // Stroke the selection circle on the triangle. - let selection_circle_center = - vec2f(FRAC_PI_2_3.cos(), FRAC_PI_2_3.sin()).scale(triangle_radius) - .scale_xy(vec2f(0.3, 0.4)); + let selection_circle_center = vec2f(FRAC_PI_2_3.cos(), FRAC_PI_2_3.sin()) * triangle_radius * + vec2f(0.3, 0.4); canvas.set_stroke_style(rgbau(255, 255, 255, 192)); canvas.set_line_width(2.0); let mut path = Path2D::new(); @@ -442,9 +439,9 @@ fn draw_lines(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f32) { LineJoin::Miter, LineJoin::Round, LineJoin::Bevel ].iter().enumerate() { let origin = rect.origin() + - vec2f(spacing, -spacing).scale(0.5) + + vec2f(0.5, -0.5) * spacing + vec2f((cap_index * 3 + join_index) as f32 / 9.0 * rect.width(), 0.0) + - vec2f(PADDING, PADDING); + PADDING; canvas.set_line_cap(cap); canvas.set_line_join(join); @@ -584,7 +581,7 @@ fn draw_search_box(canvas: &mut CanvasRenderingContext2D, text: &str, rect: Rect canvas.set_fill_style(rgbau(255, 255, 255, 64)); canvas.set_text_align(TextAlign::Left); canvas.set_text_baseline(TextBaseline::Middle); - canvas.fill_text(text, rect.origin() + Vector2F::splat(rect.height()) * vec2f(1.05, 0.5)); + canvas.fill_text(text, rect.origin() + vec2f(1.05, 0.5) * rect.height()); } fn draw_dropdown(canvas: &mut CanvasRenderingContext2D, text: &str, rect: RectF) { @@ -606,7 +603,7 @@ fn draw_dropdown(canvas: &mut CanvasRenderingContext2D, text: &str, rect: RectF) canvas.set_fill_style(rgbau(255, 255, 255, 160)); canvas.set_text_align(TextAlign::Left); canvas.set_text_baseline(TextBaseline::Middle); - canvas.fill_text(text, rect.origin() + Vector2F::splat(rect.height()) * vec2f(0.3, 0.5)); + canvas.fill_text(text, rect.origin() + vec2f(0.3, 0.5) * rect.height()); } fn draw_label(canvas: &mut CanvasRenderingContext2D, text: &str, rect: RectF) { @@ -644,7 +641,7 @@ fn draw_text_edit_box(canvas: &mut CanvasRenderingContext2D, text: &str, rect: R canvas.set_fill_style(rgbau(255, 255, 255, 64)); canvas.set_text_align(TextAlign::Left); canvas.set_text_baseline(TextBaseline::Middle); - canvas.fill_text(text, rect.origin() + Vector2F::splat(rect.height()) * vec2f(0.3, 0.5)); + canvas.fill_text(text, rect.origin() + vec2f(0.3, 0.5) * rect.height()); } fn draw_numeric_edit_box(canvas: &mut CanvasRenderingContext2D, @@ -660,7 +657,7 @@ fn draw_numeric_edit_box(canvas: &mut CanvasRenderingContext2D, canvas.set_fill_style(rgbau(255, 255, 255, 64)); canvas.set_text_align(TextAlign::Right); canvas.set_text_baseline(TextBaseline::Middle); - canvas.fill_text(unit, rect.upper_right() + vec2f(-0.3, 0.5) * Vector2F::splat(rect.height())); + canvas.fill_text(unit, rect.upper_right() + vec2f(-0.3, 0.5) * rect.height()); canvas.set_font_size(17.0); canvas.set_fill_style(rgbau(255, 255, 255, 128)); @@ -681,7 +678,7 @@ fn draw_check_box(canvas: &mut CanvasRenderingContext2D, text: &str, rect: RectF canvas.fill_text(text, rect.origin() + vec2f(28.0, rect.height() * 0.5)); let check_box_rect = RectF::new(vec2f(rect.origin_x(), rect.center().y().floor() - 9.0), - vec2f(20.0, 20.0)).contract(Vector2F::splat(1.0)); + vec2f(20.0, 20.0)).contract(1.0); fill_path_with_box_gradient(canvas, create_rounded_rect_path(check_box_rect, CORNER_RADIUS), FillRule::Winding, @@ -754,9 +751,8 @@ fn draw_slider(canvas: &mut CanvasRenderingContext2D, value: f32, rect: RectF) { background_gradient.add_color_stop(rgbau(0, 0, 0, 0), 1.0); canvas.set_fill_style(background_gradient); let mut path = Path2D::new(); - path.rect(RectF::new(knob_position, - Vector2F::zero()).dilate(Vector2F::splat(knob_radius + 5.0))); - path.ellipse(knob_position, Vector2F::splat(knob_radius), 0.0, 0.0, PI_2); + path.rect(RectF::new(knob_position, Vector2F::zero()).dilate(knob_radius + 5.0)); + path.ellipse(knob_position, knob_radius, 0.0, 0.0, PI_2); canvas.fill_path(path, FillRule::EvenOdd); // Fill knob. @@ -766,7 +762,7 @@ fn draw_slider(canvas: &mut CanvasRenderingContext2D, value: f32, rect: RectF) { background_gradient.add_color_stop(rgbau(255, 255, 255, 16), 0.0); background_gradient.add_color_stop(rgbau(0, 0, 0, 16), 1.0); let mut path = Path2D::new(); - path.ellipse(knob_position, Vector2F::splat(knob_radius - 1.0), 0.0, 0.0, PI_2); + path.ellipse(knob_position, knob_radius - 1.0, 0.0, 0.0, PI_2); canvas.set_fill_style(rgbu(40, 43, 48)); canvas.fill_path(path.clone(), FillRule::Winding); canvas.set_fill_style(background_gradient); @@ -774,7 +770,7 @@ fn draw_slider(canvas: &mut CanvasRenderingContext2D, value: f32, rect: RectF) { // Outline knob. let mut path = Path2D::new(); - path.ellipse(knob_position, Vector2F::splat(knob_radius - 0.5), 0.0, 0.0, PI_2); + path.ellipse(knob_position, knob_radius - 0.5, 0.0, 0.0, PI_2); canvas.set_stroke_style(rgbau(0, 0, 0, 92)); canvas.stroke_path(path); @@ -831,8 +827,7 @@ fn draw_thumbnails(canvas: &mut CanvasRenderingContext2D, for image_index in 0..image_count { let image_origin = rect.origin() + vec2f(10.0, 10.0) + - vec2i(image_index as i32 % 2, image_index as i32 / 2).to_f32() - .scale(THUMB_HEIGHT + 10.0); + vec2i(image_index as i32 % 2, image_index as i32 / 2).to_f32() * (THUMB_HEIGHT + 10.0); let image_rect = RectF::new(image_origin, Vector2F::splat(THUMB_HEIGHT)); let image_y = image_index as f32 * image_y_scale; @@ -845,8 +840,8 @@ fn draw_thumbnails(canvas: &mut CanvasRenderingContext2D, let pattern_transform = Transform2F::from_translation( image_rect.origin() - vec2i( (image_index % IMAGES_ACROSS) as i32, - (image_index / IMAGES_ACROSS) as i32).to_f32().scale(THUMB_HEIGHT)) * - Transform2F::from_scale(vec2f(0.5, 0.5)); + (image_index / IMAGES_ACROSS) as i32).to_f32() * THUMB_HEIGHT) * + Transform2F::from_scale(0.5); let pattern = Pattern::new(PatternSource::Image((*image).clone()), pattern_transform, PatternFlags::empty()); @@ -863,7 +858,7 @@ fn draw_thumbnails(canvas: &mut CanvasRenderingContext2D, canvas, shadow_path, FillRule::EvenOdd, - image_rect.dilate(Vector2F::splat(1.0)) + vec2f(0.0, 1.0), + image_rect.dilate(1.0) + vec2f(0.0, 1.0), 5.0, 3.0, rgbau(0, 0, 0, 128), @@ -871,7 +866,7 @@ fn draw_thumbnails(canvas: &mut CanvasRenderingContext2D, */ canvas.set_stroke_style(rgbau(255, 255, 255, 192)); - canvas.stroke_path(create_rounded_rect_path(image_rect.dilate(Vector2F::splat(0.5)), 3.5)); + canvas.stroke_path(create_rounded_rect_path(image_rect.dilate(0.5), 3.5)); } canvas.restore(); @@ -934,8 +929,8 @@ fn draw_spinner(canvas: &mut CanvasRenderingContext2D, center: Vector2F, radius: path.close_path(); set_linear_gradient_fill_style( canvas, - center + vec2f(outer_radius.cos(), outer_radius.sin()).scale(average_radius), - center + vec2f(inner_radius.cos(), inner_radius.sin()).scale(average_radius), + center + vec2f(outer_radius.cos(), outer_radius.sin()) * average_radius, + center + vec2f(inner_radius.cos(), inner_radius.sin()) * average_radius, rgbau(0, 0, 0, 0), rgbau(0, 0, 0, 128)); canvas.fill_path(path, FillRule::Winding); @@ -954,8 +949,7 @@ fn fill_path_with_box_gradient(canvas: &mut CanvasRenderingContext2D, // TODO(pcwalton): Fill the corners with radial gradients. let window_rect = RectF::new(Vector2F::zero(), vec2i(WINDOW_WIDTH, WINDOW_HEIGHT).to_f32()); - let inner_rect = rect.contract(Vector2F::splat(blur_radius)); - let outer_rect = rect.dilate(Vector2F::splat(blur_radius)); + let (inner_rect, outer_rect) = (rect.contract(blur_radius), rect.dilate(blur_radius)); canvas.save(); diff --git a/examples/swf_basic/src/main.rs b/examples/swf_basic/src/main.rs index 4ae8f31d..11c15424 100644 --- a/examples/swf_basic/src/main.rs +++ b/examples/swf_basic/src/main.rs @@ -106,16 +106,15 @@ fn main() { ); // Clear to swf stage background color. let mut scene = Scene::new(); - scene.set_view_box(RectF::new( - Vector2F::zero(), - vec2f(stage.width() as f32, stage.height() as f32).scale(device_pixel_ratio) - )); + scene.set_view_box(RectF::new(Vector2F::zero(), + vec2f(stage.width() as f32, + stage.height() as f32) * device_pixel_ratio)); draw_paths_into_scene(&library, &mut scene); // Render the canvas to screen. let scene = SceneProxy::from_scene(scene, RayonExecutor); let mut build_options = BuildOptions::default(); - let scale_transform = Transform2F::from_scale(Vector2F::splat(device_pixel_ratio)); + let scale_transform = Transform2F::from_scale(device_pixel_ratio); build_options.transform = RenderTransform::Transform2D(scale_transform); scene.build_and_render(&mut renderer, build_options); diff --git a/export/src/lib.rs b/export/src/lib.rs index 4bbb671a..48d57bc8 100644 --- a/export/src/lib.rs +++ b/export/src/lib.rs @@ -100,8 +100,8 @@ fn export_pdf(scene: &Scene, writer: &mut W) -> io::Result<()> { let current = segment.baseline.from(); let c = segment.ctrl.from(); let p = segment.baseline.to(); - let c1 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * current; - let c2 = Vector2F::splat(2./3.) * c + Vector2F::splat(1./3.) * p; + let c1 = c * (2.0 / 3.0) + current * (1.0 / 3.0); + let c2 = c * (2.0 / 3.0) + p * (1.0 / 3.0); pdf.cubic_to(c1, c2, p); } SegmentKind::Cubic => { @@ -166,8 +166,8 @@ fn export_ps(scene: &Scene, writer: &mut W) -> io::Result<()> { let current = segment.baseline.from(); let c = segment.ctrl.from(); let p = segment.baseline.to(); - let c1 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * current; - let c2 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * p; + let c1 = c * (2.0 / 3.0) + current * (1.0 / 3.0); + let c2 = c * (2.0 / 3.0) + p * (1.0 / 3.0); writeln!(writer, "{} {} {} curveto", P(c1), P(c2), P(p))?; } SegmentKind::Cubic => { diff --git a/geometry/src/line_segment.rs b/geometry/src/line_segment.rs index 77640274..2cc06be3 100644 --- a/geometry/src/line_segment.rs +++ b/geometry/src/line_segment.rs @@ -11,10 +11,10 @@ //! Line segment types, optimized with SIMD. use crate::transform2d::Matrix2x2F; -use crate::vector::Vector2F; +use crate::vector::{Vector2F, vec2f}; use crate::util; use pathfinder_simd::default::F32x4; -use std::ops::{Add, Sub}; +use std::ops::{Add, Mul, MulAssign, Sub}; #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct LineSegment2F(pub F32x4); @@ -87,21 +87,6 @@ impl LineSegment2F { self.0[3] = y } - #[inline] - pub fn translate(self, offset: Vector2F) -> LineSegment2F { - LineSegment2F(self.0 + offset.0.to_f32x4().xyxy()) - } - - #[inline] - pub fn scale(self, factor: f32) -> LineSegment2F { - LineSegment2F(self.0 * F32x4::splat(factor)) - } - - #[inline] - pub fn scale_xy(self, factors: Vector2F) -> LineSegment2F { - LineSegment2F(self.0 * factors.0.to_f32x4().xyxy()) - } - #[inline] pub fn split(self, t: f32) -> (LineSegment2F, LineSegment2F) { debug_assert!(t >= 0.0 && t <= 1.0); @@ -239,7 +224,7 @@ impl LineSegment2F { #[inline] pub fn sample(self, t: f32) -> Vector2F { - self.from() + self.vector().scale(t) + self.from() + self.vector() * t } #[inline] @@ -252,7 +237,7 @@ impl LineSegment2F { if self.is_zero_length() { self } else { - self + self.vector().yx().normalize().scale_xy(Vector2F::new(-distance, distance)) + self + self.vector().yx().normalize() * vec2f(-distance, distance) } } @@ -278,6 +263,29 @@ impl Sub for LineSegment2F { } } +impl Mul for LineSegment2F { + type Output = LineSegment2F; + #[inline] + fn mul(self, factors: Vector2F) -> LineSegment2F { + LineSegment2F(self.0 * factors.0.to_f32x4().xyxy()) + } +} + +impl Mul for LineSegment2F { + type Output = LineSegment2F; + #[inline] + fn mul(self, factor: f32) -> LineSegment2F { + LineSegment2F(self.0 * F32x4::splat(factor)) + } +} + +impl MulAssign for LineSegment2F { + #[inline] + fn mul_assign(&mut self, factors: Vector2F) { + *self = *self * factors + } +} + #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct LineSegmentU4 { diff --git a/geometry/src/rect.rs b/geometry/src/rect.rs index 37b3656b..e8c1194e 100644 --- a/geometry/src/rect.rs +++ b/geometry/src/rect.rs @@ -10,9 +10,9 @@ //! 2D axis-aligned rectangles, optimized with SIMD. -use crate::vector::{Vector2F, Vector2I}; +use crate::vector::{IntoVector2F, Vector2F, Vector2I}; use pathfinder_simd::default::{F32x4, I32x4}; -use std::ops::Add; +use std::ops::{Add, Mul}; #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct RectF(pub F32x4); @@ -158,17 +158,7 @@ impl RectF { #[inline] pub fn center(self) -> Vector2F { - self.origin() + self.size().scale(0.5) - } - - #[inline] - pub fn scale(self, factor: f32) -> RectF { - RectF(self.0 * F32x4::splat(factor)) - } - - #[inline] - pub fn scale_xy(self, factors: Vector2F) -> RectF { - RectF(self.0 * factors.0.concat_xy_xy(factors.0)) + self.origin() + self.size() * 0.5 } /// Rounds all points to the nearest integer. @@ -183,12 +173,14 @@ impl RectF { } #[inline] - pub fn dilate(self, amount: Vector2F) -> RectF { + pub fn dilate(self, amount: A) -> RectF where A: IntoVector2F { + let amount = amount.into_vector_2f(); RectF::from_points(self.origin() - amount, self.lower_right() + amount) } #[inline] - pub fn contract(self, amount: Vector2F) -> RectF { + pub fn contract(self, amount: A) -> RectF where A: IntoVector2F { + let amount = amount.into_vector_2f(); RectF::from_points(self.origin() + amount, self.lower_right() - amount) } @@ -206,6 +198,22 @@ impl Add for RectF { } } +impl Mul for RectF { + type Output = RectF; + #[inline] + fn mul(self, factors: Vector2F) -> RectF { + RectF(self.0 * factors.0.concat_xy_xy(factors.0)) + } +} + +impl Mul for RectF { + type Output = RectF; + #[inline] + fn mul(self, factor: f32) -> RectF { + RectF(self.0 * F32x4::splat(factor)) + } +} + /// NB: The origin is inclusive, while the lower right point is exclusive. #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct RectI(pub I32x4); @@ -319,7 +327,7 @@ impl RectI { #[inline] pub fn contains_point(&self, point: Vector2I) -> bool { // self.origin <= point && point <= self.lower_right - 1 - let lower_right = self.lower_right() - Vector2I::splat(1); + let lower_right = self.lower_right() - 1; self.origin() .0 .concat_xy_xy(point.0) diff --git a/geometry/src/transform2d.rs b/geometry/src/transform2d.rs index daaa4a6b..c6e6acd9 100644 --- a/geometry/src/transform2d.rs +++ b/geometry/src/transform2d.rs @@ -14,7 +14,7 @@ use crate::line_segment::LineSegment2F; use crate::rect::RectF; use crate::transform3d::Transform4F; use crate::unit_vector::UnitVector; -use crate::vector::{Vector2F, vec2f}; +use crate::vector::{IntoVector2F, Vector2F, vec2f}; use pathfinder_simd::default::F32x4; use std::ops::{Mul, MulAssign, Sub}; @@ -25,13 +25,14 @@ pub struct Matrix2x2F(pub F32x4); impl Default for Matrix2x2F { #[inline] fn default() -> Matrix2x2F { - Self::from_scale(vec2f(1.0, 1.0)) + Self::from_scale(1.0) } } impl Matrix2x2F { #[inline] - pub fn from_scale(scale: Vector2F) -> Matrix2x2F { + pub fn from_scale(scale: S) -> Matrix2x2F where S: IntoVector2F { + let scale = scale.into_vector_2f(); Matrix2x2F(F32x4::new(scale.x(), 0.0, 0.0, scale.y())) } @@ -137,18 +138,14 @@ impl Default for Transform2F { impl Transform2F { #[inline] - pub fn from_scale(scale: Vector2F) -> Transform2F { + pub fn from_scale(scale: S) -> Transform2F where S: IntoVector2F { + let scale = scale.into_vector_2f(); Transform2F { matrix: Matrix2x2F::from_scale(scale), vector: Vector2F::zero(), } } - #[inline] - pub fn from_uniform_scale(scale: f32) -> Transform2F { - Transform2F::from_scale(Vector2F::splat(scale)) - } - #[inline] pub fn from_rotation(theta: f32) -> Transform2F { Transform2F { @@ -171,11 +168,9 @@ impl Transform2F { } #[inline] - pub fn from_scale_rotation_translation( - scale: Vector2F, - theta: f32, - translation: Vector2F, - ) -> Transform2F { + pub fn from_scale_rotation_translation(scale: S, theta: f32, translation: Vector2F) + -> Transform2F where S: IntoVector2F { + let scale = scale.into_vector_2f(); let rotation = Transform2F::from_rotation(theta); let translation = Transform2F::from_translation(translation); Transform2F::from_scale(scale) * rotation * translation @@ -245,15 +240,11 @@ impl Transform2F { } #[inline] - pub fn scale(&self, scale: Vector2F) -> Transform2F { + pub fn scale(&self, scale: S) -> Transform2F where S: IntoVector2F { + let scale = scale.into_vector_2f(); Transform2F::from_scale(scale) * *self } - #[inline] - pub fn uniform_scale(&self, scale: f32) -> Transform2F { - self.scale(Vector2F::splat(scale)) - } - /// Returns the translation part of this matrix. /// /// This decomposition assumes that scale, rotation, and translation are applied in that order. diff --git a/geometry/src/transform3d.rs b/geometry/src/transform3d.rs index 73230f67..94d36485 100644 --- a/geometry/src/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -12,7 +12,7 @@ use crate::rect::RectF; use crate::transform2d::Matrix2x2F; -use crate::vector::{Vector2F, Vector2I, Vector3F, Vector4F, vec2f}; +use crate::vector::{Vector2F, Vector2I, Vector3F, Vector4F}; use pathfinder_simd::default::F32x4; use std::ops::{Add, Mul, MulAssign, Neg}; @@ -407,7 +407,7 @@ impl Mul for Perspective { #[inline] fn mul(self, vector: Vector2F) -> Vector2F { let point = (self.transform * vector.to_4d()).to_2d() * Vector2F::new(1.0, -1.0); - (point + vec2f(1.0, 1.0)) * self.window_size.to_f32().scale(0.5) + (point + 1.0) * self.window_size.to_f32() * 0.5 } } diff --git a/geometry/src/vector.rs b/geometry/src/vector.rs index 3fd20b2c..77550c7b 100644 --- a/geometry/src/vector.rs +++ b/geometry/src/vector.rs @@ -12,7 +12,7 @@ use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::hash::{Hash, Hasher}; -use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub}; +use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub}; /// 2D points with 32-bit floating point coordinates. #[derive(Clone, Copy, Debug, Default)] @@ -90,16 +90,6 @@ impl Vector2F { xy.x() + xy.y() } - #[inline] - pub fn scale(self, x: f32) -> Vector2F { - Vector2F(self.0 * F32x2::splat(x)) - } - - #[inline] - pub fn scale_xy(self, factors: Vector2F) -> Vector2F { - Vector2F(self.0 * factors.0) - } - #[inline] pub fn floor(self) -> Vector2F { Vector2F(self.0.floor()) @@ -132,7 +122,7 @@ impl Vector2F { /// Treats this point as a vector and normalizes it. #[inline] pub fn normalize(self) -> Vector2F { - self.scale(1.0 / self.length()) + self * (1.0 / self.length()) } /// Swaps y and x. @@ -157,7 +147,7 @@ impl Vector2F { #[inline] pub fn lerp(self, other: Vector2F, t: f32) -> Vector2F { - self + (other - self).scale(t) + self + (other - self) * t } #[inline] @@ -187,6 +177,14 @@ impl Add for Vector2F { } } +impl Add for Vector2F { + type Output = Vector2F; + #[inline] + fn add(self, other: f32) -> Vector2F { + self + Vector2F::splat(other) + } +} + impl AddAssign for Vector2F { #[inline] fn add_assign(&mut self, other: Vector2F) { @@ -210,6 +208,28 @@ impl Mul for Vector2F { } } +impl Mul for Vector2F { + type Output = Vector2F; + #[inline] + fn mul(self, other: f32) -> Vector2F { + self * Vector2F::splat(other) + } +} + +impl MulAssign for Vector2F { + #[inline] + fn mul_assign(&mut self, other: Vector2F) { + *self = *self * other + } +} + +impl MulAssign for Vector2F { + #[inline] + fn mul_assign(&mut self, other: f32) { + *self = *self * other + } +} + impl Div for Vector2F { type Output = Vector2F; #[inline] @@ -226,6 +246,30 @@ impl Neg for Vector2F { } } +/// Either a scalar or a `Vector2F`. +/// +/// Scalars will be automatically splatted (i.e. `x` becomes `vec2f(x, x)`). +/// +/// Be judicious with the use of this trait. Only use it if it will aid readability without the +/// potential to introduce bugs. +pub trait IntoVector2F { + fn into_vector_2f(self) -> Vector2F; +} + +impl IntoVector2F for Vector2F { + #[inline] + fn into_vector_2f(self) -> Vector2F { + self + } +} + +impl IntoVector2F for f32 { + #[inline] + fn into_vector_2f(self) -> Vector2F { + Vector2F::splat(self) + } +} + /// 2D points with 32-bit signed integer coordinates. #[derive(Clone, Copy, Debug, Default)] pub struct Vector2I(pub I32x2); @@ -276,16 +320,6 @@ impl Vector2I { Vector2I(self.0.max(other.0)) } - #[inline] - pub fn scale(self, factor: i32) -> Vector2I { - Vector2I(self.0 * I32x2::splat(factor)) - } - - #[inline] - pub fn scale_xy(self, factors: Vector2I) -> Vector2I { - Vector2I(self.0 * factors.0) - } - #[inline] pub fn to_f32(self) -> Vector2F { Vector2F(self.0.to_f32x2()) @@ -306,6 +340,14 @@ impl Add for Vector2I { } } +impl Add for Vector2I { + type Output = Vector2I; + #[inline] + fn add(self, other: i32) -> Vector2I { + self + Vector2I::splat(other) + } +} + impl AddAssign for Vector2I { #[inline] fn add_assign(&mut self, other: Vector2I) { @@ -329,6 +371,30 @@ impl Sub for Vector2I { } } +impl Sub for Vector2I { + type Output = Vector2I; + #[inline] + fn sub(self, other: i32) -> Vector2I { + self - Vector2I::splat(other) + } +} + +impl Mul for Vector2I { + type Output = Vector2I; + #[inline] + fn mul(self, other: Vector2I) -> Vector2I { + Vector2I(self.0 * other.0) + } +} + +impl Mul for Vector2I { + type Output = Vector2I; + #[inline] + fn mul(self, other: i32) -> Vector2I { + self * Vector2I::splat(other) + } +} + impl PartialEq for Vector2I { #[inline] fn eq(&self, other: &Vector2I) -> bool { diff --git a/renderer/src/allocator.rs b/renderer/src/allocator.rs index ee661ed8..b366271c 100644 --- a/renderer/src/allocator.rs +++ b/renderer/src/allocator.rs @@ -189,10 +189,9 @@ impl TreeNode { requested_size) { return Some(origin); } - if let Some(origin) = kids[3].allocate( - this_origin + Vector2I::splat(kid_size as i32), - kid_size, - requested_size) { + if let Some(origin) = kids[3].allocate(this_origin + kid_size as i32, + kid_size, + requested_size) { return Some(origin); } @@ -217,7 +216,7 @@ impl TreeNode { } let child_size = this_size / 2; - let this_center = this_origin + Vector2I::splat(child_size as i32); + let this_center = this_origin + child_size as i32; let child_index; let mut child_origin = this_origin; diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index de566858..fbadbb69 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -278,9 +278,7 @@ impl<'a> SceneBuilder<'a> { continue; } - let uv_rect = - RectI::new(tile_coords, Vector2I::splat(1)).to_f32() - .scale_xy(uv_scale); + let uv_rect = RectI::new(tile_coords, vec2i(1, 1)).to_f32() * uv_scale; tiles.push(Tile::new_solid_from_texture_rect(tile_coords, uv_rect)); } } @@ -894,12 +892,12 @@ fn calculate_mask_uv(tile_index: u16, tile_offset: Vector2I) -> Vector2F { let mask_u = tile_index as i32 % MASK_TILES_ACROSS as i32; let mask_v = tile_index as i32 / MASK_TILES_ACROSS as i32; let scale = vec2f(1.0 / MASK_TILES_ACROSS as f32, 1.0 / MASK_TILES_DOWN as f32); - (vec2i(mask_u, mask_v) + tile_offset).to_f32().scale_xy(scale) + (vec2i(mask_u, mask_v) + tile_offset).to_f32() * scale } fn calculate_opacity_uv(draw_tiling_path_info: &DrawTilingPathInfo) -> Vector2F { let DrawTilingPathInfo { opacity_tile_transform, opacity, .. } = *draw_tiling_path_info; let texel_coord = (vec2i((opacity % 16) as i32, (opacity / 16) as i32).to_f32() + - vec2f(0.5, 0.5)).scale(1.0 / 16.0); + vec2f(0.5, 0.5)) * (1.0 / 16.0); opacity_tile_transform * texel_coord } diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index cade6633..5afa78bb 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -297,8 +297,7 @@ impl Palette { Paint::Gradient(Gradient { radii: Some(_), .. }) => { let texture_origin_uv = rect_to_inset_uv(metadata.location.rect, texture_scale).origin(); - let gradient_tile_scale = - texture_scale.scale((GRADIENT_TILE_LENGTH - 1) as f32); + let gradient_tile_scale = texture_scale * (GRADIENT_TILE_LENGTH - 1) as f32; Transform2F { matrix: Matrix2x2F::from_scale(gradient_tile_scale), vector: texture_origin_uv, @@ -320,7 +319,7 @@ impl Palette { let texture_origin_uv = rect_to_uv(metadata.location.rect, texture_scale).lower_left(); Transform2F::from_translation(texture_origin_uv) * - Transform2F::from_scale(texture_scale.scale_xy(vec2f(1.0, -1.0))) * + Transform2F::from_scale(texture_scale * vec2f(1.0, -1.0)) * transform.inverse() } } @@ -372,7 +371,7 @@ impl PaintMetadata { // TODO(pcwalton): Apply clamp/repeat to tile rect. pub(crate) fn calculate_tex_coords(&self, tile_position: Vector2I) -> Vector2F { let tile_size = vec2i(TILE_WIDTH as i32, TILE_HEIGHT as i32); - let position = tile_position.scale_xy(tile_size).to_f32(); + let position = (tile_position * tile_size).to_f32(); let tex_coords = self.texture_transform * position; tex_coords } @@ -394,11 +393,11 @@ impl PaintMetadata { } fn rect_to_uv(rect: RectI, texture_scale: Vector2F) -> RectF { - rect.to_f32().scale_xy(texture_scale) + rect.to_f32() * texture_scale } fn rect_to_inset_uv(rect: RectI, texture_scale: Vector2F) -> RectF { - rect_to_uv(rect, texture_scale).contract(texture_scale.scale(0.5)) + rect_to_uv(rect, texture_scale).contract(texture_scale * 0.5) } // Opacity allocation @@ -424,7 +423,7 @@ impl OpacityTileBuilder { fn tile_transform(&self, allocator: &TextureAllocator) -> Transform2F { let texture_scale = allocator.page_scale(self.tile_location.page); - let matrix = Matrix2x2F::from_scale(texture_scale.scale(16.0)); + let matrix = Matrix2x2F::from_scale(texture_scale * 16.0); let vector = rect_to_uv(self.tile_location.rect, texture_scale).origin(); Transform2F { matrix, vector } } @@ -548,8 +547,7 @@ impl GradientTileBuilder { render_commands.push(RenderCommand::UploadTexelData { texels: Arc::new(tile.texels), location: TextureLocation { - rect: RectI::new(Vector2I::zero(), - Vector2I::splat(GRADIENT_TILE_LENGTH as i32)), + rect: RectI::new(vec2i(0, 0), Vector2I::splat(GRADIENT_TILE_LENGTH as i32)), page: tile.page, }, }); diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 8fa2642b..47cfca94 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -177,7 +177,7 @@ impl Scene { #[inline] pub(crate) fn effective_view_box(&self, render_options: &PreparedBuildOptions) -> RectF { if render_options.subpixel_aa_enabled { - self.view_box.scale_xy(vec2f(3.0, 1.0)) + self.view_box * vec2f(3.0, 1.0) } else { self.view_box } diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index e3f5382e..222734cd 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -499,7 +499,7 @@ impl<'a> PackedTile<'a> { } pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI { - rect.scale_xy(vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32() + (rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32() } fn process_active_segment( diff --git a/swf/src/lib.rs b/swf/src/lib.rs index 80565f68..911181fc 100644 --- a/swf/src/lib.rs +++ b/swf/src/lib.rs @@ -13,7 +13,7 @@ use pathfinder_color::{ColorF, ColorU}; use pathfinder_content::fill::FillRule; use pathfinder_content::outline::{Outline, Contour}; use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle}; -use pathfinder_geometry::vector::{Vector2F, vec2f}; +use pathfinder_geometry::vector::vec2f; use pathfinder_renderer::scene::{DrawPath, Scene}; use swf_types::tags::SetBackgroundColor;