| 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 // Stroked arc
574 FML_DCHECK(!use_center_);
575 count *= 2;
576 if (cap_ == Cap::kSquare) {
577 count += 4;
578 } else if (cap_ == Cap::kRound) {
579 FML_DCHECK(round_cap_trigs_);
580 // 4 vertices for each Trig in round_cap_trigs_: 2 vertices for each in
581 // the start cap and 2 for each in the end cap. Subtract 4 because the cap
582 // vertices elide the beginning and end vertices of the arc.
583 count += round_cap_trigs_->size() * 4 - 4;
584 }
585 } else if (supports_triangle_fans_) {
586 // Filled arc using a triangle fan
587 if (use_center_) {
588 count++;
589 }
590 } else {
591 // Filled arc using a triangle strip
592 count = (2 * count) - 1;
593 }
594 return count;
595 }
596
597 void ArcVertexGenerator::GenerateVertices(
598 const TessellatedVertexProc& proc) const {
599 if (half_width_ > 0) {
600 FML_DCHECK(!use_center_);
601 Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_,
602 half_width_, cap_, round_cap_trigs_, proc);
603 } else if (supports_triangle_fans_) {
604 Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_,
605 use_center_, proc);
606 } else {
607 Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_,
608 use_center_, proc);
609 }
610 }
611
612 ArcVertexGenerator Tessellator::FilledArc(const Matrix& view_transform,
613 const Arc& arc,
614 bool supports_triangle_fans) {
615 size_t divisions = ComputeQuadrantDivisions(
616 view_transform.GetMaxBasisLengthXY() * arc.GetOvalSize().MaxDimension());
617
618 return ArcVertexGenerator::MakeFilled(
619 arc.ComputeIterations(divisions), GetTrigsForDivisions(divisions),
620 arc.GetOvalBounds(), arc.IncludeCenter(), supports_triangle_fans);
621 };
622
623 ArcVertexGenerator Tessellator::StrokedArc(const Matrix& view_transform,
624 const Arc& arc,
625 Cap cap,
626 Scalar half_width) {
627 FML_DCHECK(half_width > 0);
628 FML_DCHECK(arc.IsPerfectCircle());
629 FML_DCHECK(!arc.IncludeCenter());
630 size_t divisions =
631 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() *
632 (arc.GetOvalSize().MaxDimension() + half_width));
633
634 std::unique_ptr<Trigs> round_cap_trigs;
635 if (cap == Cap::kRound) {
636 round_cap_trigs = std::make_unique<Trigs>(GetTrigsForDeviceRadius(
637 view_transform.GetMaxBasisLengthXY() * half_width));
638 }
639
640 return ArcVertexGenerator::MakeStroked(
641 arc.ComputeIterations(divisions), GetTrigsForDivisions(divisions),
642 arc.GetOvalBounds(), half_width, cap, std::move(round_cap_trigs));
643 }
644
645 EllipticalVertexGenerator Tessellator::RoundCapLine(
646 const Matrix& view_transform,
647 const Point& p0,
648 const Point& p1,
649 Scalar radius) {
650 auto along = p1 - p0;
651 auto length = along.GetLength();
652 if (length > kEhCloseEnough) {
653 auto divisions =
654 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * radius);
655 return EllipticalVertexGenerator(Tessellator::GenerateRoundCapLine,
656 GetTrigsForDivisions(divisions),
657 PrimitiveType::kTriangleStrip, 4,
658 {
659 .reference_centers = {p0, p1},
660 .radii = {radius, radius},
661 .half_width = -1.0f,
662 });
663 } else {
664 return FilledCircle(view_transform, p0, radius);
665 }
666 }
667
668 EllipticalVertexGenerator Tessellator::FilledEllipse(
669 const Matrix& view_transform,
670 const Rect& bounds) {
671 if (bounds.IsSquare()) {
672 return FilledCircle(view_transform, bounds.GetCenter(),
673 bounds.GetWidth() * 0.5f);
674 }
675 auto max_radius = bounds.GetSize().MaxDimension();
676 auto divisions = ComputeQuadrantDivisions(
677 view_transform.GetMaxBasisLengthXY() * max_radius);
678 auto center = bounds.GetCenter();
679 return EllipticalVertexGenerator(Tessellator::GenerateFilledEllipse,
680 GetTrigsForDivisions(divisions),
681 PrimitiveType::kTriangleStrip, 4,
682 {
683 .reference_centers = {center, center},
684 .radii = bounds.GetSize() * 0.5f,
685 .half_width = -1.0f,
686 });
687 }
688
689 EllipticalVertexGenerator Tessellator::FilledRoundRect(
690 const Matrix& view_transform,
691 const Rect& bounds,
692 const Size& radii) {
693 if (radii.width * 2 < bounds.GetWidth() ||
694 radii.height * 2 < bounds.GetHeight()) {
695 auto max_radius = radii.MaxDimension();
696 auto divisions = ComputeQuadrantDivisions(
697 view_transform.GetMaxBasisLengthXY() * max_radius);
698 auto upper_left = bounds.GetLeftTop() + radii;
699 auto lower_right = bounds.GetRightBottom() - radii;
700 return EllipticalVertexGenerator(Tessellator::GenerateFilledRoundRect,
701 GetTrigsForDivisions(divisions),
702 PrimitiveType::kTriangleStrip, 4,
703 {
704 .reference_centers =
705 {
706 upper_left,
707 lower_right,
708 },
709 .radii = radii,
710 .half_width = -1.0f,
711 });
712 } else {
713 return FilledEllipse(view_transform, bounds);
714 }
715 }
716
717 void Tessellator::GenerateFilledCircle(
718 const Trigs& trigs,
719 const EllipticalVertexGenerator::Data& data,
720 const TessellatedVertexProc& proc) {
721 auto center = data.reference_centers[0];
722 auto radius = data.radii.width;
723
724 FML_DCHECK(center == data.reference_centers[1]);
725 FML_DCHECK(radius == data.radii.height);
726 FML_DCHECK(data.half_width < 0);
727
728 // Quadrant 1 connecting with Quadrant 4:
729 for (auto& trig : trigs) {
730 auto offset = trig * radius;
731 proc({center.x - offset.x, center.y + offset.y});
732 proc({center.x - offset.x, center.y - offset.y});
733 }
734
735 // The second half of the circle should be iterated in reverse, but
736 // we can instead iterate forward and swap the x/y values of the
737 // offset as the angles should be symmetric and thus should generate
738 // symmetrically reversed trig vectors.
739 // Quadrant 2 connecting with Quadrant 3:
740 for (auto& trig : trigs) {
741 auto offset = trig * radius;
742 proc({center.x + offset.y, center.y + offset.x});
743 proc({center.x + offset.y, center.y - offset.x});
744 }
745 }
746
747 void Tessellator::GenerateStrokedCircle(
748 const Trigs& trigs,
749 const EllipticalVertexGenerator::Data& data,
750 const TessellatedVertexProc& proc) {
751 auto center = data.reference_centers[0];
752
753 FML_DCHECK(center == data.reference_centers[1]);
754 FML_DCHECK(data.radii.IsSquare());
755 FML_DCHECK(data.half_width > 0 && data.half_width < data.radii.width);
756
757 auto outer_radius = data.radii.width + data.half_width;
758 auto inner_radius = data.radii.width - data.half_width;
759
760 // Zig-zag back and forth between points on the outer circle and the
761 // inner circle. Both circles are evaluated at the same number of
762 // quadrant divisions so the points for a given division should match
763 // 1 for 1 other than their applied radius.
764
765 // Quadrant 1:
766 for (auto& trig : trigs) {
767 auto outer = trig * outer_radius;
768 auto inner = trig * inner_radius;
769 proc({center.x - outer.x, center.y - outer.y});
770 proc({center.x - inner.x, center.y - inner.y});
771 }
772
773 // The even quadrants of the circle should be iterated in reverse, but
774 // we can instead iterate forward and swap the x/y values of the
775 // offset as the angles should be symmetric and thus should generate
776 // symmetrically reversed trig vectors.
777 // Quadrant 2:
778 for (auto& trig : trigs) {
779 auto outer = trig * outer_radius;
780 auto inner = trig * inner_radius;
781 proc({center.x + outer.y, center.y - outer.x});
782 proc({center.x + inner.y, center.y - inner.x});
783 }
784
785 // Quadrant 3:
786 for (auto& trig : trigs) {
787 auto outer = trig * outer_radius;
788 auto inner = trig * inner_radius;
789 proc({center.x + outer.x, center.y + outer.y});
790 proc({center.x + inner.x, center.y + inner.y});
791 }
792
793 // Quadrant 4:
794 for (auto& trig : trigs) {
795 auto outer = trig * outer_radius;
796 auto inner = trig * inner_radius;
797 proc({center.x - outer.y, center.y + outer.x});
798 proc({center.x - inner.y, center.y + inner.x});
799 }
800 }
801
802 void Tessellator::GenerateFilledArcFan(const Trigs& trigs,
803 const Arc::Iteration& iteration,
804 const Rect& oval_bounds,
805 bool use_center,
806 const TessellatedVertexProc& proc) {
807 Point center = oval_bounds.GetCenter();
808 Size radii = oval_bounds.GetSize() * 0.5f;
809
810 if (use_center) {
811 proc(center);
812 }
813 proc(center + iteration.start * radii);
814 for (size_t i = 0; i < iteration.quadrant_count; i++) {
815 auto quadrant = iteration.quadrants[i];
816 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
817 proc(center + trigs[j] * quadrant.axis * radii);
818 }
819 }
820 proc(center + iteration.end * radii);
821 }
822
823 void Tessellator::GenerateFilledArcStrip(const Trigs& trigs,
824 const Arc::Iteration& iteration,
825 const Rect& oval_bounds,
826 bool use_center,
827 const TessellatedVertexProc& proc) {
828 Point center = oval_bounds.GetCenter();
829 Size radii = oval_bounds.GetSize() * 0.5f;
830
831 Point origin;
832 if (use_center) {
833 origin = center;
834 } else {
835 Point midpoint = (iteration.start + iteration.end) * 0.5f;
836 origin = center + midpoint * radii;
837 }
838
839 proc(center + iteration.start * radii);
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 proc(origin);
844 proc(center + trigs[j] * quadrant.axis * radii);
845 }
846 }
847 proc(origin);
848 proc(center + iteration.end * radii);
849 }
850
851 void Tessellator::GenerateStrokedArc(
852 const Trigs& trigs,
853 const Arc::Iteration& iteration,
854 const Rect& oval_bounds,
855 Scalar half_width,
856 Cap cap,
857 const std::unique_ptr<Trigs>& round_cap_trigs,
858 const TessellatedVertexProc& proc) {
859 Point center = oval_bounds.GetCenter();
860 Size base_radii = oval_bounds.GetSize() * 0.5f;
861 Size inner_radii = base_radii - Size(half_width, half_width);
862 Size outer_radii = base_radii + Size(half_width, half_width);
863
864 // Starting cap
865 switch (cap) {
866 case Cap::kButt:
867 proc(center + iteration.start * inner_radii);
868 proc(center + iteration.start * outer_radii);
869 break;
870 case Cap::kRound:
871 FML_DCHECK(round_cap_trigs);
872 Tessellator::GenerateStartRoundCap(center + iteration.start * base_radii,
873 -iteration.start * half_width,
874 *round_cap_trigs, proc);
875 break;
876 case Cap::kSquare:
877 Vector2 offset =
878 Vector2{iteration.start.y, -iteration.start.x} * half_width;
879 proc(center + iteration.start * inner_radii + offset);
880 proc(center + iteration.start * outer_radii + offset);
881 proc(center + iteration.start * inner_radii);
882 proc(center + iteration.start * outer_radii);
883 break;
884 }
885
886 for (size_t i = 0; i < iteration.quadrant_count; i++) {
887 auto quadrant = iteration.quadrants[i];
888 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
889 proc(center + trigs[j] * quadrant.axis * inner_radii);
890 proc(center + trigs[j] * quadrant.axis * outer_radii);
891 }
892 }
893
894 // Ending cap
895 switch (cap) {
896 case Cap::kButt:
897 proc(center + iteration.end * inner_radii);
898 proc(center + iteration.end * outer_radii);
899 break;
900 case Cap::kRound:
901 FML_DCHECK(round_cap_trigs);
902 Tessellator::GenerateEndRoundCap(center + iteration.end * base_radii,
903 -iteration.end * half_width,
904 *round_cap_trigs, proc);
905 break;
906 case Cap::kSquare:
907 Vector2 offset = Vector2{-iteration.end.y, iteration.end.x} * half_width;
908 proc(center + iteration.end * inner_radii);
909 proc(center + iteration.end * outer_radii);
910 proc(center + iteration.end * inner_radii + offset);
911 proc(center + iteration.end * outer_radii + offset);
912 break;
913 }
914 }
915
916 void Tessellator::GenerateRoundCapLine(
917 const Trigs& trigs,
918 const EllipticalVertexGenerator::Data& data,
919 const TessellatedVertexProc& proc) {
920 auto p0 = data.reference_centers[0];
921 auto p1 = data.reference_centers[1];
922 auto radius = data.radii.width;
923
924 FML_DCHECK(radius == data.radii.height);
925 FML_DCHECK(data.half_width < 0);
926
927 auto along = p1 - p0;
928 along *= radius / along.GetLength();
929 auto across = Point(-along.y, along.x);
930
931 Tessellator::GenerateStartRoundCap(p0, across, trigs, proc);
932 Tessellator::GenerateEndRoundCap(p1, across, trigs, proc);
933 }
934
935 void Tessellator::GenerateFilledEllipse(
936 const Trigs& trigs,
937 const EllipticalVertexGenerator::Data& data,
938 const TessellatedVertexProc& proc) {
939 auto center = data.reference_centers[0];
940 auto radii = data.radii;
941
942 FML_DCHECK(center == data.reference_centers[1]);
943 FML_DCHECK(data.half_width < 0);
944
945 // Quadrant 1 connecting with Quadrant 4:
946 for (auto& trig : trigs) {
947 auto offset = trig * radii;
948 proc({center.x - offset.x, center.y + offset.y});
949 proc({center.x - offset.x, center.y - offset.y});
950 }
951
952 // The second half of the circle should be iterated in reverse, but
953 // we can instead iterate forward and swap the x/y values of the
954 // offset as the angles should be symmetric and thus should generate
955 // symmetrically reversed trig vectors.
956 // Quadrant 2 connecting with Quadrant 2:
957 for (auto& trig : trigs) {
958 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
959 proc({center.x + offset.x, center.y + offset.y});
960 proc({center.x + offset.x, center.y - offset.y});
961 }
962 }
963
964 void Tessellator::GenerateFilledRoundRect(
965 const Trigs& trigs,
966 const EllipticalVertexGenerator::Data& data,
967 const TessellatedVertexProc& proc) {
968 Scalar left = data.reference_centers[0].x;
969 Scalar top = data.reference_centers[0].y;
970 Scalar right = data.reference_centers[1].x;
971 Scalar bottom = data.reference_centers[1].y;
972 auto radii = data.radii;
973
974 FML_DCHECK(data.half_width < 0);
975
976 // Quadrant 1 connecting with Quadrant 4:
977 for (auto& trig : trigs) {
978 auto offset = trig * radii;
979 proc({left - offset.x, bottom + offset.y});
980 proc({left - offset.x, top - offset.y});
981 }
982
983 // The second half of the round rect should be iterated in reverse, but
984 // we can instead iterate forward and swap the x/y values of the
985 // offset as the angles should be symmetric and thus should generate
986 // symmetrically reversed trig vectors.
987 // Quadrant 2 connecting with Quadrant 2:
988 for (auto& trig : trigs) {
989 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
990 proc({right + offset.x, bottom + offset.y});
991 proc({right + offset.x, top - offset.y});
992 }
993 }
994
995 void Tessellator::GenerateStartRoundCap(const Point& p,
996 const Vector2& perpendicular,
997 const Trigs& trigs,
998 const TessellatedVertexProc& proc) {
999 Point along(perpendicular.y, -perpendicular.x);
1000
1001 for (auto& trig : trigs) {
1002 auto relative_along = along * trig.cos;
1003 auto relative_across = perpendicular * trig.sin;
1004 proc(p - relative_along + relative_across);
1005 proc(p - relative_along - relative_across);
1006 }
1007 }
1008
1009 void Tessellator::GenerateEndRoundCap(const Point& p,
1010 const Vector2& perpendicular,
1011 const Trigs& trigs,
1012 const TessellatedVertexProc& proc) {
1013 Point along(perpendicular.y, -perpendicular.x);
1014
1015 // The ending round cap should be iterated in reverse, but
1016 // we can instead iterate forward and swap the sin/cos values as they
1017 // should be symmetric.
1018 for (auto& trig : trigs) {
1019 auto relative_along = along * trig.sin;
1020 auto relative_across = perpendicular * trig.cos;
1021 proc(p + relative_along + relative_across);
1022 proc(p + relative_along - relative_across);
1023 }
1024 }
1025
1026 } // namespace impeller
use_center
bool use_center
Definition: aiks_dl_basic_unittests.cc:925
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:308
impeller::PathTessellator::CountFillStorage
static std::pair< size_t, size_t > CountFillStorage(const PathSource &source, Scalar scale)
Definition: path_tessellator.cc:298
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:597
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:645
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:689
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:623
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:668
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:612
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:429
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:425
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
p1
Point p1
Definition: round_superellipse_param.cc:313
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:209
impeller::TPoint::y
Type y
Definition: point.h:32
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