Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / bmesh / operators / bmo_fill_attribute.c
1
2 /*
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  */
17
18 /** \file \ingroup bmesh
19  *
20  * Fill in geometry with the attributes of their adjacent data.
21  */
22
23 #include "BLI_utildefines.h"
24 #include "BLI_linklist_stack.h"
25
26 #include "bmesh.h"
27
28 #include "intern/bmesh_operators_private.h" /* own include */
29
30 /**
31  * Check if all other loops are tagged.
32  */
33 static bool bm_loop_is_all_radial_tag(BMLoop *l)
34 {
35         BMLoop *l_iter;
36         l_iter = l->radial_next;
37         do {
38                 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG) == 0) {
39                         return false;
40                 }
41         } while ((l_iter = l_iter->radial_next) != l);
42
43         return true;
44 }
45
46 /**
47  * Callback to run on source-loops for #BM_face_copy_shared
48  */
49 static bool bm_loop_is_face_untag(const BMLoop *l, void *UNUSED(user_data))
50 {
51         return (BM_elem_flag_test(l->f, BM_ELEM_TAG) == 0);
52 }
53
54 /**
55  * Copy all attributes from adjacent untagged faces.
56  */
57 static void bm_face_copy_shared_all(
58         BMesh *bm, BMLoop *l,
59         const bool use_normals, const bool use_data)
60 {
61         BMLoop *l_other = l->radial_next;
62         BMFace *f = l->f, *f_other;
63         while (BM_elem_flag_test(l_other->f, BM_ELEM_TAG)) {
64                 l_other = l_other->radial_next;
65         }
66         f_other = l_other->f;
67
68         if (use_data) {
69                 /* copy face-attrs */
70                 BM_elem_attrs_copy(bm, bm, f_other, f);
71
72                 /* copy loop-attrs */
73                 BM_face_copy_shared(bm, f, bm_loop_is_face_untag, NULL);
74         }
75
76         if (use_normals) {
77                 /* copy winding (flipping) */
78                 if (l->v == l_other->v) {
79                         BM_face_normal_flip(bm, f);
80                 }
81         }
82 }
83
84 /**
85  * Flood fill attributes.
86  */
87 static uint bmesh_face_attribute_fill(
88         BMesh *bm,
89         const bool use_normals, const bool use_data)
90 {
91         BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *);
92         BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *);
93
94         BMFace *f;
95         BMIter iter;
96         BMLoop *l;
97
98         uint face_tot = 0;
99
100
101         BLI_LINKSTACK_INIT(loop_queue_prev);
102         BLI_LINKSTACK_INIT(loop_queue_next);
103
104         BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
105                 if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
106                         BMLoop *l_iter, *l_first;
107                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
108                         do {
109                                 if (bm_loop_is_all_radial_tag(l_iter) == false) {
110                                         BLI_LINKSTACK_PUSH(loop_queue_prev, l_iter);
111                                 }
112                         } while ((l_iter = l_iter->next) != l_first);
113                 }
114         }
115
116         while (BLI_LINKSTACK_SIZE(loop_queue_prev)) {
117                 while ((l = BLI_LINKSTACK_POP(loop_queue_prev))) {
118                         /* check we're still un-assigned */
119                         if (BM_elem_flag_test(l->f, BM_ELEM_TAG)) {
120                                 BMLoop *l_iter;
121
122                                 BM_elem_flag_disable(l->f, BM_ELEM_TAG);
123
124                                 l_iter = l->next;
125                                 do {
126                                         BMLoop *l_radial_iter = l_iter->radial_next;
127                                         if (l_radial_iter != l_iter) {
128                                                 do {
129                                                         if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) {
130                                                                 BLI_LINKSTACK_PUSH(loop_queue_next, l_radial_iter);
131                                                         }
132                                                 } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
133                                         }
134                                 } while ((l_iter = l_iter->next) != l);
135
136                                 /* do last because of face flipping */
137                                 bm_face_copy_shared_all(bm, l,
138                                                         use_normals, use_data);
139                                 face_tot += 1;
140                         }
141                 }
142
143                 BLI_LINKSTACK_SWAP(loop_queue_prev, loop_queue_next);
144         }
145
146         BLI_LINKSTACK_FREE(loop_queue_prev);
147         BLI_LINKSTACK_FREE(loop_queue_next);
148
149         return face_tot;
150 }
151
152 void  bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op)
153 {
154         const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals");
155         const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data");
156
157         int face_tot;
158
159         BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
160         BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);  /* do inline */
161
162         /* now we can copy adjacent data */
163         face_tot = bmesh_face_attribute_fill(bm, use_normals, use_data);
164
165         if (face_tot != BMO_slot_buffer_count(op->slots_in, "faces")) {
166                 /* any remaining tags will be skipped */
167                 BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces_fail.out", BM_FACE, BM_ELEM_TAG);
168         }
169 }