13static constexpr int kPrecomputedDivisionCount = 1024;
15static int kPrecomputedDivisions[kPrecomputedDivisionCount] = {
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,
85 if (pixel_radius <= 0.0) {
88 int radius_index = ceil(pixel_radius);
89 if (radius_index < kPrecomputedDivisionCount) {
90 return kPrecomputedDivisions[radius_index];
140template <
typename IndexT>
153template <
typename IndexT>
157 IndexT* index_buffer)
158 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
160 ~FanPathVertexWriter() =
default;
162 size_t GetIndexCount()
const {
return index_count_; }
163 size_t GetPointCount()
const {
return count_; }
169 index_buffer_[index_count_++] =
static_cast<IndexT
>(-1);
173 index_buffer_[index_count_++] = count_;
174 point_buffer_[count_++] = point;
179 size_t index_count_ = 0;
181 IndexT* index_buffer_ =
nullptr;
186template <
typename IndexT>
190 IndexT* index_buffer)
191 : point_buffer_(point_buffer), index_buffer_(index_buffer) {}
193 ~StripPathVertexWriter() =
default;
195 size_t GetIndexCount()
const {
return index_count_; }
196 size_t GetPointCount()
const {
return count_; }
199 if (count_ == 0u || contour_start_ == count_ - 1) {
204 size_t start = contour_start_;
205 size_t end = count_ - 1;
207 index_buffer_[index_count_++] =
start;
209 size_t a =
start + 1;
212 index_buffer_[index_count_++] = a;
213 index_buffer_[index_count_++] =
b;
218 index_buffer_[index_count_++] = a;
221 contour_start_ = count_;
222 index_buffer_[index_count_++] =
static_cast<IndexT
>(-1);
226 point_buffer_[count_++] = point;
231 size_t index_count_ = 0;
232 size_t contour_start_ = 0;
234 IndexT* index_buffer_ =
nullptr;
238template <
typename IndexT>
241 explicit GLESPathVertexWriter(std::vector<impeller::Point>&
points,
242 std::vector<IndexT>& indices)
243 : points_(
points), indices_(indices) {}
245 ~GLESPathVertexWriter() =
default;
248 if (points_.size() == 0u || contour_start_ == points_.size() - 1) {
253 auto start = contour_start_;
254 auto end = points_.size() - 1;
259 if (points_[
end] == points_[start]) {
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);
273 if (previous_contour_odd_points_) {
274 indices_.push_back(start);
277 indices_.push_back(start);
280 size_t a =
start + 1;
283 indices_.push_back(a);
284 indices_.push_back(b);
289 indices_.push_back(a);
290 previous_contour_odd_points_ =
false;
292 previous_contour_odd_points_ =
true;
294 contour_start_ = points_.size();
297 void Write(
impeller::Point point)
override { points_.push_back(point); }
300 bool previous_contour_odd_points_ =
false;
301 size_t contour_start_ = 0u;
302 std::vector<impeller::Point>& points_;
303 std::vector<IndexT>& indices_;
306template <
typename IndexT>
308 std::vector<impeller::Point>& point_buffer,
309 std::vector<IndexT>& index_buffer,
311 point_buffer.clear();
312 index_buffer.clear();
314 GLESPathVertexWriter writer(point_buffer, index_buffer);
323template <
typename IndexT>
324class ConvexTessellatorImpl :
public Tessellator::ConvexTessellator {
326 ConvexTessellatorImpl() {
327 point_buffer_.reserve(2048);
328 index_buffer_.reserve(2048);
331 VertexBuffer TessellateConvex(
const PathSource& path,
332 HostBuffer& data_host_buffer,
333 HostBuffer& indexes_host_buffer,
335 bool supports_primitive_restart,
336 bool supports_triangle_fan)
override {
337 if (supports_primitive_restart) {
339 const auto [point_count, contour_count] =
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),
348 reinterpret_cast<Point*
>(point_buffer.GetBuffer()->OnGetContents() +
349 point_buffer.GetRange().offset);
351 reinterpret_cast<IndexT*
>(index_buffer.GetBuffer()->OnGetContents() +
352 index_buffer.GetRange().offset);
354 auto tessellate_path = [&](
auto& writer) {
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());
362 .vertex_buffer = std::move(point_buffer),
363 .index_buffer = std::move(index_buffer),
364 .vertex_count = writer.GetIndexCount(),
365 .index_type = IndexTypeFor<IndexT>(),
369 if (supports_triangle_fan) {
370 FanPathVertexWriter writer(points_ptr, indices_ptr);
371 return tessellate_path(writer);
373 StripPathVertexWriter writer(points_ptr, indices_ptr);
374 return tessellate_path(writer);
378 DoTessellateConvexInternal(path, point_buffer_, index_buffer_, tolerance);
380 if (point_buffer_.empty()) {
385 .index_type = IndexTypeFor<IndexT>(),
389 BufferView vertex_buffer = data_host_buffer.Emplace(
390 point_buffer_.data(),
sizeof(
Point) * point_buffer_.size(),
393 BufferView index_buffer = indexes_host_buffer.Emplace(
394 index_buffer_.data(),
sizeof(IndexT) * index_buffer_.size(),
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>(),
406 std::vector<Point> point_buffer_;
407 std::vector<IndexT> index_buffer_;
412 if (supports_32bit_primitive_indices) {
413 convex_tessellator_ = std::make_unique<ConvexTessellatorImpl<uint32_t>>();
415 convex_tessellator_ = std::make_unique<ConvexTessellatorImpl<uint16_t>>();
422 return stroke_points_;
426 return GetTrigsForDivisions(ComputeQuadrantDivisions(pixel_radius));
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);
441 std::vector<Point>& point_buffer,
442 std::vector<uint16_t>& index_buffer,
444 DoTessellateConvexInternal(path, point_buffer, index_buffer, tolerance);
450void Tessellator::Trigs::init(
size_t divisions) {
451 if (!trigs_.empty()) {
456 trigs_.reserve(divisions + 1);
458 double angle_scale =
kPiOver2 / divisions;
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));
464 trigs_.emplace_back(0.0, 1.0);
467Tessellator::Trigs Tessellator::GetTrigsForDivisions(
size_t divisions) {
468 return divisions < Tessellator::kCachedTrigCount
469 ? Trigs(precomputed_trigs_[divisions], divisions)
474using EllipticalVertexGenerator = Tessellator::EllipticalVertexGenerator;
475using ArcVertexGenerator = Tessellator::ArcVertexGenerator;
477EllipticalVertexGenerator::EllipticalVertexGenerator(
478 EllipticalVertexGenerator::GeneratorProc& generator,
481 size_t vertices_per_trig,
484 trigs_(
std::move(trigs)),
486 vertices_per_trig_(vertices_per_trig) {}
489 const Matrix& view_transform,
495 GetTrigsForDivisions(divisions),
498 .reference_centers = {center, center},
499 .radii = {radius, radius},
505 const Matrix& view_transform,
509 if (half_width > 0) {
510 auto divisions = ComputeQuadrantDivisions(
513 GetTrigsForDivisions(divisions),
516 .reference_centers = {center, center},
517 .radii = {radius, radius},
518 .half_width = half_width,
528 const Rect& oval_bounds,
530 bool supports_triangle_fans) {
539 const Rect& oval_bounds,
542 std::unique_ptr<Trigs> round_cap_trigs) {
544 false, half_width, cap, std::move(round_cap_trigs));
547ArcVertexGenerator::ArcVertexGenerator(
const Arc::Iteration& iteration,
549 const Rect& oval_bounds,
551 bool supports_triangle_fans,
554 std::unique_ptr<Trigs> round_cap_trigs)
555 : iteration_(iteration),
556 trigs_(
std::move(trigs)),
557 oval_bounds_(oval_bounds),
559 supports_triangle_fans_(supports_triangle_fans),
560 half_width_(half_width),
562 round_cap_trigs_(
std::move(round_cap_trigs)) {}
565 return (half_width_ < 0 && supports_triangle_fans_)
572 if (half_width_ > 0) {
582 count += round_cap_trigs_->size() * 4 - 4;
584 }
else if (supports_triangle_fans_) {
590 count += (count + 1) / 2;
597 if (half_width_ > 0) {
599 Tessellator::GenerateStrokedArc(trigs_, iteration_, oval_bounds_,
600 half_width_, cap_, round_cap_trigs_, proc);
601 }
else if (supports_triangle_fans_) {
602 Tessellator::GenerateFilledArcFan(trigs_, iteration_, oval_bounds_,
605 Tessellator::GenerateFilledArcStrip(trigs_, iteration_, oval_bounds_,
612 bool supports_triangle_fans) {
613 size_t divisions = ComputeQuadrantDivisions(
632 std::unique_ptr<Trigs> round_cap_trigs;
640 arc.
GetOvalBounds(), half_width, cap, std::move(round_cap_trigs));
644 const Matrix& view_transform,
648 auto along = p1 - p0;
654 GetTrigsForDivisions(divisions),
657 .reference_centers = {p0, p1},
658 .radii = {radius, radius},
667 const Matrix& view_transform,
668 const Rect& bounds) {
673 auto max_radius = bounds.
GetSize().MaxDimension();
674 auto divisions = ComputeQuadrantDivisions(
678 GetTrigsForDivisions(divisions),
681 .reference_centers = {center, center},
682 .radii = bounds.
GetSize() * 0.5f,
688 const Matrix& view_transform,
694 auto divisions = ComputeQuadrantDivisions(
696 auto upper_left = bounds.
GetLeftTop() + radii;
699 GetTrigsForDivisions(divisions),
715void Tessellator::GenerateFilledCircle(
717 const EllipticalVertexGenerator::Data&
data,
718 const TessellatedVertexProc& proc) {
719 auto center =
data.reference_centers[0];
720 auto radius =
data.radii.width;
727 for (
auto& trig : trigs) {
728 auto offset = trig * radius;
729 proc({center.x - offset.x, center.y + offset.y});
730 proc({center.x - offset.x, center.y - offset.y});
738 for (
auto& trig : trigs) {
739 auto offset = trig * radius;
745void Tessellator::GenerateStrokedCircle(
747 const EllipticalVertexGenerator::Data&
data,
755 auto outer_radius =
data.radii.width +
data.half_width;
756 auto inner_radius =
data.radii.width -
data.half_width;
764 for (
auto& trig : trigs) {
765 auto outer = trig * outer_radius;
766 auto inner = trig * inner_radius;
776 for (
auto& trig : trigs) {
777 auto outer = trig * outer_radius;
778 auto inner = trig * inner_radius;
784 for (
auto& trig : trigs) {
785 auto outer = trig * outer_radius;
786 auto inner = trig * inner_radius;
792 for (
auto& trig : trigs) {
793 auto outer = trig * outer_radius;
794 auto inner = trig * inner_radius;
800void Tessellator::GenerateFilledArcFan(
const Trigs& trigs,
801 const Arc::Iteration& iteration,
802 const Rect& oval_bounds,
806 Size radii = oval_bounds.GetSize() * 0.5f;
811 proc(center + iteration.start * radii);
812 for (
size_t i = 0;
i < iteration.quadrant_count;
i++) {
813 auto quadrant = iteration.quadrants[
i];
814 for (
size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
815 proc(center + trigs[j] * quadrant.axis * radii);
818 proc(center + iteration.end * radii);
821void Tessellator::GenerateFilledArcStrip(
const Trigs& trigs,
822 const Arc::Iteration& iteration,
823 const Rect& oval_bounds,
827 Size radii = oval_bounds.GetSize() * 0.5f;
833 Point midpoint = (iteration.start + iteration.end) * 0.5f;
834 origin =
center + midpoint * radii;
838 proc(center + iteration.start * radii);
839 bool insert_origin =
false;
840 for (
size_t i = 0;
i < iteration.quadrant_count;
i++) {
841 auto quadrant = iteration.quadrants[
i];
842 for (
size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
846 insert_origin = !insert_origin;
847 proc(center + trigs[j] * quadrant.axis * radii);
853 proc(center + iteration.end * radii);
856void Tessellator::GenerateStrokedArc(
858 const Arc::Iteration& iteration,
859 const Rect& oval_bounds,
862 const std::unique_ptr<Trigs>& round_cap_trigs,
865 Size base_radii = oval_bounds.GetSize() * 0.5f;
866 Size inner_radii = base_radii -
Size(half_width, half_width);
867 Size outer_radii = base_radii +
Size(half_width, half_width);
872 proc(center + iteration.start * inner_radii);
873 proc(center + iteration.start * outer_radii);
877 Tessellator::GenerateStartRoundCap(center + iteration.start * base_radii,
878 -iteration.start * half_width,
879 *round_cap_trigs, proc);
883 Vector2{iteration.start.
y, -iteration.start.x} * half_width;
884 proc(center + iteration.start * inner_radii + offset);
885 proc(center + iteration.start * outer_radii + offset);
886 proc(center + iteration.start * inner_radii);
887 proc(center + iteration.start * outer_radii);
891 for (
size_t i = 0;
i < iteration.quadrant_count;
i++) {
892 auto quadrant = iteration.quadrants[
i];
893 for (
size_t j = quadrant.start_index; j < quadrant.end_index; j++) {
894 proc(center + trigs[j] * quadrant.axis * inner_radii);
895 proc(center + trigs[j] * quadrant.axis * outer_radii);
902 proc(center + iteration.end * inner_radii);
903 proc(center + iteration.end * outer_radii);
907 Tessellator::GenerateEndRoundCap(center + iteration.end * base_radii,
908 -iteration.end * half_width,
909 *round_cap_trigs, proc);
912 Vector2 offset =
Vector2{-iteration.end.
y, iteration.end.x} * half_width;
913 proc(center + iteration.end * inner_radii);
914 proc(center + iteration.end * outer_radii);
915 proc(center + iteration.end * inner_radii + offset);
916 proc(center + iteration.end * outer_radii + offset);
921void Tessellator::GenerateRoundCapLine(
923 const EllipticalVertexGenerator::Data&
data,
925 auto p0 =
data.reference_centers[0];
926 auto p1 =
data.reference_centers[1];
927 auto radius =
data.radii.width;
932 auto along = p1 - p0;
933 along *= radius / along.GetLength();
934 auto across =
Point(-along.y, along.x);
936 Tessellator::GenerateStartRoundCap(p0, across, trigs, proc);
937 Tessellator::GenerateEndRoundCap(p1, across, trigs, proc);
940void Tessellator::GenerateFilledEllipse(
942 const EllipticalVertexGenerator::Data&
data,
945 auto radii =
data.radii;
951 for (
auto& trig : trigs) {
952 auto offset = trig * radii;
962 for (
auto& trig : trigs) {
963 auto offset =
Point(trig.sin * radii.width, trig.cos * radii.height);
969void Tessellator::GenerateFilledRoundRect(
971 const EllipticalVertexGenerator::Data&
data,
977 auto radii =
data.radii;
982 for (
auto& trig : trigs) {
983 auto offset = trig * radii;
984 proc({
left - offset.x, bottom + offset.y});
985 proc({
left - offset.x, top - offset.y});
993 for (
auto& trig : trigs) {
994 auto offset =
Point(trig.sin * radii.width, trig.cos * radii.height);
995 proc({
right + offset.x, bottom + offset.y});
996 proc({
right + offset.x, top - offset.y});
1000void Tessellator::GenerateStartRoundCap(
const Point& p,
1004 Point along(perpendicular.y, -perpendicular.x);
1006 for (
auto& trig : trigs) {
1007 auto relative_along = along * trig.cos;
1008 auto relative_across = perpendicular * trig.sin;
1009 proc(p - relative_along + relative_across);
1010 proc(p - relative_along - relative_across);
1014void Tessellator::GenerateEndRoundCap(
const Point& p,
1018 Point along(perpendicular.y, -perpendicular.x);
1023 for (
auto& trig : trigs) {
1024 auto relative_along = along * trig.sin;
1025 auto relative_across = perpendicular * trig.cos;
1026 proc(p + relative_along + relative_across);
1027 proc(p + relative_along - relative_across);
An interface for generating a multi contour polyline as a triangle strip.
virtual void EndContour()=0
static void PathToFilledVertices(const PathSource &source, VertexWriter &writer, Scalar scale)
static std::pair< size_t, size_t > CountFillStorage(const PathSource &source, Scalar scale)
The |VertexGenerator| implementation common to all shapes that are based on a polygonal representatio...
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)
size_t GetVertexCount() const override
|VertexGenerator|
PrimitiveType GetTriangleType() const override
|VertexGenerator|
static ArcVertexGenerator MakeFilled(const Arc::Iteration &iteration, Trigs &&trigs, const Rect &oval_bounds, bool use_center, bool supports_triangle_fans)
void GenerateVertices(const TessellatedVertexProc &proc) const override
|VertexGenerator|
The |VertexGenerator| implementation common to all shapes that are based on a polygonal representatio...
Trigs(Scalar pixel_radius)
A utility that generates triangles of the specified fill type given a polyline. This happens on the C...
Trigs GetTrigsForDeviceRadius(Scalar pixel_radius)
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...
std::vector< Point > & GetStrokePointCache()
Retrieve a pre-allocated arena of kPointArenaSize points.
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 ...
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
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.
EllipticalVertexGenerator FilledCircle(const Matrix &view_transform, const Point ¢er, Scalar radius)
Create a |VertexGenerator| that can produce vertices for a filled circle of the given radius around t...
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...
static void TessellateConvexInternal(const PathSource &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
EllipticalVertexGenerator StrokedCircle(const Matrix &view_transform, const Point ¢er, Scalar radius, Scalar half_width)
Create a |VertexGenerator| that can produce vertices for a stroked circle of the given radius and hal...
EllipticalVertexGenerator FilledEllipse(const Matrix &view_transform, const Rect &bounds)
Create a |VertexGenerator| that can produce vertices for a filled ellipse inscribed within the given ...
Tessellator(bool supports_32bit_primitive_indices=true)
std::function< void(const Point &p)> TessellatedVertexProc
A callback function for a |VertexGenerator| to deliver the vertices it computes as |Point| objects.
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...
#define FML_DCHECK(condition)
PrimitiveType
Decides how backend draws pixels based on input vertices.
constexpr float kEhCloseEnough
Cap
An enum that describes ways to decorate the end of a path contour.
static constexpr size_t kPointArenaSize
The size of the point arena buffer stored on the tessellator.
size_t GetPointCount() const
Iteration ComputeIterations(size_t step_count, bool simplify_360=true) const
constexpr bool IncludeCenter() const
const Size GetOvalSize() const
Returns the size of the oval bounds.
constexpr bool IsPerfectCircle() const
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
A 4x4 matrix using column-major storage.
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
constexpr Type GetLength() const
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...
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr TPoint< T > GetLeftTop() const
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
constexpr TPoint< T > GetRightBottom() const
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr Type MaxDimension() const
std::vector< Point > points
std::shared_ptr< const fml::Mapping > data