Blender V5.0
pbvh_uv_islands.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_map.hh"
6#include "BLI_math_geom.h"
7#include "BLI_math_matrix.hh"
8#include "BLI_math_vector.h"
9#include "BLI_ordered_edge.hh"
10#include "BLI_rect.h"
11
12#include "pbvh_uv_islands.hh"
13
14#include <iostream>
15#include <optional>
16#include <sstream>
17
19
21{
22 for (UVVertex *vertex : uv_edge.vertices) {
23 vertex->uv_edges.append_non_duplicates(&uv_edge);
24 }
25}
26
28{
29 for (UVEdge *uv_edge : uv_primitive.edges) {
31 }
32}
33
35{
36 for (UVEdge *uv_edge : uv_primitive.edges) {
38 }
39}
40
41/* -------------------------------------------------------------------- */
44
45static int primitive_get_other_uv_vertex(const MeshData &mesh_data,
46 const int3 &tri,
47 const int v1,
48 const int v2)
49{
50 const Span<int> corner_verts = mesh_data.corner_verts;
51 BLI_assert(ELEM(v1, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
52 BLI_assert(ELEM(v2, corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]));
53 for (const int loop : {tri[0], tri[1], tri[2]}) {
54 const int vert = corner_verts[loop];
55 if (!ELEM(vert, v1, v2)) {
56 return vert;
57 }
58 }
59 return -1;
60}
61
63 const int3 &tri,
64 const int3 &tri_other)
65{
66 int shared_uv_verts = 0;
67 for (const int loop : {tri[0], tri[1], tri[2]}) {
68 for (const int other_loop : {tri_other[0], tri_other[1], tri_other[2]}) {
69 if (uv_map[loop] == uv_map[other_loop]) {
70 shared_uv_verts += 1;
71 }
72 }
73 }
74 return shared_uv_verts >= 2;
75}
76
77static int get_uv_loop(const MeshData &mesh_data, const int3 &tri, const int vert)
78{
79 for (const int loop : {tri[0], tri[1], tri[2]}) {
80 if (mesh_data.corner_verts[loop] == vert) {
81 return loop;
82 }
83 }
85 return tri[0];
86}
87
88static rctf primitive_uv_bounds(const int3 &tri, const Span<float2> uv_map)
89{
92 for (const int loop : {tri[0], tri[1], tri[2]}) {
93 BLI_rctf_do_minmax_v(&result, uv_map[loop]);
94 }
95 return result;
96}
97
99
100/* -------------------------------------------------------------------- */
103
104static void mesh_data_init_edges(MeshData &mesh_data)
105{
106 mesh_data.edges.reserve(mesh_data.corner_tris.size() * 2);
108 eh.reserve(mesh_data.corner_tris.size() * 3);
109 for (int64_t i = 0; i < mesh_data.corner_tris.size(); i++) {
110 const int3 &tri = mesh_data.corner_tris[i];
111 Vector<int, 3> edges;
112 for (int j = 0; j < 3; j++) {
113 int v1 = mesh_data.corner_verts[tri[j]];
114 int v2 = mesh_data.corner_verts[tri[(j + 1) % 3]];
115
116 int64_t edge_index;
117 eh.add_or_modify(
118 {v1, v2},
119 [&](int *value) {
120 edge_index = mesh_data.edges.size();
121 *value = edge_index + 1;
122 mesh_data.edges.append({v1, v2});
123 mesh_data.vert_to_edge_map.add(edge_index, v1, v2);
124 },
125 [&](int *value) {
126 edge_index = *value - 1;
127 *value = edge_index;
128 });
129
130 edges.append(edge_index);
131 }
132 mesh_data.primitive_to_edge_map.add(edges, i);
133 }
134 /* Build edge to neighboring triangle map. */
135 mesh_data.edge_to_primitive_map = EdgeToPrimitiveMap(mesh_data.edges.size());
136 for (const int prim_i : mesh_data.corner_tris.index_range()) {
137 for (const int edge_i : mesh_data.primitive_to_edge_map[prim_i]) {
138 mesh_data.edge_to_primitive_map.add(prim_i, edge_i);
139 }
140 }
141}
142static constexpr int INVALID_UV_ISLAND_ID = -1;
147static void extract_uv_neighbors(const MeshData &mesh_data,
148 const Span<int> uv_island_ids,
149 const int primitive_i,
150 Vector<int> &prims_to_add)
151{
152 for (const int edge : mesh_data.primitive_to_edge_map[primitive_i]) {
153 for (const int other_primitive_i : mesh_data.edge_to_primitive_map[edge]) {
154 if (primitive_i == other_primitive_i) {
155 continue;
156 }
157 if (uv_island_ids[other_primitive_i] != INVALID_UV_ISLAND_ID) {
158 continue;
159 }
160
162 mesh_data.corner_tris[primitive_i],
163 mesh_data.corner_tris[other_primitive_i]))
164 {
165 prims_to_add.append(other_primitive_i);
166 }
167 }
168 }
169}
170
172{
173 mesh_data.uv_island_ids.reinitialize(mesh_data.corner_tris.size());
175
176 int uv_island_id = 0;
177 Vector<int> prims_to_add;
178 for (const int primitive_i : mesh_data.corner_tris.index_range()) {
179 /* Early exit when uv island id is already extracted during uv neighbor extractions. */
180 if (mesh_data.uv_island_ids[primitive_i] != INVALID_UV_ISLAND_ID) {
181 continue;
182 }
183
184 prims_to_add.append(primitive_i);
185 while (!prims_to_add.is_empty()) {
186 const int other_primitive_i = prims_to_add.pop_last();
187 mesh_data.uv_island_ids[other_primitive_i] = uv_island_id;
188 extract_uv_neighbors(mesh_data, mesh_data.uv_island_ids, other_primitive_i, prims_to_add);
189 }
190 uv_island_id++;
191 }
192
193 return uv_island_id;
194}
195
196static void mesh_data_init(MeshData &mesh_data)
197{
198 mesh_data_init_edges(mesh_data);
200}
201
218
220
221/* -------------------------------------------------------------------- */
224
225static void uv_vertex_init_flags(UVVertex &uv_vertex)
226{
227 uv_vertex.flags.is_border = false;
228 uv_vertex.flags.is_extended = false;
229}
230
235
236UVVertex::UVVertex(const MeshData &mesh_data, const int loop)
237 : vertex(mesh_data.corner_verts[loop]), uv(mesh_data.uv_map[loop])
238{
240}
241
247{
248 Vector<int> primitives_around_uv_vertex;
249 for (const UVEdge *uv_edge : uv_vertex.uv_edges) {
250 for (const int uv_primitive_index : uv_edge->uv_primitive_indices) {
251 primitives_around_uv_vertex.append_non_duplicates(uv_primitive_index);
252 }
253 }
254 return primitives_around_uv_vertex;
255}
256
258
259/* -------------------------------------------------------------------- */
262
263bool UVEdge::has_shared_edge(const Span<float2> uv_map, const int loop_1, const int loop_2) const
264{
265 return (vertices[0]->uv == uv_map[loop_1] && vertices[1]->uv == uv_map[loop_2]) ||
266 (vertices[0]->uv == uv_map[loop_2] && vertices[1]->uv == uv_map[loop_1]);
267}
268
269bool UVEdge::has_shared_edge(const UVVertex &v1, const UVVertex &v2) const
270{
271 return (vertices[0]->uv == v1.uv && vertices[1]->uv == v2.uv) ||
272 (vertices[0]->uv == v2.uv && vertices[1]->uv == v1.uv);
273}
274
275bool UVEdge::has_shared_edge(const UVEdge &other) const
276{
277 return has_shared_edge(*other.vertices[0], *other.vertices[1]);
278}
279
280bool UVEdge::has_same_vertices(const int vert1, const int vert2) const
281{
282 return (vertices[0]->vertex == vert1 && vertices[1]->vertex == vert2) ||
283 (vertices[0]->vertex == vert2 && vertices[1]->vertex == vert1);
284}
285
286bool UVEdge::has_same_uv_vertices(const UVEdge &other) const
287{
288 return has_shared_edge(other) &&
289 has_same_vertices(other.vertices[0]->vertex, other.vertices[1]->vertex);
290}
291
292bool UVEdge::has_same_vertices(const int2 &edge) const
293{
294 return has_same_vertices(edge[0], edge[1]);
295}
296
298{
299 return uv_primitive_indices.size() == 1;
300}
301
303{
304 if (vertices[0]->vertex == vertex) {
305 return vertices[1];
306 }
307 return vertices[0];
308}
309
311
312/* -------------------------------------------------------------------- */
316{
317 const int vert_index = vertex.vertex;
318 const Vector<UVVertex *> &vertices = uv_vertex_lookup.lookup_or_add_default(vert_index);
319 for (UVVertex *v : vertices) {
320 if (v->uv == vertex.uv) {
321 return v;
322 }
323 }
324 return nullptr;
325}
326
328{
329 UVVertex *found_vertex = lookup(vertex);
330 if (found_vertex != nullptr) {
331 return found_vertex;
332 }
333
334 uv_vertices.append(vertex);
335 UVVertex *result = &uv_vertices.last();
336 result->uv_edges.clear();
337 /* v is already a key. Ensured by UVIsland::lookup in this method. */
338 uv_vertex_lookup.lookup(vertex.vertex).append(result);
339 return result;
340}
341
343{
344 UVVertex *found_vertex = lookup(*edge.vertices[0]);
345 if (found_vertex == nullptr) {
346 return nullptr;
347 }
348 for (UVEdge *e : found_vertex->uv_edges) {
349 UVVertex *other_vertex = e->get_other_uv_vertex(found_vertex->vertex);
350 if (other_vertex->vertex == edge.vertices[1]->vertex &&
351 other_vertex->uv == edge.vertices[1]->uv)
352 {
353 return e;
354 }
355 }
356 return nullptr;
357}
358
360{
361 UVEdge *found_edge = lookup(edge);
362 if (found_edge != nullptr) {
363 return found_edge;
364 }
365
366 uv_edges.append(edge);
367 UVEdge *result = &uv_edges.last();
368 result->uv_primitive_indices.clear();
369 return result;
370}
371
372void UVIsland::append(const UVPrimitive &primitive)
373{
374 uv_primitives.append(primitive);
375 UVPrimitive *new_prim_ptr = &uv_primitives.last();
376 for (int i = 0; i < 3; i++) {
377 UVEdge *other_edge = primitive.edges[i];
378 UVEdge uv_edge_template;
379 uv_edge_template.vertices[0] = lookup_or_create(*other_edge->vertices[0]);
380 uv_edge_template.vertices[1] = lookup_or_create(*other_edge->vertices[1]);
381 new_prim_ptr->edges[i] = lookup_or_create(uv_edge_template);
382 uv_edge_append_to_uv_vertices(*new_prim_ptr->edges[i]);
383 new_prim_ptr->edges[i]->uv_primitive_indices.append(new_prim_ptr->primitive_i);
384 }
385}
386
387bool UVIsland::has_shared_edge(const UVPrimitive &primitive) const
388{
389 for (const UVPrimitive &prim : uv_primitives) {
390 if (prim.has_shared_edge(primitive)) {
391 return true;
392 }
393 }
394 return false;
395}
396
397bool UVIsland::has_shared_edge(const MeshData &mesh_data, const int primitive_i) const
398{
399 for (const UVPrimitive &prim : uv_primitives) {
400 if (prim.has_shared_edge(mesh_data, primitive_i)) {
401 return true;
402 }
403 }
404 return false;
405}
406
408{
409 for (const UVPrimitive &prim : uv_primitives) {
410 if (prim.has_shared_edge(primitive)) {
411 this->append(primitive);
412 }
413 }
414}
415
416static UVPrimitive *add_primitive(const MeshData &mesh_data,
417 UVIsland &uv_island,
418 const int primitive_i)
419{
420 UVPrimitive uv_primitive(primitive_i);
421 const int3 &tri = mesh_data.corner_tris[primitive_i];
422 uv_island.uv_primitives.append(uv_primitive);
423 UVPrimitive *uv_primitive_ptr = &uv_island.uv_primitives.last();
424 for (const int edge_i : mesh_data.primitive_to_edge_map[primitive_i]) {
425 const int2 &edge = mesh_data.edges[edge_i];
426 const int loop_1 = get_uv_loop(mesh_data, tri, edge[0]);
427 const int loop_2 = get_uv_loop(mesh_data, tri, edge[1]);
428 UVEdge uv_edge_template;
429 uv_edge_template.vertices[0] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_1));
430 uv_edge_template.vertices[1] = uv_island.lookup_or_create(UVVertex(mesh_data, loop_2));
431 UVEdge *uv_edge = uv_island.lookup_or_create(uv_edge_template);
432 uv_primitive_ptr->edges.append(uv_edge);
434 uv_edge->uv_primitive_indices.append(uv_primitive_ptr->primitive_i);
435 }
436 return uv_primitive_ptr;
437}
438
440{
441 /* Lookup all borders of the island. */
443 for (UVPrimitive &prim : uv_primitives) {
444 for (UVEdge *edge : prim.edges) {
445 if (edge->is_border_edge()) {
446 edges.append(UVBorderEdge(edge, &prim));
447 }
448 }
449 }
450
451 while (true) {
452 std::optional<UVBorder> border = UVBorder::extract_from_edges(edges);
453 if (!border.has_value()) {
454 break;
455 }
456 if (!border->is_ccw()) {
457 border->flip_order();
458 }
459 borders.append(*border);
460 }
461}
462
463static std::optional<UVBorderCorner> sharpest_border_corner(UVBorder &border, float *r_angle)
464{
465 *r_angle = std::numeric_limits<float>::max();
466 std::optional<UVBorderCorner> result;
467 for (UVBorderEdge &edge : border.edges) {
468 const UVVertex *uv_vertex = edge.get_uv_vertex(0);
469 /* Only allow extending from tagged border vertices that have not been extended yet. During
470 * extending new borders are created, those are ignored as their is_border is set to false. */
471 if (!uv_vertex->flags.is_border || uv_vertex->flags.is_extended) {
472 continue;
473 }
474 float new_angle = border.outside_angle(edge);
475 if (new_angle < *r_angle) {
476 *r_angle = new_angle;
477 result = UVBorderCorner(&border.edges[edge.prev_index], &edge, new_angle);
478 }
479 }
480 return result;
481}
482
483static std::optional<UVBorderCorner> sharpest_border_corner(UVIsland &island)
484{
485 std::optional<UVBorderCorner> result;
486 float sharpest_angle = std::numeric_limits<float>::max();
487 for (UVBorder &border : island.borders) {
488 float new_angle;
489 std::optional<UVBorderCorner> new_result = sharpest_border_corner(border, &new_angle);
490 if (new_angle < sharpest_angle) {
491 sharpest_angle = new_angle;
492 result = new_result;
493 }
494 }
495 return result;
496}
497
502 /* UVs order are already applied. So `uvs[0]` matches `primitive->vertices[vert_order[0]]`. */
505
506 struct {
507 bool found : 1;
509
510 FanSegment(const MeshData &mesh_data, const int primitive_index, const int3 tri, int vertex)
512 {
513 flags.found = false;
514
515 /* Reorder so the first edge starts with the given vertex. */
516 if (mesh_data.corner_verts[tri[1]] == vertex) {
517 vert_order[0] = 1;
518 vert_order[1] = 2;
519 vert_order[2] = 0;
520 }
521 else if (mesh_data.corner_verts[tri[2]] == vertex) {
522 vert_order[0] = 2;
523 vert_order[1] = 0;
524 vert_order[2] = 1;
525 }
526 else {
527 BLI_assert(mesh_data.corner_verts[tri[0]] == vertex);
528 vert_order[0] = 0;
529 vert_order[1] = 1;
530 vert_order[2] = 2;
531 }
532 }
533
534 void print_debug(const MeshData &mesh_data) const
535 {
536 std::stringstream ss;
537 ss << " v1:" << mesh_data.corner_verts[tri[vert_order[0]]];
538 ss << " v2:" << mesh_data.corner_verts[tri[vert_order[1]]];
539 ss << " v3:" << mesh_data.corner_verts[tri[vert_order[2]]];
540 ss << " uv1:" << uvs[0];
541 ss << " uv2:" << uvs[1];
542 ss << " uv3:" << uvs[2];
543 if (flags.found) {
544 ss << " *found";
545 }
546 ss << "\n";
547 std::cout << ss.str();
548 }
549};
550
551struct Fan {
552 /* Blades of the fan. */
554
555 struct {
560 bool is_manifold : 1;
561
563
564 Fan(const MeshData &mesh_data, const int vertex)
565 {
566 flags.is_manifold = true;
567 int current_edge = mesh_data.vert_to_edge_map[vertex].first();
568 const int stop_primitive = mesh_data.edge_to_primitive_map[current_edge].first();
569 int previous_primitive = stop_primitive;
570 while (true) {
571 bool stop = false;
572 for (const int other_primitive_i : mesh_data.edge_to_primitive_map[current_edge]) {
573 if (stop) {
574 break;
575 }
576 if (other_primitive_i == previous_primitive) {
577 continue;
578 }
579
580 const int3 &other_tri = mesh_data.corner_tris[other_primitive_i];
581
582 for (const int edge_i : mesh_data.primitive_to_edge_map[other_primitive_i]) {
583 const int2 &edge = mesh_data.edges[edge_i];
584 if (edge_i == current_edge || (edge[0] != vertex && edge[1] != vertex)) {
585 continue;
586 }
587 segments.append(FanSegment(mesh_data, other_primitive_i, other_tri, vertex));
588 current_edge = edge_i;
589 previous_primitive = other_primitive_i;
590 stop = true;
591 break;
592 }
593 }
594 if (stop == false) {
595 flags.is_manifold = false;
596 break;
597 }
598 if (stop_primitive == previous_primitive) {
599 break;
600 }
601 }
602 }
603
605 {
606 int result = 0;
607 for (const FanSegment &fan_edge : segments) {
608 if (!fan_edge.flags.found) {
609 result++;
610 }
611 }
612 return result;
613 }
614
616 {
617 Vector<int> mesh_primitive_indices = connecting_mesh_primitive_indices(uv_vertex);
618
619 /* Go over all fan edges to find if they can be found as primitive around the uv vertex. */
620 for (FanSegment &fan_edge : segments) {
621 fan_edge.flags.found = mesh_primitive_indices.contains(fan_edge.primitive_index);
622 }
623 }
624
625 void init_uv_coordinates(const MeshData &mesh_data, UVVertex &uv_vertex)
626 {
627 for (FanSegment &fan_edge : segments) {
628 int other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[0]]];
629 if (other_v == uv_vertex.vertex) {
630 other_v = mesh_data.corner_verts[fan_edge.tri[fan_edge.vert_order[1]]];
631 }
632
633 for (UVEdge *edge : uv_vertex.uv_edges) {
634 const UVVertex *other_uv_vertex = edge->get_other_uv_vertex(uv_vertex.vertex);
635 int64_t other_edge_v = other_uv_vertex->vertex;
636 if (other_v == other_edge_v) {
637 fan_edge.uvs[0] = uv_vertex.uv;
638 fan_edge.uvs[1] = other_uv_vertex->uv;
639 break;
640 }
641 }
642 }
643
644 segments.last().uvs[2] = segments.first().uvs[1];
645 for (int i = 0; i < segments.size() - 1; i++) {
646 segments[i].uvs[2] = segments[i + 1].uvs[1];
647 }
648 }
649
650#ifndef NDEBUG
655 bool contains_vertex_on_outside(const MeshData &mesh_data, const int vertex_index) const
656 {
657 for (const FanSegment &segment : segments) {
658 int v2 = mesh_data.corner_verts[segment.tri[segment.vert_order[1]]];
659 if (vertex_index == v2) {
660 return true;
661 }
662 }
663 return false;
664 }
665
666#endif
667
668 static bool is_path_valid(const Span<FanSegment *> path,
669 const MeshData &mesh_data,
670 const int from_vertex,
671 const int to_vertex)
672 {
673 int current_vert = from_vertex;
674 for (FanSegment *segment : path) {
675 int v1 = mesh_data.corner_verts[segment->tri[segment->vert_order[1]]];
676 int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[2]]];
677 if (!ELEM(current_vert, v1, v2)) {
678 return false;
679 }
680 current_vert = v1 == current_vert ? v2 : v1;
681 }
682 return current_vert == to_vertex;
683 }
684
692 const MeshData &mesh_data,
693 const int from_vertex,
694 const int to_vertex,
695 const bool reversed)
696 {
697 const int from_vert_order = 1;
698 const int to_vert_order = 2;
699 const int index_increment = reversed ? -1 : 1;
700
702 result.reserve(edge_order.size());
703 int index = 0;
704 while (true) {
705 FanSegment *segment = edge_order[index];
706 int v2 = mesh_data.corner_verts[segment->tri[segment->vert_order[from_vert_order]]];
707 if (v2 == from_vertex) {
708 break;
709 }
710 index = (index + index_increment + edge_order.size()) % edge_order.size();
711 }
712
713 while (true) {
714 FanSegment *segment = edge_order[index];
715 result.append(segment);
716
717 int v3 = mesh_data.corner_verts[segment->tri[segment->vert_order[to_vert_order]]];
718 if (v3 == to_vertex) {
719 break;
720 }
721
722 index = (index + index_increment + edge_order.size()) % edge_order.size();
723 }
724
725 return result;
726 }
727
734 static int64_t score(const Span<FanSegment *> solution)
735 {
736 int64_t not_visited_steps = 0;
737 for (FanSegment *segment : solution) {
738 if (!segment->flags.found) {
739 not_visited_steps++;
740 }
741 }
742 return solution.size() - not_visited_steps;
743 }
744
746 const int from_vertex,
747 const int to_vertex)
748 {
749 BLI_assert_msg(contains_vertex_on_outside(mesh_data, from_vertex),
750 "Inconsistency detected, `from_vertex` isn't part of the outside of the fan.");
751 BLI_assert_msg(contains_vertex_on_outside(mesh_data, to_vertex),
752 "Inconsistency detected, `to_vertex` isn't part of the outside of the fan.");
753 if (to_vertex == from_vertex) {
754 return Vector<FanSegment *>();
755 }
756
757 Array<FanSegment *> edges(segments.size());
758 for (int64_t index : segments.index_range()) {
759 edges[index] = &segments[index];
760 }
761
762 Vector<FanSegment *> winding_1 = path_between(edges, mesh_data, from_vertex, to_vertex, false);
763 Vector<FanSegment *> winding_2 = path_between(edges, mesh_data, from_vertex, to_vertex, true);
764
765 bool winding_1_valid = is_path_valid(winding_1, mesh_data, from_vertex, to_vertex);
766 bool winding_2_valid = is_path_valid(winding_2, mesh_data, from_vertex, to_vertex);
767
768 if (winding_1_valid && !winding_2_valid) {
769 return winding_1;
770 }
771 if (!winding_1_valid && winding_2_valid) {
772 return winding_2;
773 }
774 if (!winding_1_valid && !winding_2_valid) {
775 BLI_assert_msg(false, "Both solutions aren't valid.");
776 return Vector<FanSegment *>();
777 }
778 if (score(winding_1) < score(winding_2)) {
779 return winding_1;
780 }
781 return winding_2;
782 }
783
784 void print_debug(const MeshData &mesh_data) const
785 {
786 for (const FanSegment &segment : segments) {
787 segment.print_debug(mesh_data);
788 }
789 std::cout << "\n";
790 }
791};
792
793static void add_uv_primitive_shared_uv_edge(const MeshData &mesh_data,
794 UVIsland &island,
795 UVVertex *connected_vert_1,
796 UVVertex *connected_vert_2,
797 float2 uv_unconnected,
798 const int mesh_primitive_i)
799{
800 UVPrimitive prim1(mesh_primitive_i);
801 const int3 &tri = mesh_data.corner_tris[mesh_primitive_i];
802
803 const int other_vert_i = primitive_get_other_uv_vertex(
804 mesh_data, tri, connected_vert_1->vertex, connected_vert_2->vertex);
805 UVVertex vert_template;
806 vert_template.uv = uv_unconnected;
807 vert_template.vertex = other_vert_i;
808 UVVertex *vert_ptr = island.lookup_or_create(vert_template);
809
810 const int loop_1 = get_uv_loop(mesh_data, tri, connected_vert_1->vertex);
811 vert_template.uv = connected_vert_1->uv;
812 vert_template.vertex = mesh_data.corner_verts[loop_1];
813 UVVertex *vert_1_ptr = island.lookup_or_create(vert_template);
814
815 const int loop_2 = get_uv_loop(mesh_data, tri, connected_vert_2->vertex);
816 vert_template.uv = connected_vert_2->uv;
817 vert_template.vertex = mesh_data.corner_verts[loop_2];
818 UVVertex *vert_2_ptr = island.lookup_or_create(vert_template);
819
820 UVEdge edge_template;
821 edge_template.vertices[0] = vert_1_ptr;
822 edge_template.vertices[1] = vert_2_ptr;
823 prim1.edges.append(island.lookup_or_create(edge_template));
824 edge_template.vertices[0] = vert_2_ptr;
825 edge_template.vertices[1] = vert_ptr;
826 prim1.edges.append(island.lookup_or_create(edge_template));
827 edge_template.vertices[0] = vert_ptr;
828 edge_template.vertices[1] = vert_1_ptr;
829 prim1.edges.append(island.lookup_or_create(edge_template));
832 island.uv_primitives.append(prim1);
833}
834
838static int find_fill_primitive(const MeshData &mesh_data, UVBorderCorner &corner)
839{
840 if (corner.first->get_uv_vertex(1) != corner.second->get_uv_vertex(0)) {
841 return -1;
842 }
843 if (corner.first->get_uv_vertex(0) == corner.second->get_uv_vertex(1)) {
844 return -1;
845 }
846 const UVVertex *shared_vert = corner.second->get_uv_vertex(0);
847 for (const int edge_i : mesh_data.vert_to_edge_map[shared_vert->vertex]) {
848 const int2 &edge = mesh_data.edges[edge_i];
849 if (corner.first->edge->has_same_vertices(edge)) {
850 for (const int primitive_i : mesh_data.edge_to_primitive_map[edge_i]) {
851 const int3 &tri = mesh_data.corner_tris[primitive_i];
852 const int other_vert = primitive_get_other_uv_vertex(mesh_data, tri, edge[0], edge[1]);
853 if (other_vert == corner.second->get_uv_vertex(1)->vertex) {
854 return primitive_i;
855 }
856 }
857 }
858 }
859 return -1;
860}
861
862static void add_uv_primitive_fill(UVIsland &island,
863 UVVertex &uv_vertex1,
864 UVVertex &uv_vertex2,
865 UVVertex &uv_vertex3,
866 const int fill_primitive_i)
867{
868 UVPrimitive uv_primitive(fill_primitive_i);
869 UVEdge edge_template;
870 edge_template.vertices[0] = &uv_vertex1;
871 edge_template.vertices[1] = &uv_vertex2;
872 uv_primitive.edges.append(island.lookup_or_create(edge_template));
873 edge_template.vertices[0] = &uv_vertex2;
874 edge_template.vertices[1] = &uv_vertex3;
875 uv_primitive.edges.append(island.lookup_or_create(edge_template));
876 edge_template.vertices[0] = &uv_vertex3;
877 edge_template.vertices[1] = &uv_vertex1;
878 uv_primitive.edges.append(island.lookup_or_create(edge_template));
881 island.uv_primitives.append(uv_primitive);
882}
883
884static void extend_at_vert(const MeshData &mesh_data,
885 UVIsland &island,
886 UVBorderCorner &corner,
887 float min_uv_distance)
888{
889
890 int border_index = corner.first->border_index;
891 UVBorder &border = island.borders[border_index];
892 if (!corner.connected_in_mesh()) {
893 return;
894 }
895
896 UVVertex *uv_vertex = corner.second->get_uv_vertex(0);
897 Fan fan(mesh_data, uv_vertex->vertex);
898 if (!fan.flags.is_manifold) {
899 return;
900 }
901 fan.init_uv_coordinates(mesh_data, *uv_vertex);
902 fan.mark_already_added_segments(*uv_vertex);
903 int num_to_add = fan.count_edges_not_added();
904
905 /* In 3d space everything can connected, but in uv space it may not.
906 * in this case in the space between we should extract the primitives to be added
907 * from the fan. */
908 Vector<FanSegment *> winding_solution = fan.best_path_between(
909 mesh_data, corner.first->get_uv_vertex(0)->vertex, corner.second->get_uv_vertex(1)->vertex);
910
911 /*
912 * When all edges are already added and its winding solution contains one segment to be added,
913 * the segment should be split into two segments in order one for both sides.
914 *
915 * Although the tri_fill can fill the missing segment it could lead to a squashed
916 * triangle when the corner angle is near 180 degrees. In order to fix this we will
917 * always add two segments both using the same fill primitive.
918 */
919 if (winding_solution.size() < 2 && (num_to_add == 0 || corner.angle > 2.0f)) {
920 int fill_primitive_1_i = corner.second->uv_primitive->primitive_i;
921 int fill_primitive_2_i = corner.first->uv_primitive->primitive_i;
922
923 const int fill_primitive_i = winding_solution.size() == 1 ?
924 winding_solution[0]->primitive_index :
925 find_fill_primitive(mesh_data, corner);
926
927 if (fill_primitive_i != -1) {
928 fill_primitive_1_i = fill_primitive_i;
929 fill_primitive_2_i = fill_primitive_i;
930 }
931
932 float2 center_uv = corner.uv(0.5f, min_uv_distance);
934 island,
935 corner.first->get_uv_vertex(1),
936 corner.first->get_uv_vertex(0),
937 center_uv,
938 fill_primitive_1_i);
939 UVPrimitive &new_prim_1 = island.uv_primitives.last();
941 island,
942 corner.second->get_uv_vertex(0),
943 corner.second->get_uv_vertex(1),
944 center_uv,
945 fill_primitive_2_i);
946 UVPrimitive &new_prim_2 = island.uv_primitives.last();
947
948 /* Update border after adding the new geometry. */
949 {
950 UVBorderEdge *border_edge = corner.first;
951 border_edge->uv_primitive = &new_prim_1;
952 border_edge->edge = border_edge->uv_primitive->get_uv_edge(
953 corner.first->get_uv_vertex(0)->uv, center_uv);
954 border_edge->reverse_order = border_edge->edge->vertices[0]->uv == center_uv;
955 }
956 {
957 UVBorderEdge *border_edge = corner.second;
958 border_edge->uv_primitive = &new_prim_2;
959 border_edge->edge = border_edge->uv_primitive->get_uv_edge(
960 corner.second->get_uv_vertex(1)->uv, center_uv);
961 border_edge->reverse_order = border_edge->edge->vertices[1]->uv == center_uv;
962 }
963 }
964 else {
965 UVEdge *current_edge = corner.first->edge;
966 Vector<UVBorderEdge> new_border_edges;
967
968 num_to_add = winding_solution.size();
969 for (int64_t segment_index : winding_solution.index_range()) {
970
971 float2 old_uv = current_edge->get_other_uv_vertex(uv_vertex->vertex)->uv;
972 int shared_edge_vertex = current_edge->get_other_uv_vertex(uv_vertex->vertex)->vertex;
973
974 float factor = (segment_index + 1.0f) / num_to_add;
975 float2 new_uv = corner.uv(factor, min_uv_distance);
976
977 FanSegment &segment = *winding_solution[segment_index];
978
979 const int fill_primitive_i = segment.primitive_index;
980 const int3 &tri_fill = mesh_data.corner_tris[fill_primitive_i];
981 const int other_prim_vertex = primitive_get_other_uv_vertex(
982 mesh_data, tri_fill, uv_vertex->vertex, shared_edge_vertex);
983
984 UVVertex uv_vertex_template;
985 uv_vertex_template.vertex = uv_vertex->vertex;
986 uv_vertex_template.uv = uv_vertex->uv;
987 UVVertex *vertex_1_ptr = island.lookup_or_create(uv_vertex_template);
988 uv_vertex_template.vertex = shared_edge_vertex;
989 uv_vertex_template.uv = old_uv;
990 UVVertex *vertex_2_ptr = island.lookup_or_create(uv_vertex_template);
991 uv_vertex_template.vertex = other_prim_vertex;
992 uv_vertex_template.uv = new_uv;
993 UVVertex *vertex_3_ptr = island.lookup_or_create(uv_vertex_template);
994
995 add_uv_primitive_fill(island, *vertex_1_ptr, *vertex_2_ptr, *vertex_3_ptr, fill_primitive_i);
996
997 UVPrimitive &new_prim = island.uv_primitives.last();
998 current_edge = new_prim.get_uv_edge(uv_vertex->vertex, other_prim_vertex);
999 UVBorderEdge new_border(new_prim.get_uv_edge(shared_edge_vertex, other_prim_vertex),
1000 &new_prim);
1001 new_border_edges.append(new_border);
1002 }
1003
1004 int border_insert = corner.first->index;
1005 border.remove(border_insert);
1006
1007 int border_next = corner.second->index;
1008 if (border_next < border_insert) {
1009 border_insert--;
1010 }
1011 else {
1012 border_next--;
1013 }
1014 border.remove(border_next);
1015 border.edges.insert(border_insert, new_border_edges);
1016
1017 border.update_indexes(border_index);
1018 }
1019}
1020
1021/* Marks vertices that can be extended. Only vertices that are part of a border can be extended. */
1023{
1024 for (UVVertex &uv_vertex : island.uv_vertices) {
1025 uv_vertex.flags.is_border = false;
1026 uv_vertex.flags.is_extended = false;
1027 }
1028 for (const UVBorder &border : island.borders) {
1029 for (const UVBorderEdge &border_edge : border.edges) {
1030 border_edge.edge->vertices[0]->flags.is_border = true;
1031 border_edge.edge->vertices[1]->flags.is_border = true;
1032 }
1033 }
1034}
1035
1036void UVIsland::extend_border(const MeshData &mesh_data,
1037 const UVIslandsMask &mask,
1038 const short island_index)
1039{
1041
1042 int64_t border_index = 0;
1043 for (UVBorder &border : borders) {
1044 border.update_indexes(border_index++);
1045 }
1046 while (true) {
1047 std::optional<UVBorderCorner> extension_corner = sharpest_border_corner(*this);
1048 if (!extension_corner.has_value()) {
1049 break;
1050 }
1051
1052 UVVertex *uv_vertex = extension_corner->second->get_uv_vertex(0);
1053
1054 /* Found corner is outside the mask, the corner should not be considered for extension. */
1055 const UVIslandsMask::Tile *tile = mask.find_tile(uv_vertex->uv);
1056 if (tile && tile->is_masked(island_index, uv_vertex->uv)) {
1058 mesh_data, *this, *extension_corner, tile->get_pixel_size_in_uv_space() * 2.0f);
1059 }
1060 /* Mark that the vert is extended. */
1061 uv_vertex->flags.is_extended = true;
1062 }
1063}
1064
1065void UVIsland::print_debug(const MeshData &mesh_data) const
1066{
1067 std::stringstream ss;
1068 ss << "#### Start UVIsland ####\n";
1069 ss << "import bpy\n";
1070 ss << "import bpy_extras.object_utils\n";
1071 ss << "import mathutils\n";
1072
1073 ss << "uvisland_vertices = [\n";
1074 for (const float3 &vertex_position : mesh_data.vert_positions) {
1075 ss << " mathutils.Vector((" << vertex_position.x << ", " << vertex_position.y << ", "
1076 << vertex_position.z << ")),\n";
1077 }
1078 ss << "]\n";
1079
1080 ss << "uvisland_edges = []\n";
1081
1082 ss << "uvisland_faces = [\n";
1083 for (const UVPrimitive &uvprimitive : uv_primitives) {
1084 ss << " [" << uvprimitive.edges[0]->vertices[0]->vertex << ", "
1085 << uvprimitive.edges[0]->vertices[1]->vertex << ", "
1086 << uvprimitive
1087 .get_other_uv_vertex(uvprimitive.edges[0]->vertices[0],
1088 uvprimitive.edges[0]->vertices[1])
1089 ->vertex
1090 << "],\n";
1091 }
1092 ss << "]\n";
1093
1094 ss << "uvisland_uvs = [\n";
1095 for (const UVPrimitive &uvprimitive : uv_primitives) {
1096 float2 uv = uvprimitive.edges[0]->vertices[0]->uv;
1097 ss << " " << uv.x << ", " << uv.y << ",\n";
1098 uv = uvprimitive.edges[0]->vertices[1]->uv;
1099 ss << " " << uv.x << ", " << uv.y << ",\n";
1100 uv = uvprimitive
1101 .get_other_uv_vertex(uvprimitive.edges[0]->vertices[0],
1102 uvprimitive.edges[0]->vertices[1])
1103 ->uv;
1104 ss << " " << uv.x << ", " << uv.y << ",\n";
1105 }
1106 ss << "]\n";
1107
1108 ss << "uvisland_mesh = bpy.data.meshes.new(name='UVIsland')\n";
1109 ss << "uvisland_mesh.from_pydata(uvisland_vertices, uvisland_edges, uvisland_faces)\n";
1110 ss << "uv_map = uvisland_mesh.attributes.new('UVMap', 'FLOAT2', 'CORNER')\n";
1111 ss << "uv_map.data.foreach_set('vector', uvisland_uvs)\n";
1112 ss << "bpy_extras.object_utils.object_data_add(bpy.context, uvisland_mesh)\n";
1113 ss << "#### End UVIsland ####\n\n\n";
1114
1115 std::cout << ss.str();
1116}
1117
1119
1120/* -------------------------------------------------------------------- */
1123
1125{
1126 /* Find a part of the border that haven't been extracted yet. */
1127 UVBorderEdge *starting_border_edge = nullptr;
1128 for (UVBorderEdge &edge : edges) {
1129 if (edge.tag == false) {
1130 starting_border_edge = &edge;
1131 break;
1132 }
1133 }
1134 if (starting_border_edge == nullptr) {
1135 return std::nullopt;
1136 }
1137 UVBorder border;
1138 border.edges.append(*starting_border_edge);
1139 starting_border_edge->tag = true;
1140
1141 float2 first_uv = starting_border_edge->get_uv_vertex(0)->uv;
1142 float2 current_uv = starting_border_edge->get_uv_vertex(1)->uv;
1143 while (current_uv != first_uv) {
1144 for (UVBorderEdge &border_edge : edges) {
1145 if (border_edge.tag == true) {
1146 continue;
1147 }
1148 int i;
1149 for (i = 0; i < 2; i++) {
1150 if (border_edge.edge->vertices[i]->uv == current_uv) {
1151 border_edge.reverse_order = i == 1;
1152 border_edge.tag = true;
1153 current_uv = border_edge.get_uv_vertex(1)->uv;
1154 border.edges.append(border_edge);
1155 break;
1156 }
1157 }
1158 if (i != 2) {
1159 break;
1160 }
1161 }
1162 }
1163 return border;
1164}
1165
1167{
1168 const UVBorderEdge &edge = edges.first();
1169 const UVVertex *uv_vertex1 = edge.get_uv_vertex(0);
1170 const UVVertex *uv_vertex2 = edge.get_uv_vertex(1);
1171 const UVVertex *uv_vertex3 = edge.get_other_uv_vertex();
1172 float poly[3][2];
1173 copy_v2_v2(poly[0], uv_vertex1->uv);
1174 copy_v2_v2(poly[1], uv_vertex2->uv);
1175 copy_v2_v2(poly[2], uv_vertex3->uv);
1176 const bool ccw = cross_poly_v2(poly, 3) > 0.0;
1177 return ccw;
1178}
1179
1181{
1182 uint64_t border_index = edges.first().border_index;
1183 for (UVBorderEdge &edge : edges) {
1184 edge.reverse_order = !edge.reverse_order;
1185 }
1186 std::reverse(edges.begin(), edges.end());
1187 update_indexes(border_index);
1188}
1189
1191{
1192 const UVBorderEdge &prev = edges[edge.prev_index];
1193 return M_PI - angle_signed_v2v2(prev.get_uv_vertex(1)->uv - prev.get_uv_vertex(0)->uv,
1194 edge.get_uv_vertex(1)->uv - edge.get_uv_vertex(0)->uv);
1195}
1196
1198{
1199 for (int64_t i = 0; i < edges.size(); i++) {
1200 int64_t prev = (i - 1 + edges.size()) % edges.size();
1201 int64_t next = (i + 1) % edges.size();
1202 edges[i].prev_index = prev;
1203 edges[i].index = i;
1204 edges[i].next_index = next;
1205 edges[i].border_index = border_index;
1206 }
1207}
1208
1210{
1211 /* Could read the border_index from any border edge as they are consistent. */
1212 uint64_t border_index = edges[0].border_index;
1213 edges.remove(index);
1214 update_indexes(border_index);
1215}
1216
1218
1219/* -------------------------------------------------------------------- */
1222
1227
1228float2 UVBorderCorner::uv(float factor, float min_uv_distance)
1229{
1230 using namespace blender::math;
1231 float2 origin = first->get_uv_vertex(1)->uv;
1232 float angle_between = angle * factor;
1233 float desired_len = max_ff(second->length() * factor + first->length() * (1.0 - factor),
1234 min_uv_distance);
1235 float2 v = normalize(first->get_uv_vertex(0)->uv - origin);
1236
1238 float2 rotated = rot_mat * v;
1239 float2 result = rotated * desired_len + first->get_uv_vertex(1)->uv;
1240 return result;
1241}
1242
1244{
1245 return first->get_uv_vertex(1) == second->get_uv_vertex(0);
1246}
1247
1249{
1250 std::stringstream ss;
1251 ss << "# ";
1252 if (connected_in_mesh()) {
1253 ss << first->get_uv_vertex(0)->vertex << "-";
1254 ss << first->get_uv_vertex(1)->vertex << "-";
1255 ss << second->get_uv_vertex(1)->vertex << "\n";
1256 }
1257 else {
1258 ss << first->get_uv_vertex(0)->vertex << "-";
1259 ss << first->get_uv_vertex(1)->vertex << ", ";
1260 ss << second->get_uv_vertex(0)->vertex << "-";
1261 ss << second->get_uv_vertex(1)->vertex << "\n";
1262 }
1263 std::cout << ss.str();
1264}
1265
1267
1268/* -------------------------------------------------------------------- */
1271
1273
1275{
1277 for (int i = 0; i < 3; i++) {
1278 for (int j = 0; j < 3; j++) {
1279 if (edges[i]->has_shared_edge(*other.edges[j])) {
1280 result.append(std::pair<UVEdge *, UVEdge *>(edges[i], other.edges[j]));
1281 }
1282 }
1283 }
1284 return result;
1285}
1286
1288{
1289 for (int i = 0; i < 3; i++) {
1290 for (int j = 0; j < 3; j++) {
1291 if (edges[i]->has_shared_edge(*other.edges[j])) {
1292 return true;
1293 }
1294 }
1295 }
1296 return false;
1297}
1298
1299bool UVPrimitive::has_shared_edge(const MeshData &mesh_data, const int other_triangle_index) const
1300{
1301 for (const UVEdge *uv_edge : edges) {
1302 const int3 &tri = mesh_data.corner_tris[other_triangle_index];
1303 int loop_1 = tri[2];
1304 for (int i = 0; i < 3; i++) {
1305 int loop_2 = tri[i];
1306 if (uv_edge->has_shared_edge(mesh_data.uv_map, loop_1, loop_2)) {
1307 return true;
1308 }
1309 loop_1 = loop_2;
1310 }
1311 }
1312 return false;
1313}
1314
1316 const uint8_t mesh_vert_index) const
1317{
1318 const int3 &tri = mesh_data.corner_tris[this->primitive_i];
1319 const int mesh_vertex = mesh_data.corner_verts[tri[mesh_vert_index]];
1320 for (const UVEdge *uv_edge : edges) {
1321 for (const UVVertex *uv_vert : uv_edge->vertices) {
1322 if (uv_vert->vertex == mesh_vertex) {
1323 return uv_vert;
1324 }
1325 }
1326 }
1328 return nullptr;
1329}
1330
1331UVEdge *UVPrimitive::get_uv_edge(const float2 uv1, const float2 uv2) const
1332{
1333 for (UVEdge *uv_edge : edges) {
1334 const float2 &e1 = uv_edge->vertices[0]->uv;
1335 const float2 &e2 = uv_edge->vertices[1]->uv;
1336 if ((e1 == uv1 && e2 == uv2) || (e1 == uv2 && e2 == uv1)) {
1337 return uv_edge;
1338 }
1339 }
1341 return nullptr;
1342}
1343
1344UVEdge *UVPrimitive::get_uv_edge(const int v1, const int v2) const
1345{
1346 for (UVEdge *uv_edge : edges) {
1347 const int e1 = uv_edge->vertices[0]->vertex;
1348 const int e2 = uv_edge->vertices[1]->vertex;
1349 if ((e1 == v1 && e2 == v2) || (e1 == v2 && e2 == v1)) {
1350 return uv_edge;
1351 }
1352 }
1354 return nullptr;
1355}
1356
1357bool UVPrimitive::contains_uv_vertex(const UVVertex *uv_vertex) const
1358{
1359 for (UVEdge *edge : edges) {
1360 if (std::find(edge->vertices.begin(), edge->vertices.end(), uv_vertex) != edge->vertices.end())
1361 {
1362 return true;
1363 }
1364 }
1365 return false;
1366}
1367
1369{
1372
1373 for (const UVEdge *edge : edges) {
1374 for (const UVVertex *uv_vertex : edge->vertices) {
1375 if (!ELEM(uv_vertex, v1, v2)) {
1376 return uv_vertex;
1377 }
1378 }
1379 }
1381 return nullptr;
1382}
1383
1385{
1386 Vector<UVBorderEdge> border_edges;
1387 for (UVEdge *edge : edges) {
1388 /* TODO remove const cast. only needed for debugging ATM. */
1389 UVBorderEdge border_edge(edge, const_cast<UVPrimitive *>(this));
1390 border_edges.append(border_edge);
1391 }
1392 return *UVBorder::extract_from_edges(border_edges);
1393}
1394
1396
1397/* -------------------------------------------------------------------- */
1404
1406{
1407 int actual_index = reverse_order ? 1 - index : index;
1408 return edge->vertices[actual_index];
1409}
1410
1412{
1413 int actual_index = reverse_order ? 1 - index : index;
1414 return edge->vertices[actual_index];
1415}
1416
1418{
1419 return uv_primitive->get_other_uv_vertex(edge->vertices[0], edge->vertices[1]);
1420}
1421
1423{
1424 return len_v2v2(edge->vertices[0]->uv, edge->vertices[1]->uv);
1425}
1426
1428
1429/* -------------------------------------------------------------------- */
1432
1434{
1435 islands.reserve(mesh_data.uv_island_len);
1436
1437 for (const int64_t uv_island_id : IndexRange(mesh_data.uv_island_len)) {
1438 islands.append_as(UVIsland());
1439 UVIsland *uv_island = &islands.last();
1440 uv_island->id = uv_island_id;
1441 for (const int primitive_i : mesh_data.corner_tris.index_range()) {
1442 if (mesh_data.uv_island_ids[primitive_i] == uv_island_id) {
1443 add_primitive(mesh_data, *uv_island, primitive_i);
1444 }
1445 }
1446 }
1447}
1448
1450{
1451 for (UVIsland &island : islands) {
1452 island.extract_borders();
1453 }
1454}
1455
1456void UVIslands::extend_borders(const MeshData &mesh_data, const UVIslandsMask &islands_mask)
1457{
1458 ushort index = 0;
1459 for (UVIsland &island : islands) {
1460 island.extend_border(mesh_data, islands_mask, index++);
1461 }
1462}
1463
1464void UVIslands::print_debug(const MeshData &mesh_data) const
1465{
1466 for (const UVIsland &island : islands) {
1467 island.print_debug(mesh_data);
1468 }
1469}
1470
1472
1473/* -------------------------------------------------------------------- */
1476
1478{
1479 return ushort2(max_ii(tile_resolution.x >> 2, 256), max_ii(tile_resolution.y >> 2, 256));
1480}
1481
1490
1492{
1493 const float2 tile_uv = uv - udim_offset;
1494 return IN_RANGE(tile_uv.x, 0.0, 1.0f) && IN_RANGE(tile_uv.y, 0.0f, 1.0f);
1495}
1496
1498{
1499 return min_ff(1.0f / tile_resolution.x, 1.0f / tile_resolution.y);
1500}
1501
1502static void add_uv_island(const MeshData &mesh_data,
1504 const UVIsland &uv_island,
1505 int16_t island_index)
1506{
1507 for (const UVPrimitive &uv_primitive : uv_island.uv_primitives) {
1508 const int3 &tri = mesh_data.corner_tris[uv_primitive.primitive_i];
1509
1510 rctf uv_bounds = primitive_uv_bounds(tri, mesh_data.uv_map);
1511 rcti buffer_bounds;
1512 buffer_bounds.xmin = max_ii(
1513 floor((uv_bounds.xmin - tile.udim_offset.x) * tile.mask_resolution.x), 0);
1514 buffer_bounds.xmax = min_ii(
1515 ceil((uv_bounds.xmax - tile.udim_offset.x) * tile.mask_resolution.x),
1516 tile.mask_resolution.x - 1);
1517 buffer_bounds.ymin = max_ii(
1518 floor((uv_bounds.ymin - tile.udim_offset.y) * tile.mask_resolution.y), 0);
1519 buffer_bounds.ymax = min_ii(
1520 ceil((uv_bounds.ymax - tile.udim_offset.y) * tile.mask_resolution.y),
1521 tile.mask_resolution.y - 1);
1522
1523 for (int y = buffer_bounds.ymin; y < buffer_bounds.ymax + 1; y++) {
1524 for (int x = buffer_bounds.xmin; x < buffer_bounds.xmax + 1; x++) {
1525 float2 uv(float(x) / tile.mask_resolution.x, float(y) / tile.mask_resolution.y);
1526 float3 weights;
1527 barycentric_weights_v2(mesh_data.uv_map[tri[0]],
1528 mesh_data.uv_map[tri[1]],
1529 mesh_data.uv_map[tri[2]],
1530 uv + tile.udim_offset,
1531 weights);
1532 if (!barycentric_inside_triangle_v2(weights)) {
1533 continue;
1534 }
1535
1536 uint64_t offset = tile.mask_resolution.x * y + x;
1537 tile.mask[offset] = island_index;
1538 }
1539 }
1540 }
1541}
1542
1543void UVIslandsMask::add(const MeshData &mesh_data, const UVIslands &uv_islands)
1544{
1545 for (Tile &tile : tiles) {
1546 for (const int i : uv_islands.islands.index_range()) {
1547 add_uv_island(mesh_data, tile, uv_islands.islands[i], i);
1548 }
1549 }
1550}
1551
1552void UVIslandsMask::add_tile(const float2 udim_offset, ushort2 resolution)
1553{
1554 tiles.append_as(Tile(udim_offset, resolution));
1555}
1556
1557static bool dilate_x(UVIslandsMask::Tile &islands_mask)
1558{
1559 bool changed = false;
1560 const Array<uint16_t> prev_mask = islands_mask.mask;
1561 for (int y = 0; y < islands_mask.mask_resolution.y; y++) {
1562 for (int x = 0; x < islands_mask.mask_resolution.x; x++) {
1563 uint64_t offset = y * islands_mask.mask_resolution.x + x;
1564 if (prev_mask[offset] != 0xffff) {
1565 continue;
1566 }
1567 if (x != 0 && prev_mask[offset - 1] != 0xffff) {
1568 islands_mask.mask[offset] = prev_mask[offset - 1];
1569 changed = true;
1570 }
1571 else if (x < islands_mask.mask_resolution.x - 1 && prev_mask[offset + 1] != 0xffff) {
1572 islands_mask.mask[offset] = prev_mask[offset + 1];
1573 changed = true;
1574 }
1575 }
1576 }
1577 return changed;
1578}
1579
1580static bool dilate_y(UVIslandsMask::Tile &islands_mask)
1581{
1582 bool changed = false;
1583 const Array<uint16_t> prev_mask = islands_mask.mask;
1584 for (int y = 0; y < islands_mask.mask_resolution.y; y++) {
1585 for (int x = 0; x < islands_mask.mask_resolution.x; x++) {
1586 uint64_t offset = y * islands_mask.mask_resolution.x + x;
1587 if (prev_mask[offset] != 0xffff) {
1588 continue;
1589 }
1590 if (y != 0 && prev_mask[offset - islands_mask.mask_resolution.x] != 0xffff) {
1591 islands_mask.mask[offset] = prev_mask[offset - islands_mask.mask_resolution.x];
1592 changed = true;
1593 }
1594 else if (y < islands_mask.mask_resolution.y - 1 &&
1595 prev_mask[offset + islands_mask.mask_resolution.x] != 0xffff)
1596 {
1597 islands_mask.mask[offset] = prev_mask[offset + islands_mask.mask_resolution.x];
1598 changed = true;
1599 }
1600 }
1601 }
1602 return changed;
1603}
1604
1605static void dilate_tile(UVIslandsMask::Tile &tile, int max_iterations)
1606{
1607 int index = 0;
1608 while (index < max_iterations) {
1609 bool changed = dilate_x(tile);
1610 changed |= dilate_y(tile);
1611 if (!changed) {
1612 break;
1613 }
1614 index++;
1615 }
1616}
1617
1618void UVIslandsMask::dilate(int max_iterations)
1619{
1620 for (Tile &tile : tiles) {
1621 dilate_tile(tile, max_iterations);
1622 }
1623}
1624
1625bool UVIslandsMask::Tile::is_masked(const uint16_t island_index, const float2 uv) const
1626{
1627 float2 local_uv = uv - udim_offset;
1628 if (local_uv.x < 0.0f || local_uv.y < 0.0f || local_uv.x >= 1.0f || local_uv.y >= 1.0f) {
1629 return false;
1630 }
1631 float2 pixel_pos_f = local_uv * float2(mask_resolution.x, mask_resolution.y);
1632 ushort2 pixel_pos = ushort2(pixel_pos_f.x, pixel_pos_f.y);
1633 uint64_t offset = pixel_pos.y * mask_resolution.x + pixel_pos.x;
1634 return mask[offset] == island_index;
1635}
1636
1638{
1639 for (const Tile &tile : tiles) {
1640 if (tile.contains(uv)) {
1641 return &tile;
1642 }
1643 }
1644 return nullptr;
1645}
1646
1647bool UVIslandsMask::is_masked(const uint16_t island_index, const float2 uv) const
1648{
1649 const Tile *tile = find_tile(uv);
1650 if (tile == nullptr) {
1651 return false;
1652 }
1653 return tile->is_masked(island_index, uv);
1654}
1655
1657
1658} // namespace blender::bke::pbvh::uv_islands
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI
int barycentric_inside_triangle_v2(const float w[3])
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
float cross_poly_v2(const float verts[][2], unsigned int nr)
Definition math_geom.cc:149
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2])
Definition rct.cc:510
void BLI_rctf_init_minmax(struct rctf *rect)
Definition rct.cc:480
unsigned short ushort
#define IN_RANGE(a, b, c)
#define ELEM(...)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void fill(const T &value) const
Definition BLI_array.hh:272
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
void append(const T &value)
void append_non_duplicates(const T &value)
void reserve(int64_t n)
Definition BLI_map.hh:1028
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
constexpr int64_t size() const
Definition BLI_span.hh:252
int64_t size() const
bool contains(const T &value) const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void append_non_duplicates(const T &value)
void add(const int primitive_i, const int edge_i)
void add(const Span< int > edges, const int tri_i)
void add(const int edge_i, const int v1, const int v2)
VecBase< float, D > normalize(VecOp< float, D >) RET
#define floor
#define ceil
const ccl_global KernelWorkTile * tile
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
static Vector< int > connecting_mesh_primitive_indices(const UVVertex &uv_vertex)
static int get_uv_loop(const MeshData &mesh_data, const int3 &tri, const int vert)
static void uv_primitive_append_to_uv_edges(UVPrimitive &uv_primitive)
static void dilate_tile(UVIslandsMask::Tile &tile, int max_iterations)
static void add_uv_island(const MeshData &mesh_data, UVIslandsMask::Tile &tile, const UVIsland &uv_island, int16_t island_index)
static bool dilate_x(UVIslandsMask::Tile &islands_mask)
static void uv_vertex_init_flags(UVVertex &uv_vertex)
static rctf primitive_uv_bounds(const int3 &tri, const Span< float2 > uv_map)
static void reset_extendability_flags(UVIsland &island)
static int find_fill_primitive(const MeshData &mesh_data, UVBorderCorner &corner)
static void uv_edge_append_to_uv_vertices(UVEdge &uv_edge)
static bool dilate_y(UVIslandsMask::Tile &islands_mask)
static std::optional< UVBorderCorner > sharpest_border_corner(UVBorder &border, float *r_angle)
static ushort2 mask_resolution_from_tile_resolution(ushort2 tile_resolution)
static void add_uv_primitive_fill(UVIsland &island, UVVertex &uv_vertex1, UVVertex &uv_vertex2, UVVertex &uv_vertex3, const int fill_primitive_i)
static void uv_primitive_append_to_uv_vertices(UVPrimitive &uv_primitive)
static int mesh_data_init_primitive_uv_island_ids(MeshData &mesh_data)
static constexpr int INVALID_UV_ISLAND_ID
static void add_uv_primitive_shared_uv_edge(const MeshData &mesh_data, UVIsland &island, UVVertex *connected_vert_1, UVVertex *connected_vert_2, float2 uv_unconnected, const int mesh_primitive_i)
static void extract_uv_neighbors(const MeshData &mesh_data, const Span< int > uv_island_ids, const int primitive_i, Vector< int > &prims_to_add)
static void extend_at_vert(const MeshData &mesh_data, UVIsland &island, UVBorderCorner &corner, float min_uv_distance)
static void mesh_data_init(MeshData &mesh_data)
static UVPrimitive * add_primitive(const MeshData &mesh_data, UVIsland &uv_island, const int primitive_i)
static int primitive_get_other_uv_vertex(const MeshData &mesh_data, const int3 &tri, const int v1, const int v2)
static bool primitive_has_shared_uv_edge(const Span< float2 > uv_map, const int3 &tri, const int3 &tri_other)
static void mesh_data_init_edges(MeshData &mesh_data)
AngleRadianBase< float > AngleRadian
AngleRadianBase< T > angle_between(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatT from_rotation(const RotationT &rotation)
MatBase< float, 2, 2 > float2x2
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< uint16_t, 2 > ushort2
VecBase< float, 3 > float3
FanSegment(const MeshData &mesh_data, const int primitive_index, const int3 tri, int vertex)
struct blender::bke::pbvh::uv_islands::FanSegment::@356056377220164103252025316204071224237371166074 flags
void print_debug(const MeshData &mesh_data) const
Vector< FanSegment * > best_path_between(const MeshData &mesh_data, const int from_vertex, const int to_vertex)
void print_debug(const MeshData &mesh_data) const
void mark_already_added_segments(const UVVertex &uv_vertex)
struct blender::bke::pbvh::uv_islands::Fan::@053100026027005360023052335102030132303115051347 flags
void init_uv_coordinates(const MeshData &mesh_data, UVVertex &uv_vertex)
bool contains_vertex_on_outside(const MeshData &mesh_data, const int vertex_index) const
static int64_t score(const Span< FanSegment * > solution)
static Vector< FanSegment * > path_between(const Span< FanSegment * > edge_order, const MeshData &mesh_data, const int from_vertex, const int to_vertex, const bool reversed)
static bool is_path_valid(const Span< FanSegment * > path, const MeshData &mesh_data, const int from_vertex, const int to_vertex)
Fan(const MeshData &mesh_data, const int vertex)
MeshData(OffsetIndices< int > faces, Span< int3 > corner_tris, Span< int > corner_verts, Span< float2 > uv_map, Span< float3 > vert_positions)
float2 uv(float factor, float min_uv_distance)
UVBorderCorner(UVBorderEdge *first, UVBorderEdge *second, float angle)
UVBorderEdge(UVEdge *edge, UVPrimitive *uv_primitive)
float outside_angle(const UVBorderEdge &edge) const
static std::optional< UVBorder > extract_from_edges(Vector< UVBorderEdge > &edges)
void update_indexes(uint64_t border_index)
bool has_same_vertices(const int2 &edge) const
bool has_shared_edge(Span< float2 > uv_map, const int loop_1, const int loop_2) const
std::array< UVVertex *, 2 > vertices
UVVertex * get_other_uv_vertex(const int vertex_index)
Map< int64_t, Vector< UVVertex * > > uv_vertex_lookup
void print_debug(const MeshData &mesh_data) const
bool has_shared_edge(const UVPrimitive &primitive) const
void extend_border(const MeshData &mesh_data, const UVIslandsMask &mask, const short island_index)
UVVertex * lookup_or_create(const UVVertex &vertex)
UVVertex * lookup(const UVVertex &vertex)
Tile(float2 udim_offset, ushort2 tile_resolution)
bool is_masked(const uint16_t island_index, const float2 uv) const
void add(const MeshData &mesh_data, const UVIslands &islands)
const Tile * find_tile(const float2 uv) const
bool is_masked(const uint16_t island_index, const float2 uv) const
void add_tile(float2 udim_offset, ushort2 resolution)
void extend_borders(const MeshData &mesh_data, const UVIslandsMask &islands_mask)
void print_debug(const MeshData &mesh_data) const
Vector< std::pair< UVEdge *, UVEdge * > > shared_edges(UVPrimitive &other)
UVEdge * get_uv_edge(const float2 uv1, const float2 uv2) const
bool has_shared_edge(const UVPrimitive &other) const
const UVVertex * get_other_uv_vertex(const UVVertex *v1, const UVVertex *v2) const
bool contains_uv_vertex(const UVVertex *uv_vertex) const
const UVVertex * get_uv_vertex(const MeshData &mesh_data, const uint8_t mesh_vert_index) const
struct blender::bke::pbvh::uv_islands::UVVertex::@146070211233272321030042025306175335142241112375 flags
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230