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