Skip to content

Commit

Permalink
Implement drawArc (flutter#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdero authored and dnfield committed Apr 27, 2022
1 parent 82a3403 commit 69334fd
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 15 deletions.
6 changes: 5 additions & 1 deletion impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "impeller/entity/contents/solid_stroke_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/path_builder.h"
#include "impeller/geometry/scalar.h"
#include "impeller/typographer/backends/skia/text_frame_skia.h"
#include "third_party/skia/include/core/SkColor.h"

Expand Down Expand Up @@ -546,7 +547,10 @@ void DisplayListDispatcher::drawArc(const SkRect& oval_bounds,
SkScalar start_degrees,
SkScalar sweep_degrees,
bool use_center) {
UNIMPLEMENTED;
PathBuilder builder;
builder.AddArc(ToRect(oval_bounds), Degrees(start_degrees),
Degrees(sweep_degrees), use_center);
canvas_.DrawPath(builder.TakePath(), paint_);
}

// |flutter::Dispatcher|
Expand Down
21 changes: 12 additions & 9 deletions impeller/display_list/display_list_playground.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,27 @@ bool DisplayListPlayground::OpenPlaygroundHere(

bool DisplayListPlayground::OpenPlaygroundHere(
sk_sp<flutter::DisplayList> list) {
return OpenPlaygroundHere([&list]() { return list; });
}

bool DisplayListPlayground::OpenPlaygroundHere(
DisplayListPlaygroundCallback callback) {
if (!Playground::is_enabled()) {
return true;
}

if (!list) {
return false;
}

DisplayListDispatcher dispatcher;
list->Dispatch(dispatcher);
auto picture = dispatcher.EndRecordingAsPicture();

AiksContext context(GetContext());
if (!context.IsValid()) {
return false;
}
return Playground::OpenPlaygroundHere(
[&picture, &context](RenderPass& pass) -> bool {
[&context, &callback](RenderPass& pass) -> bool {
auto list = callback();

DisplayListDispatcher dispatcher;
list->Dispatch(dispatcher);
auto picture = dispatcher.EndRecordingAsPicture();

return context.Render(picture, pass);
});
}
Expand Down
5 changes: 5 additions & 0 deletions impeller/display_list/display_list_playground.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace impeller {

class DisplayListPlayground : public Playground {
public:
using DisplayListPlaygroundCallback =
std::function<sk_sp<flutter::DisplayList>()>;

DisplayListPlayground();

~DisplayListPlayground();
Expand All @@ -22,6 +25,8 @@ class DisplayListPlayground : public Playground {

bool OpenPlaygroundHere(sk_sp<flutter::DisplayList> list);

bool OpenPlaygroundHere(DisplayListPlaygroundCallback callback);

SkFont CreateTestFontOfSize(SkScalar scalar);

SkFont CreateTestFont();
Expand Down
50 changes: 48 additions & 2 deletions impeller/display_list/display_list_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gtest/gtest.h"
#include "third_party/imgui/imgui.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPathBuilder.h"

#include "flutter/display_list/display_list_builder.h"
#include "flutter/testing/testing.h"
#include "impeller/display_list/display_list_image_impeller.h"
#include "impeller/display_list/display_list_playground.h"
#include "third_party/skia/include/core/SkPathBuilder.h"
#include "impeller/geometry/point.h"
#include "impeller/playground/widgets.h"

namespace impeller {
namespace testing {
Expand Down Expand Up @@ -36,7 +42,7 @@ TEST_F(DisplayListTest, CanDrawImage) {
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}

TEST_F(DisplayListTest, CapsAndJoins) {
TEST_F(DisplayListTest, CanDrawCapsAndJoins) {
flutter::DisplayListBuilder builder;

builder.setStyle(SkPaint::Style::kStroke_Style);
Expand Down Expand Up @@ -81,5 +87,45 @@ TEST_F(DisplayListTest, CapsAndJoins) {
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}

TEST_F(DisplayListTest, CanDrawArc) {
bool first_frame = true;
auto callback = [&]() {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowSize({400, 100});
ImGui::SetNextWindowPos({300, 550});
}

static float start_angle = 45;
static float sweep_angle = 270;
static bool use_center = true;

ImGui::Begin("Controls");
ImGui::SliderFloat("Start angle", &start_angle, -360, 360);
ImGui::SliderFloat("Sweep angle", &sweep_angle, -360, 360);
ImGui::Checkbox("Use center", &use_center);
ImGui::End();

auto [p1, p2] = IMPELLER_PLAYGROUND_LINE(
Point(200, 200), Point(400, 400), 20, Color::White(), Color::White());

flutter::DisplayListBuilder builder;
builder.setStyle(SkPaint::Style::kStroke_Style);
builder.setStrokeCap(SkPaint::Cap::kRound_Cap);
builder.setStrokeJoin(SkPaint::Join::kMiter_Join);
builder.setStrokeMiter(10);
auto rect = SkRect::MakeLTRB(p1.x, p1.y, p2.x, p2.y);
builder.setColor(SK_ColorGREEN);
builder.setStrokeWidth(2);
builder.drawRect(rect);
builder.setColor(SK_ColorRED);
builder.setStrokeWidth(10);
builder.drawArc(rect, start_angle, sweep_angle, use_center);

return builder.Build();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

} // namespace testing
} // namespace impeller
5 changes: 4 additions & 1 deletion impeller/geometry/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ constexpr float klogE_2 = 0.69314718055994530942;
// log_e 10
constexpr float klogE_10 = 2.30258509299404568402;

// pi */
// pi
constexpr float kPi = 3.14159265358979323846;

// pi*2
constexpr float k2Pi = 6.28318530717958647693;

// pi/2
constexpr float kPiOver2 = 1.57079632679489661923;

Expand Down
65 changes: 63 additions & 2 deletions impeller/geometry/path_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "path_builder.h"

#include <cmath>

namespace impeller {

PathBuilder::PathBuilder() = default;
Expand Down Expand Up @@ -288,10 +290,69 @@ PathBuilder& PathBuilder::AddRoundedRect(Rect rect, RoundingRadii radii) {
return *this;
}

PathBuilder& PathBuilder::AddArc(const Rect& oval_bounds,
Radians start,
Radians sweep,
bool use_center) {
if (sweep.radians < 0) {
start.radians += sweep.radians;
sweep.radians *= -1;
}
sweep.radians = std::min(k2Pi, sweep.radians);
start.radians = std::fmod(start.radians, k2Pi);

const Point radius = {oval_bounds.size.width * 0.5f,
oval_bounds.size.height * 0.5f};
const Point center = {oval_bounds.origin.x + radius.x,
oval_bounds.origin.y + radius.y};

Vector2 p1_unit(std::cos(start.radians), std::sin(start.radians));

if (use_center) {
MoveTo(center);
LineTo(center + p1_unit * radius);
} else {
MoveTo(center + p1_unit * radius);
}

while (sweep.radians > 0) {
Vector2 p2_unit;
Scalar quadrant_angle;
if (sweep.radians < kPiOver2) {
quadrant_angle = sweep.radians;
p2_unit = Vector2(std::cos(start.radians + quadrant_angle),
std::sin(start.radians + quadrant_angle));
} else {
quadrant_angle = kPiOver2;
p2_unit = Vector2(-p1_unit.y, p1_unit.x);
}

Vector2 arc_cp_lengths =
(quadrant_angle / kPiOver2) * kArcApproximationMagic * radius;

Point p1 = center + p1_unit * radius;
Point p2 = center + p2_unit * radius;
Point cp1 = p1 + Vector2(-p1_unit.y, p1_unit.x) * arc_cp_lengths;
Point cp2 = p2 + Vector2(p2_unit.y, -p2_unit.x) * arc_cp_lengths;

prototype_.AddCubicComponent(p1, cp1, cp2, p2);
current_ = p2;

start.radians += quadrant_angle;
sweep.radians -= quadrant_angle;
p1_unit = p2_unit;
}

if (use_center) {
Close();
}

return *this;
}

PathBuilder& PathBuilder::AddOval(const Rect& container) {
const Point r = {container.size.width * 0.5f, container.size.height * 0.5f};
const Point c = {container.origin.x + (container.size.width * 0.5f),
container.origin.y + (container.size.height * 0.5f)};
const Point c = {container.origin.x + r.x, container.origin.y + r.y};
const Point m = {kArcApproximationMagic * r.x, kArcApproximationMagic * r.y};

MoveTo({c.x, c.y - r.y});
Expand Down
5 changes: 5 additions & 0 deletions impeller/geometry/path_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ class PathBuilder {

PathBuilder& AddCircle(const Point& center, Scalar radius);

PathBuilder& AddArc(const Rect& oval_bounds,
Radians start,
Radians sweep,
bool use_center = false);

PathBuilder& AddOval(const Rect& rect);

PathBuilder& AddLine(const Point& p1, const Point& p2);
Expand Down

0 comments on commit 69334fd

Please sign in to comment.