| Flutter Impeller |

tessellator.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 "impeller/tessellator/tessellator.h"
6 #include <cstdint>
7 #include <cstring>
8
9 #include "flutter/impeller/core/device_buffer.h"
10 #include "flutter/impeller/tessellator/path_tessellator.h"
11
12 namespace {
13 static constexpr int kPrecomputedDivisionCount = 1024;
14
15 static int kPrecomputedDivisions[kPrecomputedDivisionCount] = {
16 // clang-format off
17 1, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7,
18 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
19 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 13,
20 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14,
21 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16,
22 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
23 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19,
24 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
25 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
26 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23,
27 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24,
28 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25,
29 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26,
30 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27,
31 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28,
32 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
33 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
34 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
35 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
36 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32,
37 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33,
38 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
39 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
40 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35,
41 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36,
42 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
43 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
44 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38,
45 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
46 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
47 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40,
48 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
49 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41,
50 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
51 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
52 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43,
53 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
54 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44,
55 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
56 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
57 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
58 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
59 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47,
60 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
61 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48,
62 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
63 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49,
64 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
65 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50,
66 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
67 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51,
68 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
69 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52,
70 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
71 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53,
72 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
73 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54,
74 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
75 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
76 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
77 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
78 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
79 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
80 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57,
81 // clang-format on
82 };
83
84 static size_t ComputeQuadrantDivisions(impeller::Scalar pixel_radius) {
85 if (pixel_radius <= 0.0) {
86 return 1;
87 }
88 int radius_index = ceil(pixel_radius);
89 if (radius_index < kPrecomputedDivisionCount) {
90 return kPrecomputedDivisions[radius_index];
91 }
92
93 // For a circle with N divisions per quadrant, the maximum deviation of
94 // the polgyon approximation from the true circle will be at the center
95 // of the base of each triangular pie slice. We can compute that distance
96 // by finding the midpoint of the line of the first slice and compare
97 // its distance from the center of the circle to the radius. We will aim
98 // to have the length of that bisector to be within |kCircleTolerance|
99 // from the radius in pixels.
100 //
101 // Each vertex will appear at an angle of:
102 // theta(i) = (kPi / 2) * (i / N) // for i in [0..N]
103 // with each point falling at:
104 // point(i) = r * (cos(theta), sin(theta))
105 // If we consider the unit circle to simplify the calculations below then
106 // we need to scale the tolerance from its absolute quantity into a unit
107 // circle fraction:
108 // k = tolerance / radius
109 // Using this scaled tolerance below to avoid multiplying by the radius
110 // throughout all of the math, we have:
111 // first point = (1, 0) // theta(0) == 0
112 // theta = kPi / 2 / N // theta(1)
113 // second point = (cos(theta), sin(theta)) = (c, s)
114 // midpoint = (first + second) * 0.5 = ((1 + c)/2, s/2)
115 // |midpoint| = sqrt((1 + c)*(1 + c)/4 + s*s/4)
116 // = sqrt((1 + c + c + c*c + s*s) / 4)
117 // = sqrt((1 + 2c + 1) / 4)
118 // = sqrt((2 + 2c) / 4)
119 // = sqrt((1 + c) / 2)
120 // = cos(theta / 2) // using half-angle cosine formula
121 // error = 1 - |midpoint| = 1 - cos(theta / 2)
122 // cos(theta/2) = 1 - error
123 // theta/2 = acos(1 - error)
124 // kPi / 2 / N / 2 = acos(1 - error)
125 // kPi / 4 / acos(1 - error) = N
126 // Since we need error <= k, we want divisions >= N, so we use:
127 // N = ceil(kPi / 4 / acos(1 - k))
128 //
129 // Math is confirmed in https://math.stackexchange.com/a/4132095
130 // (keeping in mind that we are computing quarter circle divisions here)
131 // which also points out a performance optimization that is accurate
132 // to within an over-estimation of 1 division would be:
133 // N = ceil(kPi / 4 / sqrt(2 * k))
134 // Since we have precomputed the divisions for radii up to 1024, we can
135 // afford to be more accurate using the acos formula here for larger radii.
136 double k = impeller::Tessellator::kCircleTolerance / pixel_radius;
137 return ceil(impeller::kPiOver4 / std::acos(1 - k));
138 }
139
140 template <typename IndexT>
141 impeller::IndexType IndexTypeFor();
142 template <>
143 impeller::IndexType IndexTypeFor<uint32_t>() {
144 return impeller::IndexType::k32bit;
145 }
146 template <>
147 impeller::IndexType IndexTypeFor<uint16_t>() {
148 return impeller::IndexType::k16bit;
149 }
150
151 /// @brief A vertex writer that generates a triangle fan and requires primitive
152 /// restart.
153 template <typename IndexT>
154 class FanPathVertexWriter : public impeller::PathTessellator::VertexWriter {
155 public:
156 explicit FanPathVertexWriter(impeller::Point* point_buffer,
157 IndexT* index_buffer)
158 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
159
160 ~FanPathVertexWriter() = default;
161
162 size_t GetIndexCount() const { return index_count_; }
163 size_t GetPointCount() const { return count_; }
164
165 void EndContour() override {
166 if (count_ == 0) {
167 return;
168 }
169 index_buffer_[index_count_++] = static_cast<IndexT>(-1);
170 }
171
172 void Write(impeller::Point point) override {
173 index_buffer_[index_count_++] = count_;
174 point_buffer_[count_++] = point;
175 }
176
177 private:
178 size_t count_ = 0;
179 size_t index_count_ = 0;
180 impeller::Point* point_buffer_ = nullptr;
181 IndexT* index_buffer_ = nullptr;
182 };
183
184 /// @brief A vertex writer that generates a triangle strip and requires
185 /// primitive restart.
186 template <typename IndexT>
187 class StripPathVertexWriter : public impeller::PathTessellator::VertexWriter {
188 public:
189 explicit StripPathVertexWriter(impeller::Point* point_buffer,
190 IndexT* index_buffer)
191 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
192
193 ~StripPathVertexWriter() = default;
194
195 size_t GetIndexCount() const { return index_count_; }
196 size_t GetPointCount() const { return count_; }
197
198 void EndContour() override {
199 if (count_ == 0u || contour_start_ == count_ - 1) {
200 // Empty or first contour.
201 return;
202 }
203
204 size_t start = contour_start_;
205 size_t end = count_ - 1;
206
207 index_buffer_[index_count_++] = start;
208
209 size_t a = start + 1;
210 size_t b = end;
211 while (a < b) {
212 index_buffer_[index_count_++] = a;
213 index_buffer_[index_count_++] = b;
214 a++;
215 b--;
216 }
217 if (a == b) {
218 index_buffer_[index_count_++] = a;
219 }
220
221 contour_start_ = count_;
222 index_buffer_[index_count_++] = static_cast<IndexT>(-1);
223 }
224
225 void Write(impeller::Point point) override {
226 point_buffer_[count_++] = point;
227 }
228
229 private:
230 size_t count_ = 0;
231 size_t index_count_ = 0;
232 size_t contour_start_ = 0;
233 impeller::Point* point_buffer_ = nullptr;
234 IndexT* index_buffer_ = nullptr;
235 };
236
237 /// @brief A vertex writer that has no hardware requirements.
238 template <typename IndexT>
239 class GLESPathVertexWriter : public impeller::PathTessellator::VertexWriter {
240 public:
241 explicit GLESPathVertexWriter(std::vector<impeller::Point>& points,
242 std::vector<IndexT>& indices)
243 : points_(points), indices_(indices) {}
244
245 ~GLESPathVertexWriter() = default;
246
247 void EndContour() override {
248 if (points_.size() == 0u || contour_start_ == points_.size() - 1) {
249 // Empty or first contour.
250 return;
251 }
252
253 auto start = contour_start_;
254 auto end = points_.size() - 1;
255 // All filled paths are drawn as if they are closed, but if
256 // there is an explicit close then a lineTo to the origin
257 // is inserted. This point isn't strictly necesary to
258 // correctly render the shape and can be dropped.
259 if (points_[end] == points_[start]) {
260 end--;
261 }
262
263 // Triangle strip break for subsequent contours
264 if (contour_start_ != 0) {
265 auto back = indices_.back();
266 indices_.push_back(back);
267 indices_.push_back(start);
268 indices_.push_back(start);
269
270 // If the contour has an odd number of points, insert an extra point when
271 // bridging to the next contour to preserve the correct triangle winding
272 // order.
273 if (previous_contour_odd_points_) {
274 indices_.push_back(start);
275 }
276 } else {
277 indices_.push_back(start);
278 }
279
280 size_t a = start + 1;
281 size_t b = end;
282 while (a < b) {
283 indices_.push_back(a);
284 indices_.push_back(b);
285 a++;
286 b--;
287 }
288 if (a == b) {
289 indices_.push_back(a);
290 previous_contour_odd_points_ = false;
291 } else {
292 previous_contour_odd_points_ = true;
293 }
294 contour_start_ = points_.size();
295 }
296
297 void Write(impeller::Point point) override { points_.push_back(point); }
298
299 private:
300 bool previous_contour_odd_points_ = false;
301 size_t contour_start_ = 0u;
302 std::vector<impeller::Point>& points_;
303 std::vector<IndexT>& indices_;
304 };
305
306 template <typename IndexT>
307 void DoTessellateConvexInternal(const impeller::PathSource& path,
308 std::vector<impeller::Point>& point_buffer,
309 std::vector<IndexT>& index_buffer,
310 impeller::Scalar tolerance) {
311 point_buffer.clear();
312 index_buffer.clear();
313
314 GLESPathVertexWriter writer(point_buffer, index_buffer);
315
316 impeller::PathTessellator::PathToFilledVertices(path, writer, tolerance);
317 }
318
319 } // namespace
320
321 namespace impeller {
322
323 template <typename IndexT>
324 class ConvexTessellatorImpl : public Tessellator::ConvexTessellator {
325 public:
326 ConvexTessellatorImpl() {
327 point_buffer_.reserve(2048);
328 index_buffer_.reserve(2048);
329 }
330
331 VertexBuffer TessellateConvex(const PathSource& path,
332 HostBuffer& data_host_buffer,
333 HostBuffer& indexes_host_buffer,
334 Scalar tolerance,
335 bool supports_primitive_restart,
336 bool supports_triangle_fan) override {
337 if (supports_primitive_restart) {
338 // Primitive Restart.
339 const auto [point_count, contour_count] =
340 PathTessellator::CountFillStorage(path, tolerance);
341 BufferView point_buffer = data_host_buffer.Emplace(
342 nullptr, sizeof(Point) * point_count, alignof(Point));
343 BufferView index_buffer = indexes_host_buffer.Emplace(
344 nullptr, sizeof(IndexT) * (point_count + contour_count),
345 alignof(IndexT));
346
347 auto* points_ptr =
348 reinterpret_cast<Point*>(point_buffer.GetBuffer()->OnGetContents() +
349 point_buffer.GetRange().offset);
350 auto* indices_ptr =
351 reinterpret_cast<IndexT*>(index_buffer.GetBuffer()->OnGetContents() +
352 index_buffer.GetRange().offset);
353
354 auto tessellate_path = [&](auto& writer) {
355 PathTessellator::PathToFilledVertices(path, writer, tolerance);
356 FML_DCHECK(writer.GetPointCount() <= point_count);
357 FML_DCHECK(writer.GetIndexCount() <= (point_count + contour_count));
358 point_buffer.GetBuffer()->Flush(point_buffer.GetRange());
359 index_buffer.GetBuffer()->Flush(index_buffer.GetRange());
360
361 return VertexBuffer{
362 .vertex_buffer = std::move(point_buffer),
363 .index_buffer = std::move(index_buffer),
364 .vertex_count = writer.GetIndexCount(),
365 .index_type = IndexTypeFor<IndexT>(),
366 };
367 };
368
369 if (supports_triangle_fan) {
370 FanPathVertexWriter writer(points_ptr, indices_ptr);
371 return tessellate_path(writer);
372 } else {
373 StripPathVertexWriter writer(points_ptr, indices_ptr);
374 return tessellate_path(writer);
375 }
376 }
377
378 DoTessellateConvexInternal(path, point_buffer_, index_buffer_, tolerance);
379
380 if (point_buffer_.empty()) {
381 return VertexBuffer{
382 .vertex_buffer = {},
383 .index_buffer = {},
384 .vertex_count = 0u,
385 .index_type = IndexTypeFor<IndexT>(),
386 };
387 }
388
389 BufferView vertex_buffer = data_host_buffer.Emplace(
390 point_buffer_.data(), sizeof(Point) * point_buffer_.size(),
391 alignof(Point));
392
393 BufferView index_buffer = indexes_host_buffer.Emplace(
394 index_buffer_.data(), sizeof(IndexT) * index_buffer_.size(),
395 alignof(IndexT));
396
397 return VertexBuffer{
398 .vertex_buffer = std::move(vertex_buffer),
399 .index_buffer = std::move(index_buffer),
400 .vertex_count = index_buffer_.size(),
401 .index_type = IndexTypeFor<IndexT>(),
402 };
403 }
404
405 private:
406 std::vector<Point> point_buffer_;
407 std::vector<IndexT> index_buffer_;
408 };
409
410 Tessellator::Tessellator(bool supports_32bit_primitive_indices)
411 : stroke_points_(kPointArenaSize) {
412 if (supports_32bit_primitive_indices) {
413 convex_tessellator_ = std::make_unique<ConvexTessellatorImpl<uint32_t>>();
414 } else {
415 convex_tessellator_ = std::make_unique<ConvexTessellatorImpl<uint16_t>>();
416 }
417 }
418
419 Tessellator::~Tessellator() = default;
420
421 std::vector<Point>& Tessellator::GetStrokePointCache() {
422 return stroke_points_;
423 }
424
425 Tessellator::Trigs Tessellator::GetTrigsForDeviceRadius(Scalar pixel_radius) {
426 return GetTrigsForDivisions(ComputeQuadrantDivisions(pixel_radius));
427 }
428
429 VertexBuffer Tessellator::TessellateConvex(const PathSource& path,
430 HostBuffer& data_host_buffer,
431 HostBuffer& indexes_host_buffer,
432 Scalar tolerance,
433 bool supports_primitive_restart,
434 bool supports_triangle_fan) {
435 return convex_tessellator_->TessellateConvex(
436 path, data_host_buffer, indexes_host_buffer, tolerance,
437 supports_primitive_restart, supports_triangle_fan);
438 }
439
440 void Tessellator::TessellateConvexInternal(const PathSource& path,
441 std::vector<Point>& point_buffer,
442 std::vector<uint16_t>& index_buffer,
443 Scalar tolerance) {
444 DoTessellateConvexInternal(path, point_buffer, index_buffer, tolerance);
445 }
446
447 Tessellator::Trigs::Trigs(Scalar pixel_radius)
448 : Tessellator::Trigs(ComputeQuadrantDivisions(pixel_radius)) {}
449
450 void Tessellator::Trigs::init(size_t divisions) {
451 if (!trigs_.empty()) {
452 return;
453 }
454
455 // Either not cached yet, or we are using the temp storage...
456 trigs_.reserve(divisions + 1);
457
458 double angle_scale = kPiOver2 / divisions;
459
460 trigs_.emplace_back(1.0, 0.0);
461 for (size_t i = 1; i < divisions; i++) {
462 trigs_.emplace_back(Radians(i * angle_scale));
463 }
464 trigs_.emplace_back(0.0, 1.0);
465 }
466
467 Tessellator::Trigs Tessellator::GetTrigsForDivisions(size_t divisions) {
468 return divisions < Tessellator::kCachedTrigCount
469 ? Trigs(precomputed_trigs_[divisions], divisions)
470 : Trigs(divisions);
471 }
472
473 using TessellatedVertexProc = Tessellator::TessellatedVertexProc;
474 using EllipticalVertexGenerator = Tessellator::EllipticalVertexGenerator;
475 using ArcVertexGenerator = Tessellator::ArcVertexGenerator;
476
477 EllipticalVertexGenerator::EllipticalVertexGenerator(
478 EllipticalVertexGenerator::GeneratorProc& generator,
479 Trigs&& trigs,
480 PrimitiveType triangle_type,
481 size_t vertices_per_trig,
482 Data&& data)
483 : impl_(generator),
484 trigs_(std::move(trigs)),
485 data_(data),
486 vertices_per_trig_(vertices_per_trig) {}
487
488 EllipticalVertexGenerator Tessellator::FilledCircle(
489 const Matrix& view_transform,
490 const Point& center,
491 Scalar radius) {
492 size_t divisions =
493 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * radius);
494 return EllipticalVertexGenerator(Tessellator::GenerateFilledCircle,
495 GetTrigsForDivisions(divisions),
496 PrimitiveType::kTriangleStrip, 4,
497 {
498 .reference_centers = {center, center},
499 .radii = {radius, radius},
500 .half_width = -1.0f,
501 });
502 }
503
504 EllipticalVertexGenerator Tessellator::StrokedCircle(
505 const Matrix& view_transform,
506 const Point& center,
507 Scalar radius,
508 Scalar half_width) {
509 if (half_width > 0) {
510 auto divisions = ComputeQuadrantDivisions(
511 view_transform.GetMaxBasisLengthXY() * radius + half_width);
512 return EllipticalVertexGenerator(Tessellator::GenerateStrokedCircle,
513 GetTrigsForDivisions(divisions),
514 PrimitiveType::kTriangleStrip, 8,
515 {
516 .reference_centers = {center, center},
517 .radii = {radius, radius},
518 .half_width = half_width,
519 });
520 } else {
521 return FilledCircle(view_transform, center, radius);
522 }
523 }
524
525 ArcVertexGenerator ArcVertexGenerator::MakeFilled(
526 const Arc::Iteration& iteration,
527 Trigs&& trigs,
528 const Rect& oval_bounds,
529 bool use_center,
530 bool supports_triangle_fans) {
531 return ArcVertexGenerator(iteration, std::move(trigs), oval_bounds,
532 use_center, supports_triangle_fans, -1.0f,
533 Cap::kSquare, nullptr);
534 }
535
536 ArcVertexGenerator ArcVertexGenerator::MakeStroked(
537 const Arc::Iteration& iteration,
538 Trigs&& trigs,
539 const Rect& oval_bounds,
540 Scalar half_width,
541 Cap cap,
542 std::unique_ptr<Trigs> round_cap_trigs) {
543 return ArcVertexGenerator(iteration, std::move(trigs), oval_bounds, false,
544 false, half_width, cap, std::move(round_cap_trigs));
545 }
546
547 ArcVertexGenerator::ArcVertexGenerator(const Arc::Iteration& iteration,
548 Trigs&& trigs,
549 const Rect& oval_bounds,
550 bool use_center,
551 bool supports_triangle_fans,
552 Scalar half_width,
553 Cap cap,
554 std::unique_ptr<Trigs> round_cap_trigs)
555 : iteration_(iteration),
556 trigs_(std::move(trigs)),
557 oval_bounds_(oval_bounds),
558 use_center_(use_center),
559 supports_triangle_fans_(supports_triangle_fans),
560 half_width_(half_width),
561 cap_(cap),
562 round_cap_trigs_(std::move(round_cap_trigs)) {}
563
564 PrimitiveType ArcVertexGenerator::GetTriangleType() const {
565 return (half_width_ < 0 && supports_triangle_fans_)
566 ? PrimitiveType::kTriangleFan
567 : PrimitiveType::kTriangleStrip;
568 }
569
570 size_t ArcVertexGenerator::GetVertexCount() const {
571 size_t count = iteration_.GetPointCount();
572 if (half_width_ > 0) {
573 FML_DCHECK(!use_center_);
574 count *= 2;
575 if (cap_ == Cap::kSquare) {
576 count += 4;
577 } else if (cap_ == Cap::kRound) {
578 FML_DCHECK(round_cap_trigs_);
579 // 4 vertices for each Trig in round_cap_trigs_: 2 vertices for each in
580 // the start cap and 2 for each in the end cap. Subtract 4 because the cap
581 // vertices elide the beginning and end vertices of the arc.
582 count += round_cap_trigs_->size() * 4 - 4;
583 }
584 } else if (supports_triangle_fans_) {
585 if (use_center_) {
586 count++;
587 }
588 } else {
589 // corrugated triangle fan
590 count += (count + 1) / 2;
591 }
592 return count;
593 }
594
595 void ArcVertexGenerator::GenerateVertices(
596 const TessellatedVertexProc& proc) const {
597 if (half_width_ > 0) {
598 FML_DCHECK(!use_center_);
599 Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_,
600 half_width_, cap_, round_cap_trigs_, proc);
601 } else if (supports_triangle_fans_) {
602 Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_,
603 use_center_, proc);
604 } else {
605 Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_,
606 use_center_, proc);
607 }
608 }
609
610 ArcVertexGenerator Tessellator::FilledArc(const Matrix& view_transform,
611 const Arc& arc,
612 bool supports_triangle_fans) {
613 size_t divisions = ComputeQuadrantDivisions(
614 view_transform.GetMaxBasisLengthXY() * arc.GetOvalSize().MaxDimension());
615
616 return ArcVertexGenerator::MakeFilled(
617 arc.ComputeIterations(divisions), GetTrigsForDivisions(divisions),
618 arc.GetOvalBounds(), arc.IncludeCenter(), supports_triangle_fans);
619 };
620
621 ArcVertexGenerator Tessellator::StrokedArc(const Matrix& view_transform,
622 const Arc& arc,
623 Cap cap,
624 Scalar half_width) {
625 FML_DCHECK(half_width > 0);
626 FML_DCHECK(arc.IsPerfectCircle());
627 FML_DCHECK(!arc.IncludeCenter());
628 size_t divisions =
629 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() *
630 (arc.GetOvalSize().MaxDimension() + half_width));
631
632 std::unique_ptr<Trigs> round_cap_trigs;
633 if (cap == Cap::kRound) {
634 round_cap_trigs = std::make_unique<Trigs>(GetTrigsForDeviceRadius(
635 view_transform.GetMaxBasisLengthXY() * half_width));
636 }
637
638 return ArcVertexGenerator::MakeStroked(
639 arc.ComputeIterations(divisions), GetTrigsForDivisions(divisions),
640 arc.GetOvalBounds(), half_width, cap, std::move(round_cap_trigs));
641 }
642
643 EllipticalVertexGenerator Tessellator::RoundCapLine(
644 const Matrix& view_transform,
645 const Point& p0,
646 const Point& p1,
647 Scalar radius) {
648 auto along = p1 - p0;
649 auto length = along.GetLength();
650 if (length > kEhCloseEnough) {
651 auto divisions =
652 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * radius);
653 return EllipticalVertexGenerator(Tessellator::GenerateRoundCapLine,
654 GetTrigsForDivisions(divisions),
655 PrimitiveType::kTriangleStrip, 4,
656 {
657 .reference_centers = {p0, p1},
658 .radii = {radius, radius},
659 .half_width = -1.0f,
660 });
661 } else {
662 return FilledCircle(view_transform, p0, radius);
663 }
664 }
665
666 EllipticalVertexGenerator Tessellator::FilledEllipse(
667 const Matrix& view_transform,
668 const Rect& bounds) {
669 if (bounds.IsSquare()) {
670 return FilledCircle(view_transform, bounds.GetCenter(),
671 bounds.GetWidth() * 0.5f);
672 }
673 auto max_radius = bounds.GetSize().MaxDimension();
674 auto divisions = ComputeQuadrantDivisions(
675 view_transform.GetMaxBasisLengthXY() * max_radius);
676 auto center = bounds.GetCenter();
677 return EllipticalVertexGenerator(Tessellator::GenerateFilledEllipse,
678 GetTrigsForDivisions(divisions),
679 PrimitiveType::kTriangleStrip, 4,
680 {
681 .reference_centers = {center, center},
682 .radii = bounds.GetSize() * 0.5f,
683 .half_width = -1.0f,
684 });
685 }
686
687 EllipticalVertexGenerator Tessellator::FilledRoundRect(
688 const Matrix& view_transform,
689 const Rect& bounds,
690 const Size& radii) {
691 if (radii.width * 2 < bounds.GetWidth() ||
692 radii.height * 2 < bounds.GetHeight()) {
693 auto max_radius = radii.MaxDimension();
694 auto divisions = ComputeQuadrantDivisions(
695 view_transform.GetMaxBasisLengthXY() * max_radius);
696 auto upper_left = bounds.GetLeftTop() + radii;
697 auto lower_right = bounds.GetRightBottom() - radii;
698 return EllipticalVertexGenerator(Tessellator::GenerateFilledRoundRect,
699 GetTrigsForDivisions(divisions),
700 PrimitiveType::kTriangleStrip, 4,
701 {
702 .reference_centers =
703 {
704 upper_left,
705 lower_right,
706 },
707 .radii = radii,
708 .half_width = -1.0f,
709 });
710 } else {
711 return FilledEllipse(view_transform, bounds);
712 }
713 }
714
715 void Tessellator::GenerateFilledCircle(
716 const Trigs& trigs,
717 const EllipticalVertexGenerator::Data& data,
718 const TessellatedVertexProc& proc) {
719 auto center = data.reference_centers[0];
720 auto radius = data.radii.width;
721
722 FML_DCHECK(center == data.reference_centers[1]);
723 FML_DCHECK(radius == data.radii.height);
724 FML_DCHECK(data.half_width < 0);
725
726 // Quadrant 1 connecting with Quadrant 4:
727 for (auto& trig : trigs) {
728 auto offset = trig * radius;
729 proc({center.x - offset.x, center.y + offset.y});
730 proc({center.x - offset.x, center.y - offset.y});
731 }
732
733 // The second half of the circle should be iterated in reverse, but
734 // we can instead iterate forward and swap the x/y values of the
735 // offset as the angles should be symmetric and thus should generate
736 // symmetrically reversed trig vectors.
737 // Quadrant 2 connecting with Quadrant 3:
738 for (auto& trig : trigs) {
739 auto offset = trig * radius;
740 proc({center.x + offset.y, center.y + offset.x});
741 proc({center.x + offset.y, center.y - offset.x});
742 }
743 }
744
745 void Tessellator::GenerateStrokedCircle(
746 const Trigs& trigs,
747 const EllipticalVertexGenerator::Data& data,
748 const TessellatedVertexProc& proc) {
749 auto center = data.reference_centers[0];
750
751 FML_DCHECK(center == data.reference_centers[1]);
752 FML_DCHECK(data.radii.IsSquare());
753 FML_DCHECK(data.half_width > 0 && data.half_width < data.radii.width);
754
755 auto outer_radius = data.radii.width + data.half_width;
756 auto inner_radius = data.radii.width - data.half_width;
757
758 // Zig-zag back and forth between points on the outer circle and the
759 // inner circle. Both circles are evaluated at the same number of
760 // quadrant divisions so the points for a given division should match
761 // 1 for 1 other than their applied radius.
762
763 // Quadrant 1:
764 for (auto& trig : trigs) {
765 auto outer = trig * outer_radius;
766 auto inner = trig * inner_radius;
767 proc({center.x - outer.x, center.y - outer.y});
768 proc({center.x - inner.x, center.y - inner.y});
769 }
770
771 // The even quadrants of the circle should be iterated in reverse, but
772 // we can instead iterate forward and swap the x/y values of the
773 // offset as the angles should be symmetric and thus should generate
774 // symmetrically reversed trig vectors.
775 // Quadrant 2:
776 for (auto& trig : trigs) {
777 auto outer = trig * outer_radius;
778 auto inner = trig * inner_radius;
779 proc({center.x + outer.y, center.y - outer.x});
780 proc({center.x + inner.y, center.y - inner.x});
781 }
782
783 // Quadrant 3:
784 for (auto& trig : trigs) {
785 auto outer = trig * outer_radius;
786 auto inner = trig * inner_radius;
787 proc({center.x + outer.x, center.y + outer.y});
788 proc({center.x + inner.x, center.y + inner.y});
789 }
790
791 // Quadrant 4:
792 for (auto& trig : trigs) {
793 auto outer = trig * outer_radius;
794 auto inner = trig * inner_radius;
795 proc({center.x - outer.y, center.y + outer.x});
796 proc({center.x - inner.y, center.y + inner.x});
797 }
798 }
799
800 void Tessellator::GenerateFilledArcFan(const Trigs& trigs,
801 const Arc::Iteration& iteration,
802 const Rect& oval_bounds,
803 bool use_center,
804 const TessellatedVertexProc& proc) {
805 Point center = oval_bounds.GetCenter();
806 Size radii = oval_bounds.GetSize() * 0.5f;
807
808 if (use_center) {
809 proc(center);
810 }
811 proc(center + iteration.start * radii);
812 for (size_t i = 0; i < iteration.quadrant_count; i++) {
813 auto quadrant = iteration.quadrants[i];
814 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
815 proc(center + trigs[j] * quadrant.axis * radii);
816 }
817 }
818 proc(center + iteration.end * radii);
819 }
820
821 void Tessellator::GenerateFilledArcStrip(const Trigs& trigs,
822 const Arc::Iteration& iteration,
823 const Rect& oval_bounds,
824 bool use_center,
825 const TessellatedVertexProc& proc) {
826 Point center = oval_bounds.GetCenter();
827 Size radii = oval_bounds.GetSize() * 0.5f;
828
829 Point origin;
830 if (use_center) {
831 origin = center;
832 } else {
833 Point midpoint = (iteration.start + iteration.end) * 0.5f;
834 origin = center + midpoint * radii;
835 }
836
837 proc(origin);
838 proc(center + iteration.start * radii);
839 bool insert_origin = false;
840 for (size_t i = 0; i < iteration.quadrant_count; i++) {
841 auto quadrant = iteration.quadrants[i];
842 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
843 if (insert_origin) {
844 proc(origin);
845 }
846 insert_origin = !insert_origin;
847 proc(center + trigs[j] * quadrant.axis * radii);
848 }
849 }
850 if (insert_origin) {
851 proc(origin);
852 }
853 proc(center + iteration.end * radii);
854 }
855
856 void Tessellator::GenerateStrokedArc(
857 const Trigs& trigs,
858 const Arc::Iteration& iteration,
859 const Rect& oval_bounds,
860 Scalar half_width,
861 Cap cap,
862 const std::unique_ptr<Trigs>& round_cap_trigs,
863 const TessellatedVertexProc& proc) {
864 Point center = oval_bounds.GetCenter();
865 Size base_radii = oval_bounds.GetSize() * 0.5f;
866 Size inner_radii = base_radii - Size(half_width, half_width);
867 Size outer_radii = base_radii + Size(half_width, half_width);
868
869 // Starting cap
870 switch (cap) {
871 case Cap::kButt:
872 proc(center + iteration.start * inner_radii);
873 proc(center + iteration.start * outer_radii);
874 break;
875 case Cap::kRound:
876 FML_DCHECK(round_cap_trigs);
877 Tessellator::GenerateStartRoundCap(center + iteration.start * base_radii,
878 -iteration.start * half_width,
879 *round_cap_trigs, proc);
880 break;
881 case Cap::kSquare:
882 Vector2 offset =
883 Vector2{iteration.start.y, -iteration.start.x} * half_width;
884 proc(center + iteration.start * inner_radii + offset);
885 proc(center + iteration.start * outer_radii + offset);
886 proc(center + iteration.start * inner_radii);
887 proc(center + iteration.start * outer_radii);
888 break;
889 }
890
891 for (size_t i = 0; i < iteration.quadrant_count; i++) {
892 auto quadrant = iteration.quadrants[i];
893 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
894 proc(center + trigs[j] * quadrant.axis * inner_radii);
895 proc(center + trigs[j] * quadrant.axis * outer_radii);
896 }
897 }
898
899 // Ending cap
900 switch (cap) {
901 case Cap::kButt:
902 proc(center + iteration.end * inner_radii);
903 proc(center + iteration.end * outer_radii);
904 break;
905 case Cap::kRound:
906 FML_DCHECK(round_cap_trigs);
907 Tessellator::GenerateEndRoundCap(center + iteration.end * base_radii,
908 -iteration.end * half_width,
909 *round_cap_trigs, proc);
910 break;
911 case Cap::kSquare:
912 Vector2 offset = Vector2{-iteration.end.y, iteration.end.x} * half_width;
913 proc(center + iteration.end * inner_radii);
914 proc(center + iteration.end * outer_radii);
915 proc(center + iteration.end * inner_radii + offset);
916 proc(center + iteration.end * outer_radii + offset);
917 break;
918 }
919 }
920
921 void Tessellator::GenerateRoundCapLine(
922 const Trigs& trigs,
923 const EllipticalVertexGenerator::Data& data,
924 const TessellatedVertexProc& proc) {
925 auto p0 = data.reference_centers[0];
926 auto p1 = data.reference_centers[1];
927 auto radius = data.radii.width;
928
929 FML_DCHECK(radius == data.radii.height);
930 FML_DCHECK(data.half_width < 0);
931
932 auto along = p1 - p0;
933 along *= radius / along.GetLength();
934 auto across = Point(-along.y, along.x);
935
936 Tessellator::GenerateStartRoundCap(p0, across, trigs, proc);
937 Tessellator::GenerateEndRoundCap(p1, across, trigs, proc);
938 }
939
940 void Tessellator::GenerateFilledEllipse(
941 const Trigs& trigs,
942 const EllipticalVertexGenerator::Data& data,
943 const TessellatedVertexProc& proc) {
944 auto center = data.reference_centers[0];
945 auto radii = data.radii;
946
947 FML_DCHECK(center == data.reference_centers[1]);
948 FML_DCHECK(data.half_width < 0);
949
950 // Quadrant 1 connecting with Quadrant 4:
951 for (auto& trig : trigs) {
952 auto offset = trig * radii;
953 proc({center.x - offset.x, center.y + offset.y});
954 proc({center.x - offset.x, center.y - offset.y});
955 }
956
957 // The second half of the circle should be iterated in reverse, but
958 // we can instead iterate forward and swap the x/y values of the
959 // offset as the angles should be symmetric and thus should generate
960 // symmetrically reversed trig vectors.
961 // Quadrant 2 connecting with Quadrant 2:
962 for (auto& trig : trigs) {
963 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
964 proc({center.x + offset.x, center.y + offset.y});
965 proc({center.x + offset.x, center.y - offset.y});
966 }
967 }
968
969 void Tessellator::GenerateFilledRoundRect(
970 const Trigs& trigs,
971 const EllipticalVertexGenerator::Data& data,
972 const TessellatedVertexProc& proc) {
973 Scalar left = data.reference_centers[0].x;
974 Scalar top = data.reference_centers[0].y;
975 Scalar right = data.reference_centers[1].x;
976 Scalar bottom = data.reference_centers[1].y;
977 auto radii = data.radii;
978
979 FML_DCHECK(data.half_width < 0);
980
981 // Quadrant 1 connecting with Quadrant 4:
982 for (auto& trig : trigs) {
983 auto offset = trig * radii;
984 proc({left - offset.x, bottom + offset.y});
985 proc({left - offset.x, top - offset.y});
986 }
987
988 // The second half of the round rect should be iterated in reverse, but
989 // we can instead iterate forward and swap the x/y values of the
990 // offset as the angles should be symmetric and thus should generate
991 // symmetrically reversed trig vectors.
992 // Quadrant 2 connecting with Quadrant 2:
993 for (auto& trig : trigs) {
994 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
995 proc({right + offset.x, bottom + offset.y});
996 proc({right + offset.x, top - offset.y});
997 }
998 }
999
1000 void Tessellator::GenerateStartRoundCap(const Point& p,
1001 const Vector2& perpendicular,
1002 const Trigs& trigs,
1003 const TessellatedVertexProc& proc) {
1004 Point along(perpendicular.y, -perpendicular.x);
1005
1006 for (auto& trig : trigs) {
1007 auto relative_along = along * trig.cos;
1008 auto relative_across = perpendicular * trig.sin;
1009 proc(p - relative_along + relative_across);
1010 proc(p - relative_along - relative_across);
1011 }
1012 }
1013
1014 void Tessellator::GenerateEndRoundCap(const Point& p,
1015 const Vector2& perpendicular,
1016 const Trigs& trigs,
1017 const TessellatedVertexProc& proc) {
1018 Point along(perpendicular.y, -perpendicular.x);
1019
1020 // The ending round cap should be iterated in reverse, but
1021 // we can instead iterate forward and swap the sin/cos values as they
1022 // should be symmetric.
1023 for (auto& trig : trigs) {
1024 auto relative_along = along * trig.sin;
1025 auto relative_across = perpendicular * trig.cos;
1026 proc(p + relative_along + relative_across);
1027 proc(p + relative_along - relative_across);
1028 }
1029 }
1030
1031 } // namespace impeller
use_center
bool use_center
Definition: aiks_dl_basic_unittests.cc:830
impeller::ConvexTessellatorImpl
Definition: tessellator.cc:324
impeller::ConvexTessellatorImpl::ConvexTessellatorImpl
ConvexTessellatorImpl()
Definition: tessellator.cc:326
impeller::ConvexTessellatorImpl::TessellateConvex
VertexBuffer TessellateConvex(const PathSource &path, HostBuffer &data_host_buffer, HostBuffer &indexes_host_buffer, Scalar tolerance, bool supports_primitive_restart, bool supports_triangle_fan) override
Definition: tessellator.cc:331
impeller::DeviceBuffer::Flush
virtual void Flush(std::optional< Range > range=std::nullopt) const
Definition: device_buffer.cc:13
impeller::DeviceBuffer::OnGetContents
virtual uint8_t * OnGetContents() const =0
impeller::HostBuffer
Definition: host_buffer.h:26
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:92
impeller::PathSource
Definition: path_source.h:55
impeller::PathTessellator::VertexWriter
An interface for generating a multi contour polyline as a triangle strip.
Definition: path_tessellator.h:21
impeller::PathTessellator::VertexWriter::EndContour
virtual void EndContour()=0
impeller::PathTessellator::VertexWriter::Write
virtual void Write(Point point)=0
impeller::PathTessellator::PathToFilledVertices
static void PathToFilledVertices(const PathSource &source, VertexWriter &writer, Scalar scale)
Definition: path_tessellator.cc:307
impeller::PathTessellator::CountFillStorage
static std::pair< size_t, size_t > CountFillStorage(const PathSource &source, Scalar scale)
Definition: path_tessellator.cc:297
impeller::Tessellator::ArcVertexGenerator
The |VertexGenerator| implementation common to all shapes that are based on a polygonal representatio...
Definition: tessellator.h:191
impeller::Tessellator::ArcVertexGenerator::MakeStroked
static ArcVertexGenerator MakeStroked(const Arc::Iteration &iteration, Trigs &&trigs, const Rect &oval_bounds, Scalar half_width, Cap cap, std::unique_ptr< Trigs > round_cap_trigs)
Definition: tessellator.cc:536
impeller::Tessellator::ArcVertexGenerator::GetVertexCount
size_t GetVertexCount() const override
|VertexGenerator|
Definition: tessellator.cc:570
impeller::Tessellator::ArcVertexGenerator::GetTriangleType
PrimitiveType GetTriangleType() const override
|VertexGenerator|
Definition: tessellator.cc:564
impeller::Tessellator::ArcVertexGenerator::MakeFilled
static ArcVertexGenerator MakeFilled(const Arc::Iteration &iteration, Trigs &&trigs, const Rect &oval_bounds, bool use_center, bool supports_triangle_fans)
Definition: tessellator.cc:525
impeller::Tessellator::ArcVertexGenerator::GenerateVertices
void GenerateVertices(const TessellatedVertexProc &proc) const override
|VertexGenerator|
Definition: tessellator.cc:595
impeller::Tessellator::EllipticalVertexGenerator
The |VertexGenerator| implementation common to all shapes that are based on a polygonal representatio...
Definition: tessellator.h:140
impeller::Tessellator::Trigs
Definition: tessellator.h:48
impeller::Tessellator::Trigs::Trigs
Trigs(Scalar pixel_radius)
Definition: tessellator.cc:447
impeller::Tessellator
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Definition: tessellator.h:37
impeller::Tessellator::GetTrigsForDeviceRadius
Trigs GetTrigsForDeviceRadius(Scalar pixel_radius)
Definition: tessellator.cc:425
impeller::Tessellator::RoundCapLine
EllipticalVertexGenerator RoundCapLine(const Matrix &view_transform, const Point &p0, const Point &p1, Scalar radius)
Create a |VertexGenerator| that can produce vertices for a line with round end caps of the given radi...
Definition: tessellator.cc:643
impeller::Tessellator::GetStrokePointCache
std::vector< Point > & GetStrokePointCache()
Retrieve a pre-allocated arena of kPointArenaSize points.
Definition: tessellator.cc:421
impeller::Tessellator::FilledRoundRect
EllipticalVertexGenerator FilledRoundRect(const Matrix &view_transform, const Rect &bounds, const Size &radii)
Create a |VertexGenerator| that can produce vertices for a filled round rect within the given bounds ...
Definition: tessellator.cc:687
impeller::Tessellator::kCircleTolerance
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
Definition: tessellator.h:280
impeller::Tessellator::TessellateConvex
VertexBuffer TessellateConvex(const PathSource &path, HostBuffer &data_host_buffer, HostBuffer &indexes_host_buffer, Scalar tolerance, bool supports_primitive_restart=false, bool supports_triangle_fan=false)
Given a convex path, create a triangle fan structure.
Definition: tessellator.cc:429
impeller::Tessellator::FilledCircle
EllipticalVertexGenerator FilledCircle(const Matrix &view_transform, const Point &center, Scalar radius)
Create a |VertexGenerator| that can produce vertices for a filled circle of the given radius around t...
Definition: tessellator.cc:488
impeller::Tessellator::StrokedArc
ArcVertexGenerator StrokedArc(const Matrix &view_transform, const Arc &arc, Cap cap, Scalar half_width)
Create a |VertexGenerator| that can produce vertices for a stroked arc inscribed within the given ova...
Definition: tessellator.cc:621
impeller::Tessellator::TessellateConvexInternal
static void TessellateConvexInternal(const PathSource &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
Definition: tessellator.cc:440
impeller::Tessellator::~Tessellator
virtual ~Tessellator()
impeller::Tessellator::FilledEllipse
EllipticalVertexGenerator FilledEllipse(const Matrix &view_transform, const Rect &bounds)
Create a |VertexGenerator| that can produce vertices for a filled ellipse inscribed within the given ...
Definition: tessellator.cc:666
impeller::Tessellator::Tessellator
Tessellator(bool supports_32bit_primitive_indices=true)
Definition: tessellator.cc:410
impeller::Tessellator::TessellatedVertexProc
std::function< void(const Point &p)> TessellatedVertexProc
A callback function for a |VertexGenerator| to deliver the vertices it computes as |Point| objects.
Definition: tessellator.h:97
impeller::Tessellator::FilledArc
ArcVertexGenerator FilledArc(const Matrix &view_transform, const Arc &arc, bool supports_triangle_fans)
Create a |VertexGenerator| that can produce vertices for a stroked arc inscribed within the given ova...
Definition: tessellator.cc:610
device_buffer.h
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller
Definition: allocation.cc:12
impeller::TessellatedVertexProc
Tessellator::TessellatedVertexProc TessellatedVertexProc
Definition: tessellator.cc:473
impeller::PrimitiveType
PrimitiveType
Decides how backend draws pixels based on input vertices.
Definition: formats.h:355
impeller::PrimitiveType::kTriangleFan
@ kTriangleFan
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::Scalar
float Scalar
Definition: scalar.h:19
impeller::IndexType
IndexType
Definition: formats.h:346
impeller::IndexType::k16bit
@ k16bit
impeller::IndexType::k32bit
@ k32bit
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:57
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:788
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::Cap
Cap
An enum that describes ways to decorate the end of a path contour.
Definition: stroke_parameters.h:13
impeller::Cap::kRound
@ kRound
impeller::Cap::kButt
@ kButt
impeller::Cap::kSquare
@ kSquare
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
impeller::EllipticalVertexGenerator
Tessellator::EllipticalVertexGenerator EllipticalVertexGenerator
Definition: tessellator.cc:474
impeller::ArcVertexGenerator
Tessellator::ArcVertexGenerator ArcVertexGenerator
Definition: tessellator.cc:475
impeller::kPiOver4
constexpr float kPiOver4
Definition: constants.h:35
impeller::Size
TSize< Scalar > Size
Definition: size.h:159
impeller::kPointArenaSize
static constexpr size_t kPointArenaSize
The size of the point arena buffer stored on the tessellator.
Definition: tessellator.h:25
std
Definition: comparable.h:95
path_tessellator.h
impeller::Arc::Iteration
Definition: arc.h:42
impeller::Arc::Iteration::GetPointCount
size_t GetPointCount() const
Definition: arc.cc:36
impeller::Arc
Definition: arc.h:13
impeller::Arc::ComputeIterations
Iteration ComputeIterations(size_t step_count, bool simplify_360=true) const
Definition: arc.cc:102
impeller::Arc::IncludeCenter
constexpr bool IncludeCenter() const
Definition: arc.h:110
impeller::Arc::GetOvalSize
const Size GetOvalSize() const
Returns the size of the oval bounds.
Definition: arc.h:100
impeller::Arc::IsPerfectCircle
constexpr bool IsPerfectCircle() const
Definition: arc.h:112
impeller::Arc::GetOvalBounds
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
Definition: arc.h:94
impeller::BufferView
Definition: buffer_view.h:19
impeller::BufferView::GetRange
Range GetRange() const
Definition: buffer_view.h:27
impeller::BufferView::GetBuffer
const DeviceBuffer * GetBuffer() const
Definition: buffer_view.cc:17
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::GetMaxBasisLengthXY
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
Definition: matrix.h:328
impeller::Radians
Definition: scalar.h:44
impeller::Range::offset
size_t offset
Definition: range.h:14
impeller::TPoint< Scalar >
impeller::TPoint::GetLength
constexpr Type GetLength() const
Definition: point.h:206
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TRect< Scalar >
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:347
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:327
impeller::TRect::IsSquare
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
Definition: rect.h:304
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:341
impeller::TRect::GetRightBottom
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:371
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:382
impeller::TRect::GetLeftTop
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:359
impeller::TSize< Scalar >
impeller::TSize::MaxDimension
constexpr Type MaxDimension() const
Definition: size.h:106
impeller::TSize::height
Type height
Definition: size.h:29
impeller::TSize::width
Type width
Definition: size.h:28
impeller::VertexBuffer
Definition: vertex_buffer.h:15
impeller::VertexBuffer::vertex_buffer
BufferView vertex_buffer
Definition: vertex_buffer.h:16
tessellator.h
start
const size_t start
Definition: tessellator_libtess.cc:62
end
const size_t end
Definition: tessellator_libtess.cc:63
points
std::vector< Point > points
Definition: tessellator_libtess.cc:76
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:69