Blender V4.3
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
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
68typedef void (*subd_pattern_fill_fp)(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
106/* see bug #32665, 0.00005 means a we get face splits at a little under 1.0 degrees */
107#define FLT_FACE_SPLIT_EPSILON 0.00005f
108
109/*
110 * NOTE: beauty has been renamed to flag!
111 */
112
113/* generic subdivision rules:
114 *
115 * - two selected edges in a face should make a link
116 * between them.
117 *
118 * - one edge should do, what? make pretty topology, or just
119 * split the edge only?
120 */
121
122/* connects face with smallest len, which I think should always be correct for
123 * edge subdivision */
124static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new)
125{
126 BMLoop *l_a, *l_b;
127 BMFace *f;
128
129 /* this isn't the best thing in the world. it doesn't handle cases where there's
130 * multiple faces yet. that might require a convexity test to figure out which
131 * face is "best" and who knows what for non-manifold conditions.
132 *
133 * NOTE: we allow adjacent here, since there's no chance this happens.
134 */
135 f = BM_vert_pair_share_face_by_len(v_a, v_b, &l_a, &l_b, true);
136
137 if (f) {
138 BMFace *f_new;
139 BMLoop *l_new;
140
142
143 f_new = BM_face_split(bm, f, l_a, l_b, &l_new, nullptr, false);
144
145 if (r_f_new) {
146 *r_f_new = f_new;
147 }
148 return l_new ? l_new->e : nullptr;
149 }
150
151 return nullptr;
152}
153
158 const float co_a[3],
159 const float no_a[3],
160 const float co_b[3],
161 const float no_b[3],
162 const float no_dir[3], /* caller already knows, avoid normalize */
163 float fac,
164 float r_co[3])
165{
166 /* center of the sphere defined by both normals */
167 float center[3];
168
169 BLI_assert(len_squared_v3v3(no_a, no_b) != 0);
170
171 /* calculate sphere 'center' */
172 {
173 /* use point on plane to */
174 float no_mid[3], no_ortho[3];
175/* pass this as an arg instead */
176#if 0
177 float no_dir[3];
178#endif
179
180 add_v3_v3v3(no_mid, no_a, no_b);
181 normalize_v3(no_mid);
182
183#if 0
184 sub_v3_v3v3(no_dir, co_a, co_b);
185 normalize_v3(no_dir);
186#endif
187
188 /* axis of slerp */
189 bool center_ok = false;
190 cross_v3_v3v3(no_ortho, no_mid, no_dir);
191 if (normalize_v3(no_ortho) != 0.0f) {
192 float plane_a[4], plane_b[4], plane_c[4];
193 float v_a_no_ortho[3], v_b_no_ortho[3];
194
195 /* create planes */
196 cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
197 cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
198 project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
199 project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);
200
201 plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
202 plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
203 plane_from_point_normal_v3(plane_c, co_b, no_ortho);
204
205 /* find the sphere center from 3 planes */
206 if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
207 center_ok = true;
208 }
209 }
210 if (center_ok == false) {
211 mid_v3_v3v3(center, co_a, co_b);
212 }
213 }
214
215 /* calculate the final output 'r_co' */
216 {
217 float ofs_a[3], ofs_b[3], ofs_slerp[3];
218 float dist_a, dist_b;
219
220 sub_v3_v3v3(ofs_a, co_a, center);
221 sub_v3_v3v3(ofs_b, co_b, center);
222
223 dist_a = normalize_v3(ofs_a);
224 dist_b = normalize_v3(ofs_b);
225
226 if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
227 madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
228 }
229 else {
230 interp_v3_v3v3(r_co, co_a, co_b, fac);
231 }
232 }
233}
234
235/* Calculates offset for co, based on fractal, sphere or smooth settings. */
236static void alter_co(BMVert *v,
237 BMEdge * /*e_orig*/,
238 const SubDParams *params,
239 const float perc,
240 const BMVert *v_a,
241 const BMVert *v_b)
242{
243 float *co = static_cast<float *>(
244 BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
245 int i;
246
247 copy_v3_v3(co, v->co);
248
249 if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
250 normalize_v3_length(co, params->smooth);
251 }
252 else if (params->use_smooth) {
253/* calculating twice and blending gives smoother results,
254 * removing visible seams. */
255#define USE_SPHERE_DUAL_BLEND
256
257 const float eps_unit_vec = 1e-5f;
258 float smooth;
259 float no_dir[3];
260
261#ifdef USE_SPHERE_DUAL_BLEND
262 float no_reflect[3], co_a[3], co_b[3];
263#endif
264
265 sub_v3_v3v3(no_dir, v_a->co, v_b->co);
266 normalize_v3(no_dir);
267
268#ifndef USE_SPHERE_DUAL_BLEND
269 if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
270 interp_v3_v3v3(co, v_a->co, v_b->co, perc);
271 }
272 else {
273 interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
274 }
275#else
276 /* sphere-a */
277 reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
278 if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
279 interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
280 }
281 else {
282 interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
283 }
284
285 /* sphere-b */
286 reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
287 if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
288 interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
289 }
290 else {
291 interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
292 }
293
294 /* blend both spheres */
295 interp_v3_v3v3(co, co_a, co_b, perc);
296#endif /* USE_SPHERE_DUAL_BLEND */
297
298 /* apply falloff */
299 if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
300 smooth = 1.0f;
301 }
302 else {
303 smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
304 smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
305 }
306
307 if (params->use_smooth_even) {
308 smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
309 }
310
311 smooth *= params->smooth;
312 if (smooth != 1.0f) {
313 float co_flat[3];
314 interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
315 interp_v3_v3v3(co, co_flat, co, smooth);
316 }
317
318#undef USE_SPHERE_DUAL_BLEND
319 }
320
321 if (params->use_fractal) {
322 float normal[3], co2[3], base1[3], base2[3], tvec[3];
323 const float len = len_v3v3(v_a->co, v_b->co);
324 float fac;
325
326 fac = params->fractal * len;
327
328 mid_v3_v3v3(normal, v_a->no, v_b->no);
329 ortho_basis_v3v3_v3(base1, base2, normal);
330
331 add_v3_v3v3(co2, v->co, params->fractal_ofs);
332 mul_v3_fl(co2, 10.0f);
333
334 tvec[0] = fac *
335 (BLI_noise_generic_turbulence(1.0, co2[0], co2[1], co2[2], 15, false, 2) - 0.5f);
336 tvec[1] = fac *
337 (BLI_noise_generic_turbulence(1.0, co2[1], co2[0], co2[2], 15, false, 2) - 0.5f);
338 tvec[2] = fac *
339 (BLI_noise_generic_turbulence(1.0, co2[1], co2[2], co2[0], 15, false, 2) - 0.5f);
340
341 /* add displacement */
342 madd_v3_v3fl(co, normal, tvec[0]);
343 madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
344 madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
345 }
346
347 /* apply the new difference to the rest of the shape keys,
348 * note that this doesn't take rotations into account, we _could_ support
349 * this by getting the normals and coords for each shape key and
350 * re-calculate the smooth value for each but this is quite involved.
351 * for now its ok to simply apply the difference IMHO - campbell */
352
353 if (params->shape_info.totlayer > 1) {
354 float tvec[3];
355
356 sub_v3_v3v3(tvec, v->co, co);
357
358 /* skip the last layer since its the temp */
359 i = params->shape_info.totlayer - 1;
360 co = static_cast<float *>(BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset));
361 while (i--) {
362 BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
363 sub_v3_v3(co += 3, tvec);
364 }
365 }
366}
367
368/* assumes in the edge is the correct interpolated vertices already */
369/* percent defines the interpolation, rad and flag are for special options */
370/* results in new vertex with correct coordinate, vertex normal and weight group info */
372 BMEdge *edge,
373 BMEdge *e_orig,
374 const SubDParams *params,
375 const float factor_edge_split,
376 const float factor_subd,
377 BMVert *v_a,
378 BMVert *v_b,
379 BMEdge **r_edge)
380{
381 BMVert *v_new;
382
383 v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split);
384
386
387 /* offset for smooth or sphere or fractal */
388 alter_co(v_new, e_orig, params, factor_subd, v_a, v_b);
389
390#if 0 // BMESH_TODO
391 /* clip if needed by mirror modifier */
392 if (edge->v1->f2) {
393 if (edge->v1->f2 & edge->v2->f2 & 1) {
394 co[0] = 0.0f;
395 }
396 if (edge->v1->f2 & edge->v2->f2 & 2) {
397 co[1] = 0.0f;
398 }
399 if (edge->v1->f2 & edge->v2->f2 & 4) {
400 co[2] = 0.0f;
401 }
402 }
403#endif
404
405 interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd);
406 normalize_v3(v_new->no);
407
408 return v_new;
409}
410
412 BMEdge *edge,
413 BMEdge *e_orig,
414 int curpoint,
415 int totpoint,
416 const SubDParams *params,
417 BMVert *v_a,
418 BMVert *v_b,
419 BMEdge **r_edge)
420{
421 BMVert *v_new;
422 float factor_edge_split, factor_subd;
423
424 if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) {
425 factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge);
426 factor_subd = 0.0f;
427 }
428 else {
429 factor_edge_split = 1.0f / float(totpoint + 1 - curpoint);
430 factor_subd = float(curpoint + 1) / float(totpoint + 1);
431 }
432
434 bm, edge, e_orig, params, factor_edge_split, factor_subd, v_a, v_b, r_edge);
435 return v_new;
436}
437
439 BMesh *bm, BMEdge *edge, const SubDParams *params, BMVert *v_a, BMVert *v_b)
440{
441 BMEdge *eed = edge, *e_new, e_tmp = *edge;
442 BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2;
443 int i, numcuts = params->numcuts;
444
445 e_tmp.v1 = &v1_tmp;
446 e_tmp.v2 = &v2_tmp;
447
448 for (i = 0; i < numcuts; i++) {
449 v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new);
450
454
456 if (v->e) {
458 }
459 if (v->e && v->e->l) {
460 BM_CHECK_ELEMENT(v->e->l->f);
461 }
462 }
463
464 alter_co(v1, &e_tmp, params, 0, &v1_tmp, &v2_tmp);
465 alter_co(v2, &e_tmp, params, 1.0, &v1_tmp, &v2_tmp);
466}
467
468/* NOTE: the patterns are rotated as necessary to
469 * match the input geometry. they're based on the
470 * pre-split state of the face */
471
483 BMFace * /*face*/,
484 BMVert **verts,
485 const SubDParams *params)
486{
487 BMFace *f_new;
488 int i, add, numcuts = params->numcuts;
489
490 /* if it's odd, the middle face is a quad, otherwise it's a triangle */
491 if ((numcuts % 2) == 0) {
492 add = 2;
493 for (i = 0; i < numcuts; i++) {
494 if (i == numcuts / 2) {
495 add -= 1;
496 }
497 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
498 }
499 }
500 else {
501 add = 2;
502 for (i = 0; i < numcuts; i++) {
503 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
504 if (i == numcuts / 2) {
505 add -= 1;
506 connect_smallest_face(bm, verts[i], verts[numcuts + add], &f_new);
507 }
508 }
509 }
510}
511
512static const SubDPattern quad_1edge = {
513 {1, 0, 0, 0},
515 4,
516};
517
529 BMFace * /*face*/,
530 BMVert **verts,
531 const SubDParams *params)
532{
533 BMFace *f_new;
534 int i, numcuts = params->numcuts;
535
536 for (i = 0; i < numcuts; i++) {
537 connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
538 }
539 connect_smallest_face(bm, verts[numcuts * 2 + 3], verts[numcuts * 2 + 1], &f_new);
540}
541
543 {1, 1, 0, 0},
545 4,
546};
547
559 BMFace * /*face*/,
560 BMVert **verts,
561 const SubDParams *params)
562{
563 BMFace *f_new;
564 BMVert *v, *v_last;
565 BMEdge *e, *e_new, e_tmp;
566 int i, numcuts = params->numcuts;
567
568 v_last = verts[numcuts];
569
570 for (i = numcuts - 1; i >= 0; i--) {
571 e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new);
572
573 e_tmp = *e;
574 v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new);
575
576 if (i != numcuts - 1) {
577 connect_smallest_face(bm, v_last, v, &f_new);
578 }
579
580 v_last = v;
581 }
582
583 connect_smallest_face(bm, v_last, verts[numcuts * 2 + 2], &f_new);
584}
585
587 {1, 1, 0, 0},
589 4,
590};
591
603 BMFace * /*face*/,
604 BMVert **verts,
605 const SubDParams *params)
606{
607 BMFace *f_new;
608 // BMVert *v; /* UNUSED */
609 // BMVert *v_last = verts[2]; /* UNUSED */
610 // BMEdge *e, *e_new; /* UNUSED */
611 int i, numcuts = params->numcuts;
612
613 for (i = 0; i < numcuts; i++) {
614 connect_smallest_face(bm, verts[i], verts[numcuts * 2 + 2], &f_new);
615 connect_smallest_face(bm, verts[numcuts + (numcuts - i)], verts[numcuts * 2 + 2], &f_new);
616 }
617}
618
620 {1, 1, 0, 0},
622 4,
623};
624
638 BMFace * /*face*/,
639 BMVert **verts,
640 const SubDParams *params)
641{
642 BMFace *f_new;
643 int i, add = 0, numcuts = params->numcuts;
644
645 for (i = 0; i < numcuts; i++) {
646 if (i == numcuts / 2) {
647 if (numcuts % 2 != 0) {
648 connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new);
649 }
650 add = numcuts * 2 + 2;
651 }
652 connect_smallest_face(bm, verts[numcuts - i - 1 + add], verts[i + numcuts + 1], &f_new);
653 }
654
655 for (i = 0; i < numcuts / 2 + 1; i++) {
656 connect_smallest_face(bm, verts[i], verts[(numcuts - i) + numcuts * 2 + 1], &f_new);
657 }
658}
659
660static const SubDPattern quad_3edge = {
661 {1, 1, 1, 0},
663 4,
664};
665
679 BMFace * /*face*/,
680 BMVert **verts,
681 const SubDParams *params)
682{
683 BMFace *f_new;
684 BMVert *v, *v1, *v2;
685 BMEdge *e, *e_new, e_tmp;
686 BMVert **lines;
687 int numcuts = params->numcuts;
688 int i, j, a, b, s = numcuts + 2 /* , totv = numcuts * 4 + 4 */;
689
690 lines = static_cast<BMVert **>(
691 MEM_callocN(sizeof(BMVert *) * (numcuts + 2) * (numcuts + 2), "q_4edge_split"));
692 /* build a 2-dimensional array of verts,
693 * containing every vert (and all new ones)
694 * in the face */
695
696 /* first line */
697 for (i = 0; i < numcuts + 2; i++) {
698 lines[i] = verts[numcuts * 3 + 2 + (numcuts - i + 1)];
699 }
700
701 /* last line */
702 for (i = 0; i < numcuts + 2; i++) {
703 lines[(s - 1) * s + i] = verts[numcuts + i];
704 }
705
706 /* first and last members of middle lines */
707 for (i = 0; i < numcuts; i++) {
708 a = i;
709 b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
710
711 e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
712 if (!e) {
713 continue;
714 }
715
718
719 v1 = lines[(i + 1) * s] = verts[a];
720 v2 = lines[(i + 1) * s + s - 1] = verts[b];
721
722 e_tmp = *e;
723 for (a = 0; a < numcuts; a++) {
724 v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new);
725
726 BMESH_ASSERT(v != nullptr);
727
729 lines[(i + 1) * s + a + 1] = v;
730 }
731 }
732
733 for (i = 1; i < numcuts + 2; i++) {
734 for (j = 1; j <= numcuts; j++) {
735 a = i * s + j;
736 b = (i - 1) * s + j;
737 e = connect_smallest_face(bm, lines[a], lines[b], &f_new);
738 if (!e) {
739 continue;
740 }
741
744 }
745 }
746
747 MEM_freeN(lines);
748}
749
762static void tri_1edge_split(BMesh *bm, BMFace * /*face*/, BMVert **verts, const SubDParams *params)
763{
764 BMFace *f_new;
765 int i, numcuts = params->numcuts;
766
767 for (i = 0; i < numcuts; i++) {
768 connect_smallest_face(bm, verts[i], verts[numcuts + 1], &f_new);
769 }
770}
771
772static const SubDPattern tri_1edge = {
773 {1, 0, 0},
775 3,
776};
777
791 BMFace * /*face*/,
792 BMVert **verts,
793 const SubDParams *params)
794{
795 BMFace *f_new;
796 BMEdge *e, *e_new, e_tmp;
797 BMVert ***lines, *v, v1_tmp, v2_tmp;
798 void *stackarr[1];
799 int i, j, a, b, numcuts = params->numcuts;
800
801 /* number of verts in each lin */
802 lines = static_cast<BMVert ***>(
803 MEM_callocN(sizeof(void *) * (numcuts + 2), "triangle vert table"));
804
805 lines[0] = (BMVert **)stackarr;
806 lines[0][0] = verts[numcuts * 2 + 1];
807
808 lines[numcuts + 1] = static_cast<BMVert **>(
809 MEM_callocN(sizeof(void *) * (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] = static_cast<BMVert **>(
818 MEM_callocN(sizeof(void *) * (2 + i), "triangle vert table row"));
819 a = numcuts * 2 + 2 + i;
820 b = numcuts + numcuts - i;
821 e = connect_smallest_face(bm, verts[a], verts[b], &f_new);
822 if (!e) {
823 goto cleanup;
824 }
825
828
829 lines[i + 1][0] = verts[a];
830 lines[i + 1][i + 1] = verts[b];
831
832 e_tmp = *e;
833 v1_tmp = *verts[a];
834 v2_tmp = *verts[b];
835 e_tmp.v1 = &v1_tmp;
836 e_tmp.v2 = &v2_tmp;
837 for (j = 0; j < i; j++) {
838 v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new);
839 lines[i + 1][j + 1] = v;
840
842 }
843 }
844
857 for (i = 1; i <= numcuts; i++) {
858 for (j = 0; j < i; j++) {
859 e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new);
860
863
864 e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new);
865
868 }
869 }
870
871cleanup:
872 for (i = 1; i < numcuts + 2; i++) {
873 if (lines[i]) {
874 MEM_freeN(lines[i]);
875 }
876 }
877
878 MEM_freeN(lines);
879}
880
881static const SubDPattern tri_3edge = {
882 {1, 1, 1},
884 3,
885};
886
887static const SubDPattern quad_4edge = {
888 {1, 1, 1, 1},
890 4,
891};
892
893static const SubDPattern *patterns[] = {
894 nullptr, /* quad single edge pattern is inserted here */
895 nullptr, /* quad corner vert pattern is inserted here */
896 nullptr, /* tri single edge pattern is inserted here */
897 nullptr,
898 &quad_3edge,
899 nullptr,
900};
901
902#define PATTERNS_TOT ARRAY_SIZE(patterns)
903
907 int totedgesel; /* only used if pat was nullptr, e.g. no pattern was found */
909};
910
912{
913 BMOpSlot *einput;
914 const SubDPattern *pat;
916 BLI_Stack *facedata;
917 BMIter viter, fiter, liter;
918 BMVert *v;
919 BMEdge *edge;
920 BMLoop *l_new, *l;
921 BMFace *face;
922 float smooth, fractal, along_normal;
923 bool use_sphere, use_single_edge, use_grid_fill, use_only_quads;
924 int cornertype, seed, i, j, a, b, numcuts, totesel, smooth_falloff;
925
927
928 numcuts = BMO_slot_int_get(op->slots_in, "cuts");
929 seed = BMO_slot_int_get(op->slots_in, "seed");
930 smooth = BMO_slot_float_get(op->slots_in, "smooth");
931 smooth_falloff = BMO_slot_int_get(op->slots_in, "smooth_falloff");
932 fractal = BMO_slot_float_get(op->slots_in, "fractal");
933 along_normal = BMO_slot_float_get(op->slots_in, "along_normal");
934 cornertype = BMO_slot_int_get(op->slots_in, "quad_corner_type");
935
936 use_single_edge = BMO_slot_bool_get(op->slots_in, "use_single_edge");
937 use_grid_fill = BMO_slot_bool_get(op->slots_in, "use_grid_fill");
938 use_only_quads = BMO_slot_bool_get(op->slots_in, "use_only_quads");
939 use_sphere = BMO_slot_bool_get(op->slots_in, "use_sphere");
940
941 patterns[1] = nullptr;
942 /* straight cut is patterns[1] == nullptr */
943 switch (cornertype) {
944 case SUBD_CORNER_PATH:
946 break;
949 break;
950 case SUBD_CORNER_FAN:
952 break;
953 }
954
955 if (use_single_edge) {
956 patterns[0] = &quad_1edge;
957 patterns[2] = &tri_1edge;
958 }
959 else {
960 patterns[0] = nullptr;
961 patterns[2] = nullptr;
962 }
963
964 if (use_grid_fill) {
965 patterns[3] = &quad_4edge;
966 patterns[5] = &tri_3edge;
967 }
968 else {
969 patterns[3] = nullptr;
970 patterns[5] = nullptr;
971 }
972
973 /* Add a temporary shape-key layer to store displacements on current geometry. */
975
977
978 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
979 float *co = static_cast<float *>(
980 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
981 copy_v3_v3(co, v->co);
982 }
983
984 /* first go through and tag edges */
986
987 params.numcuts = numcuts;
988 params.op = op;
989 params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents");
990 params.slot_custom_patterns = BMO_slot_get(op->slots_in, "custom_patterns");
991 params.smooth = smooth;
992 params.smooth_falloff = smooth_falloff;
993 params.seed = seed;
994 params.fractal = fractal;
995 params.along_normal = along_normal;
996 params.use_smooth = (smooth != 0.0f);
997 params.use_smooth_even = BMO_slot_bool_get(op->slots_in, "use_smooth_even");
998 params.use_fractal = (fractal != 0.0f);
999 params.use_sphere = use_sphere;
1000
1001 if (params.use_fractal) {
1003
1004 params.fractal_ofs[0] = BLI_rng_get_float(rng) * 200.0f;
1005 params.fractal_ofs[1] = BLI_rng_get_float(rng) * 200.0f;
1006 params.fractal_ofs[2] = BLI_rng_get_float(rng) * 200.0f;
1007
1008 BLI_rng_free(rng);
1009 }
1010
1011 BMO_slot_map_to_flag(bm, op->slots_in, "custom_patterns", BM_FACE, FACE_CUSTOMFILL);
1012
1013 BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT);
1014
1015 facedata = BLI_stack_new(sizeof(SubDFaceData), __func__);
1016
1019
1020 BM_ITER_MESH (face, &fiter, bm, BM_FACES_OF_MESH) {
1021 BMEdge *e1 = nullptr, *e2 = nullptr;
1022 float vec1[3], vec2[3];
1023 bool matched = false;
1024
1025 /* skip non-quads if requested */
1026 if (use_only_quads && face->len != 4) {
1027 continue;
1028 }
1029
1030 /* figure out which pattern to use */
1031 verts.reinitialize(face->len);
1032 edges.reinitialize(face->len);
1033
1034 totesel = 0;
1035 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, i) {
1036 edges[i] = l_new->e;
1037 verts[i] = l_new->v;
1038
1039 if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) {
1040 if (!e1) {
1041 e1 = edges[i];
1042 }
1043 else {
1044 e2 = edges[i];
1045 }
1046
1047 totesel++;
1048 }
1049 }
1050
1051 /* make sure the two edges have a valid angle to each other */
1052 if (totesel == 2 && BM_edge_share_vert_check(e1, e2)) {
1053 sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co);
1054 sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co);
1055 normalize_v3(vec1);
1056 normalize_v3(vec2);
1057
1058 if (fabsf(dot_v3v3(vec1, vec2)) > 1.0f - FLT_FACE_SPLIT_EPSILON) {
1059 totesel = 0;
1060 }
1061 }
1062
1064 pat = static_cast<const SubDPattern *>(
1065 *BMO_slot_map_data_get(params.slot_custom_patterns, face));
1066 for (i = 0; i < pat->len; i++) {
1067 matched = true;
1068 for (j = 0; j < pat->len; j++) {
1069 a = (j + i) % pat->len;
1070 if (!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT) != (!!pat->seledges[j])) {
1071 matched = false;
1072 break;
1073 }
1074 }
1075 if (matched) {
1076 SubDFaceData *fd;
1077
1078 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1079 fd->pat = pat;
1080 fd->start = verts[i];
1081 fd->face = face;
1082 fd->totedgesel = totesel;
1084 break;
1085 }
1086 }
1087
1088 /* Obviously don't test for other patterns matching. */
1089 continue;
1090 }
1091
1092 for (i = 0; i < PATTERNS_TOT; i++) {
1093 pat = patterns[i];
1094 if (!pat) {
1095 continue;
1096 }
1097
1098 if (pat->len == face->len) {
1099 for (a = 0; a < pat->len; a++) {
1100 matched = true;
1101 for (b = 0; b < pat->len; b++) {
1102 j = (b + a) % pat->len;
1103 if (!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT) != (!!pat->seledges[b])) {
1104 matched = false;
1105 break;
1106 }
1107 }
1108 if (matched) {
1109 break;
1110 }
1111 }
1112 if (matched) {
1113 SubDFaceData *fd;
1114
1116
1117 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1118 fd->pat = pat;
1119 fd->start = verts[a];
1120 fd->face = face;
1121 fd->totedgesel = totesel;
1122 break;
1123 }
1124 }
1125 }
1126
1127 if (!matched && totesel) {
1128 SubDFaceData *fd;
1129
1131
1132 /* must initialize all members here */
1133 fd = static_cast<SubDFaceData *>(BLI_stack_push_r(facedata));
1134 fd->start = nullptr;
1135 fd->pat = nullptr;
1136 fd->totedgesel = totesel;
1137 fd->face = face;
1138 }
1139 }
1140
1141 einput = BMO_slot_get(op->slots_in, "edges");
1142
1143 /* go through and split edges */
1144 for (i = 0; i < einput->len; i++) {
1145 edge = static_cast<BMEdge *>(einput->data.buf[i]);
1146 bm_subdivide_multicut(bm, edge, &params, edge->v1, edge->v2);
1147 }
1148
1149 /* copy original-geometry displacements to current coordinates */
1150 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1151 const float *co = static_cast<const float *>(
1152 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
1153 copy_v3_v3(v->co, co);
1154 }
1155
1156 using LoopPair = std::array<BMLoop *, 2>;
1159 for (; !BLI_stack_is_empty(facedata); BLI_stack_discard(facedata)) {
1160 SubDFaceData *fd = static_cast<SubDFaceData *>(BLI_stack_peek(facedata));
1161
1162 face = fd->face;
1163
1164 /* figure out which pattern to use */
1165 pat = fd->pat;
1166
1167 if (!pat && fd->totedgesel == 2) {
1168 /* ok, no pattern. we still may be able to do something */
1169
1170 /* for case of two edges, connecting them shouldn't be too hard */
1171 loops.reinitialize(face->len);
1172 BM_ITER_ELEM_INDEX (l, &liter, face, BM_LOOPS_OF_FACE, a) {
1173 loops[a] = l;
1174 }
1175
1176 const int64_t vlen = loops.size();
1177
1178 /* find the boundary of one of the split edges */
1179 for (a = 0; a < vlen; a++) {
1180 if (!BMO_vert_flag_test(bm, loops[a ? (a - 1) : (vlen - 1)]->v, ELE_INNER) &&
1181 BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER))
1182 {
1183 break;
1184 }
1185 }
1186 /* Failure to break means there is an internal error. */
1187 BLI_assert(a < vlen);
1188
1189 if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) {
1190 b = (a + numcuts + 1) % vlen;
1191 }
1192 else {
1193 /* find the boundary of the other edge. */
1194 for (j = 0; j < vlen; j++) {
1195 b = (j + a + numcuts + 1) % vlen;
1196 if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) &&
1197 BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER))
1198 {
1199 break;
1200 }
1201 }
1202 }
1203
1204 b += numcuts - 1;
1205
1206 loops_split.reinitialize(numcuts);
1207 for (j = 0; j < numcuts; j++) {
1208 bool ok = true;
1209
1210 /* Check for special case, see: #32500.
1211 * This edge pair could be used by more than one face,
1212 * in this case it used to (2.63), split both faces along the same verts
1213 * while it could be calculated which face should do the split,
1214 * it's ambiguous, so in this case we're better off to skip them as exceptional cases
1215 * and not try to be clever guessing which face to cut up.
1216 *
1217 * To avoid this case we need to check:
1218 * Do the verts of each share a face besides the one we are subdividing,
1219 * (but not connect to make an edge of that face).
1220 */
1221 {
1222 BMLoop *other_loop;
1223 BMIter other_fiter;
1224 BM_ITER_ELEM (other_loop, &other_fiter, loops[a]->v, BM_LOOPS_OF_VERT) {
1225 if (other_loop->f != face) {
1226 if (BM_vert_in_face(loops[b]->v, other_loop->f)) {
1227 /* we assume that these verts are not making an edge in the face */
1228 BLI_assert(other_loop->prev->v != loops[a]->v);
1229 BLI_assert(other_loop->next->v != loops[a]->v);
1230
1231 ok = false;
1232 break;
1233 }
1234 }
1235 }
1236 }
1237
1238 if (ok == true) {
1239 loops_split[j][0] = loops[a];
1240 loops_split[j][1] = loops[b];
1241 }
1242 else {
1243 loops_split[j][0] = nullptr;
1244 loops_split[j][1] = nullptr;
1245 }
1246
1247 b = (b - 1) % vlen;
1248 a = (a + 1) % vlen;
1249 }
1250
1251 /* Since these are newly created vertices, we don't need to worry about them being legal,
1252 * ... though there are some cases we _should_ check for
1253 * - concave corner of an ngon.
1254 * - 2 edges being used in 2+ ngons.
1255 */
1256 // BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split));
1257
1258 for (const LoopPair &loop_split : loops_split) {
1259 if (loop_split[0]) {
1260 BMFace *f_new;
1261 BLI_assert(BM_edge_exists(loop_split[0]->v, loop_split[1]->v) == nullptr);
1262 f_new = BM_face_split(bm, face, loop_split[0], loop_split[1], &l_new, nullptr, false);
1263 if (f_new) {
1265 }
1266 }
1267 }
1268
1269 continue;
1270 }
1271 if (!pat) {
1272 continue;
1273 }
1274
1275 a = 0;
1276 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) {
1277 if (l_new->v == fd->start) {
1278 a = j + 1;
1279 break;
1280 }
1281 }
1282
1283 verts.reinitialize(face->len);
1284 BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) {
1285 b = (j - a + face->len) % face->len;
1286 verts[b] = l_new->v;
1287 }
1288
1289 BM_CHECK_ELEMENT(face);
1290 pat->connectexec(bm, face, verts.data(), &params);
1291 }
1292
1293 /* copy original-geometry displacements to current coordinates */
1294 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
1295 const float *co = static_cast<const float *>(
1296 BM_ELEM_CD_GET_VOID_P(v, params.shape_info.cd_vert_shape_offset_tmp));
1297 copy_v3_v3(v->co, co);
1298 }
1299
1300 BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey);
1301
1302 BLI_stack_free(facedata);
1303
1305 bm, op, op->slots_out, "geom_inner.out", BM_ALL_NOLOOP, ELE_INNER);
1307 bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT);
1308
1310 bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, ELE_INNER | ELE_SPLIT | SUBD_SPLIT);
1311}
1312
1313/* editmesh-emulating function */
1315 const char edge_hflag,
1316 const float smooth,
1317 const short smooth_falloff,
1318 const bool use_smooth_even,
1319 const float fractal,
1320 const float along_normal,
1321 const int numcuts,
1322 const int seltype,
1323 const int cornertype,
1324 const short use_single_edge,
1325 const short use_grid_fill,
1326 const short use_only_quads,
1327 const int seed)
1328{
1329 BMOperator op;
1330
1331 /* `use_sphere` isn't exposed here since its only used for new primitives. */
1333 &op,
1335 "subdivide_edges edges=%he "
1336 "smooth=%f smooth_falloff=%i use_smooth_even=%b "
1337 "fractal=%f along_normal=%f "
1338 "cuts=%i "
1339 "quad_corner_type=%i "
1340 "use_single_edge=%b use_grid_fill=%b "
1341 "use_only_quads=%b "
1342 "seed=%i",
1343 edge_hflag,
1344 smooth,
1345 smooth_falloff,
1346 use_smooth_even,
1347 fractal,
1348 along_normal,
1349 numcuts,
1350 cornertype,
1351 use_single_edge,
1352 use_grid_fill,
1353 use_only_quads,
1354 seed);
1355
1356 BMO_op_exec(bm, &op);
1357
1358 switch (seltype) {
1359 case SUBDIV_SELECT_NONE:
1360 break;
1361 case SUBDIV_SELECT_ORIG:
1362 /* set the newly created data to be selected */
1364 bm, op.slots_out, "geom_inner.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
1366 break;
1369 bm, op.slots_out, "geom_inner.out", BM_EDGE | BM_VERT, BM_ELEM_SELECT, true);
1370 break;
1372 /* deselect input */
1375 bm, op.slots_out, "geom_inner.out", BM_EDGE, BM_ELEM_SELECT, true);
1376 break;
1377 }
1378
1379 BMO_op_finish(bm, &op);
1380}
1381
1383{
1384 BMOIter siter;
1385 BMEdge *e;
1386 SubDParams params = {0};
1387
1388 params.numcuts = BMO_slot_int_get(op->slots_in, "cuts");
1389 params.op = op;
1390 params.slot_edge_percents = BMO_slot_get(op->slots_in, "edge_percents");
1391
1393
1395
1396 /* tag edges in map */
1397 BMO_slot_map_to_flag(bm, op->slots_in, "edge_percents", BM_EDGE, EDGE_PERCENT);
1398
1399 /* go through and split edges */
1400 BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
1401 bm_subdivide_multicut(bm, e, &params, e->v1, e->v2);
1402 }
1403
1405 bm, op, op->slots_out, "geom_split.out", BM_ALL_NOLOOP, ELE_SPLIT);
1406
1407 BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey);
1408}
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:50
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:215
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
Definition math_vector.c:55
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)
Definition math_vector.c:36
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:1210
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:58
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:93
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:249
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:96
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:168
void * BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:103
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:175
#define BLI_stack_new(esize, descr)
#define UNLIKELY(x)
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)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_select_flush(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
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_FALLOFF_LIN
@ SUBD_CORNER_FAN
@ SUBD_CORNER_PATH
@ SUBD_CORNER_INNERVERT
@ SUBDIV_SELECT_ORIG
@ SUBDIV_SELECT_INNER
@ SUBDIV_SELECT_LOOPCUT
@ SUBDIV_SELECT_NONE
#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_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
void(* subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts, const SubDParams *params)
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)
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
static unsigned long seed
Definition btSoftBody.h:39
void reinitialize(const int64_t new_size)
local_group_size(16, 16) .push_constant(Type b
#define fabsf(x)
int len
draw_view in_light_buf[] float
smooth(Type::VEC3, "P") .flat(Type out_color storage_buf(0, Qualifier::READ, "Surfel", "surfels_buf[]") .push_constant(Type smooth(Type::VEC4, "interp_color")
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:227
__int64 int64_t
Definition stdint.h:89
BMVert * v1
BMVert * v2
struct BMLoop * l
struct BMVert * v
struct BMEdge * e
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
union BMOpSlot::@139 data
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
struct BMEdge * e
float no[3]
CustomData vdata
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
int cd_vert_shape_offset_tmp
struct SubDParams::@160 shape_info
float along_normal
BMOpSlot * slot_edge_percents
subd_pattern_fill_fp connectexec
int seledges[20]