From 9ac0765bb8a0ee32db8ce916a02c7282ebbb1bcb Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 15:30:45 -0700 Subject: [PATCH 01/10] [Impeller] add support for rectellipse. --- impeller/aiks/aiks_unittests.cc | 25 +++++ impeller/aiks/canvas.cc | 16 ++++ impeller/aiks/canvas.h | 6 ++ impeller/entity/BUILD.gn | 2 + .../entity/geometry/rectellipse_geometry.cc | 94 +++++++++++++++++++ .../entity/geometry/rectellipse_geometry.h | 49 ++++++++++ 6 files changed, 192 insertions(+) create mode 100644 impeller/entity/geometry/rectellipse_geometry.cc create mode 100644 impeller/entity/geometry/rectellipse_geometry.h diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index cc36718db17bd..ceff44219267e 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -486,6 +486,31 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) { } } +TEST_P(AiksTest, DrawSuperEllipse) { + auto callback = [&](AiksContext& renderer) -> std::optional { + // UI state. + static float alpha = 1; + static float beta = 1; + static float radius = 40; + static Color color = Color::Red(); + + if (AiksTest::ImGuiBegin("Controls", nullptr, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::SliderFloat("Alpha", &alpha, 0, 100); + ImGui::SliderFloat("Beta", &beta, 0, 100); + ImGui::SliderFloat("Radius", &radius, 0, 400); + ImGui::ColorEdit4("Color", reinterpret_cast(&color)); + ImGui::End(); + } + + Canvas canvas; + canvas.DrawSuperEllipse({400, 400}, radius, alpha, beta, {.color = color}); + return canvas.EndRecordingAsPicture(); + }; + + OpenPlaygroundHere(callback); +} + } // namespace testing } // namespace impeller diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index a1a5704736260..80222703c51f0 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -23,6 +23,7 @@ #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" #include "impeller/entity/geometry/geometry.h" +#include "impeller/entity/geometry/rectellipse_geometry.h" #include "impeller/geometry/color.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/path_builder.h" @@ -846,6 +847,21 @@ void Canvas::SaveLayer(const Paint& paint, new_layer_pass.SetDelegate(std::make_shared(paint_copy)); } +void Canvas::DrawSuperEllipse(Point center, + Scalar radius, + Scalar alpha, + Scalar beta, + const Paint& paint) { + Entity entity; + entity.SetTransform(GetCurrentTransform()); + entity.SetBlendMode(paint.blend_mode); + entity.SetContents(CreateContentsForGeometryWithFilters( + paint, + std::make_shared(center, radius, alpha, beta))); + + AddRenderEntityToCurrentPass(std::move(entity)); +} + void Canvas::DrawTextFrame(const std::shared_ptr& text_frame, Point position, const Paint& paint) { diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index e5bdc379b0622..77ea4ad9a4a29 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -133,6 +133,12 @@ class Canvas { const Paint& paint, SamplerDescriptor sampler = {}); + void DrawSuperEllipse(Point center, + Scalar radius, + Scalar alpha, + Scalar beta, + const Paint& paint); + void DrawImageRect( const std::shared_ptr& image, Rect source, diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index d91d56cdfe5fe..46a2cbaa67e1b 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -192,6 +192,8 @@ impeller_component("entity") { "geometry/point_field_geometry.h", "geometry/rect_geometry.cc", "geometry/rect_geometry.h", + "geometry/rectellipse_geometry.cc", + "geometry/rectellipse_geometry.h", "geometry/round_rect_geometry.cc", "geometry/round_rect_geometry.h", "geometry/stroke_path_geometry.cc", diff --git a/impeller/entity/geometry/rectellipse_geometry.cc b/impeller/entity/geometry/rectellipse_geometry.cc new file mode 100644 index 0000000000000..5a339d77a4395 --- /dev/null +++ b/impeller/entity/geometry/rectellipse_geometry.cc @@ -0,0 +1,94 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "flutter/impeller/entity/geometry/rectellipse_geometry.h" + +#include "impeller/geometry/constants.h" + +namespace impeller { + +RectellipseGeometry::RectellipseGeometry(const Point& center, + Scalar radius, + Scalar alpha, + Scalar beta, + Scalar n) + : center_(center), radius_(radius), alpha_(alpha), beta_(beta), n_(n) {} + +GeometryResult RectellipseGeometry::GetPositionBuffer( + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + // https://math.stackexchange.com/questions/2573746/superellipse-parametric-equation + Scalar a = alpha_; + Scalar b = beta_; + Scalar n = 4; + + // TODO(jonahwilliams): determine parameter values based on scaling factor. + Scalar step = kPi / 80; + + // Generate the points for the top left quadrant, and then mirror to the other + // quadrants. + std::vector points; + for (Scalar t = 0; t < (kPi / 2) - step; t += step) { + Scalar x = a * pow(abs(cos(t)), 2 / n); + Scalar y = b * pow(abs(sin(t)), 2 / n); + points.emplace_back(x, y); + } + Scalar x = a * pow(abs(cos(kPi / 2)), 2 / n); + Scalar y = b * pow(abs(sin(kPi / 2)), 2 / n); + points.emplace_back(x, y); + + // Reflect into the other 3 quadrants and generate the tessellated mesh. + std::vector geometry; + static constexpr Point reflection[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}; + + geometry.push_back(center_); + for (auto sc : reflection) { + for (auto pt : points) { + geometry.push_back(center_ + ((sc * pt) * radius_)); + } + } + + std::vector indices; + for (auto i = 2u; i < geometry.size(); i++) { + indices.push_back(0); + indices.push_back(i - 1); + indices.push_back(i); + } + + auto& host_buffer = renderer.GetTransientsBuffer(); + return GeometryResult{ + .type = PrimitiveType::kTriangle, + .vertex_buffer = + { + .vertex_buffer = host_buffer.Emplace( + geometry.data(), geometry.size() * sizeof(Point), + alignof(Point)), + .index_buffer = host_buffer.Emplace( + indices.data(), indices.size() * sizeof(uint16_t), + alignof(uint16_t)), + .vertex_count = indices.size(), + .index_type = IndexType::k16bit, + }, + .transform = entity.GetShaderTransform(pass), + }; +} + +std::optional RectellipseGeometry::GetCoverage( + const Matrix& transform) const { + return Rect::MakeMaximum(); +} + +bool RectellipseGeometry::CoversArea(const Matrix& transform, + const Rect& rect) const { + return false; +} + +bool RectellipseGeometry::IsAxisAlignedRect() const { + return false; +} + +} // namespace impeller diff --git a/impeller/entity/geometry/rectellipse_geometry.h b/impeller/entity/geometry/rectellipse_geometry.h new file mode 100644 index 0000000000000..dc862f1d9eb0d --- /dev/null +++ b/impeller/entity/geometry/rectellipse_geometry.h @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ +#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ + +#include "impeller/entity/geometry/geometry.h" + +namespace impeller { + +// Geometry class that can generate vertices for a rectellipse. +class RectellipseGeometry final : public Geometry { + public: + explicit RectellipseGeometry(const Point& center, + Scalar radius, + Scalar alpha, + Scalar beta); + + ~RectellipseGeometry() = default; + + // |Geometry| + bool CoversArea(const Matrix& transform, const Rect& rect) const override; + + // |Geometry| + bool IsAxisAlignedRect() const override; + + private: + // |Geometry| + GeometryResult GetPositionBuffer(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + // |Geometry| + std::optional GetCoverage(const Matrix& transform) const override; + + Point center_; + Scalar radius_; + Scalar alpha_; + Scalar beta_; + + RectellipseGeometry(const RectellipseGeometry&) = delete; + + RectellipseGeometry& operator=(const RectellipseGeometry&) = delete; +}; + +} // namespace impeller + +#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ From ffddf05f2d46bcb33140b440c6567a2745b36c51 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 17:04:44 -0700 Subject: [PATCH 02/10] full configuration. --- impeller/aiks/aiks_unittests.cc | 14 ++++- impeller/aiks/canvas.cc | 9 +-- impeller/aiks/canvas.h | 3 +- impeller/entity/BUILD.gn | 4 +- ...e_geometry.cc => superellipse_geometry.cc} | 60 ++++++++++++------- ...pse_geometry.h => superellipse_geometry.h} | 27 +++++---- 6 files changed, 75 insertions(+), 42 deletions(-) rename impeller/entity/geometry/{rectellipse_geometry.cc => superellipse_geometry.cc} (54%) rename impeller/entity/geometry/{rectellipse_geometry.h => superellipse_geometry.h} (51%) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index ceff44219267e..e84b3cf37e71c 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -489,22 +489,30 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) { TEST_P(AiksTest, DrawSuperEllipse) { auto callback = [&](AiksContext& renderer) -> std::optional { // UI state. - static float alpha = 1; - static float beta = 1; + static float alpha = 10; + static float beta = 10; static float radius = 40; + static int degree = 4; static Color color = Color::Red(); if (AiksTest::ImGuiBegin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::SliderFloat("Alpha", &alpha, 0, 100); ImGui::SliderFloat("Beta", &beta, 0, 100); + ImGui::SliderInt("Degreee", °ree, 1, 20); ImGui::SliderFloat("Radius", &radius, 0, 400); ImGui::ColorEdit4("Color", reinterpret_cast(&color)); ImGui::End(); } Canvas canvas; - canvas.DrawSuperEllipse({400, 400}, radius, alpha, beta, {.color = color}); + canvas.DrawSuperellipse( + /*center=*/{400, 400}, + /*radius=*/radius, + /*degree=*/degree, + /*alpha=*/alpha, + /*beta=*/beta, + /*paint=*/{.color = color}); return canvas.EndRecordingAsPicture(); }; diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 80222703c51f0..c8860043bf972 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -23,7 +23,7 @@ #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" #include "impeller/entity/geometry/geometry.h" -#include "impeller/entity/geometry/rectellipse_geometry.h" +#include "impeller/entity/geometry/superellipse_geometry.h" #include "impeller/geometry/color.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/path_builder.h" @@ -847,8 +847,9 @@ void Canvas::SaveLayer(const Paint& paint, new_layer_pass.SetDelegate(std::make_shared(paint_copy)); } -void Canvas::DrawSuperEllipse(Point center, +void Canvas::DrawSuperellipse(Point center, Scalar radius, + int degree, Scalar alpha, Scalar beta, const Paint& paint) { @@ -856,8 +857,8 @@ void Canvas::DrawSuperEllipse(Point center, entity.SetTransform(GetCurrentTransform()); entity.SetBlendMode(paint.blend_mode); entity.SetContents(CreateContentsForGeometryWithFilters( - paint, - std::make_shared(center, radius, alpha, beta))); + paint, std::make_shared(center, radius, degree, + alpha, beta))); AddRenderEntityToCurrentPass(std::move(entity)); } diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 77ea4ad9a4a29..11ee307247e1e 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -133,8 +133,9 @@ class Canvas { const Paint& paint, SamplerDescriptor sampler = {}); - void DrawSuperEllipse(Point center, + void DrawSuperellipse(Point center, Scalar radius, + int degree, Scalar alpha, Scalar beta, const Paint& paint); diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 46a2cbaa67e1b..98e5831ac0ee6 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -192,12 +192,12 @@ impeller_component("entity") { "geometry/point_field_geometry.h", "geometry/rect_geometry.cc", "geometry/rect_geometry.h", - "geometry/rectellipse_geometry.cc", - "geometry/rectellipse_geometry.h", "geometry/round_rect_geometry.cc", "geometry/round_rect_geometry.h", "geometry/stroke_path_geometry.cc", "geometry/stroke_path_geometry.h", + "geometry/superellipse_geometry.cc", + "geometry/superellipse_geometry.h", "geometry/vertices_geometry.cc", "geometry/vertices_geometry.h", "inline_pass_context.cc", diff --git a/impeller/entity/geometry/rectellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc similarity index 54% rename from impeller/entity/geometry/rectellipse_geometry.cc rename to impeller/entity/geometry/superellipse_geometry.cc index 5a339d77a4395..14418fe7f49f5 100644 --- a/impeller/entity/geometry/rectellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -4,27 +4,31 @@ #include -#include "flutter/impeller/entity/geometry/rectellipse_geometry.h" +#include "flutter/impeller/entity/geometry/superellipse_geometry.h" #include "impeller/geometry/constants.h" namespace impeller { -RectellipseGeometry::RectellipseGeometry(const Point& center, - Scalar radius, - Scalar alpha, - Scalar beta, - Scalar n) - : center_(center), radius_(radius), alpha_(alpha), beta_(beta), n_(n) {} - -GeometryResult RectellipseGeometry::GetPositionBuffer( +SuperellipseGeometry::SuperellipseGeometry(const Point& center, + Scalar radius, + int degree, + Scalar alpha, + Scalar beta) + : center_(center), + degree_(degree), + radius_(radius), + alpha_(alpha), + beta_(beta) {} + +GeometryResult SuperellipseGeometry::GetPositionBuffer( const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { // https://math.stackexchange.com/questions/2573746/superellipse-parametric-equation Scalar a = alpha_; Scalar b = beta_; - Scalar n = 4; + Scalar n = degree_; // TODO(jonahwilliams): determine parameter values based on scaling factor. Scalar step = kPi / 80; @@ -41,15 +45,30 @@ GeometryResult RectellipseGeometry::GetPositionBuffer( Scalar y = b * pow(abs(sin(kPi / 2)), 2 / n); points.emplace_back(x, y); - // Reflect into the other 3 quadrants and generate the tessellated mesh. std::vector geometry; static constexpr Point reflection[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}; + if (points.empty()) { + return {}; + } + + // Reflect into the 4 quadrants and generate the tessellated mesh. The + // iteration order is reversed so that the trianges are continuous from + // quadrant to quadrant. geometry.push_back(center_); - for (auto sc : reflection) { - for (auto pt : points) { - geometry.push_back(center_ + ((sc * pt) * radius_)); - } + for (auto i = 0u; i < points.size(); i++) { + geometry.push_back(center_ + ((reflection[0] * points[i]) * radius_)); + } + for (auto i = 0u; i < points.size(); i++) { + geometry.push_back( + center_ + ((reflection[1] * points[points.size() - i - 1]) * radius_)); + } + for (auto i = 0u; i < points.size(); i++) { + geometry.push_back(center_ + ((reflection[2] * points[i]) * radius_)); + } + for (auto i = 0u; i < points.size(); i++) { + geometry.push_back( + center_ + ((reflection[3] * points[points.size() - i - 1]) * radius_)); } std::vector indices; @@ -77,17 +96,18 @@ GeometryResult RectellipseGeometry::GetPositionBuffer( }; } -std::optional RectellipseGeometry::GetCoverage( +std::optional SuperellipseGeometry::GetCoverage( const Matrix& transform) const { - return Rect::MakeMaximum(); + return Rect::MakeOriginSize(center_ - Point(radius_, radius_), + Size(radius_ * 2, radius_ * 2)); } -bool RectellipseGeometry::CoversArea(const Matrix& transform, - const Rect& rect) const { +bool SuperellipseGeometry::CoversArea(const Matrix& transform, + const Rect& rect) const { return false; } -bool RectellipseGeometry::IsAxisAlignedRect() const { +bool SuperellipseGeometry::IsAxisAlignedRect() const { return false; } diff --git a/impeller/entity/geometry/rectellipse_geometry.h b/impeller/entity/geometry/superellipse_geometry.h similarity index 51% rename from impeller/entity/geometry/rectellipse_geometry.h rename to impeller/entity/geometry/superellipse_geometry.h index dc862f1d9eb0d..a0d8eb4a355e0 100644 --- a/impeller/entity/geometry/rectellipse_geometry.h +++ b/impeller/entity/geometry/superellipse_geometry.h @@ -2,22 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ -#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ +#ifndef FLUTTER_IMPELLER_ENTITY_GEOMETRY_SUPERELLIPSE_GEOMETRY_H_ +#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_SUPERELLIPSE_GEOMETRY_H_ #include "impeller/entity/geometry/geometry.h" namespace impeller { -// Geometry class that can generate vertices for a rectellipse. -class RectellipseGeometry final : public Geometry { +// Geometry class that can generate vertices for a super ellipse. +class SuperellipseGeometry final : public Geometry { public: - explicit RectellipseGeometry(const Point& center, - Scalar radius, - Scalar alpha, - Scalar beta); + explicit SuperellipseGeometry(const Point& center, + Scalar radius, + int degree, + Scalar alpha, + Scalar beta); - ~RectellipseGeometry() = default; + ~SuperellipseGeometry() = default; // |Geometry| bool CoversArea(const Matrix& transform, const Rect& rect) const override; @@ -35,15 +36,17 @@ class RectellipseGeometry final : public Geometry { std::optional GetCoverage(const Matrix& transform) const override; Point center_; + // 4 is a rectellipse + int degree_; Scalar radius_; Scalar alpha_; Scalar beta_; - RectellipseGeometry(const RectellipseGeometry&) = delete; + SuperellipseGeometry(const SuperellipseGeometry&) = delete; - RectellipseGeometry& operator=(const RectellipseGeometry&) = delete; + SuperellipseGeometry& operator=(const SuperellipseGeometry&) = delete; }; } // namespace impeller -#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_RECTELLIPSE_GEOMETRY_H_ +#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_SUPERELLIPSE_GEOMETRY_H_ From 190dfc8acb3c93cd44e3cf2ef55ee975fa2ce532 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 17:55:59 -0700 Subject: [PATCH 03/10] linting. --- ci/licenses_golden/licenses_flutter | 4 ++++ impeller/entity/geometry/superellipse_geometry.cc | 15 ++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b650e4d16999a..2ec9a5af87ed5 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42862,6 +42862,8 @@ ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc + ../.. ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/superellipse_geometry.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/impeller/entity/geometry/superellipse_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/vertices_geometry.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/geometry/vertices_geometry.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/entity/inline_pass_context.cc + ../../../flutter/LICENSE @@ -45739,6 +45741,8 @@ FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h +FILE: ../../../flutter/impeller/entity/geometry/superellipse_geometry.cc +FILE: ../../../flutter/impeller/entity/geometry/superellipse_geometry.h FILE: ../../../flutter/impeller/entity/geometry/vertices_geometry.cc FILE: ../../../flutter/impeller/entity/geometry/vertices_geometry.h FILE: ../../../flutter/impeller/entity/inline_pass_context.cc diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 14418fe7f49f5..924c989027d5d 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -36,25 +36,21 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( // Generate the points for the top left quadrant, and then mirror to the other // quadrants. std::vector points; - for (Scalar t = 0; t < (kPi / 2) - step; t += step) { + points.reserve(40); + for (int i = 0; i < 40; i++) { + Scalar t = i * step; Scalar x = a * pow(abs(cos(t)), 2 / n); Scalar y = b * pow(abs(sin(t)), 2 / n); points.emplace_back(x, y); } - Scalar x = a * pow(abs(cos(kPi / 2)), 2 / n); - Scalar y = b * pow(abs(sin(kPi / 2)), 2 / n); - points.emplace_back(x, y); - std::vector geometry; static constexpr Point reflection[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}; - if (points.empty()) { - return {}; - } - // Reflect into the 4 quadrants and generate the tessellated mesh. The // iteration order is reversed so that the trianges are continuous from // quadrant to quadrant. + std::vector geometry; + geometry.reserve(1 + 4 * points.size()); geometry.push_back(center_); for (auto i = 0u; i < points.size(); i++) { geometry.push_back(center_ + ((reflection[0] * points[i]) * radius_)); @@ -72,6 +68,7 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( } std::vector indices; + indices.reserve(geometry.size() * 3); for (auto i = 2u; i < geometry.size(); i++) { indices.push_back(0); indices.push_back(i - 1); From ded4ae8ee4af492377b7b619868edd65170b5b8e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 17:59:11 -0700 Subject: [PATCH 04/10] quick fix --- impeller/entity/geometry/superellipse_geometry.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 924c989027d5d..709d0489dc22c 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -36,8 +36,8 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( // Generate the points for the top left quadrant, and then mirror to the other // quadrants. std::vector points; - points.reserve(40); - for (int i = 0; i < 40; i++) { + points.reserve(41); + for (int i = 0; i < 41; i++) { Scalar t = i * step; Scalar x = a * pow(abs(cos(t)), 2 / n); Scalar y = b * pow(abs(sin(t)), 2 / n); From 0d161ad26f3d1702404e6874aab3203485162bbe Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 20:39:46 -0700 Subject: [PATCH 05/10] move to entity tests. --- impeller/aiks/aiks_unittests.cc | 33 ----------------------------- impeller/aiks/canvas.cc | 16 -------------- impeller/aiks/canvas.h | 7 ------ impeller/entity/entity_unittests.cc | 32 ++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 56 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index e84b3cf37e71c..cc36718db17bd 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -486,39 +486,6 @@ TEST_P(AiksTest, CorrectClipDepthAssignedToEntities) { } } -TEST_P(AiksTest, DrawSuperEllipse) { - auto callback = [&](AiksContext& renderer) -> std::optional { - // UI state. - static float alpha = 10; - static float beta = 10; - static float radius = 40; - static int degree = 4; - static Color color = Color::Red(); - - if (AiksTest::ImGuiBegin("Controls", nullptr, - ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::SliderFloat("Alpha", &alpha, 0, 100); - ImGui::SliderFloat("Beta", &beta, 0, 100); - ImGui::SliderInt("Degreee", °ree, 1, 20); - ImGui::SliderFloat("Radius", &radius, 0, 400); - ImGui::ColorEdit4("Color", reinterpret_cast(&color)); - ImGui::End(); - } - - Canvas canvas; - canvas.DrawSuperellipse( - /*center=*/{400, 400}, - /*radius=*/radius, - /*degree=*/degree, - /*alpha=*/alpha, - /*beta=*/beta, - /*paint=*/{.color = color}); - return canvas.EndRecordingAsPicture(); - }; - - OpenPlaygroundHere(callback); -} - } // namespace testing } // namespace impeller diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index c8860043bf972..2a69722f49610 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -847,22 +847,6 @@ void Canvas::SaveLayer(const Paint& paint, new_layer_pass.SetDelegate(std::make_shared(paint_copy)); } -void Canvas::DrawSuperellipse(Point center, - Scalar radius, - int degree, - Scalar alpha, - Scalar beta, - const Paint& paint) { - Entity entity; - entity.SetTransform(GetCurrentTransform()); - entity.SetBlendMode(paint.blend_mode); - entity.SetContents(CreateContentsForGeometryWithFilters( - paint, std::make_shared(center, radius, degree, - alpha, beta))); - - AddRenderEntityToCurrentPass(std::move(entity)); -} - void Canvas::DrawTextFrame(const std::shared_ptr& text_frame, Point position, const Paint& paint) { diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 11ee307247e1e..e5bdc379b0622 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -133,13 +133,6 @@ class Canvas { const Paint& paint, SamplerDescriptor sampler = {}); - void DrawSuperellipse(Point center, - Scalar radius, - int degree, - Scalar alpha, - Scalar beta, - const Paint& paint); - void DrawImageRect( const std::shared_ptr& image, Rect source, diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 7f476eb5281d6..92408fd7da6e2 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -39,6 +39,7 @@ #include "impeller/entity/geometry/geometry.h" #include "impeller/entity/geometry/point_field_geometry.h" #include "impeller/entity/geometry/stroke_path_geometry.h" +#include "impeller/entity/geometry/superellipse_geometry.h" #include "impeller/entity/render_target_cache.h" #include "impeller/geometry/color.h" #include "impeller/geometry/geometry_asserts.h" @@ -2587,6 +2588,37 @@ TEST_P(EntityTest, CanRenderEmptyPathsWithoutCrashing) { ASSERT_TRUE(OpenPlaygroundHere(std::move(entity))); } +TEST_P(EntityTest, DrawSuperEllipse) { + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + // UI state. + static float alpha = 10; + static float beta = 10; + static float radius = 40; + static int degree = 4; + static Color color = Color::Red(); + + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::SliderFloat("Alpha", &alpha, 0, 100); + ImGui::SliderFloat("Beta", &beta, 0, 100); + ImGui::SliderInt("Degreee", °ree, 1, 20); + ImGui::SliderFloat("Radius", &radius, 0, 400); + ImGui::ColorEdit4("Color", reinterpret_cast(&color)); + ImGui::End(); + + auto contents = std::make_shared(); + contents->SetColor(color); + contents->SetGeometry(std::make_shared( + Point{400, 400}, radius, degree, alpha, beta)); + + Entity entity; + entity.SetContents(contents); + + return entity.Render(context, pass); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller From e3693280695b506c47eddac555960b9fe35d271f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 20:46:46 -0700 Subject: [PATCH 06/10] add doc comment. --- impeller/entity/geometry/superellipse_geometry.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/impeller/entity/geometry/superellipse_geometry.h b/impeller/entity/geometry/superellipse_geometry.h index a0d8eb4a355e0..3020af328c0da 100644 --- a/impeller/entity/geometry/superellipse_geometry.h +++ b/impeller/entity/geometry/superellipse_geometry.h @@ -9,7 +9,17 @@ namespace impeller { -// Geometry class that can generate vertices for a super ellipse. +/// Geometry class that can generate vertices for a superellipse. +/// +/// A Superellipse is an ellipse-like shape that is defined by the parameters N, +/// alpha, and beta: +/// +/// 1 = |x / b| ^n + |y / a| ^n +/// +/// The radius and center apply a uniform scaling and offset that is separate +/// from alpha or beta. When n = 4, the shape is referred to as a rectellipse. +/// +/// See also: https://en.wikipedia.org/wiki/Superellipse class SuperellipseGeometry final : public Geometry { public: explicit SuperellipseGeometry(const Point& center, From 2e9d74b57f2051fafa458a03ef036aa2af111469 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 15 Aug 2024 11:18:51 -0700 Subject: [PATCH 07/10] Update superellipse_geometry.h --- impeller/entity/geometry/superellipse_geometry.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/entity/geometry/superellipse_geometry.h b/impeller/entity/geometry/superellipse_geometry.h index 3020af328c0da..19c049f2962ff 100644 --- a/impeller/entity/geometry/superellipse_geometry.h +++ b/impeller/entity/geometry/superellipse_geometry.h @@ -24,7 +24,7 @@ class SuperellipseGeometry final : public Geometry { public: explicit SuperellipseGeometry(const Point& center, Scalar radius, - int degree, + Scalar degree, Scalar alpha, Scalar beta); @@ -47,7 +47,7 @@ class SuperellipseGeometry final : public Geometry { Point center_; // 4 is a rectellipse - int degree_; + Scalar degree_; Scalar radius_; Scalar alpha_; Scalar beta_; From 4cc92e0f2d07c9b05cf17177dca469bf4e840ebd Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 15 Aug 2024 11:19:03 -0700 Subject: [PATCH 08/10] Update superellipse_geometry.cc --- impeller/entity/geometry/superellipse_geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 709d0489dc22c..44d64c347c4b4 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -12,7 +12,7 @@ namespace impeller { SuperellipseGeometry::SuperellipseGeometry(const Point& center, Scalar radius, - int degree, + Scalar degree, Scalar alpha, Scalar beta) : center_(center), From a037a7d4c384cb13914796a1f039f2142d7cdb75 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 15 Aug 2024 11:31:17 -0700 Subject: [PATCH 09/10] Update superellipse_geometry.cc --- impeller/entity/geometry/superellipse_geometry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 44d64c347c4b4..e22b6c2d502a2 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -37,7 +37,7 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( // quadrants. std::vector points; points.reserve(41); - for (int i = 0; i < 41; i++) { + for (int i = 0; i <= 40; i++) { Scalar t = i * step; Scalar x = a * pow(abs(cos(t)), 2 / n); Scalar y = b * pow(abs(sin(t)), 2 / n); From e014ce9e511e3f2a82684a268c43ebf16e64256b Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 15 Aug 2024 14:36:03 -0700 Subject: [PATCH 10/10] inline radius. --- impeller/entity/geometry/superellipse_geometry.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/impeller/entity/geometry/superellipse_geometry.cc b/impeller/entity/geometry/superellipse_geometry.cc index 709d0489dc22c..1181d809b8d0f 100644 --- a/impeller/entity/geometry/superellipse_geometry.cc +++ b/impeller/entity/geometry/superellipse_geometry.cc @@ -41,7 +41,7 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( Scalar t = i * step; Scalar x = a * pow(abs(cos(t)), 2 / n); Scalar y = b * pow(abs(sin(t)), 2 / n); - points.emplace_back(x, y); + points.emplace_back(x * radius_, y * radius_); } static constexpr Point reflection[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}; @@ -53,18 +53,18 @@ GeometryResult SuperellipseGeometry::GetPositionBuffer( geometry.reserve(1 + 4 * points.size()); geometry.push_back(center_); for (auto i = 0u; i < points.size(); i++) { - geometry.push_back(center_ + ((reflection[0] * points[i]) * radius_)); + geometry.push_back(center_ + (reflection[0] * points[i])); } for (auto i = 0u; i < points.size(); i++) { - geometry.push_back( - center_ + ((reflection[1] * points[points.size() - i - 1]) * radius_)); + geometry.push_back(center_ + + (reflection[1] * points[points.size() - i - 1])); } for (auto i = 0u; i < points.size(); i++) { - geometry.push_back(center_ + ((reflection[2] * points[i]) * radius_)); + geometry.push_back(center_ + (reflection[2] * points[i])); } for (auto i = 0u; i < points.size(); i++) { - geometry.push_back( - center_ + ((reflection[3] * points[points.size() - i - 1]) * radius_)); + geometry.push_back(center_ + + (reflection[3] * points[points.size() - i - 1])); } std::vector indices;