Blender V5.0
bmo_subdivide.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <array>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_math_geom.h"
16#include "BLI_math_vector.h"
17#include "BLI_noise.h"
18#include "BLI_rand.h"
19#include "BLI_stack.h"
20#include "BLI_vector.hh"
21
22#include "BKE_customdata.hh"
23
24#include "bmesh.hh"
27
28using blender::Vector;
29
30struct SubDParams {
32 float smooth;
34 float fractal;
36 // int beauty;
41 int seed;
43 BMOpSlot *slot_edge_percents; /* `BMO_slot_get(params->op->slots_in, "edge_percents")`. */
44 BMOpSlot *slot_custom_patterns; /* `BMO_slot_get(params->op->slots_in, "custom_patterns")`. */
45 float fractal_ofs[3];
46
47 /* Runtime storage for shape key. */
48 struct {
52
53 /* Shape-key holding displaced vertex coordinates for current geometry. */
54 int tmpkey;
56};
57
59{
60 const int skey = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY) - 1;
61 params->shape_info.tmpkey = skey;
62 params->shape_info.cd_vert_shape_offset = CustomData_get_offset(&bm->vdata, CD_SHAPEKEY);
63 params->shape_info.cd_vert_shape_offset_tmp = CustomData_get_n_offset(
64 &bm->vdata, CD_SHAPEKEY, skey);
65 params->shape_info.totlayer = CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY);
66}
67
68using subd_pattern_fill_fp = void (*)(BMesh *bm,
69 BMFace *face,
70 BMVert **verts,
71 const SubDParams *params);
72
73/*
74 * NOTE: this is a pattern-based edge subdivider.
75 * it tries to match a pattern to edge selections on faces,
76 * then executes functions to cut them.
77 */
79 int seledges[20]; /* selected edges mask, for splitting */
80
81 /* verts starts at the first new vert cut, not the first vert in the face */
83 int len; /* total number of verts, before any subdivision */
84};
85
86/* generic subdivision rules:
87 *
88 * - two selected edges in a face should make a link
89 * between them.
90 *
91 * - one edge should do, what? make pretty topology, or just
92 * split the edge only?
93 */
94
96#define SUBD_SPLIT 1
97
98#define EDGE_PERCENT 2
99
100/* I don't think new faces are flagged, currently, but
101 * better safe than sorry. */
102#define FACE_CUSTOMFILL 4
103#define ELE_INNER 8
104#define ELE_SPLIT 16
105
109#define FLT_FACE_SPLIT_EPSILON 0.00005f
110
111/*
112 * NOTE: beauty has been renamed to flag!
113 */
114
115/* generic subdivision rules:
116 *
117 * - two selected edges in a face should make a link
118 * between them.
119 *
120 * - one edge should do, what? make pretty topology, or just
121 * split the edge only?
122 */
123
124/* connects face with smallest len, which I think should always be correct for
125 * edge subdivision */
126static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new)
127{
128 BMLoop *l_a, *l_b;
129 BMFace *f;
130
131 /* this isn't the best thing in the world. it doesn't handle cases where there's
132 * multiple faces yet. that might require a convexity test to figure out which
133 * face is "best" and who knows what for non-manifold conditions.
134 *
135 * NOTE: we allow adjacent here, since there's no chance this happens.
136 */
137 f = BM_vert_pair_share_face_by_len(v_a, v_b, &l_a, &l_b, true);
138
139 if (f) {
140 BMFace *f_new;
141 BMLoop *l_new;
142
144
145 f_new = BM_face_split(bm, f, l_a, l_b, &l_new, nullptr, false);
146
147 if (r_f_new) {
148 *r_f_new = f_new;
149 }
150 return l_new ? l_new->e : nullptr;
151 }
152
153 return nullptr;
154}
155
160 const float co_a[3],
161 const float no_a[3],
162 const float co_b[3],
163 const float no_b[3],
164 const float no_dir[3], /* caller already knows, avoid normalize */
165 float fac,
166 float r_co[3])
167{
168 /* center of the sphere defined by both normals */
169 float center[3];
170
171 BLI_assert(len_squared_v3v3(no_a, no_b) != 0);
172
173 /* calculate sphere 'center' */
174 {
175 /* use point on plane to */
176 float no_mid[3], no_ortho[3];
177/* pass this as an arg instead */
178#if 0
179 float no_dir[3];
180#endif
181
182 add_v3_v3v3(no_mid, no_a, no_b);
183 normalize_v3(no_mid);
184
185#if 0
186 sub_v3_v3v3(no_dir, co_a, co_b);
187 normalize_v3(no_dir);
188#endif
189
190 /* axis of slerp */
191 bool center_ok = false;
192 cross_v3_v3v3(no_ortho, no_mid, no_dir);
193 if (normalize_v3(no_ortho) != 0.0f) {
194 float plane_a[4], plane_b[4], plane_c[4];
195 float v_a_no_ortho[3], v_b_no_ortho[3];
196
197 /* create planes */
198 cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
199 cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
200 project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
201 project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);
202
203 plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
204 plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
205 plane_from_point_normal_v3(plane_c, co_b, no_ortho);
206
207 /* find the sphere center from 3 planes */
208 if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
209 center_ok = true;
210 }
211 }
212 if (center_ok == false) {
213 mid_v3_v3v3(center, co_a, co_b);
214 }
215 }
216
217 /* calculate the final output 'r_co' */
218 {
219 float ofs_a[3], ofs_b[3], ofs_slerp[3];
220 float dist_a, dist_b;
221
222 sub_v3_v3v3(ofs_a, co_a, center);
223 sub_v3_v3v3(ofs_b, co_b, center);
224
225 dist_a = normalize_v3(ofs_a);
226 dist_b = normalize_v3(ofs_b);
227
228 if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
229 madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
230 }
231 else {
232 interp_v3_v3v3(r_co, co_a, co_b, fac);
233 }
234 }
235}
236
237/* Calculates offset for co, based on fractal, sphere or smooth settings. */
238static void alter_co(BMVert *v,
239 BMEdge * /*e_orig*/,
240 const SubDParams *params,
241 const float perc,
242 const BMVert *v_a,
243 const BMVert *v_b)
244{
245 float *co = static_cast<float *>(
246 BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
247 int i;
248
249 copy_v3_v3(co, v->co);
250
251 if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
252 normalize_v3_length(co, params->smooth);
253 }
254 else if (params->use_smooth) {
255/* calculating twice and blending gives smoother results,
256 * removing visible seams. */
257#define USE_SPHERE_DUAL_BLEND
258
259 const float eps_unit_vec = 1e-5f;
260 float smooth;
261 float no_dir[3];
262
263#ifdef USE_SPHERE_DUAL_BLEND
264 float no_reflect[3], co_a[3], co_b[3];
265#endif
266
267 sub_v3_v3v3(no_dir, v_a->co, v_b->co);
268 normalize_v3(no_dir);
269
270#ifndef USE_SPHERE_DUAL_BLEND
271 if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
272 interp_v3_v3v3(co, v_a->co, v_b->co, perc);
273 }
274 else {
275 interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
276 }
277#else
278 /* sphere-a */
279 reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
280 if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
281 interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
282 }
283 else {
284 interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
285 }
286
287 /* sphere-b */
288 reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
289 if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
290 interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
291 }
292 else {
293 interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
294 }
295
296 /* blend both spheres */
297 interp_v3_v3v3(co, co_a, co_b, perc);
298#endif /* USE_SPHERE_DUAL_BLEND */
299
300 /* apply falloff */
301 if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
302 smooth = 1.0f;
303 }
304 else {
305 smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
306 smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
307 }
308
309 if (params->use_smooth_even) {
310 smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
311 }
312
313 smooth *= params->smooth;
314 if (smooth != 1.0f) {
315 float co_flat[3];
316 interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
317 interp_v3_v3v3(co, co_flat, co, smooth);
318 }
319
320#undef USE_SPHERE_DUAL_BLEND
321 }
322
323 if (params->use_fractal) {
324 float normal[3], co2[3], base1[3], base2[3], tvec[3];
325 const float len = len_v3v3(v_a->co, v_b->co);
326 float fac;
327
328 fac = params->fractal * len;
329
330 mid_v3_v3v3(normal, v_a->no, v_b->no);
331 ortho_basis_v3v3_v3(base1, base2, normal);
332
333 add_v3_v3v3(co2, v->co, params->fractal_ofs);
334 mul_v3_fl(co2, 10.0f);
335
336 tvec[0] = fac *
337 (BLI_noise_generic_turbulence(1.0, co2[0], co2[1], co2[2], 15, false, 2) - 0.5f);
338 tvec[1] = fac *
339 (BLI_noise_generic_turbulence(1.0, co2[1], co2[0], co2[2], 15, false, 2) - 0.5f);
340 tvec[2] = fac *
341 (BLI_noise_generic_turbulence(1.0, co2[1], co2[2], co2[0], 15, false, 2) - 0.5f);
342
343 /* add displacement */
344 madd_v3_v3fl(co, normal, tvec[0]);
345 madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
346 madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
347 }
348
349 /* apply the new difference to the rest of the shape keys,
350 * note that this doesn't take rotations into account, we _could_ support
351 * this by getting the normals and coords for each shape key and
352 * re-calculate the smooth value for each but this is quite involved.
353 * for now its ok to simply apply the difference IMHO - campbell */
354
355 if (params->shape_info.totlayer > 1) {
356 float tvec[3];
357
358 sub_v3_v3v3(tvec, v->co, co);
359
360 /* skip the last layer since its the temp */
361 i = params->shape_info.totlayer - 1;
362 co = static_cast<float *>(BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset));
363 while (i--) {
364 BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
365 sub_v3_v3(co += 3, tvec);
366 }
367 }
368}
369
370/* assumes in the edge is the correct interpolated vertices already */
371/* percent defines the interpolation, rad and flag are for special options */
372/* results in new vertex with correct coordinate, vertex normal and weight group info */
374 BMEdge *edge,
375 BMEdge *e_orig,
376 const SubDParams *params,
377 const float factor_edge_split,
378 const float factor_subd,
379 BMVert *v_a,
380 BMVert *v_b,
381 BMEdge **r_edge)
382{
383 BMVert *v_new;
384
385 v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
386
388
389 /* offset for smooth or sphere or fractal */
390 alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
391
392#if 0 // BMESH_TODO
393 /* clip if needed by mirror modifier */
394 if (edge->v1->f2) {
395 if (edge->v1->f2 & edge->v2->f2 & 1) {
396 co[0] = 0.0f;
397 }
398 if (edge->v1->f2 & edge->v2->f2 & 2) {
399 co[1] = 0.0f;
400 }
401 if (edge->v1->f2 & edge->v2->f2 & 4) {
402 co[2] = 0.0f;
403 }
404 }
405#endif
406
407 interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd);
408 normalize_v3(v_new->no);
409
410 return v_new;
411}
412
414 BMEdge *edge,
415 BMEdge *e_orig,
416 int curpoint,
417 int totpoint,
418 const SubDParams *params,
419 BMVert *v_a,
420 BMVert *v_b,
421 BMEdge **r_edge)
422{
423 BMVert *v_new;
424 float factor_edge_split, factor_subd;
425
426 if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
427 factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
428 factor_subd = 0.0f;
429 }
430 else {
431 factor_edge_split = 1.0f / float(totpoint + 1 - curpoint);
432 factor_subd = float(curpoint + 1) / float(totpoint + 1);
433 }
434
436 bm, edge, e_orig, params, factor_edge_split, factor_subd, v_a, v_b, r_edge);
437 return v_new;
438}
439
441 BMesh *bm, BMEdge *edge, const SubDParams *params, BMVert *v_a, BMVert *v_b)
442{
443 BMEdge *eed = edge, *e_new, e_tmp = *edge;
444 BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2;
445 int i, numcuts = params->numcuts;
446
447 e_tmp.v1 = &v1_tmp;
448 e_tmp.v2 = &v2_tmp;
449
450 for (i = 0; i < numcuts; i++) {
451 v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
452
456
458 if (v->e) {
460 }
461 if (v->e && v->e->l) {
462 BM_CHECK_ELEMENT(v->e->l->f);
463 }
464 }
465
466 alter_co(v1, &e_tmp, params, 0, &v1_tmp, &v2_tmp);
467 alter_co(v2, &e_tmp, params, 1.0, &v1_tmp, &v2_tmp);
468}
469
470/* NOTE: the patterns are rotated as necessary to
471 * match the input geometry. they're based on the
472 * pre-split state of the face */
473
485 BMFace * /*face*/,
486 BMVert **verts,
487 const SubDParams *params)
488{
489 BMFace *f_new;
490 int i, add, numcuts = params->numcuts;
491
492 /* if it's odd, the middle face is a quad, otherwise it's a triangle */
493 if ((numcuts % 2) == 0) {
494 add = 2;
495 for (i = 0; i < numcuts; i++) {
496 if (i == numcuts / 2) {
497 add -= 1;
498 }
499 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
500 }
501 }
502 else {
503 add = 2;
504 for (i = 0; i < numcuts; i++) {
505 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
506 if (i == numcuts / 2) {
507 add -= 1;
508 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
509 }
510 }
511 }
512}
513
514static const SubDPattern quad_1edge = {
515 {1, 0, 0, 0},
517 4,
518};
519
531 BMFace * /*face*/,
532 BMVert **verts,
533 const SubDParams *params)
534{
535 BMFace *f_new;
536 int i, numcuts = params->numcuts;
537
538 for (i = 0; i < numcuts; i++) {
539 connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
540 }
541 connect_smallest_face(bm, verts[numcuts * 2 + 3], verts[numcuts * 2 + 1], &f_new);
542}
543
545 {1, 1, 0, 0},
547 4,
548};
549
561 BMFace * /*face*/,
562 BMVert **verts,
563 const SubDParams *params)
564{
565 BMFace *f_new;
566 BMVert *v, *v_last;
567 BMEdge *e, *e_new, e_tmp;
568 int i, numcuts = params->numcuts;
569
570 v_last = verts[numcuts];
571
572 for (i = numcuts - 1; i >= 0; i--) {
573 e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
574
575 e_tmp = *e;
576 v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new);
577
578 if (i != numcuts - 1) {
579 connect_smallest_face(bm, v_last, v, &f_new);
580 }
581
582 v_last = v;
583 }
584
585 connect_smallest_face(bm, v_last, verts[numcuts * 2 + 2], &f_new);
586}
587
589 {1, 1, 0, 0},
591 4,
592};
593
605 BMFace * /*face*/,
606 BMVert **verts,
607 const SubDParams *params)
608{
609 BMFace *f_new;
610 // BMVert *v; /* UNUSED */
611 // BMVert *v_last = verts[2]; /* UNUSED */
612 // BMEdge *e, *e_new; /* UNUSED */
613 int i, numcuts = params->numcuts;
614
615 for (i = 0; i < numcuts; i++) {
616 connect_smallest_face(bm, verts[i], verts[numcuts * 2 + 2], &f_new);
617 connect_smallest_face(bm, verts[numcuts + (numcuts - i)], verts[numcuts * 2 + 2], &f_new);
618 }
619}
620
622 {1, 1, 0, 0},
624 4,
625};
626
640 BMFace * /*face*/,
641 BMVert **verts,
642 const SubDParams *params)
643{
644 BMFace *f_new;
645 int i, add = 0, numcuts = params->numcuts;
646
647 for (i = 0; i < numcuts; i++) {
648 if (i == numcuts / 2) {
649 if (numcuts % 2 != 0) {
650 connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new);
651 }
652 add = numcuts * 2 + 2;
653 }
654 connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new);
655 }
656
657 for (i = 0; i < numcuts / 2 + 1; i++) {
658 connect_smallest_face(bm, verts[i], verts[(numcuts - i) + numcuts * 2 + 1], &f_new);
659 }
660}
661
662static const SubDPattern quad_3edge = {
663 {1, 1, 1, 0},
665 4,
666};
667
681 BMFace * /*face*/,
682 BMVert **verts,
683 const SubDParams *params)
684{
685 BMFace *f_new;
686 BMVert *v, *v1, *v2;
687 BMEdge *e, *e_new, e_tmp;
688 BMVert **lines;
689 int numcuts = params->numcuts;
690 int i, j, a, b, s = numcuts + 2 /* , totv = numcuts * 4 + 4 */;
691
692 lines = MEM_calloc_arrayN<BMVert *>(size_t(numcuts + 2) * size_t(numcuts + 2), "q_4edge_split");
693 /* build a 2-dimensional array of verts,
694 * containing every vert (and all new ones)
695 * in the face */
696
697 /* first line */
698 for (i = 0; i < numcuts + 2; i++) {
699 lines[i] = verts[numcuts * 3 + 2 + (numcuts - i + 1)];
700 }
701
702 /* last line */
703 for (i = 0; i < numcuts + 2; i++) {
704 lines[(s - 1) * s + i] = verts[numcuts + i];
705 }
706
707 /* first and last members of middle lines */
708 for (i = 0; i < numcuts; i++) {
709 a = i;
710 b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
711
712 e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
713 if (!e) {
714 continue;
715 }
716
719
720 v1 = lines[(i + 1) * s] = verts[a];
721 v2 = lines[(i + 1) * s + s - 1] = verts[b];
722
723 e_tmp = *e;
724 for (a = 0; a < numcuts; a++) {
725 v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new);
726
727 BMESH_ASSERT(v != nullptr);
728
730 lines[(i + 1) * s + a + 1] = v;
731 }
732 }
733
734 for (i = 1; i < numcuts + 2; i++) {
735 for (j = 1; j <= numcuts; j++) {
736 a = i * s + j;
737 b = (i - 1) * s + j;
738 e = connect_smallest_face(bm, lines[a], lines[b], &f_new);
739 if (!e) {
740 continue;
741 }
742
745 }
746 }
747
748 MEM_freeN(lines);
749}
750
763static void tri_1edge_split(BMesh *bm, BMFace * /*face*/, BMVert **verts, const SubDParams *params)
764{
765 BMFace *f_new;
766 int i, numcuts = params->numcuts;
767
768 for (i = 0; i < numcuts; i++) {
769 connect_smallest_face(bm, verts[i], verts[numcuts + 1], &f_new);
770 }
771}
772
773static const SubDPattern tri_1edge = {
774 {1, 0, 0},
776 3,
777};
778
792 BMFace * /*face*/,
793 BMVert **verts,
794 const SubDParams *params)
795{
796 BMFace *f_new;
797 BMEdge *e, *e_new, e_tmp;
798 BMVert ***lines, *v, v1_tmp, v2_tmp;
799 void *stackarr[1];
800 int i, j, a, b, numcuts = params->numcuts;
801
802 /* number of verts in each lin */
803 lines = static_cast<BMVert ***>(
804 MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table"));
805
806 lines[0] = (BMVert **)stackarr;
807 lines[0][0] = verts[numcuts * 2 + 1];
808
809 lines[numcuts + 1] = MEM_calloc_arrayN<BMVert *>(numcuts + 2, "triangle vert table 2");
810 for (i = 0; i < numcuts; i++) {
811 lines[numcuts + 1][i + 1] = verts[i];
812 }
813 lines[numcuts + 1][0] = verts[numcuts * 3 + 2];
814 lines[numcuts + 1][numcuts + 1] = verts[numcuts];
815
816 for (i = 0; i < numcuts; i++) {
817 lines[i + 1] = MEM_calloc_arrayN<BMVert *>(2 + i, "triangle vert table row");
818 a = numcuts * 2 + 2 + i;
819 b = numcuts + numcuts - i;
820 e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
821 if (!e) {
822 goto cleanup;
823 }
824
827
828 lines[i + 1][0] = verts[a];
829 lines[i + 1][i + 1] = verts[b];
830
831 e_tmp = *e;
832 v1_tmp = *verts[a];
833 v2_tmp = *verts[b];
834 e_tmp.v1 = &v1_tmp;
835 e_tmp.v2 = &v2_tmp;
836 for (j = 0; j < i; j++) {
837 v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
838 lines[i + 1][j + 1] = v;
839
841 }
842 }
843
856 for (i = 1; i <= numcuts; i++) {
857 for (j = 0; j < i; j++) {
858 e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new);
859
862
863 e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new);
864
867 }
868 }
869
870cleanup:
871 for (i = 1; i < numcuts + 2; i++) {
872 if (lines[i]) {
873 MEM_freeN(lines[i]);
874 }
875 }
876
877 MEM_freeN(lines);
878}
879
880static const SubDPattern tri_3edge = {
881 {1, 1, 1},
883 3,
884};
885
886static const SubDPattern quad_4edge = {
887 {1, 1, 1, 1},
889 4,
890};
891
892static const SubDPattern *patterns[] = {
893 nullptr, /* quad single edge pattern is inserted here */
894 nullptr, /* quad corner vert pattern is inserted here */
895 nullptr, /* tri single edge pattern is inserted here */
896 nullptr,
897 &quad_3edge,
898 nullptr,
899};
900
901#define PATTERNS_TOT ARRAY_SIZE(patterns)
902
906 int totedgesel; /* only used if pat was nullptr, e.g. no pattern was found */
908};
909
911{
912 BMOpSlot *einput;
913 const SubDPattern *pat;
915 BLI_Stack *facedata;
916 BMIter viter, fiter, liter;
917 BMVert *v;
918 BMEdge *edge;
919 BMLoop *l_new, *l;
920 BMFace *face;
921 float smooth, fractal, along_normal;
922 bool use_sphere, use_single_edge, use_grid_fill, use_only_quads;
923 int cornertype, seed, i, j, a, b, numcuts, totesel, smooth_falloff;
924
926
927 numcuts = BMO_slot_int_get(op->slots_in, "cuts");
928 seed = BMO_slot_int_get(op->slots_in, "seed");
929 smooth = BMO_slot_float_get(op->slots_in, "smooth");
930 smooth_falloff = BMO_slot_int_get(op->slots_in, "smooth_falloff");
931 fractal = BMO_slot_float_get(op->slots_in, "fractal");
932 along_normal = BMO_slot_float_get(op->slots_in, "along_normal");
933 cornertype = BMO_slot_int_get(op->slots_in, "quad_corner_type");
934
935 use_single_edge = BMO_slot_bool_get(op->slots_in, "use_single_edge");
936 use_grid_fill = BMO_slot_bool_get(op->slots_in, "use_grid_fill");
937 use_only_quads = BMO_slot_bool_get(op->slots_in, "use_only_quads");
938 use_sphere = BMO_slot_bool_get(op->slots_in, "use_sphere");
939
940 patterns[1] = nullptr;
941 /* straight cut is patterns[1] == nullptr */
942 switch (cornertype) {
943 case SUBD_CORNER_PATH:
945 break;
948 break;
949 case SUBD_CORNER_FAN:
951 break;
952 }
953
954 if (use_single_edge) {
955 patterns[0] = &quad_1edge;
956 patterns[2] = &tri_1edge;
957 }
958 else {
959 patterns[0] = nullptr;
960 patterns[2] = nullptr;
961 }
962
963 if (use_grid_fill) {
964 patterns[3] = &quad_4edge;
965 patterns[5] = &tri_3edge;
966 }
967 else {
968 patterns[3] = nullptr;
969 patterns[5] = nullptr;
970 }
971
972 /* Add a temporary shape-key layer to store displacements on current geometry. */
974
976
977 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
978 float *co = static_cast<float *>(
979 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
980 copy_v3_v3(co, v->co);
981 }
982
983 /* first go through and tag edges */
985
986 params.numcuts = numcuts;
987 params.op = op;
988 params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents");
989 params.slot_custom_patterns = BMO_slot_get(op->slots_in, "custom_patterns");
990 params.smooth = smooth;
991 params.smooth_falloff = smooth_falloff;
992 params.seed = seed;
993 params.fractal = fractal;
994 params.along_normal = along_normal;
995 params.use_smooth = (smooth != 0.0f);
996 params.use_smooth_even = BMO_slot_bool_get(op->slots_in, "use_smooth_even");
997 params.use_fractal = (fractal != 0.0f);
998 params.use_sphere = use_sphere;
999
1000 if (params.use_fractal) {
1002
1003 params.fractal_ofs[0] = BLI_rng_get_float(rng) * 200.0f;
1004 params.fractal_ofs[1] = BLI_rng_get_float(rng) * 200.0f;
1005 params.fractal_ofs[2] = BLI_rng_get_float(rng) * 200.0f;
1006
1007 BLI_rng_free(rng);
1008 }
1009
1010 BMO_slot_map_to_flag(bm, op->slots_in, "custom_patterns", BM_FACE, FACE_CUSTOMFILL);
1011
1012 BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT);
1013
1014 facedata = BLI_stack_new(sizeof(SubDFaceData), __func__);
1015
1018
1019 BM_ITER_MESH (face, &fiter, bm, BM_FACES_OF_MESH) {
1020 BMEdge *e1 = nullptr, *e2 = nullptr;
1021 float vec1[3], vec2[3];
1022 bool matched = false;
1023
1024 /* skip non-quads if requested */
1025 if (use_only_quads && face->len != 4) {
1026 continue;
1027 }
1028
1029 /* figure out which pattern to use */
1030 verts.reinitialize(face->len);
1031 edges.reinitialize(face->len);
1032
1033 totesel = 0;
1034 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, i) {
1035 edges[i] = l_new->e;
1036 verts[i] = l_new->v;
1037
1038 if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) {
1039 if (!e1) {
1040 e1 = edges[i];
1041 }
1042 else {
1043 e2 = edges[i];
1044 }
1045
1046 totesel++;
1047 }
1048 }
1049
1050 /* make sure the two edges have a valid angle to each other */
1051 if (totesel == 2 && BM_edge_share_vert_check(e1, e2)) {
1052 sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co);
1053 sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co);
1054 normalize_v3(vec1);
1055 normalize_v3(vec2);
1056
1057 if (fabsf(dot_v3v3(vec1, vec2)) > 1.0f - FLT_FACE_SPLIT_EPSILON) {
1058 totesel = 0;
1059 }
1060 }
1061
1063 pat = static_cast<const SubDPattern *>(
1064 *BMO_slot_map_data_get(params.slot_custom_patterns, face));
1065 for (i = 0; i < pat->len; i++) {
1066 matched = true;
1067 for (j = 0; j < pat->len; j++) {
1068 a = (j + i) % pat->len;
1069 if (!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT) != (!!pat->seledges[j])) {
1070 matched = false;
1071 break;
1072 }
1073 }
1074 if (matched) {
1075 SubDFaceData *fd;
1076
1077 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1078 fd->pat = pat;
1079 fd->start = verts[i];
1080 fd->face = face;
1081 fd->totedgesel = totesel;
1083 break;
1084 }
1085 }
1086
1087 /* Obviously don't test for other patterns matching. */
1088 continue;
1089 }
1090
1091 for (i = 0; i < PATTERNS_TOT; i++) {
1092 pat = patterns[i];
1093 if (!pat) {
1094 continue;
1095 }
1096
1097 if (pat->len == face->len) {
1098 for (a = 0; a < pat->len; a++) {
1099 matched = true;
1100 for (b = 0; b < pat->len; b++) {
1101 j = (b + a) % pat->len;
1102 if (!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT) != (!!pat->seledges[b])) {
1103 matched = false;
1104 break;
1105 }
1106 }
1107 if (matched) {
1108 break;
1109 }
1110 }
1111 if (matched) {
1112 SubDFaceData *fd;
1113
1115
1116 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1117 fd->pat = pat;
1118 fd->start = verts[a];
1119 fd->face = face;
1120 fd->totedgesel = totesel;
1121 break;
1122 }
1123 }
1124 }
1125
1126 if (!matched && totesel) {
1127 SubDFaceData *fd;
1128
1130
1131 /* must initialize all members here */
1132 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1133 fd->start = nullptr;
1134 fd->pat = nullptr;
1135 fd->totedgesel = totesel;
1136 fd->face = face;
1137 }
1138 }
1139
1140 einput = BMO_slot_get(op->slots_in, "edges");
1141
1142 /* go through and split edges */
1143 for (i = 0; i < einput->len; i++) {
1144 edge = static_cast<BMEdge *>(einput->data.buf[i]);
1145 bm_subdivide_multicut(bm, edge, &params, edge->v1, edge->v2);
1146 }
1147
1148 /* copy original-geometry displacements to current coordinates */
1149 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1150 const float *co = static_cast<const float *>(
1151 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
1152 copy_v3_v3(v->co, co);
1153 }
1154
1155 using LoopPair = std::array<BMLoop *, 2>;
1158 for (; !BLI_stack_is_empty(facedata); BLI_stack_discard(facedata)) {
1159 SubDFaceData *fd = static_cast<SubDFaceData *>(BLI_stack_peek(facedata));
1160
1161 face = fd->face;
1162
1163 /* figure out which pattern to use */
1164 pat = fd->pat;
1165
1166 if (!pat && fd->totedgesel == 2) {
1167 /* ok, no pattern. we still may be able to do something */
1168
1169 /* for case of two edges, connecting them shouldn't be too hard */
1170 loops.reinitialize(face->len);
1171 BM_ITER_ELEM_INDEX (l, &liter, face, BM_LOOPS_OF_FACE, a) {
1172 loops[a] = l;
1173 }
1174
1175 const int64_t vlen = loops.size();
1176
1177 /* find the boundary of one of the split edges */
1178 for (a = 0; a < vlen; a++) {
1179 if (!BMO_vert_flag_test(bm, loops[a ? (a - 1) : (vlen - 1)]->v, ELE_INNER) &&
1180 BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER))
1181 {
1182 break;
1183 }
1184 }
1185 /* Failure to break means there is an internal error. */
1186 BLI_assert(a < vlen);
1187
1188 if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
1189 b = (a + numcuts + 1) % vlen;
1190 }
1191 else {
1192 /* find the boundary of the other edge. */
1193 for (j = 0; j < vlen; j++) {
1194 b = (j + a + numcuts + 1) % vlen;
1195 if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
1196 BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER))
1197 {
1198 break;
1199 }
1200 }
1201 }
1202
1203 b += numcuts - 1;
1204
1205 loops_split.reinitialize(numcuts);
1206 for (j = 0; j < numcuts; j++) {
1207 bool ok = true;
1208
1209 /* Check for special case, see: #32500.
1210 * This edge pair could be used by more than one face,
1211 * in this case it used to (2.63), split both faces along the same verts
1212 * while it could be calculated which face should do the split,
1213 * it's ambiguous, so in this case we're better off to skip them as exceptional cases
1214 * and not try to be clever guessing which face to cut up.
1215 *
1216 * To avoid this case we need to check:
1217 * Do the verts of each share a face besides the one we are subdividing,
1218 * (but not connect to make an edge of that face).
1219 */
1220 {
1221 BMLoop *other_loop;
1222 BMIter other_fiter;
1223 BM_ITER_ELEM (other_loop, &other_fiter, loops[a]->v, BM_LOOPS_OF_VERT) {
1224 if (other_loop->f != face) {
1225 if (BM_vert_in_face(loops[b]->v, other_loop->f)) {
1226 /* we assume that these verts are not making an edge in the face */
1227 BLI_assert(other_loop->prev->v != loops[a]->v);
1228 BLI_assert(other_loop->next->v != loops[a]->v);
1229
1230 ok = false;
1231 break;
1232 }
1233 }
1234 }
1235 }
1236
1237 if (ok == true) {
1238 loops_split[j][0] = loops[a];
1239 loops_split[j][1] = loops[b];
1240 }
1241 else {
1242 loops_split[j][0] = nullptr;
1243 loops_split[j][1] = nullptr;
1244 }
1245
1246 b = (b - 1) % vlen;
1247 a = (a + 1) % vlen;
1248 }
1249
1250 /* Since these are newly created vertices, we don't need to worry about them being legal,
1251 * ... though there are some cases we _should_ check for
1252 * - concave corner of an ngon.
1253 * - 2 edges being used in 2+ ngons.
1254 */
1255 // BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split));
1256
1257 for (const LoopPair &loop_split : loops_split) {
1258 if (loop_split[0]) {
1259 BMFace *f_new;
1260 BLI_assert(BM_edge_exists(loop_split[0]->v, loop_split[1]->v) == nullptr);
1261 f_new = BM_face_split(bm, face, loop_split[0], loop_split[1], &l_new, nullptr, false);
1262 if (f_new) {
1264 }
1265 }
1266 }
1267
1268 continue;
1269 }
1270 if (!pat) {
1271 continue;
1272 }
1273
1274 a = 0;
1275 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) {
1276 if (l_new->v == fd->start) {
1277 a = j + 1;
1278 break;
1279 }
1280 }
1281
1282 verts.reinitialize(face->len);
1283 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) {
1284 b = (j - a + face->len) % face->len;
1285 verts[b] = l_new->v;
1286 }
1287
1288 BM_CHECK_ELEMENT(face);
1289 pat->connectexec(bm, face, verts.data(), &params);
1290 }
1291
1292 /* copy original-geometry displacements to current coordinates */
1293 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1294 const float *co = static_cast<const float *>(
1295 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
1296 copy_v3_v3(v->co, co);
1297 }
1298
1299 BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey);
1300
1301 BLI_stack_free(facedata);
1302
1304 bm, op, op->slots_out, "geom_inner.out", BM_ALL_NOLOOP, ELE_INNER);
1306 bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT);
1307
1309 bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_INNER | ELE_SPLIT | SUBD_SPLIT);
1310}
1311
1313 const char edge_hflag,
1314 const float smooth,
1315 const short smooth_falloff,
1316 const bool use_smooth_even,
1317 const float fractal,
1318 const float along_normal,
1319 const int numcuts,
1320 const int seltype,
1321 const int cornertype,
1322 const short use_single_edge,
1323 const short use_grid_fill,
1324 const short use_only_quads,
1325 const int seed)
1326{
1327 BMOperator op;
1328
1329 /* `use_sphere` isn't exposed here since its only used for new primitives. */
1331 &op,
1333 "subdivide_edges edges=%he "
1334 "smooth=%f smooth_falloff=%i use_smooth_even=%b "
1335 "fractal=%f along_normal=%f "
1336 "cuts=%i "
1337 "quad_corner_type=%i "
1338 "use_single_edge=%b use_grid_fill=%b "
1339 "use_only_quads=%b "
1340 "seed=%i",
1341 edge_hflag,
1342 smooth,
1343 smooth_falloff,
1344 use_smooth_even,
1345 fractal,
1346 along_normal,
1347 numcuts,
1348 cornertype,
1349 use_single_edge,
1350 use_grid_fill,
1351 use_only_quads,
1352 seed);
1353
1354 BMO_op_exec(bm, &op);
1355
1356 switch (seltype) {
1357 case SUBDIV_SELECT_NONE: {
1358 break;
1359 }
1360 case SUBDIV_SELECT_ORIG: {
1361 /* set the newly created data to be selected */
1362 if (edge_hflag & BM_ELEM_SELECT) {
1364 bm, op.slots_out, "geom_inner.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
1366 }
1367 break;
1368 }
1369 case SUBDIV_SELECT_INNER: {
1370 if (edge_hflag & BM_ELEM_SELECT) {
1372 bm, op.slots_out, "geom_inner.out", BM_EDGE | BM_VERT, BM_ELEM_SELECT, true);
1373 }
1374 break;
1375 }
1376 case SUBDIV_SELECT_LOOPCUT: {
1377 if (edge_hflag & BM_ELEM_SELECT) {
1378 /* deselect input */
1381 bm, op.slots_out, "geom_inner.out", BM_EDGE, BM_ELEM_SELECT, true);
1382 }
1383 break;
1384 }
1385 }
1386 if (edge_hflag & BM_ELEM_SELECT) {
1387 /* TODO(@ideasman42): the current behavior for face selection flushing
1388 * can cause parts of disconnected UV islands to become selected.
1389 * This is caused by the underlying geometry becoming selected.
1390 * while this is not a bug in UV selection uses are likely to
1391 * notice this problem when dealing with the UV selections.
1392 * This can be observed after subdividing the default "Suzanne" model
1393 * when the UV island of one of the ears is selected.
1394 *
1395 * We may want to change the resulting selection after a subdivision
1396 * to avoid this problem occurring. */
1397
1398 if (bm->uv_select_sync_valid) {
1399 const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_PROP_FLOAT2);
1400 BM_mesh_uvselect_flush_post_subdivide(bm, cd_loop_uv_offset);
1401 }
1402 }
1403
1404 BMO_op_finish(bm, &op);
1405}
1406
1408{
1409 BMOIter siter;
1410 BMEdge *e;
1411 SubDParams params = {0};
1412
1413 params.numcuts = BMO_slot_int_get(op->slots_in, "cuts");
1414 params.op = op;
1415 params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents");
1416
1418
1420
1421 /* tag edges in map */
1422 BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT);
1423
1424 /* go through and split edges */
1425 BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
1426 bm_subdivide_multicut(bm, e, &params, e->v1, e->v2);
1427 }
1428
1430 bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT);
1431
1432 BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey);
1433}
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
int CustomData_get_n_offset(const CustomData *data, eCustomDataType type, int n)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float interpf(float target, float origin, float t)
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:217
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
bool isect_plane_plane_plane_v3(const float plane_a[4], const float plane_b[4], const float plane_c[4], float r_isect_co[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], float t) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3(float r[3], const float a[3])
void reflect_v3_v3v3(float out[3], const float v[3], const float normal[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE float normalize_v3_length(float n[3], float unit_length)
MINLINE float normalize_v3(float n[3])
float BLI_noise_generic_turbulence(float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis)
Definition noise_c.cc:1210
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:53
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition rand.cc:46
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:88
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:250
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:96
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:169
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.cc:103
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.cc:176
#define BLI_stack_new(esize, descr)
#define UNLIKELY(x)
@ CD_PROP_FLOAT2
Read Guarded memory(de)allocation.
#define BM_ALL_NOLOOP
@ BM_ELEM_SELECT
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BMESH_ASSERT(a)
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_select_flush_from_verts(BMesh *bm, const bool select)
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
#define BMO_edge_flag_test(bm, e, oflag)
void BMO_slot_map_to_flag(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_edge_flag_enable(bm, e, oflag)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_enable(bm, e, oflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
#define BMO_FLAG_DEFAULTS
#define BMO_face_flag_test(bm, e, oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
@ SUBD_CORNER_FAN
@ SUBD_CORNER_PATH
@ SUBD_CORNER_INNERVERT
@ SUBDIV_SELECT_ORIG
@ SUBDIV_SELECT_INNER
@ SUBDIV_SELECT_LOOPCUT
@ SUBDIV_SELECT_NONE
@ SUBD_FALLOFF_LIN
#define BM_CHECK_ELEMENT(el)
float bmesh_subd_falloff_calc(const int falloff, float val)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
bool BM_vert_in_face(BMVert *v, BMFace *f)
BMFace * BM_vert_pair_share_face_by_len(BMVert *v_a, BMVert *v_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_mesh_uvselect_flush_post_subdivide(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag, const float smooth, const short smooth_falloff, const bool use_smooth_even, const float fractal, const float along_normal, const int numcuts, const int seltype, const int cornertype, const short use_single_edge, const short use_grid_fill, const short use_only_quads, const int seed)
static void quad_2edge_split_path(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
#define EDGE_PERCENT
static void interp_slerp_co_no_v3(const float co_a[3], const float no_a[3], const float co_b[3], const float no_b[3], const float no_dir[3], float fac, float r_co[3])
static const SubDPattern quad_1edge
static void quad_2edge_split_fan(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static void quad_3edge_split(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static void tri_1edge_split(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static const SubDPattern * patterns[]
#define FLT_FACE_SPLIT_EPSILON
static const SubDPattern quad_2edge_fan
static const SubDPattern quad_4edge
static BMVert * bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *e_orig, const SubDParams *params, const float factor_edge_split, const float factor_subd, BMVert *v_a, BMVert *v_b, BMEdge **r_edge)
void(*)(BMesh *bm, BMFace *face, BMVert **verts, const SubDParams *params) subd_pattern_fill_fp
static void alter_co(BMVert *v, BMEdge *, const SubDParams *params, const float perc, const BMVert *v_a, const BMVert *v_b)
static const SubDPattern quad_3edge
#define FACE_CUSTOMFILL
static const SubDPattern quad_2edge_path
void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
void bmo_bisect_edges_exec(BMesh *bm, BMOperator *op)
static void quad_2edge_split_innervert(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
#define ELE_INNER
static BMVert * subdivide_edge_num(BMesh *bm, BMEdge *edge, BMEdge *e_orig, int curpoint, int totpoint, const SubDParams *params, BMVert *v_a, BMVert *v_b, BMEdge **r_edge)
#define SUBD_SPLIT
static void tri_3edge_subdivide(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static const SubDPattern tri_1edge
static void quad_1edge_split(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static void bmo_subd_init_shape_info(BMesh *bm, SubDParams *params)
static void quad_4edge_subdivide(BMesh *bm, BMFace *, BMVert **verts, const SubDParams *params)
static const SubDPattern tri_3edge
static BMEdge * connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new)
static const SubDPattern quad_2edge_innervert
#define ELE_SPLIT
static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *params, BMVert *v_a, BMVert *v_b)
#define PATTERNS_TOT
long long int int64_t
static unsigned long seed
Definition btSoftBody.h:39
int64_t size() const
void reinitialize(const int64_t new_size)
nullptr float
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
#define fabsf
BMVert * v1
BMVert * v2
struct BMVert * v
struct BMEdge * e
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
union BMOpSlot::@313121210037300127305053354046356312170117023254 data
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
float no[3]
Definition rand.cc:33
const SubDPattern * pat
bool use_smooth_even
float fractal_ofs[3]
BMOpSlot * slot_custom_patterns
int cd_vert_shape_offset
BMOperator * op
struct SubDParams::@217262064261340334267141171163117170271177340220 shape_info
int cd_vert_shape_offset_tmp
float along_normal
BMOpSlot * slot_edge_percents
subd_pattern_fill_fp connectexec
int seledges[20]
i
Definition text_draw.cc:230
uint len