| 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 /// @brief A vertex writer that generates a triangle fan and requires primitive
141 /// restart.
142 class FanPathVertexWriter : public impeller::PathTessellator::VertexWriter {
143 public:
144 explicit FanPathVertexWriter(impeller::Point* point_buffer,
145 uint16_t* index_buffer)
146 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
147
148 ~FanPathVertexWriter() = default;
149
150 size_t GetIndexCount() const { return index_count_; }
151 size_t GetPointCount() const { return count_; }
152
153 void EndContour() override {
154 if (count_ == 0) {
155 return;
156 }
157 index_buffer_[index_count_++] = 0xFFFF;
158 }
159
160 void Write(impeller::Point point) override {
161 index_buffer_[index_count_++] = count_;
162 point_buffer_[count_++] = point;
163 }
164
165 private:
166 size_t count_ = 0;
167 size_t index_count_ = 0;
168 impeller::Point* point_buffer_ = nullptr;
169 uint16_t* index_buffer_ = nullptr;
170 };
171
172 /// @brief A vertex writer that generates a triangle strip and requires
173 /// primitive restart.
174 class StripPathVertexWriter : public impeller::PathTessellator::VertexWriter {
175 public:
176 explicit StripPathVertexWriter(impeller::Point* point_buffer,
177 uint16_t* index_buffer)
178 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
179
180 ~StripPathVertexWriter() = default;
181
182 size_t GetIndexCount() const { return index_count_; }
183 size_t GetPointCount() const { return count_; }
184
185 void EndContour() override {
186 if (count_ == 0u || contour_start_ == count_ - 1) {
187 // Empty or first contour.
188 return;
189 }
190
191 size_t start = contour_start_;
192 size_t end = count_ - 1;
193
194 index_buffer_[index_count_++] = start;
195
196 size_t a = start + 1;
197 size_t b = end;
198 while (a < b) {
199 index_buffer_[index_count_++] = a;
200 index_buffer_[index_count_++] = b;
201 a++;
202 b--;
203 }
204 if (a == b) {
205 index_buffer_[index_count_++] = a;
206 }
207
208 contour_start_ = count_;
209 index_buffer_[index_count_++] = 0xFFFF;
210 }
211
212 void Write(impeller::Point point) override {
213 point_buffer_[count_++] = point;
214 }
215
216 private:
217 size_t count_ = 0;
218 size_t index_count_ = 0;
219 size_t contour_start_ = 0;
220 impeller::Point* point_buffer_ = nullptr;
221 uint16_t* index_buffer_ = nullptr;
222 };
223
224 /// @brief A vertex writer that has no hardware requirements.
225 class GLESPathVertexWriter : public impeller::PathTessellator::VertexWriter {
226 public:
227 explicit GLESPathVertexWriter(std::vector<impeller::Point>& points,
228 std::vector<uint16_t>& indices)
229 : points_(points), indices_(indices) {}
230
231 ~GLESPathVertexWriter() = default;
232
233 void EndContour() override {
234 if (points_.size() == 0u || contour_start_ == points_.size() - 1) {
235 // Empty or first contour.
236 return;
237 }
238
239 auto start = contour_start_;
240 auto end = points_.size() - 1;
241 // All filled paths are drawn as if they are closed, but if
242 // there is an explicit close then a lineTo to the origin
243 // is inserted. This point isn't strictly necesary to
244 // correctly render the shape and can be dropped.
245 if (points_[end] == points_[start]) {
246 end--;
247 }
248
249 // Triangle strip break for subsequent contours
250 if (contour_start_ != 0) {
251 auto back = indices_.back();
252 indices_.push_back(back);
253 indices_.push_back(start);
254 indices_.push_back(start);
255
256 // If the contour has an odd number of points, insert an extra point when
257 // bridging to the next contour to preserve the correct triangle winding
258 // order.
259 if (previous_contour_odd_points_) {
260 indices_.push_back(start);
261 }
262 } else {
263 indices_.push_back(start);
264 }
265
266 size_t a = start + 1;
267 size_t b = end;
268 while (a < b) {
269 indices_.push_back(a);
270 indices_.push_back(b);
271 a++;
272 b--;
273 }
274 if (a == b) {
275 indices_.push_back(a);
276 previous_contour_odd_points_ = false;
277 } else {
278 previous_contour_odd_points_ = true;
279 }
280 contour_start_ = points_.size();
281 }
282
283 void Write(impeller::Point point) override { points_.push_back(point); }
284
285 private:
286 bool previous_contour_odd_points_ = false;
287 size_t contour_start_ = 0u;
288 std::vector<impeller::Point>& points_;
289 std::vector<uint16_t>& indices_;
290 };
291
292 } // namespace
293
294 namespace impeller {
295
296 Tessellator::Tessellator()
297 : point_buffer_(std::make_unique<std::vector<Point>>()),
298 index_buffer_(std::make_unique<std::vector<uint16_t>>()),
299 stroke_points_(kPointArenaSize) {
300 point_buffer_->reserve(2048);
301 index_buffer_->reserve(2048);
302 }
303
304 Tessellator::~Tessellator() = default;
305
306 std::vector<Point>& Tessellator::GetStrokePointCache() {
307 return stroke_points_;
308 }
309
310 Tessellator::Trigs Tessellator::GetTrigsForDeviceRadius(Scalar pixel_radius) {
311 return GetTrigsForDivisions(ComputeQuadrantDivisions(pixel_radius));
312 }
313
314 VertexBuffer Tessellator::TessellateConvex(const PathSource& path,
315 HostBuffer& data_host_buffer,
316 HostBuffer& indexes_host_buffer,
317 Scalar tolerance,
318 bool supports_primitive_restart,
319 bool supports_triangle_fan) {
320 if (supports_primitive_restart) {
321 // Primitive Restart.
322 const auto [point_count, contour_count] =
323 PathTessellator::CountFillStorage(path, tolerance);
324 BufferView point_buffer = data_host_buffer.Emplace(
325 nullptr, sizeof(Point) * point_count, alignof(Point));
326 BufferView index_buffer = indexes_host_buffer.Emplace(
327 nullptr, sizeof(uint16_t) * (point_count + contour_count),
328 alignof(uint16_t));
329
330 if (supports_triangle_fan) {
331 FanPathVertexWriter writer(
332 reinterpret_cast<Point*>(point_buffer.GetBuffer()->OnGetContents() +
333 point_buffer.GetRange().offset),
334 reinterpret_cast<uint16_t*>(
335 index_buffer.GetBuffer()->OnGetContents() +
336 index_buffer.GetRange().offset));
337 PathTessellator::PathToFilledVertices(path, writer, tolerance);
338 FML_DCHECK(writer.GetPointCount() <= point_count);
339 FML_DCHECK(writer.GetIndexCount() <= (point_count + contour_count));
340 point_buffer.GetBuffer()->Flush(point_buffer.GetRange());
341 index_buffer.GetBuffer()->Flush(index_buffer.GetRange());
342
343 return VertexBuffer{
344 .vertex_buffer = std::move(point_buffer),
345 .index_buffer = std::move(index_buffer),
346 .vertex_count = writer.GetIndexCount(),
347 .index_type = IndexType::k16bit,
348 };
349 } else {
350 StripPathVertexWriter writer(
351 reinterpret_cast<Point*>(point_buffer.GetBuffer()->OnGetContents() +
352 point_buffer.GetRange().offset),
353 reinterpret_cast<uint16_t*>(
354 index_buffer.GetBuffer()->OnGetContents() +
355 index_buffer.GetRange().offset));
356 PathTessellator::PathToFilledVertices(path, writer, tolerance);
357 FML_DCHECK(writer.GetPointCount() <= point_count);
358 FML_DCHECK(writer.GetIndexCount() <= (point_count + contour_count));
359 point_buffer.GetBuffer()->Flush(point_buffer.GetRange());
360 index_buffer.GetBuffer()->Flush(index_buffer.GetRange());
361
362 return VertexBuffer{
363 .vertex_buffer = std::move(point_buffer),
364 .index_buffer = std::move(index_buffer),
365 .vertex_count = writer.GetIndexCount(),
366 .index_type = IndexType::k16bit,
367 };
368 }
369 }
370
371 FML_DCHECK(point_buffer_);
372 FML_DCHECK(index_buffer_);
373 TessellateConvexInternal(path, *point_buffer_, *index_buffer_, tolerance);
374
375 if (point_buffer_->empty()) {
376 return VertexBuffer{
377 .vertex_buffer = {},
378 .index_buffer = {},
379 .vertex_count = 0u,
380 .index_type = IndexType::k16bit,
381 };
382 }
383
384 BufferView vertex_buffer = data_host_buffer.Emplace(
385 point_buffer_->data(), sizeof(Point) * point_buffer_->size(),
386 alignof(Point));
387
388 BufferView index_buffer = indexes_host_buffer.Emplace(
389 index_buffer_->data(), sizeof(uint16_t) * index_buffer_->size(),
390 alignof(uint16_t));
391
392 return VertexBuffer{
393 .vertex_buffer = std::move(vertex_buffer),
394 .index_buffer = std::move(index_buffer),
395 .vertex_count = index_buffer_->size(),
396 .index_type = IndexType::k16bit,
397 };
398 }
399
400 void Tessellator::TessellateConvexInternal(const PathSource& path,
401 std::vector<Point>& point_buffer,
402 std::vector<uint16_t>& index_buffer,
403 Scalar tolerance) {
404 point_buffer.clear();
405 index_buffer.clear();
406
407 GLESPathVertexWriter writer(point_buffer, index_buffer);
408
409 PathTessellator::PathToFilledVertices(path, writer, tolerance);
410 }
411
412 Tessellator::Trigs::Trigs(Scalar pixel_radius)
413 : Tessellator::Trigs(ComputeQuadrantDivisions(pixel_radius)) {}
414
415 void Tessellator::Trigs::init(size_t divisions) {
416 if (!trigs_.empty()) {
417 return;
418 }
419
420 // Either not cached yet, or we are using the temp storage...
421 trigs_.reserve(divisions + 1);
422
423 double angle_scale = kPiOver2 / divisions;
424
425 trigs_.emplace_back(1.0, 0.0);
426 for (size_t i = 1; i < divisions; i++) {
427 trigs_.emplace_back(Radians(i * angle_scale));
428 }
429 trigs_.emplace_back(0.0, 1.0);
430 }
431
432 Tessellator::Trigs Tessellator::GetTrigsForDivisions(size_t divisions) {
433 return divisions < Tessellator::kCachedTrigCount
434 ? Trigs(precomputed_trigs_[divisions], divisions)
435 : Trigs(divisions);
436 }
437
438 using TessellatedVertexProc = Tessellator::TessellatedVertexProc;
439 using EllipticalVertexGenerator = Tessellator::EllipticalVertexGenerator;
440 using ArcVertexGenerator = Tessellator::ArcVertexGenerator;
441
442 EllipticalVertexGenerator::EllipticalVertexGenerator(
443 EllipticalVertexGenerator::GeneratorProc& generator,
444 Trigs&& trigs,
445 PrimitiveType triangle_type,
446 size_t vertices_per_trig,
447 Data&& data)
448 : impl_(generator),
449 trigs_(std::move(trigs)),
450 data_(data),
451 vertices_per_trig_(vertices_per_trig) {}
452
453 EllipticalVertexGenerator Tessellator::FilledCircle(
454 const Matrix& view_transform,
455 const Point& center,
456 Scalar radius) {
457 size_t divisions =
458 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * radius);
459 return EllipticalVertexGenerator(Tessellator::GenerateFilledCircle,
460 GetTrigsForDivisions(divisions),
461 PrimitiveType::kTriangleStrip, 4,
462 {
463 .reference_centers = {center, center},
464 .radii = {radius, radius},
465 .half_width = -1.0f,
466 });
467 }
468
469 EllipticalVertexGenerator Tessellator::StrokedCircle(
470 const Matrix& view_transform,
471 const Point& center,
472 Scalar radius,
473 Scalar half_width) {
474 if (half_width > 0) {
475 auto divisions = ComputeQuadrantDivisions(
476 view_transform.GetMaxBasisLengthXY() * radius + half_width);
477 return EllipticalVertexGenerator(Tessellator::GenerateStrokedCircle,
478 GetTrigsForDivisions(divisions),
479 PrimitiveType::kTriangleStrip, 8,
480 {
481 .reference_centers = {center, center},
482 .radii = {radius, radius},
483 .half_width = half_width,
484 });
485 } else {
486 return FilledCircle(view_transform, center, radius);
487 }
488 }
489
490 ArcVertexGenerator::ArcVertexGenerator(const Arc::Iteration& iteration,
491 Trigs&& trigs,
492 const Rect& oval_bounds,
493 bool use_center,
494 bool supports_triangle_fans)
495 : iteration_(iteration),
496 trigs_(std::move(trigs)),
497 oval_bounds_(oval_bounds),
498 use_center_(use_center),
499 half_width_(-1.0f),
500 cap_(Cap::kButt),
501 supports_triangle_fans_(supports_triangle_fans) {}
502
503 ArcVertexGenerator::ArcVertexGenerator(const Arc::Iteration& iteration,
504 Trigs&& trigs,
505 const Rect& oval_bounds,
506 Scalar half_width,
507 Cap cap)
508 : iteration_(iteration),
509 trigs_(std::move(trigs)),
510 oval_bounds_(oval_bounds),
511 use_center_(false),
512 half_width_(half_width),
513 cap_(cap),
514 supports_triangle_fans_(false) {}
515
516 PrimitiveType ArcVertexGenerator::GetTriangleType() const {
517 return (half_width_ < 0 && supports_triangle_fans_)
518 ? PrimitiveType::kTriangleFan
519 : PrimitiveType::kTriangleStrip;
520 }
521
522 size_t ArcVertexGenerator::GetVertexCount() const {
523 size_t count = iteration_.GetPointCount();
524 if (half_width_ > 0) {
525 FML_DCHECK(!use_center_);
526 FML_DCHECK(cap_ != Cap::kRound);
527 count *= 2;
528 if (cap_ == Cap::kSquare) {
529 count += 4;
530 }
531 } else if (supports_triangle_fans_) {
532 if (use_center_) {
533 count++;
534 }
535 } else {
536 // corrugated triangle fan
537 count += (count + 1) / 2;
538 }
539 return count;
540 }
541
542 void ArcVertexGenerator::GenerateVertices(
543 const TessellatedVertexProc& proc) const {
544 if (half_width_ > 0) {
545 FML_DCHECK(!use_center_);
546 Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_,
547 half_width_, cap_, proc);
548 } else if (supports_triangle_fans_) {
549 Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_,
550 use_center_, proc);
551 } else {
552 Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_,
553 use_center_, proc);
554 }
555 }
556
557 ArcVertexGenerator Tessellator::FilledArc(const Matrix& view_transform,
558 const Arc& arc,
559 bool supports_triangle_fans) {
560 size_t divisions = ComputeQuadrantDivisions(
561 view_transform.GetMaxBasisLengthXY() * arc.GetOvalSize().MaxDimension());
562
563 return ArcVertexGenerator(
564 arc.ComputeIterations(divisions), GetTrigsForDivisions(divisions),
565 arc.GetOvalBounds(), arc.IncludeCenter(), supports_triangle_fans);
566 };
567
568 ArcVertexGenerator Tessellator::StrokedArc(const Matrix& view_transform,
569 const Arc& arc,
570 Cap cap,
571 Scalar half_width) {
572 FML_DCHECK(half_width > 0);
573 FML_DCHECK(arc.IsPerfectCircle());
574 FML_DCHECK(!arc.IncludeCenter());
575 size_t divisions =
576 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() *
577 (arc.GetOvalSize().MaxDimension() + half_width));
578
579 return ArcVertexGenerator(arc.ComputeIterations(divisions),
580 GetTrigsForDivisions(divisions),
581 arc.GetOvalBounds(), half_width, cap);
582 }
583
584 EllipticalVertexGenerator Tessellator::RoundCapLine(
585 const Matrix& view_transform,
586 const Point& p0,
587 const Point& p1,
588 Scalar radius) {
589 auto along = p1 - p0;
590 auto length = along.GetLength();
591 if (length > kEhCloseEnough) {
592 auto divisions =
593 ComputeQuadrantDivisions(view_transform.GetMaxBasisLengthXY() * radius);
594 return EllipticalVertexGenerator(Tessellator::GenerateRoundCapLine,
595 GetTrigsForDivisions(divisions),
596 PrimitiveType::kTriangleStrip, 4,
597 {
598 .reference_centers = {p0, p1},
599 .radii = {radius, radius},
600 .half_width = -1.0f,
601 });
602 } else {
603 return FilledCircle(view_transform, p0, radius);
604 }
605 }
606
607 EllipticalVertexGenerator Tessellator::FilledEllipse(
608 const Matrix& view_transform,
609 const Rect& bounds) {
610 if (bounds.IsSquare()) {
611 return FilledCircle(view_transform, bounds.GetCenter(),
612 bounds.GetWidth() * 0.5f);
613 }
614 auto max_radius = bounds.GetSize().MaxDimension();
615 auto divisions = ComputeQuadrantDivisions(
616 view_transform.GetMaxBasisLengthXY() * max_radius);
617 auto center = bounds.GetCenter();
618 return EllipticalVertexGenerator(Tessellator::GenerateFilledEllipse,
619 GetTrigsForDivisions(divisions),
620 PrimitiveType::kTriangleStrip, 4,
621 {
622 .reference_centers = {center, center},
623 .radii = bounds.GetSize() * 0.5f,
624 .half_width = -1.0f,
625 });
626 }
627
628 EllipticalVertexGenerator Tessellator::FilledRoundRect(
629 const Matrix& view_transform,
630 const Rect& bounds,
631 const Size& radii) {
632 if (radii.width * 2 < bounds.GetWidth() ||
633 radii.height * 2 < bounds.GetHeight()) {
634 auto max_radius = radii.MaxDimension();
635 auto divisions = ComputeQuadrantDivisions(
636 view_transform.GetMaxBasisLengthXY() * max_radius);
637 auto upper_left = bounds.GetLeftTop() + radii;
638 auto lower_right = bounds.GetRightBottom() - radii;
639 return EllipticalVertexGenerator(Tessellator::GenerateFilledRoundRect,
640 GetTrigsForDivisions(divisions),
641 PrimitiveType::kTriangleStrip, 4,
642 {
643 .reference_centers =
644 {
645 upper_left,
646 lower_right,
647 },
648 .radii = radii,
649 .half_width = -1.0f,
650 });
651 } else {
652 return FilledEllipse(view_transform, bounds);
653 }
654 }
655
656 void Tessellator::GenerateFilledCircle(
657 const Trigs& trigs,
658 const EllipticalVertexGenerator::Data& data,
659 const TessellatedVertexProc& proc) {
660 auto center = data.reference_centers[0];
661 auto radius = data.radii.width;
662
663 FML_DCHECK(center == data.reference_centers[1]);
664 FML_DCHECK(radius == data.radii.height);
665 FML_DCHECK(data.half_width < 0);
666
667 // Quadrant 1 connecting with Quadrant 4:
668 for (auto& trig : trigs) {
669 auto offset = trig * radius;
670 proc({center.x - offset.x, center.y + offset.y});
671 proc({center.x - offset.x, center.y - offset.y});
672 }
673
674 // The second half of the circle should be iterated in reverse, but
675 // we can instead iterate forward and swap the x/y values of the
676 // offset as the angles should be symmetric and thus should generate
677 // symmetrically reversed trig vectors.
678 // Quadrant 2 connecting with Quadrant 3:
679 for (auto& trig : trigs) {
680 auto offset = trig * radius;
681 proc({center.x + offset.y, center.y + offset.x});
682 proc({center.x + offset.y, center.y - offset.x});
683 }
684 }
685
686 void Tessellator::GenerateStrokedCircle(
687 const Trigs& trigs,
688 const EllipticalVertexGenerator::Data& data,
689 const TessellatedVertexProc& proc) {
690 auto center = data.reference_centers[0];
691
692 FML_DCHECK(center == data.reference_centers[1]);
693 FML_DCHECK(data.radii.IsSquare());
694 FML_DCHECK(data.half_width > 0 && data.half_width < data.radii.width);
695
696 auto outer_radius = data.radii.width + data.half_width;
697 auto inner_radius = data.radii.width - data.half_width;
698
699 // Zig-zag back and forth between points on the outer circle and the
700 // inner circle. Both circles are evaluated at the same number of
701 // quadrant divisions so the points for a given division should match
702 // 1 for 1 other than their applied radius.
703
704 // Quadrant 1:
705 for (auto& trig : trigs) {
706 auto outer = trig * outer_radius;
707 auto inner = trig * inner_radius;
708 proc({center.x - outer.x, center.y - outer.y});
709 proc({center.x - inner.x, center.y - inner.y});
710 }
711
712 // The even quadrants of the circle should be iterated in reverse, but
713 // we can instead iterate forward and swap the x/y values of the
714 // offset as the angles should be symmetric and thus should generate
715 // symmetrically reversed trig vectors.
716 // Quadrant 2:
717 for (auto& trig : trigs) {
718 auto outer = trig * outer_radius;
719 auto inner = trig * inner_radius;
720 proc({center.x + outer.y, center.y - outer.x});
721 proc({center.x + inner.y, center.y - inner.x});
722 }
723
724 // Quadrant 3:
725 for (auto& trig : trigs) {
726 auto outer = trig * outer_radius;
727 auto inner = trig * inner_radius;
728 proc({center.x + outer.x, center.y + outer.y});
729 proc({center.x + inner.x, center.y + inner.y});
730 }
731
732 // Quadrant 4:
733 for (auto& trig : trigs) {
734 auto outer = trig * outer_radius;
735 auto inner = trig * inner_radius;
736 proc({center.x - outer.y, center.y + outer.x});
737 proc({center.x - inner.y, center.y + inner.x});
738 }
739 }
740
741 void Tessellator::GenerateFilledArcFan(const Trigs& trigs,
742 const Arc::Iteration& iteration,
743 const Rect& oval_bounds,
744 bool use_center,
745 const TessellatedVertexProc& proc) {
746 Point center = oval_bounds.GetCenter();
747 Size radii = oval_bounds.GetSize() * 0.5f;
748
749 if (use_center) {
750 proc(center);
751 }
752 proc(center + iteration.start * radii);
753 for (size_t i = 0; i < iteration.quadrant_count; i++) {
754 auto quadrant = iteration.quadrants[i];
755 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
756 proc(center + trigs[j] * quadrant.axis * radii);
757 }
758 }
759 proc(center + iteration.end * radii);
760 }
761
762 void Tessellator::GenerateFilledArcStrip(const Trigs& trigs,
763 const Arc::Iteration& iteration,
764 const Rect& oval_bounds,
765 bool use_center,
766 const TessellatedVertexProc& proc) {
767 Point center = oval_bounds.GetCenter();
768 Size radii = oval_bounds.GetSize() * 0.5f;
769
770 Point origin;
771 if (use_center) {
772 origin = center;
773 } else {
774 Point midpoint = (iteration.start + iteration.end) * 0.5f;
775 origin = center + midpoint * radii;
776 }
777
778 proc(origin);
779 proc(center + iteration.start * radii);
780 bool insert_origin = false;
781 for (size_t i = 0; i < iteration.quadrant_count; i++) {
782 auto quadrant = iteration.quadrants[i];
783 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
784 if (insert_origin) {
785 proc(origin);
786 }
787 insert_origin = !insert_origin;
788 proc(center + trigs[j] * quadrant.axis * radii);
789 }
790 }
791 if (insert_origin) {
792 proc(origin);
793 }
794 proc(center + iteration.end * radii);
795 }
796
797 void Tessellator::GenerateStrokedArc(const Trigs& trigs,
798 const Arc::Iteration& iteration,
799 const Rect& oval_bounds,
800 Scalar half_width,
801 Cap cap,
802 const TessellatedVertexProc& proc) {
803 Point center = oval_bounds.GetCenter();
804 Size base_radii = oval_bounds.GetSize() * 0.5f;
805 Size inner_radii = base_radii - Size(half_width, half_width);
806 Size outer_radii = base_radii + Size(half_width, half_width);
807
808 FML_DCHECK(cap != Cap::kRound);
809 if (cap == Cap::kSquare) {
810 Vector2 offset =
811 Vector2{iteration.start.y, -iteration.start.x} * half_width;
812 proc(center + iteration.start * inner_radii + offset);
813 proc(center + iteration.start * outer_radii + offset);
814 }
815 proc(center + iteration.start * inner_radii);
816 proc(center + iteration.start * outer_radii);
817 for (size_t i = 0; i < iteration.quadrant_count; i++) {
818 auto quadrant = iteration.quadrants[i];
819 for (size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
820 proc(center + trigs[j] * quadrant.axis * inner_radii);
821 proc(center + trigs[j] * quadrant.axis * outer_radii);
822 }
823 }
824 proc(center + iteration.end * inner_radii);
825 proc(center + iteration.end * outer_radii);
826 if (cap == Cap::kSquare) {
827 Vector2 offset = Vector2{-iteration.end.y, iteration.end.x} * half_width;
828 proc(center + iteration.end * inner_radii + offset);
829 proc(center + iteration.end * outer_radii + offset);
830 }
831 }
832
833 void Tessellator::GenerateRoundCapLine(
834 const Trigs& trigs,
835 const EllipticalVertexGenerator::Data& data,
836 const TessellatedVertexProc& proc) {
837 auto p0 = data.reference_centers[0];
838 auto p1 = data.reference_centers[1];
839 auto radius = data.radii.width;
840
841 FML_DCHECK(radius == data.radii.height);
842 FML_DCHECK(data.half_width < 0);
843
844 auto along = p1 - p0;
845 along *= radius / along.GetLength();
846 auto across = Point(-along.y, along.x);
847
848 for (auto& trig : trigs) {
849 auto relative_along = along * trig.cos;
850 auto relative_across = across * trig.sin;
851 proc(p0 - relative_along + relative_across);
852 proc(p0 - relative_along - relative_across);
853 }
854
855 // The second half of the round caps should be iterated in reverse, but
856 // we can instead iterate forward and swap the sin/cos values as they
857 // should be symmetric.
858 for (auto& trig : trigs) {
859 auto relative_along = along * trig.sin;
860 auto relative_across = across * trig.cos;
861 proc(p1 + relative_along + relative_across);
862 proc(p1 + relative_along - relative_across);
863 }
864 }
865
866 void Tessellator::GenerateFilledEllipse(
867 const Trigs& trigs,
868 const EllipticalVertexGenerator::Data& data,
869 const TessellatedVertexProc& proc) {
870 auto center = data.reference_centers[0];
871 auto radii = data.radii;
872
873 FML_DCHECK(center == data.reference_centers[1]);
874 FML_DCHECK(data.half_width < 0);
875
876 // Quadrant 1 connecting with Quadrant 4:
877 for (auto& trig : trigs) {
878 auto offset = trig * radii;
879 proc({center.x - offset.x, center.y + offset.y});
880 proc({center.x - offset.x, center.y - offset.y});
881 }
882
883 // The second half of the circle should be iterated in reverse, but
884 // we can instead iterate forward and swap the x/y values of the
885 // offset as the angles should be symmetric and thus should generate
886 // symmetrically reversed trig vectors.
887 // Quadrant 2 connecting with Quadrant 2:
888 for (auto& trig : trigs) {
889 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
890 proc({center.x + offset.x, center.y + offset.y});
891 proc({center.x + offset.x, center.y - offset.y});
892 }
893 }
894
895 void Tessellator::GenerateFilledRoundRect(
896 const Trigs& trigs,
897 const EllipticalVertexGenerator::Data& data,
898 const TessellatedVertexProc& proc) {
899 Scalar left = data.reference_centers[0].x;
900 Scalar top = data.reference_centers[0].y;
901 Scalar right = data.reference_centers[1].x;
902 Scalar bottom = data.reference_centers[1].y;
903 auto radii = data.radii;
904
905 FML_DCHECK(data.half_width < 0);
906
907 // Quadrant 1 connecting with Quadrant 4:
908 for (auto& trig : trigs) {
909 auto offset = trig * radii;
910 proc({left - offset.x, bottom + offset.y});
911 proc({left - offset.x, top - offset.y});
912 }
913
914 // The second half of the round rect should be iterated in reverse, but
915 // we can instead iterate forward and swap the x/y values of the
916 // offset as the angles should be symmetric and thus should generate
917 // symmetrically reversed trig vectors.
918 // Quadrant 2 connecting with Quadrant 2:
919 for (auto& trig : trigs) {
920 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
921 proc({right + offset.x, bottom + offset.y});
922 proc({right + offset.x, top - offset.y});
923 }
924 }
925
926 } // namespace impeller
use_center
bool use_center
Definition: aiks_dl_basic_unittests.cc:830
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::GetVertexCount
size_t GetVertexCount() const override
|VertexGenerator|
Definition: tessellator.cc:522
impeller::Tessellator::ArcVertexGenerator::GetTriangleType
PrimitiveType GetTriangleType() const override
|VertexGenerator|
Definition: tessellator.cc:516
impeller::Tessellator::ArcVertexGenerator::GenerateVertices
void GenerateVertices(const TessellatedVertexProc &proc) const override
|VertexGenerator|
Definition: tessellator.cc:542
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:412
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:310
impeller::Tessellator::stroke_points_
std::vector< Point > stroke_points_
Used for stroke path generation.
Definition: tessellator.h:383
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:584
impeller::Tessellator::GetStrokePointCache
std::vector< Point > & GetStrokePointCache()
Retrieve a pre-allocated arena of kPointArenaSize points.
Definition: tessellator.cc:306
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:628
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:264
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:314
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:453
impeller::Tessellator::Tessellator
Tessellator()
Definition: tessellator.cc:296
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:568
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:400
impeller::Tessellator::~Tessellator
virtual ~Tessellator()
impeller::Tessellator::point_buffer_
std::unique_ptr< std::vector< Point > > point_buffer_
Used for polyline generation.
Definition: tessellator.h:380
impeller::Tessellator::index_buffer_
std::unique_ptr< std::vector< uint16_t > > index_buffer_
Definition: tessellator.h:381
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:607
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:557
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:438
impeller::PrimitiveType
PrimitiveType
Decides how backend draws pixels based on input vertices.
Definition: formats.h:352
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::k16bit
@ k16bit
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:439
impeller::ArcVertexGenerator
Tessellator::ArcVertexGenerator ArcVertexGenerator
Definition: tessellator.cc:440
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:68