Skip to content

Commit

Permalink
render: Add DrawCommand::CubicCurveTo
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinnerbone committed Aug 27, 2023
1 parent 076977c commit eb2afb1
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion core/src/drawing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ruffle_render::backend::{RenderBackend, ShapeHandle};
use ruffle_render::bitmap::{BitmapHandle, BitmapInfo, BitmapSize, BitmapSource};
use ruffle_render::commands::CommandHandler;
use ruffle_render::shape_utils::{
quadratic_curve_bounds, DistilledShape, DrawCommand, DrawPath, FillRule,
cubic_curve_bounds, quadratic_curve_bounds, DistilledShape, DrawCommand, DrawPath, FillRule,
};
use std::cell::{Cell, RefCell};
use swf::{FillStyle, LineStyle, Point, Rectangle, Twips};
Expand Down Expand Up @@ -458,5 +458,16 @@ fn stretch_bounds(
DrawCommand::QuadraticCurveTo { control, anchor } => {
bounds.union(&quadratic_curve_bounds(from, stroke_width, control, anchor))
}
DrawCommand::CubicCurveTo {
control_a,
control_b,
anchor,
} => bounds.union(&cubic_curve_bounds(
from,
stroke_width,
control_a,
control_b,
anchor,
)),
}
}
1 change: 1 addition & 0 deletions render/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ flate2 = "1.0.27"
smallvec = { version = "1.11.0", features = ["union"] }
downcast-rs = "1.2.0"
lyon = { version = "1.0.1", optional = true }
lyon_geom = "1.0.1"
thiserror = "1.0"
wasm-bindgen = { version = "=0.2.87", optional = true }
enum-map = "2.6.1"
Expand Down
12 changes: 12 additions & 0 deletions render/canvas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,18 @@ fn draw_commands_to_path2d(commands: &[DrawCommand], is_closed: bool) -> Path2d
anchor.x.get().into(),
anchor.y.get().into(),
),
DrawCommand::CubicCurveTo {
control_a,
control_b,
anchor,
} => path.bezier_curve_to(
control_a.x.get().into(),
control_a.y.get().into(),
control_b.x.get().into(),
control_b.y.get().into(),
anchor.x.get().into(),
anchor.y.get().into(),
),
};
}

Expand Down
83 changes: 82 additions & 1 deletion render/src/shape_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,20 @@ pub enum DrawCommand {
control: swf::Point<Twips>,
anchor: swf::Point<Twips>,
},
CubicCurveTo {
control_a: swf::Point<Twips>,
control_b: swf::Point<Twips>,
anchor: swf::Point<Twips>,
},
}

impl DrawCommand {
pub fn end_point(&self) -> swf::Point<Twips> {
match self {
DrawCommand::MoveTo(point)
| DrawCommand::LineTo(point)
| DrawCommand::QuadraticCurveTo { anchor: point, .. } => *point,
| DrawCommand::QuadraticCurveTo { anchor: point, .. }
| DrawCommand::CubicCurveTo { anchor: point, .. } => *point,
}
}
}
Expand Down Expand Up @@ -680,6 +686,27 @@ pub fn draw_command_fill_hit_test(commands: &[DrawCommand], test_point: swf::Poi
winding += winding_number_curve(test_point, cursor, *control, *anchor);
cursor = *anchor;
}
DrawCommand::CubicCurveTo {
control_a,
control_b,
anchor,
} => {
lyon_geom::CubicBezierSegment {
from: lyon_geom::Point::new(cursor.x.to_pixels(), cursor.y.to_pixels()),
ctrl1: lyon_geom::Point::new(control_a.x.to_pixels(), control_a.y.to_pixels()),
ctrl2: lyon_geom::Point::new(control_b.x.to_pixels(), control_b.y.to_pixels()),
to: lyon_geom::Point::new(anchor.x.to_pixels(), anchor.y.to_pixels()),
}
.for_each_quadratic_bezier(0.01, &mut |quadratic_curve| {
winding += winding_number_curve(
test_point,
swf::Point::from_pixels(quadratic_curve.from.x, quadratic_curve.from.y),
swf::Point::from_pixels(quadratic_curve.ctrl.x, quadratic_curve.ctrl.y),
swf::Point::from_pixels(quadratic_curve.to.x, quadratic_curve.to.y),
);
});
cursor = *anchor;
}
}
}
if cursor != fill_start {
Expand Down Expand Up @@ -719,6 +746,35 @@ pub fn draw_command_stroke_hit_test(
}
cursor = *anchor;
}
DrawCommand::CubicCurveTo {
control_a,
control_b,
anchor,
} => {
let mut hit = false;
lyon_geom::CubicBezierSegment {
from: lyon_geom::Point::new(cursor.x.to_pixels(), cursor.y.to_pixels()),
ctrl1: lyon_geom::Point::new(control_a.x.to_pixels(), control_a.y.to_pixels()),
ctrl2: lyon_geom::Point::new(control_b.x.to_pixels(), control_b.y.to_pixels()),
to: lyon_geom::Point::new(anchor.x.to_pixels(), anchor.y.to_pixels()),
}
.for_each_quadratic_bezier(0.01, &mut |quadratic_curve| {
if hit_test_stroke_curve(
test_point,
swf::Point::from_pixels(quadratic_curve.from.x, quadratic_curve.from.y),
swf::Point::from_pixels(quadratic_curve.ctrl.x, quadratic_curve.ctrl.y),
swf::Point::from_pixels(quadratic_curve.to.x, quadratic_curve.to.y),
stroke_widths,
) {
hit = true;
}
});
cursor = *anchor;

if hit {
return true;
}
}
}
}

Expand Down Expand Up @@ -1222,6 +1278,31 @@ pub fn quadratic_curve_bounds(
))
}

pub fn cubic_curve_bounds(
start: swf::Point<Twips>,
stroke_width: Twips,
control_a: swf::Point<Twips>,
control_b: swf::Point<Twips>,
anchor: swf::Point<Twips>,
) -> Rectangle<Twips> {
// [NA] Should we just move most of our math in this file to lyon_geom?
let bounds = lyon_geom::CubicBezierSegment {
from: lyon_geom::Point::new(start.x.to_pixels(), start.y.to_pixels()),
ctrl1: lyon_geom::Point::new(control_a.x.to_pixels(), control_a.y.to_pixels()),
ctrl2: lyon_geom::Point::new(control_b.x.to_pixels(), control_b.y.to_pixels()),
to: lyon_geom::Point::new(anchor.x.to_pixels(), anchor.y.to_pixels()),
}
.bounding_box();

let radius = stroke_width / 2;
Rectangle {
x_min: Twips::from_pixels(bounds.min.x) - radius,
x_max: Twips::from_pixels(bounds.max.x) + radius,
y_min: Twips::from_pixels(bounds.min.y) - radius,
y_max: Twips::from_pixels(bounds.max.y) + radius,
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 10 additions & 0 deletions render/src/tessellator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,16 @@ fn ruffle_path_to_lyon_path(commands: &[DrawCommand], is_closed: bool) -> Path {
}
builder.quadratic_bezier_to(point(*control), point(*anchor));
}
DrawCommand::CubicCurveTo {
control_a,
control_b,
anchor,
} => {
if let Some(cursor) = cursor.take() {
builder.begin(point(cursor));
}
builder.cubic_bezier_to(point(*control_a), point(*control_b), point(*anchor));
}
}
}

Expand Down

0 comments on commit eb2afb1

Please sign in to comment.