From 90d9ac596138ba60ed892f0ea5f0c15020573599 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 26 Mar 2023 05:09:20 -0700 Subject: [PATCH] [Impeller] Fix stroke cap disconnection --- .../display_list/display_list_playground.cc | 8 ++ .../display_list/display_list_unittests.cc | 2 +- impeller/entity/geometry.cc | 78 +++++++++++-------- impeller/entity/geometry.h | 4 +- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/impeller/display_list/display_list_playground.cc b/impeller/display_list/display_list_playground.cc index c9da19ad90b98..9063816ae9837 100644 --- a/impeller/display_list/display_list_playground.cc +++ b/impeller/display_list/display_list_playground.cc @@ -7,6 +7,8 @@ #include "flutter/testing/testing.h" #include "impeller/aiks/aiks_context.h" #include "impeller/display_list/display_list_dispatcher.h" + +#include "third_party/imgui/imgui.h" #include "third_party/skia/include/core/SkData.h" namespace impeller { @@ -37,6 +39,12 @@ bool DisplayListPlayground::OpenPlaygroundHere( } return Playground::OpenPlaygroundHere( [&context, &callback](RenderTarget& render_target) -> bool { + static bool wireframe = false; + if (ImGui::IsKeyPressed(ImGuiKey_Z)) { + wireframe = !wireframe; + context.GetContentContext().SetWireframe(wireframe); + } + auto list = callback(); DisplayListDispatcher dispatcher; diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 63f0be439606b..03f176fab41d1 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -158,7 +158,7 @@ TEST_P(DisplayListTest, CanDrawArc) { ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); ImGui::SliderFloat("Start angle", &start_angle, -360, 360); ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360); - ImGui::SliderFloat("Stroke width", &stroke_width, 0, 100); + ImGui::SliderFloat("Stroke width", &stroke_width, 0, 300); ImGui::Combo("Cap", &selected_cap, cap_names, sizeof(cap_names) / sizeof(char*)); ImGui::Checkbox("Use center", &use_center); diff --git a/impeller/entity/geometry.cc b/impeller/entity/geometry.cc index 80bf0580a5eb3..f5d5a819e86c5 100644 --- a/impeller/entity/geometry.cc +++ b/impeller/entity/geometry.cc @@ -331,33 +331,47 @@ StrokePathGeometry::CapProc StrokePathGeometry::GetCapProc(Cap stroke_cap) { switch (stroke_cap) { case Cap::kButt: cap_proc = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& offset, Scalar scale) { + const Point& position, const Point& offset, Scalar scale, + bool reverse) { + Point orientation = offset * (reverse ? -1 : 1); VS::PerVertexData vtx; - vtx.position = position + offset; + vtx.position = position + orientation; vtx_builder.AppendVertex(vtx); - vtx.position = position - offset; + vtx.position = position - orientation; vtx_builder.AppendVertex(vtx); }; break; case Cap::kRound: cap_proc = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& offset, Scalar scale) { + const Point& position, const Point& offset, Scalar scale, + bool reverse) { + Point orientation = offset * (reverse ? -1 : 1); + VS::PerVertexData vtx; Point forward(offset.y, -offset.x); Point forward_normal = forward.Normalize(); - auto arc_points = - CubicPathComponent( - offset, offset + forward * PathBuilder::kArcApproximationMagic, - forward + offset * PathBuilder::kArcApproximationMagic, forward) - .CreatePolyline(scale); + CubicPathComponent arc; + if (reverse) { + arc = CubicPathComponent( + forward, + forward + orientation * PathBuilder::kArcApproximationMagic, + orientation + forward * PathBuilder::kArcApproximationMagic, + orientation); + } else { + arc = CubicPathComponent( + orientation, + orientation + forward * PathBuilder::kArcApproximationMagic, + forward + orientation * PathBuilder::kArcApproximationMagic, + forward); + } - vtx.position = position + offset; + vtx.position = position + orientation; vtx_builder.AppendVertex(vtx); - vtx.position = position - offset; + vtx.position = position - orientation; vtx_builder.AppendVertex(vtx); - for (const auto& point : arc_points) { + for (const auto& point : arc.CreatePolyline(scale)) { vtx.position = position + point; vtx_builder.AppendVertex(vtx); vtx.position = position + (-point).Reflect(forward_normal); @@ -367,18 +381,21 @@ StrokePathGeometry::CapProc StrokePathGeometry::GetCapProc(Cap stroke_cap) { break; case Cap::kSquare: cap_proc = [](VertexBufferBuilder& vtx_builder, - const Point& position, const Point& offset, Scalar scale) { + const Point& position, const Point& offset, Scalar scale, + bool reverse) { + Point orientation = offset * (reverse ? -1 : 1); + VS::PerVertexData vtx; Point forward(offset.y, -offset.x); - vtx.position = position + offset; + vtx.position = position + orientation; vtx_builder.AppendVertex(vtx); - vtx.position = position - offset; + vtx.position = position - orientation; vtx_builder.AppendVertex(vtx); - vtx.position = position + offset + forward; + vtx.position = position + orientation + forward; vtx_builder.AppendVertex(vtx); - vtx.position = position - offset + forward; + vtx.position = position - orientation + forward; vtx_builder.AppendVertex(vtx); }; break; @@ -392,7 +409,6 @@ StrokePathGeometry::CreateSolidStrokeVertices( const Path& path, Scalar stroke_width, Scalar scaled_miter_limit, - Cap cap, const StrokePathGeometry::JoinProc& join_proc, const StrokePathGeometry::CapProc& cap_proc, Scalar scale) { @@ -423,8 +439,8 @@ StrokePathGeometry::CreateSolidStrokeVertices( switch (contour_end_point_i - contour_start_point_i) { case 1: { Point p = polyline.points[contour_start_point_i]; - cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale); - cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale); + cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale, false); + cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale, false); continue; } case 0: @@ -461,17 +477,11 @@ StrokePathGeometry::CreateSolidStrokeVertices( // Generate start cap. if (!polyline.contours[contour_i].is_closed) { - Vector2 direction; - if (cap == Cap::kButt) { - direction = - Vector2(contour.start_direction.y, -contour.start_direction.x); - } else { - direction = - Vector2(-contour.start_direction.y, contour.start_direction.x); - } - auto cap_offset = direction * stroke_width * 0.5; + auto cap_offset = + Vector2(-contour.start_direction.y, contour.start_direction.x) * + stroke_width * 0.5; // Counterclockwise normal cap_proc(vtx_builder, polyline.points[contour_start_point_i], cap_offset, - scale); + scale, true); } // Generate contour geometry. @@ -500,9 +510,9 @@ StrokePathGeometry::CreateSolidStrokeVertices( if (!polyline.contours[contour_i].is_closed) { auto cap_offset = Vector2(-contour.end_direction.y, contour.end_direction.x) * - stroke_width * 0.5; + stroke_width * 0.5; // Clockwise normal cap_proc(vtx_builder, polyline.points[contour_end_point_i - 1], - cap_offset, scale); + cap_offset, scale, false); } else { join_proc(vtx_builder, polyline.points[contour_start_point_i], offset, contour_first_offset, scaled_miter_limit, scale); @@ -529,7 +539,7 @@ GeometryResult StrokePathGeometry::GetPositionBuffer( auto& host_buffer = pass.GetTransientsBuffer(); auto vertex_builder = CreateSolidStrokeVertices( - path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, stroke_cap_, + path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, GetJoinProc(stroke_join_), GetCapProc(stroke_cap_), entity.GetTransformation().GetMaxBasisLength()); @@ -561,7 +571,7 @@ GeometryResult StrokePathGeometry::GetPositionUVBuffer( auto& host_buffer = pass.GetTransientsBuffer(); auto stroke_builder = CreateSolidStrokeVertices( - path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, stroke_cap_, + path_, stroke_width, miter_limit_ * stroke_width_ * 0.5, GetJoinProc(stroke_join_), GetCapProc(stroke_cap_), entity.GetTransformation().GetMaxBasisLength()); diff --git a/impeller/entity/geometry.h b/impeller/entity/geometry.h index 4bb5180b8b5d2..225d8600f574d 100644 --- a/impeller/entity/geometry.h +++ b/impeller/entity/geometry.h @@ -149,7 +149,8 @@ class StrokePathGeometry : public Geometry { std::function& vtx_builder, const Point& position, const Point& offset, - Scalar scale)>; + Scalar scale, + bool reverse)>; using JoinProc = std::function& vtx_builder, const Point& position, @@ -188,7 +189,6 @@ class StrokePathGeometry : public Geometry { CreateSolidStrokeVertices(const Path& path, Scalar stroke_width, Scalar scaled_miter_limit, - Cap cap, const JoinProc& join_proc, const CapProc& cap_proc, Scalar scale);