Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / bmesh / operators / bmo_utils.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file \ingroup bmesh
18  *
19  * utility bmesh operators, e.g. transform,
20  * translate, rotate, scale, etc.
21  */
22
23 #include "MEM_guardedalloc.h"
24
25 #include "DNA_meshdata_types.h"
26
27 #include "BLI_math.h"
28 #include "BLI_alloca.h"
29
30 #include "BKE_customdata.h"
31
32 #include "bmesh.h"
33
34 #include "intern/bmesh_operators_private.h" /* own include */
35
36 #define ELE_NEW 1
37
38 void bmo_create_vert_exec(BMesh *bm, BMOperator *op)
39 {
40         float vec[3];
41
42         BMO_slot_vec_get(op->slots_in, "co", vec);
43
44         BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW);
45         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW);
46 }
47
48 void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op)
49 {
50         BMOIter iter;
51         BMVert *v;
52         float mat[4][4], mat_space[4][4], imat_space[4][4];
53
54         BMO_slot_mat4_get(op->slots_in, "matrix", mat);
55         BMO_slot_mat4_get(op->slots_in, "space", mat_space);
56
57         if (!is_zero_m4(mat_space)) {
58                 invert_m4_m4(imat_space, mat_space);
59                 mul_m4_series(mat, imat_space, mat, mat_space);
60         }
61
62         BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) {
63                 mul_m4_v3(mat, v->co);
64         }
65 }
66
67 void bmo_translate_exec(BMesh *bm, BMOperator *op)
68 {
69         float mat[4][4], vec[3];
70
71         BMO_slot_vec_get(op->slots_in, "vec", vec);
72
73         unit_m4(mat);
74         copy_v3_v3(mat[3], vec);
75
76         BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts");
77 }
78
79 void bmo_scale_exec(BMesh *bm, BMOperator *op)
80 {
81         float mat[3][3], vec[3];
82
83         BMO_slot_vec_get(op->slots_in, "vec", vec);
84
85         unit_m3(mat);
86         mat[0][0] = vec[0];
87         mat[1][1] = vec[1];
88         mat[2][2] = vec[2];
89
90         BMO_op_callf(bm, op->flag, "transform matrix=%m3 space=%s verts=%s", mat, op, "space", op, "verts");
91 }
92
93 void bmo_rotate_exec(BMesh *bm, BMOperator *op)
94 {
95         float center[3];
96         float mat[4][4];
97
98         BMO_slot_vec_get(op->slots_in, "cent", center);
99         BMO_slot_mat4_get(op->slots_in, "matrix", mat);
100         transform_pivot_set_m4(mat, center);
101
102         BMO_op_callf(bm, op->flag, "transform matrix=%m4 space=%s verts=%s", mat, op, "space", op, "verts");
103 }
104
105 void bmo_reverse_faces_exec(BMesh *bm, BMOperator *op)
106 {
107         const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
108         const bool use_loop_mdisp_flip = BMO_slot_bool_get(op->slots_in, "flip_multires");
109         BMOIter siter;
110         BMFace *f;
111
112         BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
113                 BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
114         }
115 }
116
117
118 #define SEL_FLAG        1
119 #define SEL_ORIG        2
120
121 static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, const bool value)
122 {
123         BMLoop *l_iter;
124         BMLoop *l_first;
125
126         BMO_face_flag_set(bm, f, oflag, value);
127         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
128         do {
129                 BMO_edge_flag_set(bm, l_iter->e, oflag, value);
130                 BMO_vert_flag_set(bm, l_iter->v, oflag, value);
131         } while ((l_iter = l_iter->next) != l_first);
132 }
133
134
135 static void bmo_region_extend_expand(
136         BMesh *bm, BMOperator *op,
137         const bool use_faces, const bool use_faces_step)
138 {
139         BMOIter siter;
140
141         if (!use_faces) {
142                 BMVert *v;
143
144                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
145                         bool found = false;
146
147                         {
148                                 BMIter eiter;
149                                 BMEdge *e;
150
151                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
152                                         if (!BMO_edge_flag_test(bm, e, SEL_ORIG) &&
153                                             !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
154                                         {
155                                                 found = true;
156                                                 break;
157                                         }
158                                 }
159                         }
160
161                         if (found) {
162                                 if (!use_faces_step) {
163                                         BMIter eiter;
164                                         BMEdge *e;
165
166                                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
167                                                 if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
168                                                     !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
169                                                 {
170                                                         BMO_edge_flag_enable(bm, e, SEL_FLAG);
171                                                         BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
172                                                 }
173                                         }
174                                 }
175                                 else {
176                                         BMIter fiter;
177                                         BMFace *f;
178
179                                         BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
180                                                 if (!BMO_face_flag_test(bm, f, SEL_FLAG) &&
181                                                     !BM_elem_flag_test(f, BM_ELEM_HIDDEN))
182                                                 {
183                                                         bmo_face_flag_set_flush(bm, f, SEL_FLAG, true);
184                                                 }
185                                         }
186
187                                         /* handle wire edges (when stepping over faces) */
188                                         {
189                                                 BMIter eiter;
190                                                 BMEdge *e;
191                                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
192                                                         if (BM_edge_is_wire(e)) {
193                                                                 if (!BMO_edge_flag_test(bm, e, SEL_FLAG) &&
194                                                                     !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
195                                                                 {
196                                                                         BMO_edge_flag_enable(bm, e, SEL_FLAG);
197                                                                         BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
198                                                                 }
199                                                         }
200                                                 }
201                                         }
202                                 }
203                         }
204                 }
205         }
206         else {
207                 BMFace *f;
208
209                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
210                         BMIter liter;
211                         BMLoop *l;
212
213                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
214                                 if (!use_faces_step) {
215                                         BMIter fiter;
216                                         BMFace *f_other;
217
218                                         BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
219                                                 if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
220                                                     !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
221                                                 {
222                                                         BMO_face_flag_enable(bm, f_other, SEL_FLAG);
223                                                 }
224                                         }
225                                 }
226                                 else {
227                                         BMIter fiter;
228                                         BMFace *f_other;
229
230                                         BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
231                                                 if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) &&
232                                                     !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN))
233                                                 {
234                                                         BMO_face_flag_enable(bm, f_other, SEL_FLAG);
235                                                 }
236                                         }
237                                 }
238                         }
239                 }
240         }
241 }
242
243 static void bmo_region_extend_contract(
244         BMesh *bm, BMOperator *op,
245         const bool use_faces, const bool use_faces_step)
246 {
247         BMOIter siter;
248
249         if (!use_faces) {
250                 BMVert *v;
251
252                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
253                         bool found = false;
254
255                         if (!use_faces_step) {
256                                 BMIter eiter;
257                                 BMEdge *e;
258
259                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
260                                         if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
261                                                 found = true;
262                                                 break;
263                                         }
264                                 }
265                         }
266                         else {
267                                 BMIter fiter;
268                                 BMFace *f;
269
270                                 BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
271                                         if (!BMO_face_flag_test(bm, f, SEL_ORIG)) {
272                                                 found = true;
273                                                 break;
274                                         }
275                                 }
276
277                                 /* handle wire edges (when stepping over faces) */
278                                 if (!found) {
279                                         BMIter eiter;
280                                         BMEdge *e;
281
282                                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
283                                                 if (BM_edge_is_wire(e)) {
284                                                         if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) {
285                                                                 found = true;
286                                                                 break;
287                                                         }
288                                                 }
289                                         }
290                                 }
291                         }
292
293                         if (found) {
294                                 BMIter eiter;
295                                 BMEdge *e;
296
297                                 BMO_vert_flag_enable(bm, v, SEL_FLAG);
298
299                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
300                                         BMO_edge_flag_enable(bm, e, SEL_FLAG);
301                                 }
302                         }
303                 }
304         }
305         else {
306                 BMFace *f;
307
308                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
309                         BMIter liter;
310                         BMLoop *l;
311
312                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
313
314                                 if (!use_faces_step) {
315                                         BMIter fiter;
316                                         BMFace *f_other;
317
318                                         BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) {
319                                                 if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
320                                                         BMO_face_flag_enable(bm, f, SEL_FLAG);
321                                                         break;
322                                                 }
323                                         }
324                                 }
325                                 else {
326                                         BMIter fiter;
327                                         BMFace *f_other;
328
329                                         BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) {
330                                                 if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) {
331                                                         BMO_face_flag_enable(bm, f, SEL_FLAG);
332                                                         break;
333                                                 }
334                                         }
335                                 }
336                         }
337                 }
338         }
339 }
340
341 void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
342 {
343         const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces");
344         const bool use_face_step = BMO_slot_bool_get(op->slots_in, "use_face_step");
345         const bool constrict = BMO_slot_bool_get(op->slots_in, "use_contract");
346
347         BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG);
348
349         if (constrict) {
350                 bmo_region_extend_contract(bm, op, use_faces, use_face_step);
351         }
352         else {
353                 bmo_region_extend_expand(bm, op, use_faces, use_face_step);
354         }
355
356         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
357 }
358
359 void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
360 {
361         BMOIter siter;
362         BMIter iter;
363         BMVert *v;
364         BMEdge *e;
365         float (*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), __func__);
366         float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist");
367         const float fac = BMO_slot_float_get(op->slots_in, "factor");
368         int i, j, clipx, clipy, clipz;
369         int xaxis, yaxis, zaxis;
370
371         clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x");
372         clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y");
373         clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z");
374
375         xaxis = BMO_slot_bool_get(op->slots_in, "use_axis_x");
376         yaxis = BMO_slot_bool_get(op->slots_in, "use_axis_y");
377         zaxis = BMO_slot_bool_get(op->slots_in, "use_axis_z");
378
379         i = 0;
380         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
381
382                 co = cos[i];
383                 zero_v3(co);
384
385                 j = 0;
386                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
387                         co2 = BM_edge_other_vert(e, v)->co;
388                         add_v3_v3v3(co, co, co2);
389                         j += 1;
390                 }
391
392                 if (!j) {
393                         copy_v3_v3(co, v->co);
394                         i++;
395                         continue;
396                 }
397
398                 mul_v3_fl(co, 1.0f / (float)j);
399                 interp_v3_v3v3(co, v->co, co, fac);
400
401                 if (clipx && fabsf(v->co[0]) <= clip_dist)
402                         co[0] = 0.0f;
403                 if (clipy && fabsf(v->co[1]) <= clip_dist)
404                         co[1] = 0.0f;
405                 if (clipz && fabsf(v->co[2]) <= clip_dist)
406                         co[2] = 0.0f;
407
408                 i++;
409         }
410
411         i = 0;
412         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
413                 if (xaxis)
414                         v->co[0] = cos[i][0];
415                 if (yaxis)
416                         v->co[1] = cos[i][1];
417                 if (zaxis)
418                         v->co[2] = cos[i][2];
419
420                 i++;
421         }
422
423         MEM_freeN(cos);
424 }
425
426 /**************************************************************************** *
427  * Cycle UVs for a face
428  **************************************************************************** */
429
430 void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op)
431 {
432         BMOIter fs_iter;  /* selected faces iterator */
433         BMFace *fs;       /* current face */
434         BMIter l_iter;    /* iteration loop */
435
436         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
437         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
438
439         if (cd_loop_uv_offset != -1) {
440                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
441                         if (use_ccw == false) {  /* same loops direction */
442                                 BMLoop *lf;     /* current face loops */
443                                 MLoopUV *f_luv; /* first face loop uv */
444                                 float p_uv[2];  /* previous uvs */
445                                 float t_uv[2];  /* tmp uvs */
446
447                                 int n = 0;
448                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
449                                         /* current loop uv is the previous loop uv */
450                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
451                                         if (n == 0) {
452                                                 f_luv = luv;
453                                                 copy_v2_v2(p_uv, luv->uv);
454                                         }
455                                         else {
456                                                 copy_v2_v2(t_uv, luv->uv);
457                                                 copy_v2_v2(luv->uv, p_uv);
458                                                 copy_v2_v2(p_uv, t_uv);
459                                         }
460                                         n++;
461                                 }
462
463                                 copy_v2_v2(f_luv->uv, p_uv);
464                         }
465                         else { /* counter loop direction */
466                                 BMLoop *lf;     /* current face loops */
467                                 MLoopUV *p_luv; /* previous loop uv */
468                                 MLoopUV *luv;
469                                 float t_uv[2];  /* current uvs */
470
471                                 int n = 0;
472                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
473                                         /* previous loop uv is the current loop uv */
474                                         luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
475                                         if (n == 0) {
476                                                 p_luv = luv;
477                                                 copy_v2_v2(t_uv, luv->uv);
478                                         }
479                                         else {
480                                                 copy_v2_v2(p_luv->uv, luv->uv);
481                                                 p_luv = luv;
482                                         }
483                                         n++;
484                                 }
485
486                                 copy_v2_v2(luv->uv, t_uv);
487                         }
488                 }
489         }
490 }
491
492 /**************************************************************************** *
493  * Reverse UVs for a face
494  **************************************************************************** */
495
496 static void bm_face_reverse_uvs(BMFace *f, const int cd_loop_uv_offset)
497 {
498         BMIter iter;
499         BMLoop *l;
500         int i;
501
502         float (*uvs)[2] = BLI_array_alloca(uvs, f->len);
503
504         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
505                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
506                 copy_v2_v2(uvs[i], luv->uv);
507         }
508
509         /* now that we have the uvs in the array, reverse! */
510         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
511                 /* current loop uv is the previous loop uv */
512                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
513                 copy_v2_v2(luv->uv, uvs[(f->len - i - 1)]);
514         }
515 }
516 void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op)
517 {
518         BMOIter iter;
519         BMFace *f;
520         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
521
522         if (cd_loop_uv_offset != -1) {
523                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
524                         bm_face_reverse_uvs(f, cd_loop_uv_offset);
525                 }
526         }
527 }
528
529 /**************************************************************************** *
530  * Cycle colors for a face
531  **************************************************************************** */
532
533 void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
534 {
535         BMOIter fs_iter;  /* selected faces iterator */
536         BMFace *fs;       /* current face */
537         BMIter l_iter;    /* iteration loop */
538
539         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
540         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
541
542         if (cd_loop_color_offset != -1) {
543                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
544                         if (use_ccw == false) {  /* same loops direction */
545                                 BMLoop *lf;     /* current face loops */
546                                 MLoopCol *f_lcol; /* first face loop color */
547                                 MLoopCol p_col; /* previous color */
548                                 MLoopCol t_col; /* tmp color */
549
550                                 int n = 0;
551                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
552                                         /* current loop color is the previous loop color */
553                                         MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
554                                         if (n == 0) {
555                                                 f_lcol = lcol;
556                                                 p_col = *lcol;
557                                         }
558                                         else {
559                                                 t_col = *lcol;
560                                                 *lcol = p_col;
561                                                 p_col = t_col;
562                                         }
563                                         n++;
564                                 }
565
566                                 *f_lcol = p_col;
567                         }
568                         else {  /* counter loop direction */
569                                 BMLoop *lf;     /* current face loops */
570                                 MLoopCol *p_lcol; /* previous loop color */
571                                 MLoopCol *lcol;
572                                 MLoopCol t_col; /* current color */
573
574                                 int n = 0;
575                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
576                                         /* previous loop color is the current loop color */
577                                         lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
578                                         if (n == 0) {
579                                                 p_lcol = lcol;
580                                                 t_col = *lcol;
581                                         }
582                                         else {
583                                                 *p_lcol = *lcol;
584                                                 p_lcol = lcol;
585                                         }
586                                         n++;
587                                 }
588
589                                 *lcol = t_col;
590                         }
591                 }
592         }
593 }
594
595 /*************************************************************************** *
596  * Reverse colors for a face
597  *************************************************************************** */
598 static void bm_face_reverse_colors(BMFace *f, const int cd_loop_color_offset)
599 {
600         BMIter iter;
601         BMLoop *l;
602         int i;
603
604         MLoopCol *cols = BLI_array_alloca(cols, f->len);
605
606         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
607                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
608                 cols[i] = *lcol;
609         }
610
611         /* now that we have the uvs in the array, reverse! */
612         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
613                 /* current loop uv is the previous loop color */
614                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
615                 *lcol = cols[(f->len - i - 1)];
616         }
617 }
618 void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op)
619 {
620         BMOIter iter;
621         BMFace *f;
622         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
623
624         if (cd_loop_color_offset != -1) {
625                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
626                         bm_face_reverse_colors(f, cd_loop_color_offset);
627                 }
628         }
629 }