1 | /*! |
2 | * \file partitioned_tessellated_path.cpp |
3 | * \brief file partitioned_tessellated_path.cpp |
4 | * |
5 | * Copyright 2019 by Intel. |
6 | * |
7 | * Contact: kevin.rogovin@gmail.com |
8 | * |
9 | * This Source Code Form is subject to the |
10 | * terms of the Mozilla Public License, v. 2.0. |
11 | * If a copy of the MPL was not distributed with |
12 | * this file, You can obtain one at |
13 | * http://mozilla.org/MPL/2.0/. |
14 | * |
15 | * \author Kevin Rogovin <kevin.rogovin@gmail.com> |
16 | * |
17 | */ |
18 | |
19 | #include <vector> |
20 | #include <complex> |
21 | #include <algorithm> |
22 | |
23 | #include <fastuidraw/tessellated_path.hpp> |
24 | #include <fastuidraw/path.hpp> |
25 | #include <fastuidraw/partitioned_tessellated_path.hpp> |
26 | |
27 | #include <private/util_private.hpp> |
28 | #include <private/util_private_ostream.hpp> |
29 | #include <private/bounding_box.hpp> |
30 | #include <private/path_util_private.hpp> |
31 | #include <private/clip.hpp> |
32 | |
33 | namespace |
34 | { |
35 | enum |
36 | { |
37 | splitting_threshhold = 50, |
38 | max_recursion_depth = 10 |
39 | }; |
40 | |
41 | class SubsetBuilder:fastuidraw::noncopyable |
42 | { |
43 | public: |
44 | typedef fastuidraw::TessellatedPath::segment segment; |
45 | |
46 | class PerChain |
47 | { |
48 | public: |
49 | explicit |
50 | PerChain(unsigned int start): |
51 | m_range(start, start), |
52 | m_has_before_first(false) |
53 | {} |
54 | |
55 | PerChain(unsigned int start, |
56 | const segment &before_first): |
57 | m_range(start, start), |
58 | m_before_first(before_first), |
59 | m_has_before_first(true) |
60 | {} |
61 | |
62 | fastuidraw::range_type<unsigned int> m_range; |
63 | segment m_before_first; |
64 | bool m_has_before_first; |
65 | }; |
66 | |
67 | SubsetBuilder(void): |
68 | m_has_arcs(false) |
69 | {} |
70 | |
71 | const segment* |
72 | add_segment(const segment &S) |
73 | { |
74 | FASTUIDRAWassert(!m_chains.empty()); |
75 | m_segments.push_back(S); |
76 | m_has_arcs = m_has_arcs || (S.m_type == fastuidraw::TessellatedPath::arc_segment); |
77 | m_bbox.union_point(S.m_start_pt); |
78 | m_bbox.union_point(S.m_end_pt); |
79 | ++m_chains.back().m_range.m_end; |
80 | |
81 | return &m_segments.back(); |
82 | } |
83 | |
84 | void |
85 | start_chain(const segment *before_chain) |
86 | { |
87 | if (before_chain) |
88 | { |
89 | m_chains.push_back(PerChain(m_segments.size(), *before_chain)); |
90 | } |
91 | else |
92 | { |
93 | m_chains.push_back(PerChain(m_segments.size())); |
94 | } |
95 | } |
96 | |
97 | void |
98 | process_chain(const fastuidraw::TessellatedPath::segment_chain &chain) |
99 | { |
100 | start_chain(chain.m_prev_to_start); |
101 | for (const auto &S : chain.m_segments) |
102 | { |
103 | add_segment(S); |
104 | } |
105 | } |
106 | |
107 | void |
108 | process_chains(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains) |
109 | { |
110 | for (const auto &a : chains) |
111 | { |
112 | process_chain(a); |
113 | } |
114 | } |
115 | |
116 | void |
117 | process_caps(fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps) |
118 | { |
119 | m_caps.reserve(m_caps.size() + caps.size()); |
120 | for (const auto &C : caps) |
121 | { |
122 | m_caps.push_back(C); |
123 | } |
124 | } |
125 | |
126 | void |
127 | process_joins(fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins) |
128 | { |
129 | m_joins.reserve(m_joins.size() + joins.size()); |
130 | for (const auto &J : joins) |
131 | { |
132 | m_joins.push_back(J); |
133 | m_join_bbox.union_point(J.m_position); |
134 | } |
135 | } |
136 | |
137 | fastuidraw::BoundingBox<float> m_bbox; |
138 | fastuidraw::BoundingBox<float> m_join_bbox; |
139 | std::vector<segment> m_segments; |
140 | std::vector<PerChain> m_chains; |
141 | std::vector<fastuidraw::TessellatedPath::join> m_joins; |
142 | std::vector<fastuidraw::TessellatedPath::cap> m_caps; |
143 | bool m_has_arcs; |
144 | }; |
145 | |
146 | class ScratchSpace |
147 | { |
148 | public: |
149 | std::vector<fastuidraw::vec3> m_adjusted_clip_eqs; |
150 | fastuidraw::c_array<const fastuidraw::vec2> m_clipped_rect; |
151 | fastuidraw::vecN<std::vector<fastuidraw::vec2>, 2> m_clip_scratch_vec2s; |
152 | }; |
153 | |
154 | class SubsetSelectionPrivate:fastuidraw::noncopyable |
155 | { |
156 | public: |
157 | // data from selection |
158 | fastuidraw::reference_counted_ptr<const fastuidraw::PartitionedTessellatedPath> m_source; |
159 | std::vector<unsigned int> m_subset_ids; |
160 | std::vector<unsigned int> m_join_subset_ids_backing; |
161 | fastuidraw::c_array<const unsigned int> m_join_subset_ids; |
162 | |
163 | // work-room for selection |
164 | ScratchSpace m_scratch; |
165 | }; |
166 | |
167 | class SubsetPrivate:fastuidraw::noncopyable |
168 | { |
169 | public: |
170 | typedef fastuidraw::TessellatedPath::segment segment; |
171 | typedef fastuidraw::TessellatedPath::join join; |
172 | typedef fastuidraw::TessellatedPath::cap cap; |
173 | typedef fastuidraw::TessellatedPath::segment_chain segment_chain; |
174 | |
175 | ~SubsetPrivate(); |
176 | |
177 | static |
178 | SubsetPrivate* |
179 | create(SubsetBuilder &builder, |
180 | std::vector<SubsetPrivate*> &out_values); |
181 | |
182 | const fastuidraw::Rect& |
183 | bounding_box(void) const |
184 | { |
185 | return m_bounding_box.as_rect(); |
186 | } |
187 | |
188 | bool |
189 | has_children(void) const |
190 | { |
191 | return m_children[0] != nullptr; |
192 | } |
193 | |
194 | SubsetPrivate* |
195 | child(unsigned int I) |
196 | { |
197 | return m_children[I]; |
198 | } |
199 | |
200 | unsigned int |
201 | ID(void) const |
202 | { |
203 | return m_ID; |
204 | } |
205 | |
206 | fastuidraw::c_array<const segment_chain> |
207 | segment_chains(void) const |
208 | { |
209 | return fastuidraw::make_c_array(m_chains); |
210 | } |
211 | |
212 | fastuidraw::c_array<const join> |
213 | joins(void) const |
214 | { |
215 | return fastuidraw::make_c_array(m_joins); |
216 | } |
217 | |
218 | fastuidraw::c_array<const cap> |
219 | caps(void) const |
220 | { |
221 | return fastuidraw::make_c_array(m_caps); |
222 | } |
223 | |
224 | void |
225 | select_subsets(bool miter_hunting, |
226 | ScratchSpace &scratch, |
227 | fastuidraw::c_array<const fastuidraw::vec3> clip_equations, |
228 | const fastuidraw::float3x3 &clip_matrix_local, |
229 | const fastuidraw::vec2 &one_pixel_width, |
230 | fastuidraw::c_array<const float> geometry_inflation, |
231 | std::vector<unsigned int> &dst); |
232 | |
233 | private: |
234 | /* creation will steal the vector<> values of |
235 | * the passed SubsetBuilder |
236 | */ |
237 | SubsetPrivate(int recursion_depth, SubsetBuilder &builder, |
238 | std::vector<SubsetPrivate*> &out_values); |
239 | |
240 | void |
241 | make_children(int recursion_depth, std::vector<SubsetPrivate*> &out_values); |
242 | |
243 | int |
244 | choose_splitting_coordinate(float &split_value); |
245 | |
246 | static |
247 | void |
248 | process_chain(int splitting_coordinate, float splitting_value, |
249 | const segment_chain &chain, |
250 | SubsetBuilder *before_split, SubsetBuilder *after_split); |
251 | |
252 | bool //returns true if this element is added. |
253 | select_subsets_implement(bool miter_hunting, |
254 | ScratchSpace &scratch, |
255 | float item_space_additional_room, |
256 | std::vector<unsigned int> &dst); |
257 | |
258 | unsigned int m_ID; |
259 | fastuidraw::vecN<SubsetPrivate*, 2> m_children; |
260 | std::vector<segment> m_segments; |
261 | std::vector<segment_chain> m_chains; |
262 | std::vector<segment> m_prev_start_segments; |
263 | std::vector<join> m_joins; |
264 | std::vector<cap> m_caps; |
265 | fastuidraw::BoundingBox<float> m_bounding_box; |
266 | fastuidraw::BoundingBox<float> m_join_bounding_box; |
267 | }; |
268 | |
269 | class PartitionedTessellatedPathPrivate:fastuidraw::noncopyable |
270 | { |
271 | public: |
272 | explicit |
273 | PartitionedTessellatedPathPrivate(const fastuidraw::TessellatedPath &path); |
274 | |
275 | PartitionedTessellatedPathPrivate(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains, |
276 | fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins, |
277 | fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps); |
278 | |
279 | ~PartitionedTessellatedPathPrivate(); |
280 | |
281 | bool m_has_arcs; |
282 | SubsetPrivate *m_root_subset; |
283 | std::vector<SubsetPrivate*> m_subsets; |
284 | }; |
285 | } |
286 | |
287 | ///////////////////////////////////// |
288 | // SubsetPrivate methods |
289 | SubsetPrivate* |
290 | SubsetPrivate:: |
291 | create(SubsetBuilder &builder, |
292 | std::vector<SubsetPrivate*> &out_values) |
293 | { |
294 | SubsetPrivate *root; |
295 | |
296 | root = FASTUIDRAWnew SubsetPrivate(0, builder, out_values); |
297 | return root; |
298 | } |
299 | |
300 | SubsetPrivate:: |
301 | SubsetPrivate(int recursion_depth, SubsetBuilder &builder, |
302 | std::vector<SubsetPrivate*> &out_values): |
303 | m_ID(out_values.size()), |
304 | m_children(nullptr, nullptr), |
305 | m_bounding_box(builder.m_bbox), |
306 | m_join_bounding_box(builder.m_join_bbox) |
307 | { |
308 | out_values.push_back(this); |
309 | m_segments.swap(builder.m_segments); |
310 | m_joins.swap(builder.m_joins); |
311 | m_caps.swap(builder.m_caps); |
312 | |
313 | /* reserve before hand so that addresses of |
314 | * values in m_prev_start_segments do not |
315 | * change. |
316 | */ |
317 | m_chains.reserve(builder.m_chains.size()); |
318 | m_prev_start_segments.reserve(builder.m_chains.size()); |
319 | |
320 | fastuidraw::c_array<const segment> segs(fastuidraw::make_c_array(m_segments)); |
321 | for (const SubsetBuilder::PerChain &R : builder.m_chains) |
322 | { |
323 | fastuidraw::c_array<const segment> sub_segs; |
324 | sub_segs = segs.sub_array(R.m_range); |
325 | if (!sub_segs.empty()) |
326 | { |
327 | segment_chain V; |
328 | |
329 | if (R.m_has_before_first) |
330 | { |
331 | m_prev_start_segments.push_back(R.m_before_first); |
332 | V.m_prev_to_start = &m_prev_start_segments.back(); |
333 | } |
334 | else |
335 | { |
336 | V.m_prev_to_start = nullptr; |
337 | } |
338 | V.m_segments = sub_segs; |
339 | m_chains.push_back(V); |
340 | } |
341 | } |
342 | |
343 | if (m_segments.size() >= splitting_threshhold |
344 | && recursion_depth <= max_recursion_depth) |
345 | { |
346 | make_children(recursion_depth, out_values); |
347 | } |
348 | } |
349 | |
350 | SubsetPrivate:: |
351 | ~SubsetPrivate() |
352 | { |
353 | if (m_children[0]) |
354 | { |
355 | FASTUIDRAWassert(m_children[1]); |
356 | |
357 | FASTUIDRAWdelete(m_children[0]); |
358 | FASTUIDRAWdelete(m_children[1]); |
359 | } |
360 | } |
361 | |
362 | void |
363 | SubsetPrivate:: |
364 | process_chain(int splitting_coordinate, float splitting_value, |
365 | const segment_chain &chain, |
366 | SubsetBuilder *before_split, SubsetBuilder *after_split) |
367 | { |
368 | using namespace fastuidraw; |
369 | |
370 | SubsetBuilder *last_added_to(nullptr); |
371 | const segment *prev_segment(chain.m_prev_to_start); |
372 | |
373 | for (const segment &S : chain.m_segments) |
374 | { |
375 | enum TessellatedPath::split_t split; |
376 | segment before, after; |
377 | |
378 | split = S.compute_split(splitting_value, |
379 | &before, &after, |
380 | splitting_coordinate); |
381 | |
382 | switch (split) |
383 | { |
384 | case TessellatedPath::segment_completey_before_split: |
385 | { |
386 | if (last_added_to != before_split) |
387 | { |
388 | before_split->start_chain(prev_segment); |
389 | last_added_to = before_split; |
390 | } |
391 | prev_segment = before_split->add_segment(S); |
392 | } |
393 | break; |
394 | |
395 | case TessellatedPath::segment_completey_after_split: |
396 | { |
397 | if (last_added_to != after_split) |
398 | { |
399 | after_split->start_chain(prev_segment); |
400 | last_added_to = after_split; |
401 | } |
402 | prev_segment = after_split->add_segment(S); |
403 | } |
404 | break; |
405 | |
406 | case TessellatedPath::segment_split_start_before: |
407 | { |
408 | if (last_added_to != before_split) |
409 | { |
410 | before_split->start_chain(prev_segment); |
411 | } |
412 | prev_segment = before_split->add_segment(before); |
413 | after_split->start_chain(prev_segment); |
414 | prev_segment = after_split->add_segment(after); |
415 | last_added_to = after_split; |
416 | } |
417 | break; |
418 | |
419 | case TessellatedPath::segment_split_start_after: |
420 | { |
421 | if (last_added_to != after_split) |
422 | { |
423 | after_split->start_chain(prev_segment); |
424 | } |
425 | prev_segment = after_split->add_segment(after); |
426 | before_split->start_chain(prev_segment); |
427 | prev_segment = before_split->add_segment(before); |
428 | last_added_to = before_split; |
429 | } |
430 | break; |
431 | } // switch |
432 | |
433 | } //for (const segment &S : chain) |
434 | } |
435 | |
436 | int |
437 | SubsetPrivate:: |
438 | choose_splitting_coordinate(float &split_value) |
439 | { |
440 | using namespace fastuidraw; |
441 | |
442 | vecN<float, 2> split_values; |
443 | vecN<unsigned int, 2> split_counters(0, 0); |
444 | vecN<uvec2, 2> child_counters(uvec2(0, 0), uvec2(0, 0)); |
445 | std::vector<float> qs; |
446 | unsigned int data_size(m_segments.size()); |
447 | |
448 | qs.reserve(m_segments.size()); |
449 | /* For the most balanced split, we take the median |
450 | * of the start and end points of the segments. |
451 | */ |
452 | for (int c = 0; c < 2; ++c) |
453 | { |
454 | qs.clear(); |
455 | qs.push_back(m_bounding_box.min_point()[c]); |
456 | qs.push_back(m_bounding_box.max_point()[c]); |
457 | for(const segment &seg : m_segments) |
458 | { |
459 | qs.push_back(seg.m_start_pt[c]); |
460 | } |
461 | qs.push_back(m_segments.back().m_end_pt[c]); |
462 | std::sort(qs.begin(), qs.end()); |
463 | split_values[c] = qs[qs.size() / 2]; |
464 | |
465 | for(const segment &seg : m_segments) |
466 | { |
467 | bool sA, sB; |
468 | sA = (seg.m_start_pt[c] < split_values[c]); |
469 | sB = (seg.m_end_pt[c] < split_values[c]); |
470 | if (sA != sB) |
471 | { |
472 | ++split_counters[c]; |
473 | ++child_counters[c][0]; |
474 | ++child_counters[c][1]; |
475 | } |
476 | else |
477 | { |
478 | ++child_counters[c][sA]; |
479 | } |
480 | } |
481 | } |
482 | |
483 | /* choose the coordiante that splits the smallest number of edges */ |
484 | int canidate; |
485 | canidate = (split_counters[0] < split_counters[1]) ? 0 : 1; |
486 | |
487 | /* we require that both sides will have fewer edges |
488 | * than the parent size. |
489 | */ |
490 | if (child_counters[canidate][0] < data_size |
491 | && child_counters[canidate][1] < data_size) |
492 | { |
493 | split_value = split_values[canidate]; |
494 | return canidate; |
495 | } |
496 | else |
497 | { |
498 | return -1; |
499 | } |
500 | } |
501 | |
502 | void |
503 | SubsetPrivate:: |
504 | make_children(int recursion_depth, std::vector<SubsetPrivate*> &out_values) |
505 | { |
506 | int splitting_coordinate(-1); |
507 | float splitting_value; |
508 | |
509 | /* step 1: find a good splitting coordinate and splitting value */ |
510 | splitting_coordinate = choose_splitting_coordinate(splitting_value); |
511 | if (splitting_coordinate == -1) |
512 | { |
513 | return; |
514 | } |
515 | |
516 | /* step 2: split each chain */ |
517 | SubsetBuilder before_split, after_split; |
518 | |
519 | for (const auto &chain : m_chains) |
520 | { |
521 | process_chain(splitting_coordinate, splitting_value, chain, |
522 | &before_split, &after_split); |
523 | } |
524 | |
525 | /* step 3: split the joins */ |
526 | for (const auto &join : m_joins) |
527 | { |
528 | SubsetBuilder *dst; |
529 | if (join.m_position[splitting_coordinate] > splitting_value) |
530 | { |
531 | dst = &after_split; |
532 | } |
533 | else |
534 | { |
535 | dst = &before_split; |
536 | } |
537 | dst->m_joins.push_back(join); |
538 | dst->m_join_bbox.union_point(join.m_position); |
539 | } |
540 | |
541 | /* step 4: split the caps */ |
542 | for (const auto &cap : m_caps) |
543 | { |
544 | if (cap.m_position[splitting_coordinate] > splitting_value) |
545 | { |
546 | after_split.m_caps.push_back(cap); |
547 | } |
548 | else |
549 | { |
550 | before_split.m_caps.push_back(cap); |
551 | } |
552 | } |
553 | |
554 | m_children[0]= FASTUIDRAWnew SubsetPrivate(recursion_depth + 1, before_split, out_values); |
555 | m_children[1]= FASTUIDRAWnew SubsetPrivate(recursion_depth + 1, after_split, out_values); |
556 | } |
557 | |
558 | void |
559 | SubsetPrivate:: |
560 | select_subsets(bool miter_hunting, |
561 | ScratchSpace &scratch, |
562 | fastuidraw::c_array<const fastuidraw::vec3> clip_equations, |
563 | const fastuidraw::float3x3 &clip_matrix_local, |
564 | const fastuidraw::vec2 &one_pixel_width, |
565 | fastuidraw::c_array<const float> geometry_inflation, |
566 | std::vector<unsigned int> &dst) |
567 | { |
568 | using namespace fastuidraw; |
569 | |
570 | float pixels_additional_room; |
571 | float item_space_additional_room; |
572 | |
573 | if (miter_hunting) |
574 | { |
575 | pixels_additional_room = geometry_inflation[PathEnums::pixel_space_distance_miter_joins]; |
576 | item_space_additional_room = geometry_inflation[PathEnums::item_space_distance_miter_joins]; |
577 | } |
578 | else |
579 | { |
580 | pixels_additional_room = geometry_inflation[PathEnums::pixel_space_distance]; |
581 | item_space_additional_room = geometry_inflation[PathEnums::item_space_distance]; |
582 | } |
583 | |
584 | scratch.m_adjusted_clip_eqs.resize(clip_equations.size()); |
585 | for(unsigned int i = 0; i < clip_equations.size(); ++i) |
586 | { |
587 | vec3 c(clip_equations[i]); |
588 | float f; |
589 | |
590 | /* make "w" larger by the named number of pixels. */ |
591 | f = t_abs(c.x()) * one_pixel_width.x() |
592 | + t_abs(c.y()) * one_pixel_width.y(); |
593 | |
594 | c.z() += pixels_additional_room * f; |
595 | |
596 | /* transform clip equations from clip coordinates to |
597 | * local coordinates. |
598 | */ |
599 | scratch.m_adjusted_clip_eqs[i] = c * clip_matrix_local; |
600 | } |
601 | |
602 | dst.clear(); |
603 | select_subsets_implement(miter_hunting, scratch, |
604 | item_space_additional_room, |
605 | dst); |
606 | } |
607 | |
608 | bool |
609 | SubsetPrivate:: |
610 | select_subsets_implement(bool miter_hunting, |
611 | ScratchSpace &scratch, |
612 | float item_space_additional_room, |
613 | std::vector<unsigned int> &dst) |
614 | { |
615 | using namespace fastuidraw; |
616 | |
617 | if (miter_hunting) |
618 | { |
619 | if (m_join_bounding_box.empty()) |
620 | { |
621 | return false; |
622 | } |
623 | } |
624 | else |
625 | { |
626 | if (m_bounding_box.empty()) |
627 | { |
628 | return false; |
629 | } |
630 | } |
631 | |
632 | /* clip the bounding box of this StrokedPathSubset */ |
633 | vecN<vec2, 4> bb; |
634 | bool unclipped; |
635 | |
636 | if (miter_hunting) |
637 | { |
638 | m_join_bounding_box.inflated_polygon(bb, item_space_additional_room); |
639 | } |
640 | else |
641 | { |
642 | m_bounding_box.inflated_polygon(bb, item_space_additional_room); |
643 | } |
644 | unclipped = detail::clip_against_planes(make_c_array(scratch.m_adjusted_clip_eqs), |
645 | bb, &scratch.m_clipped_rect, |
646 | scratch.m_clip_scratch_vec2s); |
647 | |
648 | //completely clipped |
649 | if (scratch.m_clipped_rect.empty()) |
650 | { |
651 | return false; |
652 | } |
653 | |
654 | //completely unclipped. |
655 | if (unclipped || !has_children()) |
656 | { |
657 | dst.push_back(m_ID); |
658 | return true; |
659 | } |
660 | |
661 | FASTUIDRAWassert(m_children[0] != nullptr); |
662 | FASTUIDRAWassert(m_children[1] != nullptr); |
663 | |
664 | bool r0, r1; |
665 | |
666 | r0 = m_children[0]->select_subsets_implement(miter_hunting, scratch, item_space_additional_room, dst); |
667 | r1 = m_children[1]->select_subsets_implement(miter_hunting, scratch, item_space_additional_room, dst); |
668 | |
669 | if (r0 && r1) |
670 | { |
671 | /* the last two elements added are m_children[0] and m_children[1]; |
672 | * remove them and add this instead (if possible). |
673 | */ |
674 | FASTUIDRAWassert(!dst.empty() && dst.back() == m_children[1]->m_ID); |
675 | dst.pop_back(); |
676 | |
677 | FASTUIDRAWassert(!dst.empty() && dst.back() == m_children[0]->m_ID); |
678 | dst.pop_back(); |
679 | |
680 | dst.push_back(m_ID); |
681 | return true; |
682 | } |
683 | |
684 | return false; |
685 | } |
686 | |
687 | //////////////////////////////////////////// |
688 | // PartitionedTessellatedPathPrivate methods |
689 | PartitionedTessellatedPathPrivate:: |
690 | PartitionedTessellatedPathPrivate(const fastuidraw::TessellatedPath &P) |
691 | { |
692 | SubsetBuilder builder; |
693 | |
694 | builder.process_chains(P.segment_chain_data()); |
695 | builder.process_joins(P.join_data()); |
696 | builder.process_caps(P.cap_data()); |
697 | m_has_arcs = builder.m_has_arcs; |
698 | m_root_subset = SubsetPrivate::create(builder, m_subsets); |
699 | } |
700 | |
701 | PartitionedTessellatedPathPrivate:: |
702 | PartitionedTessellatedPathPrivate(fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> chains, |
703 | fastuidraw::c_array<const fastuidraw::TessellatedPath::join> joins, |
704 | fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> caps) |
705 | { |
706 | SubsetBuilder builder; |
707 | |
708 | builder.process_chains(chains); |
709 | builder.process_caps(caps); |
710 | builder.process_joins(joins); |
711 | m_has_arcs = builder.m_has_arcs; |
712 | m_root_subset = SubsetPrivate::create(builder, m_subsets); |
713 | } |
714 | |
715 | PartitionedTessellatedPathPrivate:: |
716 | ~PartitionedTessellatedPathPrivate() |
717 | { |
718 | FASTUIDRAWdelete(m_root_subset); |
719 | } |
720 | |
721 | ///////////////////////////////////////////////////////////////// |
722 | // fastuidraw::PartitionedTessellatedPath::SubsetSelection methods |
723 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
724 | SubsetSelection(void) |
725 | { |
726 | m_d = FASTUIDRAWnew SubsetSelectionPrivate(); |
727 | } |
728 | |
729 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
730 | ~SubsetSelection(void) |
731 | { |
732 | SubsetSelectionPrivate *d; |
733 | d = static_cast<SubsetSelectionPrivate*>(m_d); |
734 | FASTUIDRAWdelete(d); |
735 | m_d = nullptr; |
736 | } |
737 | |
738 | fastuidraw::c_array<const unsigned int> |
739 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
740 | subset_ids(void) const |
741 | { |
742 | SubsetSelectionPrivate *d; |
743 | d = static_cast<SubsetSelectionPrivate*>(m_d); |
744 | return make_c_array(d->m_subset_ids); |
745 | } |
746 | |
747 | fastuidraw::c_array<const unsigned int> |
748 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
749 | join_subset_ids(void) const |
750 | { |
751 | SubsetSelectionPrivate *d; |
752 | d = static_cast<SubsetSelectionPrivate*>(m_d); |
753 | return d->m_join_subset_ids; |
754 | } |
755 | |
756 | const fastuidraw::reference_counted_ptr<const fastuidraw::PartitionedTessellatedPath>& |
757 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
758 | source(void) const |
759 | { |
760 | SubsetSelectionPrivate *d; |
761 | d = static_cast<SubsetSelectionPrivate*>(m_d); |
762 | return d->m_source; |
763 | } |
764 | |
765 | void |
766 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
767 | clear(const reference_counted_ptr<const PartitionedTessellatedPath> &src) |
768 | { |
769 | SubsetSelectionPrivate *d; |
770 | d = static_cast<SubsetSelectionPrivate*>(m_d); |
771 | d->m_source = src; |
772 | d->m_subset_ids.clear(); |
773 | d->m_join_subset_ids_backing.clear(); |
774 | d->m_join_subset_ids = c_array<const unsigned int>(); |
775 | } |
776 | |
777 | void |
778 | fastuidraw::PartitionedTessellatedPath::SubsetSelection:: |
779 | apply_path_effect(const PathEffect &effect, PathEffect::Storage &dst) const |
780 | { |
781 | if (!source()) |
782 | { |
783 | return; |
784 | } |
785 | |
786 | const PartitionedTessellatedPath &path(*source()); |
787 | for (unsigned int id : subset_ids()) |
788 | { |
789 | PartitionedTessellatedPath::Subset S(path.subset(id)); |
790 | c_array<const segment_chain> segment_chains(S.segment_chains()); |
791 | c_array<const TessellatedPath::cap> caps(S.caps()); |
792 | |
793 | effect.process_chains(segment_chains.begin(), segment_chains.end(), dst); |
794 | effect.process_caps(caps.begin(), caps.end(), dst); |
795 | } |
796 | |
797 | for (unsigned int id : join_subset_ids()) |
798 | { |
799 | PartitionedTessellatedPath::Subset S(path.subset(id)); |
800 | c_array<const TessellatedPath::join> joins(S.joins()); |
801 | |
802 | effect.process_joins(joins.begin(), joins.end(), dst); |
803 | } |
804 | } |
805 | |
806 | ///////////////////////////////// |
807 | // fastuidraw::PartitionedTessellatedPath::Subset methods |
808 | fastuidraw::PartitionedTessellatedPath::Subset:: |
809 | Subset(void *d): |
810 | m_d(d) |
811 | { |
812 | } |
813 | |
814 | const fastuidraw::Rect& |
815 | fastuidraw::PartitionedTessellatedPath::Subset:: |
816 | bounding_box(void) const |
817 | { |
818 | SubsetPrivate *d; |
819 | d = static_cast<SubsetPrivate*>(m_d); |
820 | FASTUIDRAWassert(d); |
821 | return d->bounding_box(); |
822 | } |
823 | |
824 | fastuidraw::c_array<const fastuidraw::TessellatedPath::segment_chain> |
825 | fastuidraw::PartitionedTessellatedPath::Subset:: |
826 | segment_chains(void) const |
827 | { |
828 | SubsetPrivate *d; |
829 | d = static_cast<SubsetPrivate*>(m_d); |
830 | FASTUIDRAWassert(d); |
831 | return d->segment_chains(); |
832 | } |
833 | |
834 | bool |
835 | fastuidraw::PartitionedTessellatedPath::Subset:: |
836 | has_children(void) const |
837 | { |
838 | SubsetPrivate *d; |
839 | d = static_cast<SubsetPrivate*>(m_d); |
840 | FASTUIDRAWassert(d); |
841 | return d->has_children(); |
842 | } |
843 | |
844 | unsigned int |
845 | fastuidraw::PartitionedTessellatedPath::Subset:: |
846 | ID(void) const |
847 | { |
848 | SubsetPrivate *d; |
849 | d = static_cast<SubsetPrivate*>(m_d); |
850 | FASTUIDRAWassert(d); |
851 | return d->ID(); |
852 | } |
853 | |
854 | fastuidraw::vecN<fastuidraw::PartitionedTessellatedPath::Subset, 2> |
855 | fastuidraw::PartitionedTessellatedPath::Subset:: |
856 | children(void) const |
857 | { |
858 | SubsetPrivate *d, *p0(nullptr), *p1(nullptr); |
859 | |
860 | d = static_cast<SubsetPrivate*>(m_d); |
861 | if (d && d->has_children()) |
862 | { |
863 | p0 = d->child(0); |
864 | p1 = d->child(1); |
865 | } |
866 | |
867 | Subset s0(p0), s1(p1); |
868 | return vecN<Subset, 2>(s0, s1); |
869 | } |
870 | |
871 | fastuidraw::c_array<const fastuidraw::TessellatedPath::join> |
872 | fastuidraw::PartitionedTessellatedPath::Subset:: |
873 | joins(void) const |
874 | { |
875 | SubsetPrivate *d; |
876 | d = static_cast<SubsetPrivate*>(m_d); |
877 | FASTUIDRAWassert(d); |
878 | return d->joins(); |
879 | } |
880 | |
881 | fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> |
882 | fastuidraw::PartitionedTessellatedPath::Subset:: |
883 | caps(void) const |
884 | { |
885 | SubsetPrivate *d; |
886 | d = static_cast<SubsetPrivate*>(m_d); |
887 | FASTUIDRAWassert(d); |
888 | return d->caps(); |
889 | } |
890 | |
891 | //////////////////////////////////////////// |
892 | // fastuidraw::PartitionedTessellatedPath methods |
893 | fastuidraw::PartitionedTessellatedPath:: |
894 | PartitionedTessellatedPath(const TessellatedPath &path) |
895 | { |
896 | m_d = FASTUIDRAWnew PartitionedTessellatedPathPrivate(path); |
897 | } |
898 | |
899 | fastuidraw::PartitionedTessellatedPath:: |
900 | PartitionedTessellatedPath(c_array<const segment_chain> chains, |
901 | c_array<const join> joins, |
902 | c_array<const cap> caps) |
903 | { |
904 | m_d = FASTUIDRAWnew PartitionedTessellatedPathPrivate(chains, joins, caps); |
905 | } |
906 | |
907 | fastuidraw::PartitionedTessellatedPath:: |
908 | ~PartitionedTessellatedPath() |
909 | { |
910 | PartitionedTessellatedPathPrivate *d; |
911 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
912 | FASTUIDRAWdelete(d); |
913 | } |
914 | |
915 | bool |
916 | fastuidraw::PartitionedTessellatedPath:: |
917 | has_arcs(void) const |
918 | { |
919 | PartitionedTessellatedPathPrivate *d; |
920 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
921 | return d->m_has_arcs; |
922 | } |
923 | |
924 | unsigned int |
925 | fastuidraw::PartitionedTessellatedPath:: |
926 | number_subsets(void) const |
927 | { |
928 | PartitionedTessellatedPathPrivate *d; |
929 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
930 | return d->m_subsets.size(); |
931 | } |
932 | |
933 | fastuidraw::PartitionedTessellatedPath::Subset |
934 | fastuidraw::PartitionedTessellatedPath:: |
935 | subset(unsigned int I) const |
936 | { |
937 | PartitionedTessellatedPathPrivate *d; |
938 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
939 | |
940 | FASTUIDRAWassert(I < d->m_subsets.size()); |
941 | return Subset(d->m_subsets[I]); |
942 | } |
943 | |
944 | fastuidraw::PartitionedTessellatedPath::Subset |
945 | fastuidraw::PartitionedTessellatedPath:: |
946 | root_subset(void) const |
947 | { |
948 | PartitionedTessellatedPathPrivate *d; |
949 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
950 | return Subset(d->m_root_subset); |
951 | } |
952 | |
953 | fastuidraw::c_array<const fastuidraw::TessellatedPath::join> |
954 | fastuidraw::PartitionedTessellatedPath:: |
955 | joins(void) const |
956 | { |
957 | PartitionedTessellatedPathPrivate *d; |
958 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
959 | return d->m_root_subset->joins(); |
960 | } |
961 | |
962 | fastuidraw::c_array<const fastuidraw::TessellatedPath::cap> |
963 | fastuidraw::PartitionedTessellatedPath:: |
964 | caps(void) const |
965 | { |
966 | PartitionedTessellatedPathPrivate *d; |
967 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
968 | return d->m_root_subset->caps(); |
969 | } |
970 | |
971 | void |
972 | fastuidraw::PartitionedTessellatedPath:: |
973 | select_subsets(c_array<const vec3> clip_equations, |
974 | const float3x3 &clip_matrix_local, |
975 | const vec2 &one_pixel_width, |
976 | c_array<const float> geometry_inflation, |
977 | bool select_miter_joins, |
978 | SubsetSelection &dst) const |
979 | { |
980 | PartitionedTessellatedPathPrivate *d; |
981 | d = static_cast<PartitionedTessellatedPathPrivate*>(m_d); |
982 | |
983 | SubsetSelectionPrivate *dst_d; |
984 | dst_d = static_cast<SubsetSelectionPrivate*>(dst.m_d); |
985 | |
986 | dst_d->m_source = this; |
987 | d->m_root_subset->select_subsets(false, |
988 | dst_d->m_scratch, |
989 | clip_equations, |
990 | clip_matrix_local, |
991 | one_pixel_width, |
992 | geometry_inflation, |
993 | dst_d->m_subset_ids); |
994 | |
995 | if (select_miter_joins) |
996 | { |
997 | d->m_root_subset->select_subsets(true, |
998 | dst_d->m_scratch, |
999 | clip_equations, |
1000 | clip_matrix_local, |
1001 | one_pixel_width, |
1002 | geometry_inflation, |
1003 | dst_d->m_join_subset_ids_backing); |
1004 | dst_d->m_join_subset_ids = make_c_array(dst_d->m_join_subset_ids_backing); |
1005 | } |
1006 | else |
1007 | { |
1008 | dst_d->m_join_subset_ids = make_c_array(dst_d->m_subset_ids); |
1009 | } |
1010 | } |
1011 | |