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