e23358bf4ffab6b42ca18271aff663a6a66483f7
[blender.git] / source / blender / bmesh / operators / bmo_utils.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.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/operators/bmo_utils.c
24  *  \ingroup bmesh
25  *
26  * utility bmesh operators, e.g. transform,
27  * translate, rotate, scale, etc.
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_meshdata_types.h"
33
34 #include "BLI_math.h"
35 #include "BLI_heap.h"
36 #include "BLI_alloca.h"
37
38 #include "BKE_customdata.h"
39
40 #include "bmesh.h"
41
42 #include "intern/bmesh_operators_private.h" /* own include */
43
44 #define ELE_NEW 1
45
46 void bmo_create_vert_exec(BMesh *bm, BMOperator *op)
47 {
48         float vec[3];
49
50         BMO_slot_vec_get(op->slots_in, "co", vec);
51
52         BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
53         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW);
54 }
55
56 void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op)
57 {
58         BMOIter iter;
59         BMVert *v;
60         float mat[4][4], mat_space[4][4], imat_space[4][4];
61
62         BMO_slot_mat4_get(op->slots_in, "matrix", mat);
63         BMO_slot_mat4_get(op->slots_in, "space", mat_space);
64
65         if (!is_zero_m4(mat_space)) {
66                 invert_m4_m4(imat_space, mat_space);
67                 mul_serie_m4(mat, imat_space, mat, mat_space, NULL, NULL, NULL, NULL, NULL);
68         }
69
70         BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) {
71                 mul_m4_v3(mat, v->co);
72         }
73 }
74
75 void bmo_translate_exec(BMesh *bm, BMOperator *op)
76 {
77         float mat[4][4], vec[3];
78         
79         BMO_slot_vec_get(op->slots_in, "vec", vec);
80
81         unit_m4(mat);
82         copy_v3_v3(mat[3], vec);
83
84         BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts");
85 }
86
87 void bmo_scale_exec(BMesh *bm, BMOperator *op)
88 {
89         float mat[3][3], vec[3];
90         
91         BMO_slot_vec_get(op->slots_in, "vec", vec);
92
93         unit_m3(mat);
94         mat[0][0] = vec[0];
95         mat[1][1] = vec[1];
96         mat[2][2] = vec[2];
97
98         BMO_op_callf(bm, op->flag, "transform matrix=%m3 space=%s verts=%s", mat, op, "space", op, "verts");
99 }
100
101 void bmo_rotate_exec(BMesh *bm, BMOperator *op)
102 {
103         float center[3];
104         float mat[4][4];
105
106         BMO_slot_vec_get(op->slots_in, "cent", center);
107         BMO_slot_mat4_get(op->slots_in, "matrix", mat);
108         transform_pivot_set_m4(mat, center);
109
110         BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts");
111 }
112
113 void bmo_reverse_faces_exec(BMesh *bm, BMOperator *op)
114 {
115         BMOIter siter;
116         BMFace *f;
117
118         BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
119                 BM_face_normal_flip(bm, f);
120         }
121 }
122
123 void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op)
124 {
125         BMOIter siter;
126         BMEdge *e, *e2;
127         const bool use_ccw   = BMO_slot_bool_get(op->slots_in, "use_ccw");
128         const bool is_single = BMO_slot_buffer_count(op->slots_in, "edges") == 1;
129         short check_flag = is_single ?
130                     BM_EDGEROT_CHECK_EXISTS :
131                     BM_EDGEROT_CHECK_EXISTS | BM_EDGEROT_CHECK_DEGENERATE;
132
133 #define EDGE_OUT   1
134 #define FACE_TAINT 1
135
136         BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
137                 /**
138                  * this ends up being called twice, could add option to not to call check in
139                  * #BM_edge_rotate to get some extra speed */
140                 if (BM_edge_rotate_check(e)) {
141                         BMFace *fa, *fb;
142                         if (BM_edge_face_pair(e, &fa, &fb)) {
143
144                                 /* check we're untouched */
145                                 if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == false &&
146                                     BMO_elem_flag_test(bm, fb, FACE_TAINT) == false)
147                                 {
148
149                                         if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) {
150 #if 0
151                                                 BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
152                                                 return;
153 #endif
154                                                 continue;
155                                         }
156
157                                         BMO_elem_flag_enable(bm, e2, EDGE_OUT);
158
159                                         /* don't touch again */
160                                         BMO_elem_flag_enable(bm, fa, FACE_TAINT);
161                                         BMO_elem_flag_enable(bm, fb, FACE_TAINT);
162                                 }
163                         }
164                 }
165         }
166
167         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT);
168
169 #undef EDGE_OUT
170 #undef FACE_TAINT
171
172 }
173
174 #define SEL_FLAG        1
175 #define SEL_ORIG        2
176
177 static void bmo_region_extend_extend(BMesh *bm, BMOperator *op, const bool use_faces)
178 {
179         BMVert *v;
180         BMEdge *e;
181         BMIter eiter;
182         BMOIter siter;
183
184         if (!use_faces) {
185                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
186                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
187                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
188                                         if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
189                                                 break;
190                         }
191
192                         if (e) {
193                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
194                                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
195                                                 BMO_elem_flag_enable(bm, e, SEL_FLAG);
196                                                 BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
197                                         }
198                                 }
199                         }
200                 }
201         }
202         else {
203                 BMIter liter, fiter;
204                 BMFace *f, *f2;
205                 BMLoop *l;
206
207                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
208                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
209                                 BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
210                                         if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
211                                                 if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
212                                                         BMO_elem_flag_enable(bm, f2, SEL_FLAG);
213                                                 }
214                                         }
215                                 }
216                         }
217                 }
218         }
219 }
220
221 static void bmo_region_extend_constrict(BMesh *bm, BMOperator *op, const bool use_faces)
222 {
223         BMVert *v;
224         BMEdge *e;
225         BMIter eiter;
226         BMOIter siter;
227
228         if (!use_faces) {
229                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
230                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
231                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
232                                         if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
233                                                 break;
234                         }
235
236                         if (e) {
237                                 BMO_elem_flag_enable(bm, v, SEL_FLAG);
238
239                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
240                                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
241                                                 BMO_elem_flag_enable(bm, e, SEL_FLAG);
242                                         }
243                                 }
244
245                         }
246                 }
247         }
248         else {
249                 BMIter liter, fiter;
250                 BMFace *f, *f2;
251                 BMLoop *l;
252
253                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
254                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
255                                 BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
256                                         if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
257                                                 if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
258                                                         BMO_elem_flag_enable(bm, f, SEL_FLAG);
259                                                         break;
260                                                 }
261                                         }
262                                 }
263                         }
264                 }
265         }
266 }
267
268 void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
269 {
270         const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces");
271         const bool constrict = BMO_slot_bool_get(op->slots_in, "use_constrict");
272
273         BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG);
274
275         if (constrict)
276                 bmo_region_extend_constrict(bm, op, use_faces);
277         else
278                 bmo_region_extend_extend(bm, op, use_faces);
279
280         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
281 }
282
283 void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
284 {
285         BMOIter siter;
286         BMIter iter;
287         BMVert *v;
288         BMEdge *e;
289         float (*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), __func__);
290         float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist");
291         int i, j, clipx, clipy, clipz;
292         int xaxis, yaxis, zaxis;
293         
294         clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x");
295         clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y");
296         clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z");
297
298         xaxis = BMO_slot_bool_get(op->slots_in, "use_axis_x");
299         yaxis = BMO_slot_bool_get(op->slots_in, "use_axis_y");
300         zaxis = BMO_slot_bool_get(op->slots_in, "use_axis_z");
301
302         i = 0;
303         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
304
305                 co = cos[i];
306                 zero_v3(co);
307
308                 j = 0;
309                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
310                         co2 = BM_edge_other_vert(e, v)->co;
311                         add_v3_v3v3(co, co, co2);
312                         j += 1;
313                 }
314                 
315                 if (!j) {
316                         copy_v3_v3(co, v->co);
317                         i++;
318                         continue;
319                 }
320
321                 mul_v3_fl(co, 1.0f / (float)j);
322                 mid_v3_v3v3(co, co, v->co);
323
324                 if (clipx && fabsf(v->co[0]) <= clip_dist)
325                         co[0] = 0.0f;
326                 if (clipy && fabsf(v->co[1]) <= clip_dist)
327                         co[1] = 0.0f;
328                 if (clipz && fabsf(v->co[2]) <= clip_dist)
329                         co[2] = 0.0f;
330
331                 i++;
332         }
333
334         i = 0;
335         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
336                 if (xaxis)
337                         v->co[0] = cos[i][0];
338                 if (yaxis)
339                         v->co[1] = cos[i][1];
340                 if (zaxis)
341                         v->co[2] = cos[i][2];
342
343                 i++;
344         }
345
346         MEM_freeN(cos);
347 }
348
349 /**************************************************************************** *
350  * Cycle UVs for a face
351  **************************************************************************** */
352
353 void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op)
354 {
355         BMOIter fs_iter;  /* selected faces iterator */
356         BMFace *fs;       /* current face */
357         BMIter l_iter;    /* iteration loop */
358
359         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
360         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
361
362         if (cd_loop_uv_offset != -1) {
363                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
364                         if (use_ccw == false) {  /* same loops direction */
365                                 BMLoop *lf;     /* current face loops */
366                                 MLoopUV *f_luv; /* first face loop uv */
367                                 float p_uv[2];  /* previous uvs */
368                                 float t_uv[2];  /* tmp uvs */
369
370                                 int n = 0;
371                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
372                                         /* current loop uv is the previous loop uv */
373                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
374                                         if (n == 0) {
375                                                 f_luv = luv;
376                                                 copy_v2_v2(p_uv, luv->uv);
377                                         }
378                                         else {
379                                                 copy_v2_v2(t_uv, luv->uv);
380                                                 copy_v2_v2(luv->uv, p_uv);
381                                                 copy_v2_v2(p_uv, t_uv);
382                                         }
383                                         n++;
384                                 }
385
386                                 copy_v2_v2(f_luv->uv, p_uv);
387                         }
388                         else { /* counter loop direction */
389                                 BMLoop *lf;     /* current face loops */
390                                 MLoopUV *p_luv; /* previous loop uv */
391                                 MLoopUV *luv;
392                                 float t_uv[2];  /* current uvs */
393
394                                 int n = 0;
395                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
396                                         /* previous loop uv is the current loop uv */
397                                         luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
398                                         if (n == 0) {
399                                                 p_luv = luv;
400                                                 copy_v2_v2(t_uv, luv->uv);
401                                         }
402                                         else {
403                                                 copy_v2_v2(p_luv->uv, luv->uv);
404                                                 p_luv = luv;
405                                         }
406                                         n++;
407                                 }
408
409                                 copy_v2_v2(luv->uv, t_uv);
410                         }
411                 }
412         }
413 }
414
415 /**************************************************************************** *
416  * Reverse UVs for a face
417  **************************************************************************** */
418
419 static void bm_face_reverse_uvs(BMFace *f, const int cd_loop_uv_offset)
420 {
421         BMIter iter;
422         BMLoop *l;
423         int i;
424
425         float (*uvs)[2] = BLI_array_alloca(uvs, f->len);
426
427         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
428                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
429                 copy_v2_v2(uvs[i], luv->uv);
430         }
431
432         /* now that we have the uvs in the array, reverse! */
433         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
434                 /* current loop uv is the previous loop uv */
435                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
436                 copy_v2_v2(luv->uv, uvs[(f->len - i - 1)]);
437         }
438 }
439 void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op)
440 {
441         BMOIter iter;
442         BMFace *f;
443         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
444
445         if (cd_loop_uv_offset != -1) {
446                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
447                         bm_face_reverse_uvs(f, cd_loop_uv_offset);
448                 }
449         }
450 }
451
452 /**************************************************************************** *
453  * Cycle colors for a face
454  **************************************************************************** */
455
456 void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
457 {
458         BMOIter fs_iter;  /* selected faces iterator */
459         BMFace *fs;       /* current face */
460         BMIter l_iter;    /* iteration loop */
461
462         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
463         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
464
465         if (cd_loop_color_offset != -1) {
466                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
467                         if (use_ccw == false) {  /* same loops direction */
468                                 BMLoop *lf;     /* current face loops */
469                                 MLoopCol *f_lcol; /* first face loop color */
470                                 MLoopCol p_col; /* previous color */
471                                 MLoopCol t_col; /* tmp color */
472
473                                 int n = 0;
474                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
475                                         /* current loop color is the previous loop color */
476                                         MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
477                                         if (n == 0) {
478                                                 f_lcol = lcol;
479                                                 p_col = *lcol;
480                                         }
481                                         else {
482                                                 t_col = *lcol;
483                                                 *lcol = p_col;
484                                                 p_col = t_col;
485                                         }
486                                         n++;
487                                 }
488
489                                 *f_lcol = p_col;
490                         }
491                         else {  /* counter loop direction */
492                                 BMLoop *lf;     /* current face loops */
493                                 MLoopCol *p_lcol; /* previous loop color */
494                                 MLoopCol *lcol;
495                                 MLoopCol t_col; /* current color */
496
497                                 int n = 0;
498                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
499                                         /* previous loop color is the current loop color */
500                                         lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
501                                         if (n == 0) {
502                                                 p_lcol = lcol;
503                                                 t_col = *lcol;
504                                         }
505                                         else {
506                                                 *p_lcol = *lcol;
507                                                 p_lcol = lcol;
508                                         }
509                                         n++;
510                                 }
511
512                                 *lcol = t_col;
513                         }
514                 }
515         }
516 }
517
518 /*************************************************************************** *
519  * Reverse colors for a face
520  *************************************************************************** */
521 static void bm_face_reverse_colors(BMFace *f, const int cd_loop_color_offset)
522 {
523         BMIter iter;
524         BMLoop *l;
525         int i;
526
527         MLoopCol *cols = BLI_array_alloca(cols, f->len);
528
529         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
530                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
531                 cols[i] = *lcol;
532         }
533
534         /* now that we have the uvs in the array, reverse! */
535         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
536                 /* current loop uv is the previous loop color */
537                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
538                 *lcol = cols[(f->len - i - 1)];
539         }
540 }
541 void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op)
542 {
543         BMOIter iter;
544         BMFace *f;
545         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
546
547         if (cd_loop_color_offset != -1) {
548                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
549                         bm_face_reverse_colors(f, cd_loop_color_offset);
550                 }
551         }
552 }