Flutter Engine
The Flutter Engine
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
6
7namespace impeller {
8
10 : point_buffer_(std::make_unique<std::vector<Point>>()),
11 index_buffer_(std::make_unique<std::vector<uint16_t>>()) {
12 point_buffer_->reserve(2048);
13 index_buffer_->reserve(2048);
14}
15
17
19 Scalar tolerance) {
21 point_buffer_->clear();
22 auto polyline =
23 path.CreatePolyline(tolerance, std::move(point_buffer_),
24 [this](Path::Polyline::PointBufferPtr point_buffer) {
25 point_buffer_ = std::move(point_buffer);
26 });
27 return polyline;
28}
29
31 HostBuffer& host_buffer,
32 Scalar tolerance) {
36
37 if (point_buffer_->empty()) {
38 return VertexBuffer{
39 .vertex_buffer = {},
40 .index_buffer = {},
41 .vertex_count = 0u,
42 .index_type = IndexType::k16bit,
43 };
44 }
45
46 BufferView vertex_buffer = host_buffer.Emplace(
47 point_buffer_->data(), sizeof(Point) * point_buffer_->size(),
48 alignof(Point));
49
50 BufferView index_buffer = host_buffer.Emplace(
51 index_buffer_->data(), sizeof(uint16_t) * index_buffer_->size(),
52 alignof(uint16_t));
53
54 return VertexBuffer{
55 .vertex_buffer = std::move(vertex_buffer),
56 .index_buffer = std::move(index_buffer),
57 .vertex_count = index_buffer_->size(),
58 .index_type = IndexType::k16bit,
59 };
60}
61
63 std::vector<Point>& point_buffer,
64 std::vector<uint16_t>& index_buffer,
65 Scalar tolerance) {
66 point_buffer.clear();
67 index_buffer.clear();
68
69 VertexWriter writer(point_buffer, index_buffer);
70
71 path.WritePolyline(tolerance, writer);
72}
73
74static constexpr int kPrecomputedDivisionCount = 1024;
76 // clang-format off
77 1, 2, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7,
78 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
79 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 13,
80 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14,
81 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16,
82 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18,
83 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19,
84 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
85 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
86 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23,
87 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24,
88 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25,
89 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26,
90 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27,
91 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28,
92 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
93 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
94 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
95 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
96 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32,
97 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33,
98 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
99 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
100 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35,
101 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36,
102 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
103 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
104 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38,
105 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
106 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
107 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40,
108 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
109 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41,
110 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
111 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
112 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43,
113 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
114 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44,
115 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
116 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
117 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
118 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
119 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47,
120 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
121 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48,
122 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
123 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49,
124 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
125 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50,
126 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
127 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51,
128 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
129 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52,
130 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
131 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53,
132 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
133 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54,
134 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
135 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
136 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
137 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
138 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
139 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
140 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57,
141 // clang-format on
142};
143
144static size_t ComputeQuadrantDivisions(Scalar pixel_radius) {
145 if (pixel_radius <= 0.0) {
146 return 1;
147 }
148 int radius_index = ceil(pixel_radius);
149 if (radius_index < kPrecomputedDivisionCount) {
150 return kPrecomputedDivisions[radius_index];
151 }
152
153 // For a circle with N divisions per quadrant, the maximum deviation of
154 // the polgyon approximation from the true circle will be at the center
155 // of the base of each triangular pie slice. We can compute that distance
156 // by finding the midpoint of the line of the first slice and compare
157 // its distance from the center of the circle to the radius. We will aim
158 // to have the length of that bisector to be within |kCircleTolerance|
159 // from the radius in pixels.
160 //
161 // Each vertex will appear at an angle of:
162 // theta(i) = (kPi / 2) * (i / N) // for i in [0..N]
163 // with each point falling at:
164 // point(i) = r * (cos(theta), sin(theta))
165 // If we consider the unit circle to simplify the calculations below then
166 // we need to scale the tolerance from its absolute quantity into a unit
167 // circle fraction:
168 // k = tolerance / radius
169 // Using this scaled tolerance below to avoid multiplying by the radius
170 // throughout all of the math, we have:
171 // first point = (1, 0) // theta(0) == 0
172 // theta = kPi / 2 / N // theta(1)
173 // second point = (cos(theta), sin(theta)) = (c, s)
174 // midpoint = (first + second) * 0.5 = ((1 + c)/2, s/2)
175 // |midpoint| = sqrt((1 + c)*(1 + c)/4 + s*s/4)
176 // = sqrt((1 + c + c + c*c + s*s) / 4)
177 // = sqrt((1 + 2c + 1) / 4)
178 // = sqrt((2 + 2c) / 4)
179 // = sqrt((1 + c) / 2)
180 // = cos(theta / 2) // using half-angle cosine formula
181 // error = 1 - |midpoint| = 1 - cos(theta / 2)
182 // cos(theta/2) = 1 - error
183 // theta/2 = acos(1 - error)
184 // kPi / 2 / N / 2 = acos(1 - error)
185 // kPi / 4 / acos(1 - error) = N
186 // Since we need error <= k, we want divisions >= N, so we use:
187 // N = ceil(kPi / 4 / acos(1 - k))
188 //
189 // Math is confirmed in https://math.stackexchange.com/a/4132095
190 // (keeping in mind that we are computing quarter circle divisions here)
191 // which also points out a performance optimization that is accurate
192 // to within an over-estimation of 1 division would be:
193 // N = ceil(kPi / 4 / sqrt(2 * k))
194 // Since we have precomputed the divisions for radii up to 1024, we can
195 // afford to be more accurate using the acos formula here for larger radii.
196 double k = Tessellator::kCircleTolerance / pixel_radius;
197 return ceil(kPiOver4 / std::acos(1 - k));
198}
199
200void Tessellator::Trigs::init(size_t divisions) {
201 if (!trigs_.empty()) {
202 return;
203 }
204
205 // Either not cached yet, or we are using the temp storage...
206 trigs_.reserve(divisions + 1);
207
208 double angle_scale = kPiOver2 / divisions;
209
210 trigs_.emplace_back(1.0, 0.0);
211 for (size_t i = 1; i < divisions; i++) {
212 trigs_.emplace_back(Radians(i * angle_scale));
213 }
214 trigs_.emplace_back(0.0, 1.0);
215}
216
217Tessellator::Trigs Tessellator::GetTrigsForDivisions(size_t divisions) {
218 return divisions < Tessellator::kCachedTrigCount
219 ? Trigs(precomputed_trigs_[divisions], divisions)
220 : Trigs(divisions);
221}
222
225
226EllipticalVertexGenerator::EllipticalVertexGenerator(
227 EllipticalVertexGenerator::GeneratorProc& generator,
228 Trigs&& trigs,
229 PrimitiveType triangle_type,
230 size_t vertices_per_trig,
231 Data&& data)
232 : impl_(generator),
233 trigs_(std::move(trigs)),
234 data_(data),
235 vertices_per_trig_(vertices_per_trig) {}
236
237EllipticalVertexGenerator Tessellator::FilledCircle(
238 const Matrix& view_transform,
239 const Point& center,
240 Scalar radius) {
241 auto divisions =
242 ComputeQuadrantDivisions(view_transform.GetMaxBasisLength() * radius);
243 return EllipticalVertexGenerator(Tessellator::GenerateFilledCircle,
244 GetTrigsForDivisions(divisions),
245 PrimitiveType::kTriangleStrip, 4,
246 {
247 .reference_centers = {center, center},
248 .radii = {radius, radius},
249 .half_width = -1.0f,
250 });
251}
252
253EllipticalVertexGenerator Tessellator::StrokedCircle(
254 const Matrix& view_transform,
255 const Point& center,
256 Scalar radius,
257 Scalar half_width) {
258 if (half_width > 0) {
259 auto divisions = ComputeQuadrantDivisions(
260 view_transform.GetMaxBasisLength() * radius + half_width);
261 return EllipticalVertexGenerator(Tessellator::GenerateStrokedCircle,
262 GetTrigsForDivisions(divisions),
263 PrimitiveType::kTriangleStrip, 8,
264 {
265 .reference_centers = {center, center},
266 .radii = {radius, radius},
267 .half_width = half_width,
268 });
269 } else {
270 return FilledCircle(view_transform, center, radius);
271 }
272}
273
274EllipticalVertexGenerator Tessellator::RoundCapLine(
275 const Matrix& view_transform,
276 const Point& p0,
277 const Point& p1,
278 Scalar radius) {
279 auto along = p1 - p0;
280 auto length = along.GetLength();
281 if (length > kEhCloseEnough) {
282 auto divisions =
283 ComputeQuadrantDivisions(view_transform.GetMaxBasisLength() * radius);
284 return EllipticalVertexGenerator(Tessellator::GenerateRoundCapLine,
285 GetTrigsForDivisions(divisions),
286 PrimitiveType::kTriangleStrip, 4,
287 {
288 .reference_centers = {p0, p1},
289 .radii = {radius, radius},
290 .half_width = -1.0f,
291 });
292 } else {
293 return FilledCircle(view_transform, p0, radius);
294 }
295}
296
297EllipticalVertexGenerator Tessellator::FilledEllipse(
298 const Matrix& view_transform,
299 const Rect& bounds) {
300 if (bounds.IsSquare()) {
301 return FilledCircle(view_transform, bounds.GetCenter(),
302 bounds.GetWidth() * 0.5f);
303 }
304 auto max_radius = bounds.GetSize().MaxDimension();
305 auto divisions =
306 ComputeQuadrantDivisions(view_transform.GetMaxBasisLength() * max_radius);
307 auto center = bounds.GetCenter();
308 return EllipticalVertexGenerator(Tessellator::GenerateFilledEllipse,
309 GetTrigsForDivisions(divisions),
310 PrimitiveType::kTriangleStrip, 4,
311 {
312 .reference_centers = {center, center},
313 .radii = bounds.GetSize() * 0.5f,
314 .half_width = -1.0f,
315 });
316}
317
318EllipticalVertexGenerator Tessellator::FilledRoundRect(
319 const Matrix& view_transform,
320 const Rect& bounds,
321 const Size& radii) {
322 if (radii.width * 2 < bounds.GetWidth() ||
323 radii.height * 2 < bounds.GetHeight()) {
324 auto max_radius = radii.MaxDimension();
325 auto divisions = ComputeQuadrantDivisions(
326 view_transform.GetMaxBasisLength() * max_radius);
327 auto upper_left = bounds.GetLeftTop() + radii;
328 auto lower_right = bounds.GetRightBottom() - radii;
329 return EllipticalVertexGenerator(Tessellator::GenerateFilledRoundRect,
330 GetTrigsForDivisions(divisions),
331 PrimitiveType::kTriangleStrip, 4,
332 {
333 .reference_centers =
334 {
335 upper_left,
336 lower_right,
337 },
338 .radii = radii,
339 .half_width = -1.0f,
340 });
341 } else {
342 return FilledEllipse(view_transform, bounds);
343 }
344}
345
346void Tessellator::GenerateFilledCircle(
347 const Trigs& trigs,
349 const TessellatedVertexProc& proc) {
350 auto center = data.reference_centers[0];
351 auto radius = data.radii.width;
352
353 FML_DCHECK(center == data.reference_centers[1]);
354 FML_DCHECK(radius == data.radii.height);
355 FML_DCHECK(data.half_width < 0);
356
357 // Quadrant 1 connecting with Quadrant 4:
358 for (auto& trig : trigs) {
359 auto offset = trig * radius;
360 proc({center.x - offset.x, center.y + offset.y});
361 proc({center.x - offset.x, center.y - offset.y});
362 }
363
364 // The second half of the circle should be iterated in reverse, but
365 // we can instead iterate forward and swap the x/y values of the
366 // offset as the angles should be symmetric and thus should generate
367 // symmetrically reversed trig vectors.
368 // Quadrant 2 connecting with Quadrant 2:
369 for (auto& trig : trigs) {
370 auto offset = trig * radius;
371 proc({center.x + offset.y, center.y + offset.x});
372 proc({center.x + offset.y, center.y - offset.x});
373 }
374}
375
376void Tessellator::GenerateStrokedCircle(
377 const Trigs& trigs,
379 const TessellatedVertexProc& proc) {
380 auto center = data.reference_centers[0];
381
382 FML_DCHECK(center == data.reference_centers[1]);
383 FML_DCHECK(data.radii.IsSquare());
384 FML_DCHECK(data.half_width > 0 && data.half_width < data.radii.width);
385
386 auto outer_radius = data.radii.width + data.half_width;
387 auto inner_radius = data.radii.width - data.half_width;
388
389 // Zig-zag back and forth between points on the outer circle and the
390 // inner circle. Both circles are evaluated at the same number of
391 // quadrant divisions so the points for a given division should match
392 // 1 for 1 other than their applied radius.
393
394 // Quadrant 1:
395 for (auto& trig : trigs) {
396 auto outer = trig * outer_radius;
397 auto inner = trig * inner_radius;
398 proc({center.x - outer.x, center.y - outer.y});
399 proc({center.x - inner.x, center.y - inner.y});
400 }
401
402 // The even quadrants of the circle should be iterated in reverse, but
403 // we can instead iterate forward and swap the x/y values of the
404 // offset as the angles should be symmetric and thus should generate
405 // symmetrically reversed trig vectors.
406 // Quadrant 2:
407 for (auto& trig : trigs) {
408 auto outer = trig * outer_radius;
409 auto inner = trig * inner_radius;
410 proc({center.x + outer.y, center.y - outer.x});
411 proc({center.x + inner.y, center.y - inner.x});
412 }
413
414 // Quadrant 3:
415 for (auto& trig : trigs) {
416 auto outer = trig * outer_radius;
417 auto inner = trig * inner_radius;
418 proc({center.x + outer.x, center.y + outer.y});
419 proc({center.x + inner.x, center.y + inner.y});
420 }
421
422 // Quadrant 4:
423 for (auto& trig : trigs) {
424 auto outer = trig * outer_radius;
425 auto inner = trig * inner_radius;
426 proc({center.x - outer.y, center.y + outer.x});
427 proc({center.x - inner.y, center.y + inner.x});
428 }
429}
430
431void Tessellator::GenerateRoundCapLine(
432 const Trigs& trigs,
434 const TessellatedVertexProc& proc) {
435 auto p0 = data.reference_centers[0];
436 auto p1 = data.reference_centers[1];
437 auto radius = data.radii.width;
438
439 FML_DCHECK(radius == data.radii.height);
440 FML_DCHECK(data.half_width < 0);
441
442 auto along = p1 - p0;
443 along *= radius / along.GetLength();
444 auto across = Point(-along.y, along.x);
445
446 for (auto& trig : trigs) {
447 auto relative_along = along * trig.cos;
448 auto relative_across = across * trig.sin;
449 proc(p0 - relative_along + relative_across);
450 proc(p0 - relative_along - relative_across);
451 }
452
453 // The second half of the round caps should be iterated in reverse, but
454 // we can instead iterate forward and swap the sin/cos values as they
455 // should be symmetric.
456 for (auto& trig : trigs) {
457 auto relative_along = along * trig.sin;
458 auto relative_across = across * trig.cos;
459 proc(p1 + relative_along + relative_across);
460 proc(p1 + relative_along - relative_across);
461 }
462}
463
464void Tessellator::GenerateFilledEllipse(
465 const Trigs& trigs,
467 const TessellatedVertexProc& proc) {
468 auto center = data.reference_centers[0];
469 auto radii = data.radii;
470
471 FML_DCHECK(center == data.reference_centers[1]);
472 FML_DCHECK(data.half_width < 0);
473
474 // Quadrant 1 connecting with Quadrant 4:
475 for (auto& trig : trigs) {
476 auto offset = trig * radii;
477 proc({center.x - offset.x, center.y + offset.y});
478 proc({center.x - offset.x, center.y - offset.y});
479 }
480
481 // The second half of the circle should be iterated in reverse, but
482 // we can instead iterate forward and swap the x/y values of the
483 // offset as the angles should be symmetric and thus should generate
484 // symmetrically reversed trig vectors.
485 // Quadrant 2 connecting with Quadrant 2:
486 for (auto& trig : trigs) {
487 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
488 proc({center.x + offset.x, center.y + offset.y});
489 proc({center.x + offset.x, center.y - offset.y});
490 }
491}
492
493void Tessellator::GenerateFilledRoundRect(
494 const Trigs& trigs,
496 const TessellatedVertexProc& proc) {
497 Scalar left = data.reference_centers[0].x;
498 Scalar top = data.reference_centers[0].y;
499 Scalar right = data.reference_centers[1].x;
500 Scalar bottom = data.reference_centers[1].y;
501 auto radii = data.radii;
502
503 FML_DCHECK(data.half_width < 0);
504
505 // Quadrant 1 connecting with Quadrant 4:
506 for (auto& trig : trigs) {
507 auto offset = trig * radii;
508 proc({left - offset.x, bottom + offset.y});
509 proc({left - offset.x, top - offset.y});
510 }
511
512 // The second half of the round rect should be iterated in reverse, but
513 // we can instead iterate forward and swap the x/y values of the
514 // offset as the angles should be symmetric and thus should generate
515 // symmetrically reversed trig vectors.
516 // Quadrant 2 connecting with Quadrant 2:
517 for (auto& trig : trigs) {
518 auto offset = Point(trig.sin * radii.width, trig.cos * radii.height);
519 proc({right + offset.x, bottom + offset.y});
520 proc({right + offset.x, top - offset.y});
521 }
522}
523
524} // namespace impeller
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
static SkScalar center(float pos0, float pos1)
BufferView Emplace(const BufferType &buffer, size_t alignment=0)
Emplace non-uniform data (like contiguous vertices) onto the host buffer.
Definition: host_buffer.h:95
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:52
The |VertexGenerator| implementation common to all shapes that are based on a polygonal representatio...
Definition: tessellator.h:121
VertexBuffer TessellateConvex(const Path &path, HostBuffer &host_buffer, Scalar tolerance)
Given a convex path, create a triangle fan structure.
Definition: tessellator.cc:30
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
Definition: tessellator.h:214
static void TessellateConvexInternal(const Path &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
Definition: tessellator.cc:62
Path::Polyline CreateTempPolyline(const Path &path, Scalar tolerance)
Create a temporary polyline. Only one per-process can exist at a time.
Definition: tessellator.cc:18
std::unique_ptr< std::vector< Point > > point_buffer_
Used for polyline generation.
Definition: tessellator.h:287
std::unique_ptr< std::vector< uint16_t > > index_buffer_
Definition: tessellator.h:288
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:78
An interface for generating a multi contour polyline as a triangle strip.
#define FML_DCHECK(condition)
Definition: logging.h:103
size_t length
static bool init()
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
struct PathData * Data(SkPath *path)
Definition: path_ops.cc:52
static size_t ComputeQuadrantDivisions(Scalar pixel_radius)
Definition: tessellator.cc:144
Tessellator::TessellatedVertexProc TessellatedVertexProc
Definition: tessellator.cc:223
PrimitiveType
Decides how backend draws pixels based on input vertices.
Definition: formats.h:352
float Scalar
Definition: scalar.h:18
constexpr float kEhCloseEnough
Definition: constants.h:56
static constexpr int kPrecomputedDivisionCount
Definition: tessellator.cc:74
TPoint< Scalar > Point
Definition: point.h:322
constexpr float kPiOver2
Definition: constants.h:32
Tessellator::EllipticalVertexGenerator EllipticalVertexGenerator
Definition: tessellator.cc:224
static int kPrecomputedDivisions[kPrecomputedDivisionCount]
Definition: tessellator.cc:75
constexpr float kPiOver4
Definition: constants.h:35
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition: SkVx.h:702
Definition: ref_ptr.h:256
const Path::Polyline & polyline
SeparatedVector2 offset
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
Scalar GetMaxBasisLength() const
Definition: matrix.cc:196
std::unique_ptr< std::vector< Point > > PointBufferPtr
Definition: path.h:98
constexpr Type MaxDimension() const
Definition: size.h:88
Type height
Definition: size.h:23
Type width
Definition: size.h:22
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63