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