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