| Flutter Impeller |

round_superellipse_geometry.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <cmath>
6 #include <variant>
7
8 #include "flutter/impeller/entity/geometry/round_superellipse_geometry.h"
9
10 #include "impeller/geometry/constants.h"
11
12 namespace impeller {
13
14 namespace {
15
16 // An interface for classes that arranges a point list that forms a convex
17 // contour into a triangle strip.
18 class ConvexRearranger {
19 public:
20 ConvexRearranger() {}
21
22 virtual ~ConvexRearranger() {}
23
24 virtual size_t ContourLength() const = 0;
25
26 virtual Point GetPoint(size_t i) const = 0;
27
28 void RearrangeIntoTriangleStrip(Point* output) {
29 size_t index_count = 0;
30
31 output[index_count++] = GetPoint(0);
32
33 size_t a = 1;
34 size_t contour_length = ContourLength();
35 size_t b = contour_length - 1;
36 while (a < b) {
37 output[index_count++] = GetPoint(a);
38 output[index_count++] = GetPoint(b);
39 a++;
40 b--;
41 }
42 if (a == b) {
43 output[index_count++] = GetPoint(b);
44 }
45 }
46
47 private:
48 ConvexRearranger(const ConvexRearranger&) = delete;
49 ConvexRearranger& operator=(const ConvexRearranger&) = delete;
50 };
51
52 // A convex rearranger whose contour is concatenated from 4 quadrant segments.
53 //
54 // The input quadrant curves must travel from the Y axis to the X axis, and
55 // include both ends. This means that the points on the axes are duplicate
56 // between segments, and will be omitted by this class.
57 class UnevenQuadrantsRearranger : public ConvexRearranger {
58 public:
59 UnevenQuadrantsRearranger(Point* cache, size_t segment_capacity)
60 : cache_(cache), segment_capacity_(segment_capacity) {}
61
62 Point* QuadCache(size_t i) { return cache_ + segment_capacity_ * i; }
63
64 const Point* QuadCache(size_t i) const {
65 return cache_ + segment_capacity_ * i;
66 }
67
68 size_t& QuadSize(size_t i) { return lengths_[i]; }
69
70 size_t ContourLength() const override {
71 return lengths_[0] + lengths_[1] + lengths_[2] + lengths_[3] - 4;
72 }
73
74 Point GetPoint(size_t i) const override {
75 // output from index
76 // 0 ... l0-2 quads[0] 0 ... l0-2
77 // next 0 ... l1-2 quads[1] l1-1 ... 1
78 // next 0 ... l2-2 quads[2] 0 ... l2-2
79 // next 0 ... l3-2 quads[3] l3-1 ... 1
80 size_t high = lengths_[0] - 1;
81 if (i < high) {
82 return QuadCache(0)[i];
83 }
84 high += lengths_[1] - 1;
85 if (i < high) {
86 return QuadCache(1)[high - i];
87 }
88 size_t low = high;
89 high += lengths_[2] - 1;
90 if (i < high) {
91 return QuadCache(2)[i - low];
92 }
93 high += lengths_[3] - 1;
94 if (i < high) {
95 return QuadCache(3)[high - i];
96 } else {
97 // Unreachable
98 return Point();
99 }
100 }
101
102 private:
103 Point* cache_;
104 size_t segment_capacity_;
105 size_t lengths_[4];
106 };
107
108 // A convex rearranger whose contour is concatenated from 4 identical quadrant
109 // segments.
110 //
111 // The input curve must travel from the Y axis to the X axis and include both
112 // ends. This means that the points on the axes are duplicate between segments,
113 // and will be omitted by this class.
114 class MirroredQuadrantRearranger : public ConvexRearranger {
115 public:
116 MirroredQuadrantRearranger(Point center, Point* cache)
117 : center_(center), cache_(cache) {}
118
119 size_t& QuadSize() { return l_; }
120
121 size_t ContourLength() const override { return l_ * 4 - 4; }
122
123 Point GetPoint(size_t i) const override {
124 // output from index
125 // 0 ... l-2 quad 0 ... l-2
126 // next 0 ... l-2 quad l-1 ... 1
127 // next 0 ... l-2 quad 0 ... l-2
128 // next 0 ... l-2 quad l-1 ... 1
129 size_t high = l_ - 1;
130 if (i < high) {
131 return cache_[i] + center_;
132 }
133 high += l_ - 1;
134 if (i < high) {
135 return cache_[high - i] * Point{1, -1} + center_;
136 }
137 size_t low = high;
138 high += l_ - 1;
139 if (i < high) {
140 return cache_[i - low] * Point{-1, -1} + center_;
141 }
142 high += l_ - 1;
143 if (i < high) {
144 return cache_[high - i] * Point{-1, 1} + center_;
145 } else {
146 // Unreachable
147 return Point();
148 }
149 }
150
151 private:
152 Point center_;
153 Point* cache_;
154 size_t l_ = 0;
155 };
156
157 // A matrix that swaps the coordinates of a point.
158 // clang-format off
159 constexpr Matrix kFlip = Matrix(
160 0.0f, 1.0f, 0.0f, 0.0f,
161 1.0f, 0.0f, 0.0f, 0.0f,
162 0.0f, 0.0f, 1.0f, 0.0f,
163 0.0f, 0.0f, 0.0f, 1.0f);
164 // clang-format on
165
166 // A look up table with precomputed variables.
167 //
168 // The columns represent the following variabls respectively:
169 //
170 // * ratio = size / a
171 // * n
172 // * d / a
173 // * thetaJ
174 //
175 // For definition of the variables, see DrawOctantSquareLikeSquircle.
176 constexpr Scalar kPrecomputedVariables[][4] = {
177 {2.000, 2.00000, 0.00000, 0.24040}, //
178 {2.020, 2.03340, 0.01447, 0.24040}, //
179 {2.040, 2.06540, 0.02575, 0.21167}, //
180 {2.060, 2.09800, 0.03668, 0.20118}, //
181 {2.080, 2.13160, 0.04719, 0.19367}, //
182 {2.100, 2.17840, 0.05603, 0.16233}, //
183 {2.120, 2.19310, 0.06816, 0.20020}, //
184 {2.140, 2.22990, 0.07746, 0.19131}, //
185 {2.160, 2.26360, 0.08693, 0.19008}, //
186 {2.180, 2.30540, 0.09536, 0.17935}, //
187 {2.200, 2.32900, 0.10541, 0.19136}, //
188 {2.220, 2.38330, 0.11237, 0.17130}, //
189 {2.240, 2.39770, 0.12271, 0.18956}, //
190 {2.260, 2.41770, 0.13251, 0.20254}, //
191 {2.280, 2.47180, 0.13879, 0.18454}, //
192 {2.300, 2.50910, 0.14658, 0.18261} //
193 };
194
195 constexpr size_t kNumRecords =
196 sizeof(kPrecomputedVariables) / sizeof(kPrecomputedVariables[0]);
197 constexpr Scalar kMinRatio = kPrecomputedVariables[0][0];
198 constexpr Scalar kMaxRatio = kPrecomputedVariables[kNumRecords - 1][0];
199 constexpr Scalar kRatioStep =
200 kPrecomputedVariables[1][0] - kPrecomputedVariables[0][0];
201
202 // Linear interpolation for `kPrecomputedVariables`.
203 //
204 // The `column` is a 0-based index that decides the target variable, where 1
205 // corresponds to the 2nd element of each row, etc.
206 //
207 // The `ratio` corresponds to column 0, on which the lerp is calculated.
208 Scalar LerpPrecomputedVariable(size_t column, Scalar ratio) {
209 Scalar steps =
210 std::clamp<Scalar>((ratio - kMinRatio) / kRatioStep, 0, kNumRecords - 1);
211 size_t left = std::clamp<size_t>(static_cast<size_t>(std::floor(steps)), 0,
212 kNumRecords - 2);
213 Scalar frac = steps - left;
214
215 return (1 - frac) * kPrecomputedVariables[left][column] +
216 frac * kPrecomputedVariables[left + 1][column];
217 }
218
219 // The max angular step that the algorithm will traverse a quadrant of the
220 // curve.
221 //
222 // This limits the max number of points of the curve.
223 constexpr Scalar kMaxQuadrantSteps = 40;
224
225 // Calculates the angular step size for a smooth curve.
226 //
227 // Returns the angular step needed to ensure a curve appears smooth
228 // based on the smallest dimension of a shape. Smaller dimensions require
229 // larger steps as less detail is needed for smoothness.
230 //
231 // The `minDimension` is the smallest dimension (e.g., width or height) of the
232 // shape.
233 //
234 // The `fullAngle` is the total angular range to traverse.
235 Scalar CalculateStep(Scalar minDimension, Scalar fullAngle) {
236 constexpr Scalar kMinAngleStep = kPiOver2 / kMaxQuadrantSteps;
237
238 // Assumes at least 1 point is needed per pixel to achieve sufficient
239 // smoothness.
240 constexpr Scalar pointsPerPixel = 1.0;
241 size_t pointsByDimension =
242 static_cast<size_t>(std::ceil(minDimension * pointsPerPixel));
243 Scalar angleByDimension = fullAngle / pointsByDimension;
244
245 return std::min(kMinAngleStep, angleByDimension);
246 }
247
248 // A factor used to calculate the "gap", defined as the distance from the
249 // midpoint of the curved corners to the nearest sides of the bounding box.
250 //
251 // When the corner radius is symmetrical on both dimensions, the midpoint of the
252 // corner is where the circular arc intersects its quadrant bisector. When the
253 // corner radius is asymmetrical, since the corner can be considered "elongated"
254 // from a symmetrical corner, the midpoint is transformed in the same way.
255 //
256 // Experiments indicate that the gap is linear with respect to the corner
257 // radius on that dimension.
258 //
259 // The formula should be kept in sync with a few files, as documented in
260 // `CalculateGap` in round_superellipse_geometry.cc.
261 constexpr Scalar kGapFactor = 0.2924066406;
262
263 // Return the value that splits the range from `left` to `right` into two
264 // portions whose ratio equals to `ratio_left` : `ratio_right`.
265 static Scalar Split(Scalar left,
266 Scalar right,
267 Scalar ratio_left,
268 Scalar ratio_right) {
269 return (left * ratio_right + right * ratio_left) / (ratio_left + ratio_right);
270 }
271
272 // Draw a circular arc from `start` to `end` with a radius of `r`.
273 //
274 // It is assumed that `start` is north-west to `end`, and the center of the
275 // circle is south-west to both points. If `reverse` is true, then the curve
276 // goes from `end` to `start` instead.
277 //
278 // The resulting points, after applying `transform`, are appended to `output`
279 // and include the effective starting point but exclude the effective ending
280 // point.
281 //
282 // Returns the number of generated points.
283 size_t DrawCircularArc(Point* output,
284 Point start,
285 Point end,
286 Scalar r,
287 bool reverse,
288 const Matrix& transform) {
289 /* Denote the middle point of S and E as M. The key is to find the center of
290 * the circle.
291 * S --__
292 * / ⟍ `、
293 * / M ⟍\
294 * / ⟋ E
295 * / ⟋ ↗
296 * / ⟋
297 * / ⟋ r
298 * C ᜱ ↙
299 */
300
301 Point s_to_e = end - start;
302 Point m = (start + end) / 2;
303 Point c_to_m = Point(-s_to_e.y, s_to_e.x);
304 Scalar distance_sm = s_to_e.GetLength() / 2;
305 Scalar distance_cm = sqrt(r * r - distance_sm * distance_sm);
306 Point c = m - distance_cm * c_to_m.Normalize();
307 Scalar angle_sce = asinf(distance_sm / r) * 2;
308 Point c_to_s = start - c;
309 Matrix full_transform = transform * Matrix::MakeTranslation(c);
310
311 Point* next = output;
312 Scalar angle = reverse ? angle_sce : 0.0f;
313 Scalar step =
314 (reverse ? -1 : 1) * CalculateStep(std::abs(s_to_e.y), angle_sce);
315 Scalar end_angle = reverse ? 0.0f : angle_sce;
316
317 while ((angle < end_angle) != reverse) {
318 *(next++) = full_transform * c_to_s.Rotate(Radians(-angle));
319 angle += step;
320 }
321 return next - output;
322 }
323
324 // Draw a superellipsoid arc.
325 //
326 // The superellipse is centered at the origin and has degree `n` and both
327 // semi-axes equal to `a`. The arc starts from positive Y axis and spans from 0
328 // to `max_theta` radiance clockwise if `reverse` is false, or from `max_theta`
329 // to 0 otherwise.
330 //
331 // The resulting points, after applying `transform`, are appended to `output`
332 // and include the starting point but exclude the ending point.
333 //
334 // Returns the number of generated points.
335 size_t DrawSuperellipsoidArc(Point* output,
336 Scalar a,
337 Scalar n,
338 Scalar max_theta,
339 bool reverse,
340 const Matrix& transform) {
341 Point* next = output;
342 Scalar angle = reverse ? max_theta : 0.0f;
343 Scalar step =
344 (reverse ? -1 : 1) *
345 CalculateStep(a - a * pow(abs(cosf(max_theta)), 2 / n), max_theta);
346 Scalar end = reverse ? 0.0f : max_theta;
347 while ((angle < end) != reverse) {
348 Scalar x = a * pow(abs(sinf(angle)), 2 / n);
349 Scalar y = a * pow(abs(cosf(angle)), 2 / n);
350 *(next++) = transform * Point(x, y);
351 angle += step;
352 }
353 return next - output;
354 }
355
356 // Draws an arc representing the top 1/8 segment of a square-like rounded
357 // superellipse centered at the origin.
358 //
359 // The square-like rounded superellipse that this arc belongs to has a width and
360 // height specified by `size` and features rounded corners determined by
361 // `corner_radius`. The `corner_radius` corresponds to the `cornerRadius`
362 // parameter in SwiftUI, rather than the literal radius of corner circles.
363 //
364 // If `reverse` is false, the resulting arc spans from 0 (inclusive) to pi/4
365 // (exclusive), moving clockwise starting from the positive Y-axis. If `reverse`
366 // is true, the curve spans from pi/4 (inclusive) to 0 (inclusive)
367 // counterclockwise instead.
368 //
369 // Returns the number of points generated.
370 size_t DrawOctantSquareLikeSquircle(Point* output,
371 Scalar size,
372 Scalar corner_radius,
373 bool reverse,
374 const Matrix& transform) {
375 /* The following figure shows the first quadrant of a square-like rounded
376 * superellipse. The target arc consists of the "stretch" (AB), a
377 * superellipsoid arc (BJ), and a circular arc (JM).
378 *
379 * straight superelipse
380 * ↓ ↓
381 * A B J circular arc
382 * ---------...._ ↙
383 * | | / `⟍ M
384 * | | / ⟋ ⟍
385 * | | / ⟋ \
386 * | | / ⟋ |
387 * | | ᜱD |
388 * | | / |
389 * ↑ +----+ S |
390 * s | | |
391 * ↓ +----+---------------| A'
392 * O
393 * ← s →
394 * ←------ size/2 ------→
395 *
396 * Define gap (g) as the distance between point M and the bounding box,
397 * therefore point M is at (size/2 - g, size/2 - g).
398 *
399 * The superellipsoid curve can be drawn with an implicit parameter θ:
400 * x = a * sinθ ^ (2/n)
401 * y = a * cosθ ^ (2/n)
402 * https://math.stackexchange.com/questions/2573746/superellipse-parametric-equation
403 *
404 * Define thetaJ as the θ at point J.
405 */
406
407 Scalar ratio = {std::min(size / corner_radius, kMaxRatio)};
408 Scalar a = ratio * corner_radius / 2;
409 Scalar s = size / 2 - a;
410 Scalar g = kGapFactor * corner_radius;
411
412 Scalar n = LerpPrecomputedVariable(1, ratio);
413 Scalar d = LerpPrecomputedVariable(2, ratio) * a;
414 Scalar thetaJ = LerpPrecomputedVariable(3, ratio);
415
416 Scalar R = (a - d - g) * sqrt(2);
417
418 Point pointA{0, size / 2};
419 Point pointM{size / 2 - g, size / 2 - g};
420 Point pointS{s, s};
421 Point pointJ =
422 Point{pow(abs(sinf(thetaJ)), 2 / n), pow(abs(cosf(thetaJ)), 2 / n)} * a +
423 pointS;
424 Matrix translationS = Matrix::MakeTranslation(pointS);
425
426 Point* next = output;
427 if (!reverse) {
428 // Point A
429 *(next++) = transform * pointA;
430 // Arc [B, J)
431 next += DrawSuperellipsoidArc(next, a, n, thetaJ, reverse,
432 transform * translationS);
433 // Arc [J, M)
434 next += DrawCircularArc(next, pointJ, pointM, R, reverse, transform);
435 } else {
436 // Arc [M, J)
437 next += DrawCircularArc(next, pointJ, pointM, R, reverse, transform);
438 // Arc [J, B)
439 next += DrawSuperellipsoidArc(next, a, n, thetaJ, reverse,
440 transform * translationS);
441 // Point B
442 *(next++) = transform * Point{s, size / 2};
443 // Point A
444 *(next++) = transform * pointA;
445 }
446 return next - output;
447 }
448
449 // Draw a quadrant curve, both ends included.
450 //
451 // Returns the number of points.
452 //
453 // The eact quadrant is specified by the direction of `outer` relative to
454 // `center`. The curve goes from the X axis to the Y axis.
455 static size_t DrawQuadrant(Point* output,
456 Point center,
457 Point outer,
458 Size radii) {
459 if (radii.width == 0 || radii.height == 0) {
460 // Degrade to rectangle. (A zero radius causes error below.)
461 output[0] = {center.x, outer.y};
462 output[1] = outer;
463 output[2] = {outer.x, center.y};
464 return 3;
465 }
466 // Normalize sizes and radii into symmetrical radius by scaling the longer of
467 // `radii` to the shorter. For example, to draw a RSE with size (200, 300)
468 // and radii (20, 10), this function draws one with size (100, 300) and radii
469 // (10, 10) and then scales it by (2x, 1x).
470 Scalar norm_radius = radii.MinDimension();
471 Size radius_scale = radii / norm_radius;
472 Point signed_size = (outer - center) * 2;
473 Point norm_size = signed_size.Abs() / radius_scale;
474 Point signed_scale = signed_size / norm_size;
475
476 // Each quadrant curve is composed of two octant curves, each of which belongs
477 // to a square-like rounded rectangle. When `norm_size`'s width != height, the
478 // centers of such square-like rounded rectangles are offset from the origin
479 // by a distance denoted as `c`.
480 Scalar c = (norm_size.x - norm_size.y) / 2;
481
482 Point* next = output;
483
484 next += DrawOctantSquareLikeSquircle(
485 next, norm_size.x, norm_radius, /*reverse=*/false,
486 Matrix::MakeTranslateScale(signed_scale, center) *
487 Matrix::MakeTranslation(Size{0, -c}));
488
489 next += DrawOctantSquareLikeSquircle(
490 next, norm_size.y, norm_radius, /*reverse=*/true,
491 Matrix::MakeTranslateScale(signed_scale, center) *
492 Matrix::MakeTranslation(Size{c, 0}) * kFlip);
493
494 return next - output;
495 }
496
497 } // namespace
498
499 RoundSuperellipseGeometry::RoundSuperellipseGeometry(const Rect& bounds,
500 const RoundingRadii& radii)
501 : bounds_(bounds.GetPositive()), radii_(radii.Scaled(bounds_)) {}
502
503 RoundSuperellipseGeometry::RoundSuperellipseGeometry(const Rect& bounds,
504 float corner_radius)
505 : RoundSuperellipseGeometry(bounds,
506 RoundingRadii::MakeRadius(corner_radius)) {}
507
508 RoundSuperellipseGeometry::~RoundSuperellipseGeometry() {}
509
510 GeometryResult RoundSuperellipseGeometry::GetPositionBuffer(
511 const ContentContext& renderer,
512 const Entity& entity,
513 RenderPass& pass) const {
514 Point* cache = renderer.GetTessellator().GetStrokePointCache().data();
515
516 // The memory size (in units of Points) allocated to store each quadrants.
517 constexpr size_t kMaxQuadSize = kPointArenaSize / 4;
518 // Since the curve is traversed in steps bounded by kMaxQuadrantSteps, the
519 // curving part will have fewer points than kMaxQuadrantSteps. Multiply it by
520 // 2 for storing other sporatic points (an extremely conservative estimate).
521 static_assert(kMaxQuadSize > 2 * kMaxQuadrantSteps);
522
523 ConvexRearranger* rearranger;
524 std::variant<std::monostate, MirroredQuadrantRearranger,
525 UnevenQuadrantsRearranger>
526 rearranger_holder;
527
528 if (radii_.AreAllCornersSame()) {
529 rearranger_holder.emplace<MirroredQuadrantRearranger>(bounds_.GetCenter(),
530 cache);
531 auto& t = std::get<MirroredQuadrantRearranger>(rearranger_holder);
532 rearranger = &t;
533
534 // The quadrant must be drawn at the origin so that it can be rotated later.
535 t.QuadSize() = DrawQuadrant(cache, Point(),
536 bounds_.GetRightTop() - bounds_.GetCenter(),
537 radii_.top_right);
538 } else {
539 rearranger_holder.emplace<UnevenQuadrantsRearranger>(cache, kMaxQuadSize);
540 auto& t = std::get<UnevenQuadrantsRearranger>(rearranger_holder);
541 rearranger = &t;
542
543 Scalar top_split = Split(bounds_.GetLeft(), bounds_.GetRight(),
544 radii_.top_left.width, radii_.top_right.width);
545 Scalar right_split =
546 Split(bounds_.GetTop(), bounds_.GetBottom(), radii_.top_right.height,
547 radii_.bottom_right.height);
548 Scalar bottom_split =
549 Split(bounds_.GetLeft(), bounds_.GetRight(), radii_.bottom_left.width,
550 radii_.bottom_right.width);
551 Scalar left_split =
552 Split(bounds_.GetTop(), bounds_.GetBottom(), radii_.top_left.height,
553 radii_.bottom_left.height);
554
555 t.QuadSize(0) = DrawQuadrant(t.QuadCache(0), Point{top_split, right_split},
556 bounds_.GetRightTop(), radii_.top_right);
557 t.QuadSize(1) =
558 DrawQuadrant(t.QuadCache(1), Point{bottom_split, right_split},
559 bounds_.GetRightBottom(), radii_.bottom_right);
560 t.QuadSize(2) =
561 DrawQuadrant(t.QuadCache(2), Point{bottom_split, left_split},
562 bounds_.GetLeftBottom(), radii_.bottom_left);
563 t.QuadSize(3) = DrawQuadrant(t.QuadCache(3), Point{top_split, left_split},
564 bounds_.GetLeftTop(), radii_.top_left);
565 }
566
567 size_t contour_length = rearranger->ContourLength();
568 BufferView vertex_buffer = renderer.GetTransientsBuffer().Emplace(
569 nullptr, sizeof(Point) * contour_length, alignof(Point));
570 Point* vertex_data =
571 reinterpret_cast<Point*>(vertex_buffer.GetBuffer()->OnGetContents() +
572 vertex_buffer.GetRange().offset);
573 rearranger->RearrangeIntoTriangleStrip(vertex_data);
574
575 return GeometryResult{
576 .type = PrimitiveType::kTriangleStrip,
577 .vertex_buffer =
578 {
579 .vertex_buffer = vertex_buffer,
580 .vertex_count = contour_length,
581 .index_type = IndexType::kNone,
582 },
583 .transform = entity.GetShaderTransform(pass),
584 };
585 }
586
587 std::optional<Rect> RoundSuperellipseGeometry::GetCoverage(
588 const Matrix& transform) const {
589 return bounds_.TransformBounds(transform);
590 }
591
592 bool RoundSuperellipseGeometry::CoversArea(const Matrix& transform,
593 const Rect& rect) const {
594 if (!transform.IsTranslationScaleOnly()) {
595 return false;
596 }
597 Scalar left_inset = std::max(radii_.top_left.width, radii_.bottom_left.width);
598 Scalar right_inset =
599 std::max(radii_.top_right.width, radii_.bottom_right.width);
600 Scalar top_inset = std::max(radii_.top_left.height, radii_.top_right.height);
601 Scalar bottom_inset =
602 std::max(radii_.bottom_left.height, radii_.bottom_right.height);
603 Rect coverage =
604 Rect::MakeLTRB(bounds_.GetLeft() + left_inset * kGapFactor,
605 bounds_.GetTop() + top_inset * kGapFactor,
606 bounds_.GetRight() - right_inset * kGapFactor,
607 bounds_.GetBottom() - bottom_inset * kGapFactor);
608 return coverage.TransformBounds(transform).Contains(rect);
609 }
610
611 bool RoundSuperellipseGeometry::IsAxisAlignedRect() const {
612 return false;
613 }
614
615 } // namespace impeller
impeller::Entity::GetShaderTransform
Matrix GetShaderTransform(const RenderPass &pass) const
Get the vertex shader transform used for drawing this Entity.
Definition: entity.cc:48
impeller::RoundingRadii::top_left
Size top_left
Definition: rounding_radii.h:15
impeller::RoundingRadii
Definition: rounding_radii.h:14
impeller::HostBuffer::Emplace
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:93
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::Matrix::MakeTranslateScale
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition: matrix.h:113
impeller::RoundingRadii::AreAllCornersSame
constexpr bool AreAllCornersSame(Scalar tolerance=kEhCloseEnough) const
Definition: rounding_radii.h:42
impeller::RoundingRadii::bottom_right
Size bottom_right
Definition: rounding_radii.h:18
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:476
impeller::TRect::GetLeftTop
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:363
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:386
impeller::Size
TSize< Scalar > Size
Definition: size.h:171
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
x
int32_t x
Definition: dl_golden_unittests.cc:443
impeller::ContentContext::GetTessellator
Tessellator & GetTessellator() const
Definition: content_context.cc:609
impeller::TRect::GetRightTop
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:367
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
impeller::RoundingRadii::bottom_left
Size bottom_left
Definition: rounding_radii.h:17
impeller::Entity
Definition: entity.h:20
impeller::kPointArenaSize
static constexpr size_t kPointArenaSize
The size of the point arena buffer stored on the tessellator.
Definition: tessellator.h:22
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:355
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
impeller::RoundingRadii::top_right
Size top_right
Definition: rounding_radii.h:16
impeller::TRect::GetLeftBottom
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:371
impeller::GeometryResult
Definition: geometry.h:21
impeller::IndexType::kNone
@ kNone
Does not use the index buffer.
impeller::RoundSuperellipseGeometry::IsAxisAlignedRect
bool IsAxisAlignedRect() const override
Definition: round_superellipse_geometry.cc:611
impeller::Tessellator::GetStrokePointCache
std::vector< Point > & GetStrokePointCache()
Retrieve a pre-allocated arena of kPointArenaSize points.
Definition: tessellator.cc:24
impeller::TSize::width
Type width
Definition: size.h:28
round_superellipse_geometry.h
impeller::TRect::Contains
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: rect.h:235
impeller::RenderPass
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition: render_pass.h:30
impeller::TPoint::Abs
constexpr TPoint Abs() const
Definition: point.h:216
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:359
constants.h
impeller::RoundSuperellipseGeometry::RoundSuperellipseGeometry
RoundSuperellipseGeometry(const Rect &bounds, const RoundingRadii &radii)
Definition: round_superellipse_geometry.cc:499
impeller::TPoint
Definition: point.h:27
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller::RoundSuperellipseGeometry
Definition: round_superellipse_geometry.h:27
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:361
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TRect::GetRightBottom
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:375
impeller::RoundSuperellipseGeometry::CoversArea
bool CoversArea(const Matrix &transform, const Rect &rect) const override
Determines if this geometry, transformed by the given transform, will completely cover all surface ar...
Definition: round_superellipse_geometry.cc:592
impeller::TPoint::Normalize
constexpr TPoint Normalize() const
Definition: point.h:208
impeller
Definition: allocation.cc:12
impeller::RoundSuperellipseGeometry::~RoundSuperellipseGeometry
~RoundSuperellipseGeometry() override
Definition: round_superellipse_geometry.cc:508
impeller::ContentContext
Definition: content_context.h:371
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:357
impeller::TRect< Scalar >
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::ContentContext::GetTransientsBuffer
HostBuffer & GetTransientsBuffer() const
Retrieve the currnent host buffer for transient storage.
Definition: content_context.h:866