style cleanup: braces/indentation
[blender-staging.git] / source / blender / bmesh / operators / bmo_create.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Campbell Barton.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/operators/bmo_create.c
24  *  \ingroup bmesh 
25  *
26  * Create faces or edges (Fkey by default).
27  */
28
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_listbase.h"
32
33 #include "bmesh.h"
34
35 #include "intern/bmesh_operators_private.h" /* own include */
36
37 #define ELE_NEW         1
38 #define ELE_OUT         2
39
40 /* This is what runs when pressing the F key
41  * doing the best thing here isn't always easy create vs dissolve, its nice to support
42  * but it it _really_ gives issues we might have to not call dissolve. - campbell
43  */
44 void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
45 {
46         BMOIter oiter;
47         BMHeader *h;
48         int totv = 0, tote = 0, totf = 0;
49         const short mat_nr     = BMO_slot_int_get(op->slots_in,  "mat_nr");
50         const bool use_smooth  = BMO_slot_bool_get(op->slots_in, "use_smooth");
51
52         /* count number of each element type we were passe */
53         BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) {
54                 switch (h->htype) {
55                         case BM_VERT: totv++; break;
56                         case BM_EDGE: tote++; break;
57                         case BM_FACE: totf++; break;
58                 }
59
60                 BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW);
61         }
62         
63         /* --- Support Edge Creation ---
64          * simple case when we only have 2 verts selected.
65          */
66         if (totv == 2 && tote == 0 && totf == 0) {
67                 BMVert *verts[2];
68                 BMEdge *e;
69
70                 BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)verts, 2);
71
72                 /* create edge */
73                 e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE);
74                 BMO_elem_flag_enable(bm, e, ELE_OUT);
75                 tote += 1;
76                 BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
77                 return;
78         }
79
80
81         /* --- Support for Special Case ---
82          * where there is a contiguous edge ring with one isolated vertex.
83          *
84          * This example shows 2 edges created from 3 verts
85          * with 1 free standing vertex. Dotted lines denote the 2 edges that are created.
86          *
87          * note that this works for any sided shape.
88          *
89          * +--------+
90          * |        .
91          * |        .
92          * |        .
93          * |        .
94          * +........+ <-- starts out free standing.
95          *
96          */
97
98         /* Here we check for consistency and create 2 edges */
99         if (totf == 0 && totv >= 4 && totv == tote + 2) {
100                 /* find a free standing vertex and 2 endpoint verts */
101                 BMVert *v, *v_free = NULL, *v_a = NULL, *v_b = NULL;
102                 bool ok = true;
103
104
105                 BMO_ITER (v, &oiter, op->slots_in, "geom", BM_VERT) {
106                         /* count how many flagged edges this vertex uses */
107                         const int tot_edges = BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, v, ELE_NEW, true);
108                         if (tot_edges == 0) {
109                                 /* only accept 1 free vert */
110                                 if (v_free == NULL)  v_free = v;
111                                 else                 ok = false;  /* only ever want one of these */
112                         }
113                         else if (tot_edges == 1) {
114                                 if      (v_a == NULL)  v_a = v;
115                                 else if (v_b == NULL)  v_b = v;
116                                 else                   ok = false;  /* only ever want 2 of these */
117                         }
118                         else if (tot_edges == 2) {
119                                 /* do nothing, regular case */
120                         }
121                         else {
122                                 ok = false; /* if a vertex has 3+ edge users then cancel - this is only simple cases */
123                         }
124
125                         if (ok == false) {
126                                 break;
127                         }
128                 }
129
130                 if (ok == true && v_free && v_a && v_b) {
131                         BMEdge *e;
132
133                         e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE);
134                         BMO_elem_flag_enable(bm, e, ELE_NEW);
135
136                         e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE);
137                         BMO_elem_flag_enable(bm, e, ELE_NEW);
138                         tote += 2;
139                 }
140         }
141         /* --- end special case support, continue as normal --- */
142
143
144         /* -------------------------------------------------------------------- */
145         /* EdgeNet Create */
146         if (tote != 0) {
147                 /* call edgenet prepare op so additional face creation cases work */
148                 BMOperator op_sub;
149                 BMO_op_initf(bm, &op_sub, op->flag, "edgenet_prepare edges=%fe", ELE_NEW);
150                 BMO_op_exec(bm, &op_sub);
151                 BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "edges.out", BM_EDGE, ELE_NEW);
152                 BMO_op_finish(bm, &op_sub);
153
154                 BMO_op_initf(bm, &op_sub, op->flag,
155                              "edgenet_fill edges=%fe use_fill_check=%b mat_nr=%i use_smooth=%b",
156                              ELE_NEW, true, mat_nr, use_smooth);
157
158                 BMO_op_exec(bm, &op_sub);
159
160                 /* return if edge net create did something */
161                 if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) {
162                         BMO_slot_copy(&op_sub, slots_out, "faces.out",
163                                       op,   slots_out, "faces.out");
164                         BMO_op_finish(bm, &op_sub);
165                         return;
166                 }
167
168                 BMO_op_finish(bm, &op_sub);
169         }
170
171
172         /* -------------------------------------------------------------------- */
173         /* Dissolve Face */
174         if (totf != 0) {  /* should be (totf > 1)... see below */
175                 /* note: allow this to run on single faces so running on a single face
176                  * won't go on to create a face, treating them as random */
177                 BMOperator op_sub;
178                 BMO_op_initf(bm, &op_sub, op->flag, "dissolve_faces faces=%ff", ELE_NEW);
179                 BMO_op_exec(bm, &op_sub);
180
181                 /* if we dissolved anything, then return */
182                 if (BMO_slot_buffer_count(op_sub.slots_out, "region.out")) {
183                         BMO_slot_copy(&op_sub, slots_out, "region.out",
184                                       op,   slots_out,  "faces.out");
185                         BMO_op_finish(bm, &op_sub);
186                         return;
187                 }
188
189                 BMO_op_finish(bm, &op_sub);
190         }
191
192
193         /* -------------------------------------------------------------------- */
194         /* Fill EdgeLoop's - fills isolated loops, different from edgenet */
195         if (tote > 2) {
196                 BMOperator op_sub;
197                 /* note: in most cases 'edgenet_fill' will handle this case since in common cases
198                  * users fill in empty spaces, however its possible to have an edge selection around
199                  * existing geometry that makes 'edgenet_fill' fail. */
200                 BMO_op_initf(bm, &op_sub, op->flag, "edgeloop_fill edges=%fe", ELE_NEW);
201                 BMO_op_exec(bm, &op_sub);
202
203                 /* return if edge loop fill did something */
204                 if (BMO_slot_buffer_count(op_sub.slots_out, "faces.out")) {
205                         BMO_slot_copy(&op_sub, slots_out, "faces.out",
206                                       op,   slots_out, "faces.out");
207                         BMO_op_finish(bm, &op_sub);
208                         return;
209                 }
210
211                 BMO_op_finish(bm, &op_sub);
212         }
213
214
215
216         /* -------------------------------------------------------------------- */
217         /* Continue with ad-hoc fill methods since operators fail,
218          * edge, vcloud... may add more */
219
220         if (0) { /* nice feature but perhaps it should be a different tool? */
221
222                 /* tricky feature for making a line/edge from selection history...
223                  *
224                  * Rather then do nothing, when 5+ verts are selected, check if they are in our history,
225                  * when this is so, we can make edges from them, but _not_ a face,
226                  * if it is the intention to make a face the user can just hit F again since there will be edges next
227                  * time around.
228                  *
229                  * if all history verts have ELE_NEW flagged and the total number of history verts == totv,
230                  * then we know the history contains all verts here and we can continue...
231                  */
232
233                 BMEditSelection *ese;
234                 int tot_ese_v = 0;
235
236                 for (ese = bm->selected.first; ese; ese = ese->next) {
237                         if (ese->htype == BM_VERT) {
238                                 if (BMO_elem_flag_test(bm, (BMElemF *)ese->ele, ELE_NEW)) {
239                                         tot_ese_v++;
240                                 }
241                                 else {
242                                         /* unflagged vert means we are not in sync */
243                                         tot_ese_v = -1;
244                                         break;
245                                 }
246                         }
247                 }
248
249                 if (tot_ese_v == totv) {
250                         BMVert *v_prev = NULL;
251                         /* yes, all select-history verts are accounted for, now make edges */
252
253                         for (ese = bm->selected.first; ese; ese = ese->next) {
254                                 if (ese->htype == BM_VERT) {
255                                         BMVert *v = (BMVert *)ese->ele;
256                                         if (v_prev) {
257                                                 BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE);
258                                                 BMO_elem_flag_enable(bm, e, ELE_OUT);
259                                         }
260                                         v_prev = v;
261                                 }
262                         }
263                 }
264                 BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT);
265                 /* done creating edges */
266
267                 return;
268         }
269
270
271         /* -------------------------------------------------------------------- */
272         /* Fill Vertex Cloud
273          *
274          * last resort when all else fails.
275          */
276         if (totv > 2) {
277                 /* TODO, some of these vertes may be connected by edges,
278                  * this connectivity could be used rather then treating
279                  * them as a bunch of isolated verts. */
280
281                 BMVert **vert_arr = MEM_mallocN(sizeof(BMVert **) * totv, __func__);
282                 BMFace *f;
283
284                 BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv);
285                 f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, BM_CREATE_NO_DOUBLE);
286
287                 if (f) {
288                         BMO_elem_flag_enable(bm, f, ELE_OUT);
289                         f->mat_nr = mat_nr;
290                         if (use_smooth) {
291                                 BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
292                         }
293                         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT);
294                 }
295
296                 MEM_freeN(vert_arr);
297         }
298 }