Math Lib: rename mul_serie_m3 to mul_m3_series & reorder args
[blender-staging.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_m4_series(mat, imat_space, mat, mat_space);
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                                         /* don't touch again (faces will be freed so run before rotating the edge) */
149                                         BMO_elem_flag_enable(bm, fa, FACE_TAINT);
150                                         BMO_elem_flag_enable(bm, fb, FACE_TAINT);
151
152                                         if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) {
153
154                                                 BMO_elem_flag_disable(bm, fa, FACE_TAINT);
155                                                 BMO_elem_flag_disable(bm, fb, FACE_TAINT);
156 #if 0
157                                                 BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge");
158                                                 return;
159 #endif
160
161                                                 continue;
162                                         }
163
164                                         BMO_elem_flag_enable(bm, e2, EDGE_OUT);
165                                 }
166                         }
167                 }
168         }
169
170         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT);
171
172 #undef EDGE_OUT
173 #undef FACE_TAINT
174
175 }
176
177 #define SEL_FLAG        1
178 #define SEL_ORIG        2
179
180 static void bmo_region_extend_extend(BMesh *bm, BMOperator *op, const bool use_faces)
181 {
182         BMVert *v;
183         BMEdge *e;
184         BMIter eiter;
185         BMOIter siter;
186
187         if (!use_faces) {
188                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
189                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
190                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
191                                         if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
192                                                 break;
193                         }
194
195                         if (e) {
196                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
197                                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
198                                                 BMO_elem_flag_enable(bm, e, SEL_FLAG);
199                                                 BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG);
200                                         }
201                                 }
202                         }
203                 }
204         }
205         else {
206                 BMIter liter, fiter;
207                 BMFace *f, *f2;
208                 BMLoop *l;
209
210                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
211                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
212                                 BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
213                                         if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
214                                                 if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
215                                                         BMO_elem_flag_enable(bm, f2, SEL_FLAG);
216                                                 }
217                                         }
218                                 }
219                         }
220                 }
221         }
222 }
223
224 static void bmo_region_extend_constrict(BMesh *bm, BMOperator *op, const bool use_faces)
225 {
226         BMVert *v;
227         BMEdge *e;
228         BMIter eiter;
229         BMOIter siter;
230
231         if (!use_faces) {
232                 BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
233                         BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
234                                 if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN))
235                                         if (!BMO_elem_flag_test(bm, e, SEL_ORIG))
236                                                 break;
237                         }
238
239                         if (e) {
240                                 BMO_elem_flag_enable(bm, v, SEL_FLAG);
241
242                                 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
243                                         if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
244                                                 BMO_elem_flag_enable(bm, e, SEL_FLAG);
245                                         }
246                                 }
247
248                         }
249                 }
250         }
251         else {
252                 BMIter liter, fiter;
253                 BMFace *f, *f2;
254                 BMLoop *l;
255
256                 BMO_ITER (f, &siter, op->slots_in, "geom", BM_FACE) {
257                         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
258                                 BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
259                                         if (!BM_elem_flag_test(f2, BM_ELEM_HIDDEN)) {
260                                                 if (!BMO_elem_flag_test(bm, f2, SEL_ORIG)) {
261                                                         BMO_elem_flag_enable(bm, f, SEL_FLAG);
262                                                         break;
263                                                 }
264                                         }
265                                 }
266                         }
267                 }
268         }
269 }
270
271 void bmo_region_extend_exec(BMesh *bm, BMOperator *op)
272 {
273         const bool use_faces = BMO_slot_bool_get(op->slots_in, "use_faces");
274         const bool constrict = BMO_slot_bool_get(op->slots_in, "use_constrict");
275
276         BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_ALL_NOLOOP, SEL_ORIG);
277
278         if (constrict)
279                 bmo_region_extend_constrict(bm, op, use_faces);
280         else
281                 bmo_region_extend_extend(bm, op, use_faces);
282
283         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG);
284 }
285
286 void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
287 {
288         BMOIter siter;
289         BMIter iter;
290         BMVert *v;
291         BMEdge *e;
292         float (*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), __func__);
293         float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist");
294         int i, j, clipx, clipy, clipz;
295         int xaxis, yaxis, zaxis;
296         
297         clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x");
298         clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y");
299         clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z");
300
301         xaxis = BMO_slot_bool_get(op->slots_in, "use_axis_x");
302         yaxis = BMO_slot_bool_get(op->slots_in, "use_axis_y");
303         zaxis = BMO_slot_bool_get(op->slots_in, "use_axis_z");
304
305         i = 0;
306         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
307
308                 co = cos[i];
309                 zero_v3(co);
310
311                 j = 0;
312                 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
313                         co2 = BM_edge_other_vert(e, v)->co;
314                         add_v3_v3v3(co, co, co2);
315                         j += 1;
316                 }
317                 
318                 if (!j) {
319                         copy_v3_v3(co, v->co);
320                         i++;
321                         continue;
322                 }
323
324                 mul_v3_fl(co, 1.0f / (float)j);
325                 mid_v3_v3v3(co, co, v->co);
326
327                 if (clipx && fabsf(v->co[0]) <= clip_dist)
328                         co[0] = 0.0f;
329                 if (clipy && fabsf(v->co[1]) <= clip_dist)
330                         co[1] = 0.0f;
331                 if (clipz && fabsf(v->co[2]) <= clip_dist)
332                         co[2] = 0.0f;
333
334                 i++;
335         }
336
337         i = 0;
338         BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
339                 if (xaxis)
340                         v->co[0] = cos[i][0];
341                 if (yaxis)
342                         v->co[1] = cos[i][1];
343                 if (zaxis)
344                         v->co[2] = cos[i][2];
345
346                 i++;
347         }
348
349         MEM_freeN(cos);
350 }
351
352 /**************************************************************************** *
353  * Cycle UVs for a face
354  **************************************************************************** */
355
356 void bmo_rotate_uvs_exec(BMesh *bm, BMOperator *op)
357 {
358         BMOIter fs_iter;  /* selected faces iterator */
359         BMFace *fs;       /* current face */
360         BMIter l_iter;    /* iteration loop */
361
362         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
363         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
364
365         if (cd_loop_uv_offset != -1) {
366                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
367                         if (use_ccw == false) {  /* same loops direction */
368                                 BMLoop *lf;     /* current face loops */
369                                 MLoopUV *f_luv; /* first face loop uv */
370                                 float p_uv[2];  /* previous uvs */
371                                 float t_uv[2];  /* tmp uvs */
372
373                                 int n = 0;
374                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
375                                         /* current loop uv is the previous loop uv */
376                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
377                                         if (n == 0) {
378                                                 f_luv = luv;
379                                                 copy_v2_v2(p_uv, luv->uv);
380                                         }
381                                         else {
382                                                 copy_v2_v2(t_uv, luv->uv);
383                                                 copy_v2_v2(luv->uv, p_uv);
384                                                 copy_v2_v2(p_uv, t_uv);
385                                         }
386                                         n++;
387                                 }
388
389                                 copy_v2_v2(f_luv->uv, p_uv);
390                         }
391                         else { /* counter loop direction */
392                                 BMLoop *lf;     /* current face loops */
393                                 MLoopUV *p_luv; /* previous loop uv */
394                                 MLoopUV *luv;
395                                 float t_uv[2];  /* current uvs */
396
397                                 int n = 0;
398                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
399                                         /* previous loop uv is the current loop uv */
400                                         luv = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_uv_offset);
401                                         if (n == 0) {
402                                                 p_luv = luv;
403                                                 copy_v2_v2(t_uv, luv->uv);
404                                         }
405                                         else {
406                                                 copy_v2_v2(p_luv->uv, luv->uv);
407                                                 p_luv = luv;
408                                         }
409                                         n++;
410                                 }
411
412                                 copy_v2_v2(luv->uv, t_uv);
413                         }
414                 }
415         }
416 }
417
418 /**************************************************************************** *
419  * Reverse UVs for a face
420  **************************************************************************** */
421
422 static void bm_face_reverse_uvs(BMFace *f, const int cd_loop_uv_offset)
423 {
424         BMIter iter;
425         BMLoop *l;
426         int i;
427
428         float (*uvs)[2] = BLI_array_alloca(uvs, f->len);
429
430         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
431                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
432                 copy_v2_v2(uvs[i], luv->uv);
433         }
434
435         /* now that we have the uvs in the array, reverse! */
436         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
437                 /* current loop uv is the previous loop uv */
438                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
439                 copy_v2_v2(luv->uv, uvs[(f->len - i - 1)]);
440         }
441 }
442 void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op)
443 {
444         BMOIter iter;
445         BMFace *f;
446         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
447
448         if (cd_loop_uv_offset != -1) {
449                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
450                         bm_face_reverse_uvs(f, cd_loop_uv_offset);
451                 }
452         }
453 }
454
455 /**************************************************************************** *
456  * Cycle colors for a face
457  **************************************************************************** */
458
459 void bmo_rotate_colors_exec(BMesh *bm, BMOperator *op)
460 {
461         BMOIter fs_iter;  /* selected faces iterator */
462         BMFace *fs;       /* current face */
463         BMIter l_iter;    /* iteration loop */
464
465         const bool use_ccw = BMO_slot_bool_get(op->slots_in, "use_ccw");
466         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
467
468         if (cd_loop_color_offset != -1) {
469                 BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) {
470                         if (use_ccw == false) {  /* same loops direction */
471                                 BMLoop *lf;     /* current face loops */
472                                 MLoopCol *f_lcol; /* first face loop color */
473                                 MLoopCol p_col; /* previous color */
474                                 MLoopCol t_col; /* tmp color */
475
476                                 int n = 0;
477                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
478                                         /* current loop color is the previous loop color */
479                                         MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
480                                         if (n == 0) {
481                                                 f_lcol = lcol;
482                                                 p_col = *lcol;
483                                         }
484                                         else {
485                                                 t_col = *lcol;
486                                                 *lcol = p_col;
487                                                 p_col = t_col;
488                                         }
489                                         n++;
490                                 }
491
492                                 *f_lcol = p_col;
493                         }
494                         else {  /* counter loop direction */
495                                 BMLoop *lf;     /* current face loops */
496                                 MLoopCol *p_lcol; /* previous loop color */
497                                 MLoopCol *lcol;
498                                 MLoopCol t_col; /* current color */
499
500                                 int n = 0;
501                                 BM_ITER_ELEM (lf, &l_iter, fs, BM_LOOPS_OF_FACE) {
502                                         /* previous loop color is the current loop color */
503                                         lcol = BM_ELEM_CD_GET_VOID_P(lf, cd_loop_color_offset);
504                                         if (n == 0) {
505                                                 p_lcol = lcol;
506                                                 t_col = *lcol;
507                                         }
508                                         else {
509                                                 *p_lcol = *lcol;
510                                                 p_lcol = lcol;
511                                         }
512                                         n++;
513                                 }
514
515                                 *lcol = t_col;
516                         }
517                 }
518         }
519 }
520
521 /*************************************************************************** *
522  * Reverse colors for a face
523  *************************************************************************** */
524 static void bm_face_reverse_colors(BMFace *f, const int cd_loop_color_offset)
525 {
526         BMIter iter;
527         BMLoop *l;
528         int i;
529
530         MLoopCol *cols = BLI_array_alloca(cols, f->len);
531
532         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
533                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
534                 cols[i] = *lcol;
535         }
536
537         /* now that we have the uvs in the array, reverse! */
538         BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, i) {
539                 /* current loop uv is the previous loop color */
540                 MLoopCol *lcol = BM_ELEM_CD_GET_VOID_P(l, cd_loop_color_offset);
541                 *lcol = cols[(f->len - i - 1)];
542         }
543 }
544 void bmo_reverse_colors_exec(BMesh *bm, BMOperator *op)
545 {
546         BMOIter iter;
547         BMFace *f;
548         const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
549
550         if (cd_loop_color_offset != -1) {
551                 BMO_ITER (f, &iter, op->slots_in, "faces", BM_FACE) {
552                         bm_face_reverse_colors(f, cd_loop_color_offset);
553                 }
554         }
555 }