mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] add support for superellipse. (flutter/engine#54562)
This is an entity testing only implementation of a superellipse. rectellipse is a special case where degree = 4. Part of https://github.com/flutter/flutter/issues/139321
This commit is contained in:
parent
e0529ddd81
commit
343fc75076
@ -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
|
||||
|
||||
@ -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/superellipse_geometry.h"
|
||||
#include "impeller/geometry/color.h"
|
||||
#include "impeller/geometry/constants.h"
|
||||
#include "impeller/geometry/path_builder.h"
|
||||
|
||||
@ -196,6 +196,8 @@ impeller_component("entity") {
|
||||
"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",
|
||||
|
||||
@ -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<float*>(&color));
|
||||
ImGui::End();
|
||||
|
||||
auto contents = std::make_shared<SolidColorContents>();
|
||||
contents->SetColor(color);
|
||||
contents->SetGeometry(std::make_shared<SuperellipseGeometry>(
|
||||
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
|
||||
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
// 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 <vector>
|
||||
|
||||
#include "flutter/impeller/entity/geometry/superellipse_geometry.h"
|
||||
|
||||
#include "impeller/geometry/constants.h"
|
||||
|
||||
namespace impeller {
|
||||
|
||||
SuperellipseGeometry::SuperellipseGeometry(const Point& center,
|
||||
Scalar radius,
|
||||
Scalar 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 = degree_;
|
||||
|
||||
// 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<Point> points;
|
||||
points.reserve(41);
|
||||
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 * radius_, y * radius_);
|
||||
}
|
||||
|
||||
static constexpr Point reflection[4] = {{1, 1}, {-1, 1}, {-1, -1}, {1, -1}};
|
||||
|
||||
// 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<Point> 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]));
|
||||
}
|
||||
for (auto i = 0u; i < points.size(); i++) {
|
||||
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]));
|
||||
}
|
||||
for (auto i = 0u; i < points.size(); i++) {
|
||||
geometry.push_back(center_ +
|
||||
(reflection[3] * points[points.size() - i - 1]));
|
||||
}
|
||||
|
||||
std::vector<uint16_t> indices;
|
||||
indices.reserve(geometry.size() * 3);
|
||||
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<Rect> SuperellipseGeometry::GetCoverage(
|
||||
const Matrix& transform) const {
|
||||
return Rect::MakeOriginSize(center_ - Point(radius_, radius_),
|
||||
Size(radius_ * 2, radius_ * 2));
|
||||
}
|
||||
|
||||
bool SuperellipseGeometry::CoversArea(const Matrix& transform,
|
||||
const Rect& rect) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SuperellipseGeometry::IsAxisAlignedRect() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
@ -0,0 +1,62 @@
|
||||
// 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_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 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,
|
||||
Scalar radius,
|
||||
Scalar degree,
|
||||
Scalar alpha,
|
||||
Scalar beta);
|
||||
|
||||
~SuperellipseGeometry() = 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<Rect> GetCoverage(const Matrix& transform) const override;
|
||||
|
||||
Point center_;
|
||||
// 4 is a rectellipse
|
||||
Scalar degree_;
|
||||
Scalar radius_;
|
||||
Scalar alpha_;
|
||||
Scalar beta_;
|
||||
|
||||
SuperellipseGeometry(const SuperellipseGeometry&) = delete;
|
||||
|
||||
SuperellipseGeometry& operator=(const SuperellipseGeometry&) = delete;
|
||||
};
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_SUPERELLIPSE_GEOMETRY_H_
|
||||
Loading…
x
Reference in New Issue
Block a user