9#include "gtest/gtest.h"
23 std::vector<impeller::Point> a,
24 std::vector<impeller::Point> b) {
25 if (a.size() != b.size()) {
26 return ::testing::AssertionFailure() <<
"Colors length does not match";
28 for (
auto i = 0u;
i < b.size();
i++) {
30 return ::testing::AssertionFailure() <<
"Positions are not equal.";
33 return ::testing::AssertionSuccess();
37 std::vector<impeller::TextureFillVertexShader::PerVertexData> a,
38 std::vector<impeller::TextureFillVertexShader::PerVertexData> b) {
39 if (a.size() != b.size()) {
40 return ::testing::AssertionFailure() <<
"Colors length does not match";
42 for (
auto i = 0u;
i < b.size();
i++) {
44 return ::testing::AssertionFailure() <<
"Positions are not equal.";
46 if (!
PointNear(a[
i].texture_coords, b[
i].texture_coords)) {
47 return ::testing::AssertionFailure() <<
"Texture coords are not equal.";
50 return ::testing::AssertionSuccess();
53#define EXPECT_SOLID_VERTICES_NEAR(a, b) \
54 EXPECT_PRED2(&::SolidVerticesNear, a, b)
55#define EXPECT_TEXTURE_VERTICES_NEAR(a, b) \
56 EXPECT_PRED2(&::TextureVerticesNear, a, b)
69 return StrokePathGeometry::GenerateSolidStrokeVertices(
70 tessellator, path, stroke, scale);
76TEST(EntityGeometryTest, RectGeometryCoversArea) {
79 ASSERT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(-1, 0, 100, 100)));
81 ASSERT_TRUE(geometry->CoversArea({},
IRect()));
84TEST(EntityGeometryTest, UberSDFGeometryPaddingIsAdjustedByInverseMaxBasis) {
91 EXPECT_TRUE(coverage.has_value());
92 if (coverage.has_value()) {
102 EXPECT_TRUE(coverage.has_value());
103 if (coverage.has_value()) {
104 EXPECT_EQ(coverage.value(),
Rect::MakeLTRB(-0.5, -0.5, 100.5, 100.5)
114 EXPECT_TRUE(coverage.has_value());
115 if (coverage.has_value()) {
116 EXPECT_EQ(coverage.value(),
Rect::MakeLTRB(-2.0, -2.0, 102.0, 102.0)
122TEST(EntityGeometryTest, FillPathGeometryCoversArea) {
128 ASSERT_TRUE(geometry->CoversArea({},
IRect::MakeLTRB(0, 0, 100, 100)));
129 ASSERT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(-1, 0, 100, 100)));
130 ASSERT_TRUE(geometry->CoversArea({},
IRect::MakeLTRB(1, 1, 100, 100)));
131 ASSERT_TRUE(geometry->CoversArea({},
IRect()));
134TEST(EntityGeometryTest, FillPathGeometryCoversAreaNoInnerRect) {
139 ASSERT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(0, 0, 100, 100)));
140 ASSERT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(-1, 0, 100, 100)));
141 ASSERT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(1, 1, 100, 100)));
142 ASSERT_FALSE(geometry->CoversArea({},
IRect()));
145TEST(EntityGeometryTest, FillArcGeometryCoverage) {
153 for (
int sweep = 360; sweep <= 720; sweep += 30) {
155 "start: " + std::to_string(
start) +
" + " + std::to_string(sweep);
158 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
159 <<
"start: " <<
start <<
", sweep: " << sweep;
162 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
163 <<
"start: " <<
start <<
", sweep: " << -sweep;
166 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
167 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", with center";
175 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
176 <<
"start: " <<
start <<
" without center";
179 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
180 <<
"start: " <<
start <<
" with center";
187 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
188 <<
"start: " <<
start <<
" without center";
191 EXPECT_EQ(geometry->GetCoverage({}), oval_bounds)
192 <<
"start: " <<
start <<
" with center";
206 <<
"start: " <<
start - 45;
217 <<
"start: " <<
start + 45;
228 <<
"start: " <<
start + 135;
239 <<
"start: " <<
start + 225;
254 <<
"start: " <<
start - 45;
265 <<
"start: " <<
start + 45;
276 <<
"start: " <<
start + 135;
287 <<
"start: " <<
start + 225;
294 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
296 EXPECT_TRUE(geometry->GetCoverage(transform45)
298 .Contains(oval_bounds));
303 ASSERT_TRUE(oval_bounds.TransformBounds(transform45).Contains(oval_bounds));
305 EXPECT_TRUE(geometry->GetCoverage(transform45)
307 .Contains(oval_bounds));
311TEST(EntityGeometryTest, StrokeArcGeometryCoverage) {
331 for (
int sweep = 360; sweep <= 720; sweep += 30) {
333 "start: " + std::to_string(
start) +
" + " + std::to_string(sweep);
336 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
337 <<
"start: " <<
start <<
", sweep: " << sweep;
340 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
341 <<
"start: " <<
start <<
", sweep: " << -sweep;
343 Degrees(-sweep), square_params);
344 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
345 <<
"start: " <<
start <<
", sweep: " << -sweep <<
", square caps";
353 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
354 <<
"start: " <<
start <<
", butt caps";
357 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
358 <<
"start: " <<
start <<
", square caps";
365 EXPECT_EQ(geometry->GetCoverage({}), expanded_bounds)
366 <<
"start: " <<
start <<
" without center";
369 EXPECT_EQ(geometry->GetCoverage({}), squared_bounds)
370 <<
"start: " <<
start <<
" with center";
384 <<
"start: " <<
start - 45;
395 <<
"start: " <<
start + 45;
406 <<
"start: " <<
start + 135;
417 <<
"start: " <<
start + 225;
433 <<
"start: " <<
start - 45;
444 <<
"start: " <<
start + 45;
455 <<
"start: " <<
start + 135;
466 <<
"start: " <<
start + 225;
474 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
476 EXPECT_TRUE(geometry->GetCoverage(transform45)
478 .Contains(expanded_bounds));
484 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
486 EXPECT_TRUE(geometry->GetCoverage(transform45)
488 .Contains(squared_bounds));
494 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
496 EXPECT_TRUE(geometry->GetCoverage(transform45)
498 .Contains(expanded_bounds));
504 oval_bounds.TransformBounds(transform45).Contains(expanded_bounds));
506 EXPECT_TRUE(geometry->GetCoverage(transform45)
508 .Contains(squared_bounds));
512TEST(EntityGeometryTest, FillRoundRectGeometryCoversArea) {
517 .top_right =
Size(2, 12),
518 .bottom_left =
Size(3, 13),
519 .bottom_right =
Size(4, 14),
525 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(102, 100, 196, 200)));
527 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(103, 100, 197, 200)));
528 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(103, 100, 196, 201)));
533 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(100, 111, 200, 186)));
534 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(100, 112, 201, 186)));
535 EXPECT_FALSE(geom.CoversArea({},
IRect::MakeLTRB(100, 112, 200, 187)));
538TEST(EntityGeometryTest, LineGeometryCoverage) {
541 {10, 10}, {20, 10}, {.width = 2, .cap =
Cap::kButt});
542 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(10, 9, 20, 11));
549 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 9, 21, 11));
555 {10, 10}, {10, 20}, {.width = 2, .cap =
Cap::kButt});
556 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 10, 11, 20));
563 EXPECT_EQ(geometry->GetCoverage({}),
Rect::MakeLTRB(9, 9, 11, 21));
568TEST(EntityGeometryTest, RoundRectGeometryCoversArea) {
571 EXPECT_FALSE(geometry->CoversArea({},
IRect::MakeLTRB(15, 15, 85, 85)));
572 EXPECT_TRUE(geometry->CoversArea({},
IRect::MakeLTRB(20, 20, 80, 80)));
577TEST(EntityGeometryTest, GeometryResultHasReasonableDefaults) {
584TEST(EntityGeometryTest, AlphaCoverageStrokePaths) {
587 ->ComputeAlphaCoverage(matrix),
590 ->ComputeAlphaCoverage(matrix),
593 ->ComputeAlphaCoverage(matrix),
596 ->ComputeAlphaCoverage(matrix),
599 ->ComputeAlphaCoverage(matrix),
602 ->ComputeAlphaCoverage(matrix),
605 ->ComputeAlphaCoverage(matrix),
609TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesButtCap) {
611 path_builder.
MoveTo({20, 20});
612 path_builder.
LineTo({30, 20});
613 path_builder.
MoveTo({120, 20});
614 path_builder.
LineTo({130, 20});
627 std::vector<Point> expected = {
647 EXPECT_EQ(
points, expected);
650TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesRoundCap) {
652 path_builder.
MoveTo({20, 20});
653 path_builder.
LineTo({30, 20});
654 path_builder.
MoveTo({120, 20});
655 path_builder.
LineTo({130, 20});
668 size_t count =
points.size();
669 ASSERT_TRUE((count & 0x1) == 0x0);
677 ASSERT_EQ(
points.size(), 40u);
683 auto offset = [](
int step,
bool left,
bool backwards) ->
Point {
687 Point center = backwards ? -along : along;
688 return left ? center + across : center - across;
693 EXPECT_EQ(
points[1],
Point(20, 20) + offset(1,
true,
true));
694 EXPECT_EQ(
points[2],
Point(20, 20) + offset(1,
false,
true));
695 EXPECT_EQ(
points[3],
Point(20, 20) + offset(2,
true,
true));
696 EXPECT_EQ(
points[4],
Point(20, 20) + offset(2,
false,
true));
697 EXPECT_EQ(
points[5],
Point(20, 20) + offset(3,
true,
true));
698 EXPECT_EQ(
points[6],
Point(20, 20) + offset(3,
false,
true));
703 EXPECT_EQ(
points[11],
Point(30, 20) + offset(3,
true,
false));
704 EXPECT_EQ(
points[12],
Point(30, 20) + offset(3,
false,
false));
705 EXPECT_EQ(
points[13],
Point(30, 20) + offset(2,
true,
false));
706 EXPECT_EQ(
points[14],
Point(30, 20) + offset(2,
false,
false));
707 EXPECT_EQ(
points[15],
Point(30, 20) + offset(1,
true,
false));
708 EXPECT_EQ(
points[16],
Point(30, 20) + offset(1,
false,
false));
719 EXPECT_EQ(
points[23],
Point(120, 20) + offset(1,
true,
true));
720 EXPECT_EQ(
points[24],
Point(120, 20) + offset(1,
false,
true));
721 EXPECT_EQ(
points[25],
Point(120, 20) + offset(2,
true,
true));
722 EXPECT_EQ(
points[26],
Point(120, 20) + offset(2,
false,
true));
723 EXPECT_EQ(
points[27],
Point(120, 20) + offset(3,
true,
true));
724 EXPECT_EQ(
points[28],
Point(120, 20) + offset(3,
false,
true));
729 EXPECT_EQ(
points[33],
Point(130, 20) + offset(3,
true,
false));
730 EXPECT_EQ(
points[34],
Point(130, 20) + offset(3,
false,
false));
731 EXPECT_EQ(
points[35],
Point(130, 20) + offset(2,
true,
false));
732 EXPECT_EQ(
points[36],
Point(130, 20) + offset(2,
false,
false));
733 EXPECT_EQ(
points[37],
Point(130, 20) + offset(1,
true,
false));
734 EXPECT_EQ(
points[38],
Point(130, 20) + offset(1,
false,
false));
738TEST(EntityGeometryTest, SimpleTwoLineStrokeVerticesSquareCap) {
740 path_builder.
MoveTo({20, 20});
741 path_builder.
LineTo({30, 20});
742 path_builder.
MoveTo({120, 20});
743 path_builder.
LineTo({130, 20});
757 std::vector<Point> expected = {
786 EXPECT_EQ(
points, expected);
789TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesBevelJoin) {
791 path_builder.
MoveTo({20, 20});
792 path_builder.
LineTo({30, 20});
793 path_builder.
LineTo({30, 30});
806 std::vector<Point> expected = {
820 EXPECT_EQ(
points, expected);
823TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesBevelJoin) {
825 path_builder.
MoveTo({20, 20});
826 path_builder.
LineTo({30, 20});
827 path_builder.
LineTo({30, 10});
840 std::vector<Point> expected = {
854 EXPECT_EQ(
points, expected);
857TEST(EntityGeometryTest, TwoLineSegmentsInDifferentContoursAreNotJoined) {
860 path_builder.
MoveTo({20, 20});
861 path_builder.
LineTo({30, 20});
864 path_builder.
MoveTo({30, 20});
866 path_builder.
LineTo({30, 30});
879 std::vector<Point> expected = {
901 EXPECT_EQ(
points, expected);
904TEST(EntityGeometryTest, TwoLineSegmentsRightTurnStrokeVerticesMiterJoin) {
906 path_builder.
MoveTo({20, 20});
907 path_builder.
LineTo({30, 20});
908 path_builder.
LineTo({30, 30});
921 std::vector<Point> expected = {
938 EXPECT_EQ(
points, expected);
941TEST(EntityGeometryTest, TwoLineSegmentsLeftTurnStrokeVerticesMiterJoin) {
943 path_builder.
MoveTo({20, 20});
944 path_builder.
LineTo({30, 20});
945 path_builder.
LineTo({30, 10});
958 std::vector<Point> expected = {
975 EXPECT_EQ(
points, expected);
978TEST(EntityGeometryTest, TinyQuadGeneratesCaps) {
980 path_builder.
MoveTo({20, 20});
994 std::vector<Point> expected = {
1012 EXPECT_EQ(
points, expected);
1015TEST(EntityGeometryTest, TinyConicGeneratesCaps) {
1017 path_builder.
MoveTo({20, 20});
1018 path_builder.
ConicCurveTo({20.125, 20}, {20.250, 20}, 0.6);
1027 .miter_limit = 4.0f,
1031 std::vector<Point> expected = {
1049 EXPECT_EQ(
points, expected);
1052TEST(EntityGeometryTest, TinyCubicGeneratesCaps) {
1054 path_builder.
MoveTo({20, 20});
1055 path_builder.
CubicCurveTo({20.0625, 20}, {20.125, 20}, {20.250, 20});
1064 .miter_limit = 4.0f,
1068 std::vector<Point> expected = {
1086 EXPECT_EQ(
points, expected);
1089TEST(EntityGeometryTest, TwoLineSegmentsMiterLimit) {
1091 for (
int degrees = 10; degrees < 180; degrees += 10) {
1099 if (pixel_delta.GetDistance(
Point(1, 0)) *
width < 1.0f) {
1108 Degrees between(180 - degrees);
1115 path_builder.
LineTo(
Point(30, 20) + pixel_delta * 10.0f);
1126 .miter_limit = limit * 0.99f,
1129 EXPECT_EQ(points1.size(), 8u)
1130 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1141 .miter_limit = limit * 1.01f,
1144 EXPECT_EQ(points2.size(), 9u)
1145 <<
"degrees: " << degrees <<
", width: " <<
width;
1146 EXPECT_LE(points2[4].GetDistance({30, 20}),
width * limit * 1.05f)
1147 <<
"degrees: " << degrees <<
", width: " <<
width <<
", "
1153TEST(EntityGeometryTest, TwoLineSegments180DegreeJoins) {
1168 .miter_limit = 4.0f,
1172 EXPECT_EQ(points_bevel.size(), 8u);
1181 .miter_limit = 400.0f,
1185 EXPECT_EQ(points_miter.size(), 8u);
1194 .miter_limit = 4.0f,
1198 EXPECT_EQ(points_round.size(), 19u);
1201TEST(EntityGeometryTest, TightQuadratic180DegreeJoins) {
1209 auto points_bevel_reference =
1216 .miter_limit = 4.0f,
1220 EXPECT_EQ(points_bevel_reference.size(), 74u);
1235 .miter_limit = 4.0f,
1239 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1248 .miter_limit = 400.0f,
1252 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1261 .miter_limit = 4.0f,
1265 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1268TEST(EntityGeometryTest, TightConic180DegreeJoins) {
1276 auto points_bevel_reference =
1283 .miter_limit = 4.0f,
1287 EXPECT_EQ(points_bevel_reference.size(), 78u);
1302 .miter_limit = 4.0f,
1306 EXPECT_GT(points_bevel.size(), points_bevel_reference.size());
1315 .miter_limit = 400.0f,
1319 EXPECT_GT(points_miter.size(), points_bevel_reference.size());
1328 .miter_limit = 4.0f,
1332 EXPECT_GT(points_round.size(), points_bevel_reference.size());
1335TEST(EntityGeometryTest, TightCubic180DegreeJoins) {
1344 auto points_reference =
1351 .miter_limit = 4.0f,
1355 EXPECT_EQ(points_reference.size(), 76u);
1370 .miter_limit = 4.0f,
1374 EXPECT_GT(points_bevel.size(), points_reference.size());
1383 .miter_limit = 400.0f,
1387 EXPECT_GT(points_miter.size(), points_reference.size());
1396 .miter_limit = 4.0f,
1400 EXPECT_GT(points_round.size(), points_reference.size());
1403TEST(EntityGeometryTest, RotatedFilledCircleGeometryCoverage) {
1407 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1413 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1414 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1415 EXPECT_TRUE(bounds.Contains(circle_bounds))
1416 <<
"geometry bounds: " << bounds << std::endl
1417 <<
" circle bounds: " << circle_bounds;
1420TEST(EntityGeometryTest, RotatedStrokedCircleGeometryCoverage) {
1424 ASSERT_EQ(geometry->GetCoverage({}).value_or(
Rect()), circle_bounds);
1430 EXPECT_TRUE(geometry->GetCoverage(transform45).has_value());
1431 Rect bounds = geometry->GetCoverage(transform45).value_or(
Rect());
1432 EXPECT_TRUE(bounds.Contains(circle_bounds))
1433 <<
"geometry bounds: " << bounds << std::endl
1434 <<
" circle bounds: " << circle_bounds;
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & ConicCurveTo(DlPoint cp, DlPoint p2, DlScalar weight)
Draw a conic curve (a rational quadratic bezier curve) from the current point to the indicated point ...
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & QuadraticCurveTo(DlPoint cp, DlPoint p2)
Draw a quadratic bezier curve from the current point to the indicated point p2, using the indicated p...
DlPathBuilder & CubicCurveTo(DlPoint cp1, DlPoint cp2, DlPoint p2)
Draw a cubic bezier curve from the current point to the indicated point p2, using the indicated point...
A Geometry class that produces fillable vertices from any |RoundRect| object regardless of radii unif...
static std::unique_ptr< Geometry > MakeFillPath(const flutter::DlPath &path, std::optional< Rect > inner_rect=std::nullopt)
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
static std::unique_ptr< Geometry > MakeFilledArc(const Rect &oval_bounds, Degrees start, Degrees sweep, bool include_center)
static std::unique_ptr< Geometry > MakeStrokePath(const flutter::DlPath &path, const StrokeParameters &stroke={})
static std::unique_ptr< Geometry > MakeCircle(const Point ¢er, Scalar radius)
static std::unique_ptr< Geometry > MakeRoundRect(const Rect &rect, const Size &radii)
static std::unique_ptr< Geometry > MakeLine(const Point &p0, const Point &p1, const StrokeParameters &stroke)
static std::unique_ptr< Geometry > MakeStrokedCircle(const Point ¢er, Scalar radius, Scalar stroke_width)
static std::unique_ptr< Geometry > MakeStrokedArc(const Rect &oval_bounds, Degrees start, Degrees sweep, const StrokeParameters &stroke)
static std::vector< Point > GenerateSolidStrokeVertices(const PathSource &path, const StrokeParameters &stroke, Scalar scale)
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Geometry for rendering shapes using the UberSDF shader.
std::optional< Rect > GetCoverage(const Matrix &transform) const override
The coverage rectangle of this geometry, transformed by the transform argument.
inline ::testing::AssertionResult PointNear(impeller::Point a, impeller::Point b)
#define EXPECT_RECT_NEAR(a, b)
inline ::testing::AssertionResult SolidVerticesNear(std::vector< impeller::Point > a, std::vector< impeller::Point > b)
inline ::testing::AssertionResult TextureVerticesNear(std::vector< impeller::TextureFillVertexShader::PerVertexData > a, std::vector< impeller::TextureFillVertexShader::PerVertexData > b)
TEST(FrameTimingsRecorderTest, RecordVsync)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
constexpr float kSqrt2Over2
static constexpr Color Red()
@ kNormal
The geometry has no overlapping triangles.
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
static Matrix MakeRotationZ(Radians r)
static constexpr Matrix MakeScale(const Vector3 &s)
static RoundRect MakeRectRadii(const Rect &rect, const RoundingRadii &radii)
A structure to store all of the parameters related to stroking a path or basic geometry object.
constexpr TRect TransformAndClipBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle, clipped against the near clippin...
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
static UberSDFParameters MakeRect(Color color, const Rect &rect, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rectangle.
std::vector< Point > points