10#include <fmt/format.h>
58#include "RNA_prototypes.hh"
81#define USE_FACE_CREATE_SEL_EXTEND
106 for (
Object *obedit : objects) {
129 params.calc_looptris =
true;
130 params.calc_normals =
false;
131 params.is_destructive =
true;
144 {0,
nullptr, 0,
nullptr,
nullptr},
152 ot->name =
"Subdivide";
153 ot->description =
"Subdivide selected edges";
154 ot->idname =
"MESH_OT_subdivide";
164 prop =
RNA_def_int(
ot->srna,
"number_cuts", 1, 1, 100,
"Number of Cuts",
"", 1, 10);
170 ot->srna,
"smoothness", 0.0f, 0.0f, 1e3f,
"Smoothness",
"Smoothness factor", 0.0f, 1.0f);
178 "When disabled, newly created faces are limited to 3 and 4 sided faces");
185 "How to subdivide quad corners (anything other than Straight Cut will prevent n-gons)");
193 "Fractal randomness factor",
197 "fractal_along_normal",
202 "Apply fractal displacement along normal only",
211 "Seed for the random number generator",
236 const int cuts_default)
243 {0,
nullptr, 0,
nullptr,
nullptr},
249 ot->srna,
"number_cuts", cuts_default, 0, 1000,
"Number of Cuts",
"", cuts_min, 64);
254 prop_subd_edgering_types,
257 "Interpolation method");
260 ot->srna,
"smoothness", 1.0f, 0.0f, 1e3f,
"Smoothness",
"Smoothness factor", 0.0f, 2.0f);
264 "profile_shape_factor",
269 "How much intermediary new edges are shrunk/expanded",
301 for (
Object *obedit : objects) {
310 "subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
311 "profile_shape=%i profile_shape_factor=%f",
323 params.calc_looptris =
true;
324 params.calc_normals =
false;
325 params.is_destructive =
true;
335 ot->name =
"Subdivide Edge-Ring";
336 ot->description =
"Subdivide perpendicular edges to the selected edge-ring";
337 ot->idname =
"MESH_OT_subdivide_edgering";
363 for (
Object *obedit : objects) {
385 params.calc_looptris =
true;
386 params.calc_normals =
false;
387 params.is_destructive =
true;
397 ot->name =
"Un-Subdivide";
398 ot->description =
"Un-subdivide selected edges and faces";
399 ot->idname =
"MESH_OT_unsubdivide";
410 ot->srna,
"iterations", 2, 1, 1000,
"Iterations",
"Number of times to un-subdivide", 1, 100);
429 const int totelem_old[3],
430 const int totelem_new[3])
434 "Removed: %d vertices, %d edges, %d faces",
435 totelem_old[0] - totelem_new[0],
436 totelem_old[1] - totelem_new[1],
437 totelem_old[2] - totelem_new[2]);
447 bool changed_multi =
false;
449 for (
Object *obedit : objects) {
505 changed_multi =
true;
512 params.calc_looptris =
true;
513 params.calc_normals =
false;
514 params.is_destructive =
true;
532 {0,
nullptr, 0,
nullptr,
nullptr},
537 ot->description =
"Delete selected vertices, edges or faces";
538 ot->idname =
"MESH_OT_delete";
552 prop_mesh_delete_types,
555 "Method used for deleting mesh data");
574 }
while ((l_iter = l_iter->
next) != l_first);
583 int totelem_old_sel[3];
595 for (
Object *obedit : objects) {
642 params.calc_looptris =
true;
643 params.calc_normals =
false;
644 params.is_destructive =
true;
659 ot->name =
"Delete Loose";
660 ot->description =
"Delete loose vertices, edges or faces";
661 ot->idname =
"MESH_OT_delete_loose";
672 RNA_def_boolean(
ot->srna,
"use_verts",
true,
"Vertices",
"Remove loose vertices");
689 for (
Object *obedit : objects) {
701 params.calc_looptris =
true;
702 params.calc_normals =
false;
703 params.is_destructive =
true;
713 ot->name =
"Collapse Edges & Faces";
715 "Collapse isolated edge and face regions, merging data such as UVs and color attributes. "
716 "This can collapse edge-rings as well as regions of connected faces into vertices";
717 ot->idname =
"MESH_OT_edge_collapse";
738 uint vote_on_smooth[2] = {0, 0};
746 return (vote_on_smooth[0] < vote_on_smooth[1]);
749#ifdef USE_FACE_CREATE_SEL_EXTEND
762 if ((e_used ==
nullptr) || (e_used != e_iter)) {
765 if (
i >= e_arr_len) {
780 if (
bm->totvertsel == 1 &&
bm->totedgesel == 0 &&
bm->totfacesel == 0) {
812 else if (
bm->totvertsel == 2 &&
bm->totedgesel == 1 &&
bm->totfacesel == 0) {
898 BMEdge *e_active =
l->next->next->e;
904 BMVert *v_active =
l->next->next->v;
916 bool changed_multi =
false;
921 for (
Object *obedit : objects) {
933#ifdef USE_FACE_CREATE_SEL_EXTEND
944 "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
959#ifdef USE_FACE_CREATE_SEL_EXTEND
963 (ele_desel_face =
static_cast<BMFace *
>(
993 params.calc_looptris =
true;
994 params.calc_normals =
false;
995 params.is_destructive =
true;
997 changed_multi =
true;
1000 if (!changed_multi) {
1010 ot->name =
"Make Edge/Face";
1011 ot->description =
"Add an edge or face to selected";
1012 ot->idname =
"MESH_OT_edge_face_add";
1038 for (
Object *obedit : objects) {
1042 if (
bm->totedgesel == 0) {
1067 for (
Object *obedit : objects) {
1069 params.calc_looptris =
true;
1070 params.calc_normals =
false;
1071 params.is_destructive =
false;
1083 ot->name =
"Mark Seam";
1084 ot->idname =
"MESH_OT_mark_seam";
1085 ot->description =
"(Un)mark selected edges as a seam";
1117 for (
Object *obedit : objects) {
1121 if ((use_verts &&
bm->totvertsel == 0) || (!use_verts &&
bm->totedgesel == 0)) {
1141 params.calc_looptris =
true;
1142 params.calc_normals =
false;
1143 params.is_destructive =
false;
1155 ot->name =
"Mark Sharp";
1156 ot->idname =
"MESH_OT_mark_sharp";
1157 ot->description =
"(Un)mark selected edges as sharp";
1173 "Consider vertices instead of edges to select which edges to (un)tag as sharp");
1187 const int verts_len =
bm->totvertsel;
1188 bool is_pair = (verts_len == 2);
1190 bool check_degenerate =
true;
1192 bool checks_succeded =
true;
1195 if (verts_len < 2) {
1214 check_degenerate =
false;
1223 "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
1229 checks_succeded =
false;
1236 "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
1242 checks_succeded =
false;
1245 if (checks_succeded) {
1254 if (
len && is_pair) {
1260 bool em_backup_free =
true;
1267 em_backup_free =
false;
1276 params.calc_looptris =
true;
1277 params.calc_normals =
false;
1278 params.is_destructive =
true;
1282 if (em_backup_free) {
1295 uint failed_objects_len = 0;
1299 for (
Object *obedit : objects) {
1303 failed_objects_len++;
1312 ot->name =
"Vertex Connect";
1313 ot->idname =
"MESH_OT_vert_connect";
1314 ot->description =
"Connect selected vertices of faces, splitting the face";
1354 const int totedge_orig =
bm->totedge;
1368 return (
bm->totedge != totedge_orig);
1382 bool changed =
false;
1383 bool has_wire =
false;
1399 if (has_wire ==
false) {
1401 if (tot ==
bm->totvertsel) {
1404 ese = ese_last->
next;
1414 }
while ((
void)(ese_last = ese), (ese = ese->
next));
1421 if (changed ==
false) {
1439 ese = ese_prev->
next;
1452 }
while ((
void)(ese_prev = ese), (ese = ese->
next));
1454 if (changed ==
false) {
1479 ListBase selected_orig = {
nullptr,
nullptr};
1493 if (
bm->totedgesel != edges_len) {
1497 std::swap(
bm->selected, selected_orig);
1502 BMEdge *e_prev = ese->prev ? (
BMEdge *)ese->prev->ele :
nullptr;
1510 if ((e_curr->
v1 != l_curr->
v) == (e_prev->
v1 != l_prev->
v)) {
1519 v = (&e_curr->
v1)[side];
1524 v = (&e_curr->
v1)[!side];
1532 *r_selected =
bm->selected;
1533 bm->selected = selected_orig;
1542 uint failed_selection_order_len = 0;
1543 uint failed_connect_len = 0;
1547 for (
Object *obedit : objects) {
1551 ListBase selected_orig = {
nullptr,
nullptr};
1553 if (
bm->totvertsel == 0) {
1560 failed_connect_len++;
1565 if (
bm->selected.first) {
1569 std::swap(
bm->selected, selected_orig);
1582 params.calc_looptris =
true;
1583 params.calc_normals =
false;
1584 params.is_destructive =
true;
1588 failed_selection_order_len++;
1593 bm->selected = selected_orig;
1597 if (failed_selection_order_len == objects.
size()) {
1601 if (failed_connect_len == objects.
size()) {
1612 ot->name =
"Vertex Connect Path";
1613 ot->idname =
"MESH_OT_vert_connect_path";
1614 ot->description =
"Connect vertices by their selection order, creating edges, splitting faces";
1636 for (
Object *obedit : objects) {
1644 em, op,
"faces.out",
true,
"connect_verts_concave faces=%hf",
BM_ELEM_SELECT))
1649 params.calc_looptris =
true;
1650 params.calc_normals =
false;
1651 params.is_destructive =
true;
1661 ot->name =
"Split Concave Faces";
1662 ot->idname =
"MESH_OT_vert_connect_concave";
1663 ot->description =
"Make all faces convex";
1687 for (
Object *obedit : objects) {
1698 "connect_verts_nonplanar faces=%hf angle_limit=%f",
1706 params.calc_looptris =
true;
1707 params.calc_normals =
false;
1708 params.is_destructive =
true;
1720 ot->name =
"Split Non-Planar Faces";
1721 ot->idname =
"MESH_OT_vert_connect_nonplanar";
1722 ot->description =
"Split non-planar faces that exceed the angle threshold";
1763 for (
Object *obedit : objects) {
1777 em, op,
"planar_faces faces=%hf iterations=%i factor=%f",
BM_ELEM_SELECT, repeat, fac))
1783 params.calc_looptris =
true;
1784 params.calc_normals =
true;
1785 params.is_destructive =
true;
1795 ot->name =
"Make Planar Faces";
1796 ot->idname =
"MESH_OT_face_make_planar";
1797 ot->description =
"Flatten selected faces";
1807 RNA_def_float(
ot->srna,
"factor", 1.0f, -10.0f, 10.0f,
"Factor",
"", 0.0f, 1.0f);
1808 RNA_def_int(
ot->srna,
"repeat", 1, 1, 10000,
"Iterations",
"", 1, 200);
1820 if (
bm->totedgesel == 0) {
1827 em, op,
"edges.out",
false,
"split_edges edges=%he",
BM_ELEM_SELECT))
1836 params.calc_looptris =
true;
1837 params.calc_normals =
false;
1838 params.is_destructive =
true;
1850 if (
bm->totvertsel == 0) {
1861 if (eed->
l !=
nullptr) {
1877 "split_edges edges=%he verts=%hv use_verts=%b",
1886 if (eed->
l !=
nullptr) {
1896 for (
int i = 0;
i < 2;
i++) {
1911 params.calc_looptris =
true;
1912 params.calc_normals =
false;
1913 params.is_destructive =
true;
1927 for (
Object *obedit : objects) {
1952 ot->name =
"Edge Split";
1953 ot->idname =
"MESH_OT_edge_split";
1954 ot->description =
"Split selected edges so that each neighbor face gets its own copy";
1965 {
BM_EDGE,
"EDGE", 0,
"Faces by Edges",
"Split faces along selected edges"},
1969 "Faces & Edges by Vertices",
1970 "Split faces and edges connected to selected vertices"},
1971 {0,
nullptr, 0,
nullptr,
nullptr},
1990 bool changed =
false;
1992 for (
Object *obedit : objects) {
2005 "duplicate geom=%hvef use_select_history=%b use_edge_flip_from_face=%b",
2027 params.calc_looptris =
true;
2028 params.calc_normals =
false;
2029 params.is_destructive =
true;
2050 ot->name =
"Duplicate";
2051 ot->description =
"Duplicate selected vertices, edges or faces";
2052 ot->idname =
"MESH_OT_duplicate";
2083 return lnors_ed_arr;
2088 if (!lnors_ed_arr) {
2092 if (lnors_ed_arr->
totloop == 0) {
2109 for (
int i = 0;
i < lnors_ed_arr_new_full->
totloop;
i++, lnor_ed_new_full++) {
2117 bm->lnor_spacearr->lspacearr[lnor_ed_new_full->
loop_index],
2145 BLI_assert(lnor_ed !=
nullptr && lnor_ed_new !=
nullptr);
2150 bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->
nloc, lnor_ed_new->
clnors_data);
2154 }
while (
l != l_start);
2179 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
2187 params.calc_looptris =
true;
2188 params.calc_normals =
false;
2189 params.is_destructive =
false;
2197 params.calc_looptris =
true;
2198 params.calc_normals =
false;
2199 params.is_destructive =
false;
2207 bool has_flipped_faces =
false;
2213 has_flipped_faces =
true;
2218 params.calc_looptris =
true;
2219 params.calc_normals =
false;
2220 params.is_destructive =
false;
2224 if (lnors_ed_arr !=
nullptr) {
2236 for (
Object *obedit : objects) {
2256 for (
Object *obedit : objects) {
2279 ot->name =
"Flip Normals";
2280 ot->description =
"Flip the direction of selected faces' normals (and of their vertices)";
2281 ot->idname =
"MESH_OT_flip_normals";
2293 "Custom Normals Only",
2294 "Only flip the custom loop normals of the selected elements");
2312 int tot_failed_all = 0;
2313 bool no_selected_edges =
true, invalid_selected_edges =
true;
2319 for (
Object *obedit : objects) {
2326 no_selected_edges =
false;
2349 invalid_selected_edges =
false;
2367 const int tot_failed = tot - tot_rotate;
2369 tot_failed_all += tot_failed;
2371 if (tot_failed != 0) {
2385 params.calc_looptris =
true;
2386 params.calc_normals =
false;
2387 params.is_destructive =
true;
2391 if (no_selected_edges) {
2393 op->
reports,
RPT_ERROR,
"Select edges or face pairs for edge loops to rotate about");
2399 if (invalid_selected_edges) {
2404 if (tot_failed_all != 0) {
2414 ot->name =
"Rotate Selected Edge";
2415 ot->description =
"Rotate selected edge or adjoining faces";
2416 ot->idname =
"MESH_OT_edge_rotate";
2440 bool changed =
false;
2444 for (
Object *obedit : objects) {
2450 if (
bm->totvertsel ==
bm->totvert) {
2455 if (
bm->totedgesel ==
bm->totedge) {
2460 if (
bm->totfacesel ==
bm->totface) {
2466 if (
bm->totvertsel == 0) {
2473 params.calc_looptris =
true;
2474 params.calc_normals =
false;
2475 params.is_destructive =
false;
2491 ot->name =
"Hide Selected";
2492 ot->idname =
"MESH_OT_hide";
2493 ot->description =
"Hide (un)selected vertices, edges or faces";
2504 ot->srna,
"unselected",
false,
"Unselected",
"Hide unselected rather than selected");
2521 for (
Object *obedit : objects) {
2526 params.calc_looptris =
true;
2527 params.calc_normals =
false;
2528 params.is_destructive =
false;
2539 ot->name =
"Reveal Hidden";
2540 ot->idname =
"MESH_OT_reveal";
2541 ot->description =
"Reveal all hidden vertices, edges and faces";
2567 for (
Object *obedit : objects) {
2588 if (lnors_ed_arr !=
nullptr) {
2594 params.calc_looptris =
true;
2595 params.calc_normals =
false;
2596 params.is_destructive =
false;
2606 ot->name =
"Recalculate Normals";
2607 ot->description =
"Make face and vertex normals point either outside or inside the mesh";
2608 ot->idname =
"MESH_OT_normals_make_consistent";
2641 int tot_selected = 0, tot_locked = 0;
2644 for (
Object *obedit : objects) {
2645 Mesh *mesh =
static_cast<Mesh *
>(obedit->data);
2647 bool mirrx =
false, mirry =
false, mirrz =
false;
2648 float clip_dist = 0.0f;
2690 for (
int i = 0;
i < repeat;
i++) {
2694 "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
2695 "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
2711 bool calc_normals =
false;
2717 calc_normals =
true;
2721 params.calc_looptris =
true;
2722 params.calc_normals = calc_normals;
2723 params.is_destructive =
false;
2727 if (tot_selected == 0 && !tot_locked) {
2737 ot->name =
"Smooth Vertices";
2738 ot->description =
"Flatten angles of selected vertices";
2739 ot->idname =
"MESH_OT_vertices_smooth";
2749 ot->srna,
"factor", 0.0f, -10.0f, 10.0f,
"Smoothing",
"Smoothing factor", 0.0f, 1.0f);
2751 ot->srna,
"repeat", 1, 1, 1000,
"Repeat",
"Number of times to smooth the mesh", 1, 100);
2771 int tot_selected = 0, tot_locked = 0;
2789 for (
Object *obedit : objects) {
2791 Mesh *mesh =
static_cast<Mesh *
>(obedit->data);
2810 bool failed_repeat_loop =
false;
2811 for (
int i = 0;
i < repeat;
i++) {
2814 "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f "
2815 "use_x=%b use_y=%b use_z=%b preserve_volume=%b",
2824 failed_repeat_loop =
true;
2828 if (failed_repeat_loop) {
2833 bool calc_normals =
false;
2839 calc_normals =
true;
2843 params.calc_looptris =
true;
2844 params.calc_normals = calc_normals;
2845 params.is_destructive =
false;
2849 if (tot_selected == 0 && !tot_locked) {
2859 ot->name =
"Laplacian Smooth Vertices";
2860 ot->description =
"Laplacian smooth of selected vertices";
2861 ot->idname =
"MESH_OT_vertices_smooth_laplacian";
2871 ot->srna,
"repeat", 1, 1, 1000,
"Number of iterations to smooth the mesh",
"", 1, 200);
2873 ot->srna,
"lambda_factor", 1.0f, 1e-7f, 1000.0f,
"Lambda factor",
"", 1e-7f, 1000.0f);
2879 "Lambda factor in border",
2886 RNA_def_boolean(
ot->srna,
"use_x",
true,
"Smooth X Axis",
"Smooth object along X axis");
2887 RNA_def_boolean(
ot->srna,
"use_y",
true,
"Smooth Y Axis",
"Smooth object along Y axis");
2888 RNA_def_boolean(
ot->srna,
"use_z",
true,
"Smooth Z Axis",
"Smooth object along Z axis");
2893 "Apply volume preservation after smooth");
2907 if (em ==
nullptr) {
2924 for (
Object *obedit : objects) {
2933 params.calc_looptris =
false;
2934 params.calc_normals =
false;
2935 params.is_destructive =
false;
2945 ot->name =
"Shade Smooth";
2946 ot->description =
"Display faces smooth (using vertex normals)";
2947 ot->idname =
"MESH_OT_faces_shade_smooth";
2969 for (
Object *obedit : objects) {
2978 params.calc_looptris =
false;
2979 params.calc_normals =
false;
2980 params.is_destructive =
false;
2990 ot->name =
"Shade Flat";
2991 ot->description =
"Display faces flat";
2992 ot->idname =
"MESH_OT_faces_shade_flat";
3017 for (
Object *obedit : objects) {
3035 params.calc_looptris =
false;
3036 params.calc_normals =
false;
3037 params.is_destructive =
false;
3050 for (
Object *obedit : objects) {
3067 params.calc_looptris =
false;
3068 params.calc_normals =
false;
3069 params.is_destructive =
false;
3086 for (
uint ob_index = 0; ob_index < objects.
size(); ob_index++) {
3087 Object *ob = objects[ob_index];
3108 "rotate_colors faces=%hf use_ccw=%b color_index=%i",
3121 params.calc_looptris =
false;
3122 params.calc_normals =
false;
3123 params.is_destructive =
false;
3137 for (
Object *obedit : objects) {
3157 em, &bmop, op,
"reverse_colors faces=%hf color_index=%i",
BM_ELEM_SELECT, color_index);
3166 params.calc_looptris =
false;
3167 params.calc_normals =
false;
3168 params.is_destructive =
false;
3178 ot->name =
"Rotate UVs";
3179 ot->idname =
"MESH_OT_uvs_rotate";
3180 ot->description =
"Rotate UV coordinates inside faces";
3196 ot->name =
"Reverse UVs";
3197 ot->idname =
"MESH_OT_uvs_reverse";
3198 ot->description =
"Flip direction of UV coordinates inside faces";
3214 ot->name =
"Rotate Colors";
3215 ot->idname =
"MESH_OT_colors_rotate";
3216 ot->description =
"Rotate face corner color attribute inside faces";
3232 ot->name =
"Reverse Colors";
3233 ot->idname =
"MESH_OT_colors_reverse";
3234 ot->description =
"Flip direction of face corner color attribute inside faces";
3245 RNA_def_enum(
ot->srna,
"axis", axis_items, DIRECTION_CW,
"Axis",
"Axis to mirror colors around");
3264 const bool use_first,
3265 const bool use_uvmerge,
3277 if (use_first ==
false) {
3300 em, wmop,
"pointmerge_facedata verts=%hv vert_snap=%e",
BM_ELEM_SELECT, mergevert))
3317 const bool use_cursor,
3318 const bool use_uvmerge,
3323 float co[3], cent[3] = {0.0f, 0.0f, 0.0f};
3324 const float *vco =
nullptr;
3330 mul_m4_v3(ob->world_to_object().ptr(), co);
3347 fac = 1.0f / float(
i);
3379 for (
Object *obedit : objects) {
3417 params.calc_looptris =
true;
3418 params.calc_normals =
false;
3419 params.is_destructive =
true;
3441 {0,
nullptr, 0,
nullptr,
nullptr},
3503 ot->description =
"Merge selected vertices";
3504 ot->idname =
"MESH_OT_merge";
3534 const bool use_sharp_edge_from_normals =
RNA_boolean_get(op->
ptr,
"use_sharp_edge_from_normals");
3536 int count_multi = 0;
3543 for (
Object *obedit : objects) {
3552 const int totvert_orig = em->
bm->
totvert;
3571 if (use_unselected) {
3579 if (!
EDBM_op_callf(em, op,
"weld_verts targetmap=%S", &bmop,
"targetmap.out")) {
3598 count_multi +=
count;
3600 params.calc_looptris =
true;
3601 params.calc_normals =
false;
3602 params.is_destructive =
true;
3609 count_multi == 1 ?
RPT_(
"Removed %d vertex") :
RPT_(
"Removed %d vertices"),
3618 ot->name =
"Merge by Distance";
3619 ot->description =
"Merge vertices based on their proximity";
3620 ot->idname =
"MESH_OT_remove_doubles";
3635 "Maximum distance between elements to merge",
3642 "Merge selected to other unselected vertices");
3645 "use_sharp_edge_from_normals",
3648 "Calculate sharp edges using custom normal data (when available)");
3680 for (
int i = 0;
i < totshape;
i++) {
3681 co =
static_cast<float *
>(
3693 int tot_shapekeys = 0;
3694 int tot_selected_verts_objects = 0;
3699 for (
Object *obedit : objects) {
3700 Mesh *mesh =
static_cast<Mesh *
>(obedit->data);
3713 tot_selected_verts_objects++;
3732 params.calc_looptris =
false;
3733 params.calc_normals =
false;
3734 params.is_destructive =
false;
3738 if (tot_selected_verts_objects == 0) {
3744 if (tot_shapekeys == 0) {
3755 ot->name =
"Shape Propagate";
3756 ot->description =
"Apply selected vertex locations to all other shape keys";
3757 ot->idname =
"MESH_OT_shape_propagate_to_all";
3778 Key *key_ref = me_ref->
key;
3786 int totshape_ref = 0;
3795 if (totshape_ref == 0 || shape_ref < 0) {
3799 if (shape_ref >= totshape_ref) {
3809 int tot_selected_verts_objects = 0, tot_locked = 0;
3812 for (
Object *obedit : objects) {
3813 Mesh *mesh =
static_cast<Mesh *
>(obedit->data);
3828 tot_selected_verts_objects++;
3852 sco =
static_cast<float *
>(
3858 const float *rco =
static_cast<const float *
>(
3876 params.calc_looptris =
true;
3877 params.calc_normals =
true;
3878 params.is_destructive =
false;
3883 if (tot_selected_verts_objects == 0 && !tot_locked) {
3911 tmp.
value = totitem;
3937 layout, op->
ptr,
"shape", &ptr_key,
"key_blocks", std::nullopt, ICON_SHAPEKEY_DATA);
3947 ot->name =
"Blend from Shape";
3948 ot->description =
"Blend in shape from a shape key";
3949 ot->idname =
"MESH_OT_blend_from_shape";
3966 RNA_def_float(
ot->srna,
"blend", 1.0f, -1e3f, 1e3f,
"Blend",
"Blending factor", -2.0f, 2.0f);
3967 RNA_def_boolean(
ot->srna,
"add",
true,
"Add",
"Add rather than blend between shapes");
3984 for (
Object *obedit : objects) {
4018 params.calc_looptris =
true;
4019 params.calc_normals =
false;
4020 params.is_destructive =
true;
4031 ot->name =
"Solidify";
4032 ot->description =
"Create a solid skin by extruding, compensating for sharp angles";
4033 ot->idname =
"MESH_OT_solidify";
4043 ot->srna,
"thickness", 0.01f, -1e4f, 1e4f,
"Thickness",
"", -10.0f, 10.0f);
4089 "duplicate geom=%hvef dest=%p",
4094 "delete geom=%hvef context=%i",
4127 bm_new_allocsize.
totvert = verts_len;
4128 bm_new_allocsize.
totedge = edges_len;
4129 bm_new_allocsize.
totloop = faces_len * 3;
4130 bm_new_allocsize.
totface = faces_len;
4132 const bool use_custom_normals = (bm_old->
lnor_spacearr !=
nullptr);
4139 if (use_custom_normals) {
4165 if (use_custom_normals) {
4169 for (
uint i = 0;
i < verts_len;
i++) {
4202 ID *obdata =
static_cast<ID *
>(ob->
data);
4207 if ((totcolp && matarar) == 0) {
4217 if (mat_nr < ob->totcol) {
4218 ma_ob = ob->
mat[mat_nr];
4226 if (mat_nr < *totcolp) {
4227 ma_obdata = (*matarar)[mat_nr];
4230 ma_obdata =
nullptr;
4240 (*matarar)[0] = ma_obdata;
4257 const short mat_nr = f_cmp->
mat_nr;
4263 if (f->
mat_nr == mat_nr) {
4272 }
while ((l_iter = l_iter->
next) != l_first);
4295 result |= (base_new !=
nullptr);
4307 const bool clear_object_data =
true;
4315 int(*groups)[3] =
nullptr;
4317 bm_old, vert_groups.
data(), edge_groups.
data(), face_groups.
data(), &groups);
4318 if (groups_len <= 1) {
4323 if (clear_object_data) {
4330 uint group_ofs[3] = {
uint(groups[0][0]),
uint(groups[0][1]),
uint(groups[0][2])};
4331 for (
int i = 1;
i < groups_len;
i++) {
4337 vert_groups.
data() + group_ofs[0],
4339 edge_groups.
data() + group_ofs[1],
4341 face_groups.
data() + group_ofs[2],
4343 result |= (base_new !=
nullptr);
4345 group_ofs[0] += groups[
i][0];
4346 group_ofs[1] += groups[
i][1];
4347 group_ofs[2] += groups[
i][2];
4353 if (clear_object_data) {
4369 bool changed_multi =
false;
4372 uint empty_selection_len = 0;
4375 for (
const int base_index : bases.
index_range()) {
4376 Base *base = bases[base_index];
4382 if (++empty_selection_len == bases.
size()) {
4390 bool changed =
false;
4408 params.calc_looptris =
true;
4409 params.calc_normals =
false;
4410 params.is_destructive =
true;
4413 changed_multi |= changed;
4424 Object *ob = base_iter->object;
4440 bool changed =
false;
4464 changed_multi |= changed;
4469 if (changed_multi) {
4487 {0,
nullptr, 0,
nullptr,
nullptr},
4491 ot->name =
"Separate";
4492 ot->description =
"Separate selected geometry into a new mesh";
4493 ot->idname =
"MESH_OT_separate";
4517 bool has_selected_edges =
false, has_faces_filled =
false;
4523 for (
Object *obedit : objects) {
4526 const int totface_orig = em->
bm->
totface;
4531 has_selected_edges =
true;
4535 em, &bmop, op,
"triangle_fill edges=%he use_beauty=%b",
BM_ELEM_SELECT, use_beauty))
4547 has_faces_filled =
true;
4558 params.calc_looptris =
true;
4559 params.calc_normals =
false;
4560 params.is_destructive =
true;
4564 if (!has_selected_edges) {
4569 if (!has_faces_filled) {
4581 ot->idname =
"MESH_OT_fill";
4582 ot->description =
"Fill a selected edge loop with faces";
4592 RNA_def_boolean(
ot->srna,
"use_beauty",
true,
"Beauty",
"Use best triangulation division");
4629 const float eps_even = 1e-3f;
4657 for (
int i = 0;
i < edges_len;
i++) {
4662 span = verts_len / 4;
4665 span =
min_ii(span, (verts_len / 2) - 1);
4667 offset =
mod_i(offset, verts_len);
4669 if ((
count == 1) && ((verts_len & 1) == 0) && (verts_len == edges_len)) {
4677 if (v_act && (v_act_link =
static_cast<LinkData *
>(
4685 float angle_best = -1.0f;
4688 if ((
angle > angle_best) || (v_link_best ==
nullptr)) {
4690 v_link_best = v_link;
4694 v_act_link = v_link_best;
4695 v_act =
static_cast<BMVert *
>(v_act_link->
data);
4703 v_act =
static_cast<BMVert *
>(v_act_link->
data);
4720 for (v_link =
static_cast<LinkData *
>(
verts->first),
i = 0; v_link;
4721 v_link = v_link->
next,
i++)
4726 ele_sort[
i].
data = v_link;
4729 if (
ELEM(
i, 0, verts_len / 2)) {
4741 if ((ele_sort[0].sort_value - ele_sort[verts_len - 3].sort_value) > eps_even) {
4753 if (span > verts_len / 2) {
4754 span = (verts_len)-span;
4755 start = (verts_len / 2) - span;
4759 for (
i = start;
i < start + span;
i++) {
4910 for (
uint ob_index = 0; ob_index < objects.
size(); ob_index++) {
4912 Object *obedit = objects[ob_index];
4918 bool use_prepare =
true;
4926 const int totedge_orig = em->
bm->
totedge;
4927 const int totface_orig = em->
bm->
totface;
4966 "grid_fill edges=%he mat_nr=%i use_smooth=%b use_interp_simple=%b",
4973 const bool has_geometry_changed = totedge_orig != em->
bm->
totedge ||
4984 if (changed || split_join) {
4986 params.calc_looptris =
true;
4987 params.calc_normals =
false;
4988 params.is_destructive =
true;
5007 ot->name =
"Grid Fill";
5008 ot->description =
"Fill grid from two loops";
5009 ot->idname =
"MESH_OT_fill_grid";
5019 prop =
RNA_def_int(
ot->srna,
"span", 1, 1, 1000,
"Span",
"Number of grid columns", 1, 100);
5027 "Vertex that is the corner of the grid",
5032 "use_interp_simple",
5035 "Use simple interpolation of grid vertices");
5053 for (
Object *obedit : objects) {
5061 em, op,
"faces.out",
true,
"holes_fill edges=%he sides=%i",
BM_ELEM_SELECT, sides))
5067 params.calc_looptris =
true;
5068 params.calc_normals =
false;
5069 params.is_destructive =
true;
5079 ot->name =
"Fill Holes";
5080 ot->idname =
"MESH_OT_fill_holes";
5081 ot->description =
"Fill in holes (boundary edge loops)";
5096 "Number of sides in hole required to fill (zero fills all holes)",
5114 const float angle_max =
M_PI;
5118 for (
Object *obedit : objects) {
5125 if (angle_limit >= angle_max) {
5142 em, op,
"geom.out",
true,
"beautify_fill faces=%hf edges=%he",
BM_ELEM_SELECT, hflag))
5148 params.calc_looptris =
true;
5149 params.calc_normals =
false;
5150 params.is_destructive =
true;
5162 ot->name =
"Beautify Faces";
5163 ot->idname =
"MESH_OT_beautify_fill";
5164 ot->description =
"Rearrange some faces to try to get less degenerated geometry";
5203 for (
Object *obedit : objects) {
5214 "poke faces=%hf offset=%f use_relative_offset=%b center_mode=%i",
5217 use_relative_offset,
5233 params.calc_looptris =
true;
5234 params.calc_normals =
true;
5235 params.is_destructive =
true;
5249 "Weighted median face center"},
5252 {0,
nullptr, 0,
nullptr,
nullptr},
5256 ot->name =
"Poke Faces";
5257 ot->idname =
"MESH_OT_poke";
5258 ot->description =
"Split a face into a fan";
5268 ot->srna,
"offset", 0.0f, -1e3f, 1e3f,
"Poke Offset",
"Poke Offset", -1.0f, 1.0f);
5270 "use_relative_offset",
5273 "Scale the offset by surrounding geometry");
5279 "Poke face center calculation");
5297 for (
Object *obedit : objects) {
5313 "triangulate faces=%hf quad_method=%i ngon_method=%i",
5337 params.calc_looptris =
true;
5338 params.calc_normals =
false;
5339 params.is_destructive =
true;
5349 ot->name =
"Triangulate Faces";
5350 ot->idname =
"MESH_OT_quads_convert_to_tris";
5351 ot->description =
"Triangulate selected faces";
5365 "Method for splitting the quads into triangles");
5371 "Method for splitting the n-gons into triangles");
5381# define USE_JOIN_TRIANGLE_TESTING_API
5398#ifdef USE_JOIN_TRIANGLE_TESTING_API
5403 const float topology_influence =
RNA_float_get(op->
ptr,
"topology_influence");
5406 float angle_face_threshold, angle_shape_threshold;
5411 is_face_pair = (totelem_sel[2] == 2);
5420 angle_face_threshold =
DEG2RADF(180.0f);
5428 angle_shape_threshold =
DEG2RADF(180.0f);
5435 for (
Object *obedit : objects) {
5444 bool extend_selection = (deselect_joined ==
false);
5446#ifdef USE_JOIN_TRIANGLE_TESTING_API
5447 if (merge_limit != -1) {
5448 extend_selection =
false;
5457 "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
5458 "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b "
5459#ifdef USE_JOIN_TRIANGLE_TESTING_API
5460 "merge_limit=%i neighbor_debug=%i "
5462 "topology_influence=%f deselect_joined=%b",
5464 angle_face_threshold,
5465 angle_shape_threshold,
5471#ifdef USE_JOIN_TRIANGLE_TESTING_API
5481 if (deselect_joined) {
5492 params.calc_looptris =
true;
5493 params.calc_normals =
false;
5494 params.is_destructive =
true;
5505#ifdef USE_JOIN_TRIANGLE_TESTING_API
5512 "Maximum number of merges",
5523 "Neighbor to highlight",
5548 "Shape angle limit",
5554 "topology_influence",
5558 "Topology Influence",
5559 "How much to prioritize regular grids of quads as well as "
5560 "quads that touch existing quads",
5574 "Only select remaining triangles that were not merged");
5580 ot->name =
"Triangles to Quads";
5581 ot->idname =
"MESH_OT_tris_convert_to_quads";
5582 ot->description =
"Merge triangles into four sided polygons where possible";
5609 const float vertex_group_factor =
RNA_float_get(op->
ptr,
"vertex_group_factor");
5612 const float symmetry_eps = 0.00002f;
5613 const int symmetry_axis = use_symmetry ?
RNA_enum_get(op->
ptr,
"symmetry_axis") : -1;
5616 if (ratio == 1.0f) {
5625 for (
Object *obedit : objects) {
5628 if (
bm->totedgesel == 0) {
5637 if (use_vertex_group && (cd_dvert_offset == -1)) {
5639 use_vertex_group =
false;
5646 float weight = 0.0f;
5648 if (use_vertex_group) {
5652 if (invert_vertex_group) {
5653 weight = 1.0f - weight;
5661 vweights[
i] = weight;
5669 if ((
bm->totface ==
bm->totfacesel) || (ratio == 0.0f)) {
5670 ratio_adjust = ratio;
5681 int totface_basis = 0;
5682 int totface_adjacent = 0;
5687 const int f_len = f->
len > 4 ? (f->
len - 2) : 1;
5688 totface_basis += f_len;
5690 BMLoop *l_iter, *l_first;
5694 totface_adjacent += f_len;
5697 }
while ((l_iter = l_iter->
next) != l_first);
5700 ratio_adjust = ratio;
5701 ratio_adjust = 1.0f - ratio_adjust;
5702 ratio_adjust *= float(totface_adjacent) / float(totface_basis);
5703 ratio_adjust = 1.0f - ratio_adjust;
5707 em->
bm, ratio_adjust, vweights, vertex_group_factor,
false, symmetry_axis, symmetry_eps);
5720 params.calc_looptris =
true;
5721 params.calc_normals =
true;
5722 params.is_destructive =
true;
5748 row = &layout->
row(
true,
IFACE_(
"Symmetry"));
5750 sub = &row->row(
true);
5758 ot->name =
"Decimate Geometry";
5759 ot->idname =
"MESH_OT_decimate";
5760 ot->description =
"Simplify geometry by collapsing edges";
5772 RNA_def_float(
ot->srna,
"ratio", 1.0f, 0.0f, 1.0f,
"Ratio",
"", 0.0f, 1.0f);
5778 "Use active vertex group as an influence");
5780 "vertex_group_factor",
5785 "Vertex group strength",
5789 ot->srna,
"invert_vertex_group",
false,
"Invert",
"Invert vertex group influence");
5791 RNA_def_boolean(
ot->srna,
"use_symmetry",
false,
"Symmetry",
"Maintain symmetry on an axis");
5809 "Dissolve Vertices",
5810 "Dissolve remaining vertices which connect to only two edges");
5822 "Split off face corners to maintain surrounding geometry");
5827 "use_boundary_tear",
5830 "Split off face corners instead of merging faces");
5842 "Remaining vertices which separate edge pairs are preserved if their edge angle exceeds "
5862 for (
Object *obedit : objects) {
5873 "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
5884 params.calc_looptris =
true;
5885 params.calc_normals =
false;
5886 params.is_destructive =
true;
5896 ot->name =
"Dissolve Vertices";
5897 ot->description =
"Dissolve vertices, merge edges and faces";
5898 ot->idname =
"MESH_OT_dissolve_verts";
5927 for (
Object *obedit : objects) {
5939 "dissolve_edges edges=%he use_verts=%b use_face_split=%b angle_threshold=%f",
5951 params.calc_looptris =
true;
5952 params.calc_normals =
false;
5953 params.is_destructive =
true;
5963 ot->name =
"Dissolve Edges";
5964 ot->description =
"Dissolve edges, merging faces";
5965 ot->idname =
"MESH_OT_dissolve_edges";
5992 for (
Object *obedit : objects) {
6005 "dissolve_faces faces=%hf use_verts=%b",
6015 params.calc_looptris =
true;
6016 params.calc_normals =
false;
6017 params.is_destructive =
true;
6027 ot->name =
"Dissolve Faces";
6028 ot->description =
"Dissolve faces";
6029 ot->idname =
"MESH_OT_dissolve_faces";
6078 bool is_edge_select_mode =
false;
6084 is_edge_select_mode =
true;
6087 if (!is_edge_select_mode) {
6089 if (
STREQ(prop_id,
"angle_threshold")) {
6099 ot->name =
"Dissolve Selection";
6100 ot->description =
"Dissolve geometry based on the selection mode";
6101 ot->idname =
"MESH_OT_dissolve_mode";
6126 const bool use_dissolve_boundaries =
RNA_boolean_get(op->
ptr,
"use_dissolve_boundaries");
6134 for (
Object *obedit : objects) {
6138 if ((
bm->totvertsel == 0) && (
bm->totedgesel == 0) && (
bm->totfacesel == 0)) {
6180 "dissolve_limit edges=%he verts=%hv angle_limit=%f use_dissolve_boundaries=%b delimit=%i",
6184 use_dissolve_boundaries,
6190 params.calc_looptris =
true;
6191 params.calc_normals =
false;
6192 params.is_destructive =
true;
6204 ot->name =
"Limited Dissolve";
6205 ot->idname =
"MESH_OT_dissolve_limited";
6207 "Dissolve selected edges and vertices, limited by the angle of surrounding geometry";
6228 "use_dissolve_boundaries",
6231 "Dissolve all vertices in between face boundaries");
6237 "Delimit dissolve operation");
6250 int totelem_old[3] = {0, 0, 0};
6251 int totelem_new[3] = {0, 0, 0};
6256 for (
Object *obedit : objects) {
6259 totelem_old[0] +=
bm->totvert;
6260 totelem_old[1] +=
bm->totedge;
6261 totelem_old[2] +=
bm->totface;
6266 for (
Object *obedit : objects) {
6278 params.calc_looptris =
true;
6279 params.calc_normals =
false;
6280 params.is_destructive =
true;
6283 totelem_new[0] +=
bm->totvert;
6284 totelem_new[1] +=
bm->totedge;
6285 totelem_new[2] +=
bm->totface;
6296 ot->name =
"Degenerate Dissolve";
6297 ot->idname =
"MESH_OT_dissolve_degenerate";
6298 ot->description =
"Dissolve zero area faces and zero length edges";
6313 "Maximum distance between elements to merge",
6333 for (
Object *obedit : objects) {
6360 "dissolve_edges edges=%he use_verts=%b use_face_split=%b angle_threshold=%f",
6374 params.calc_looptris =
true;
6375 params.calc_normals =
false;
6376 params.is_destructive =
true;
6386 ot->name =
"Delete Edge Loop";
6387 ot->description =
"Delete an edge loop by merging the faces on each side";
6388 ot->idname =
"MESH_OT_delete_edgeloop";
6401 "Split off face corners to maintain surrounding geometry");
6416 for (
Object *obedit : objects) {
6438 params.calc_looptris =
true;
6439 params.calc_normals =
true;
6440 params.is_destructive =
true;
6451 ot->idname =
"MESH_OT_split";
6452 ot->description =
"Split off selected geometry from connected unselected geometry";
6524 char *pblock[3] = {
nullptr,
nullptr,
nullptr}, *pb;
6525 BMElemSort *sblock[3] = {
nullptr,
nullptr,
nullptr}, *sb;
6526 uint *map[3] = {
nullptr,
nullptr,
nullptr}, *mp;
6527 int totelem[3] = {0, 0, 0};
6528 int affected[3] = {0, 0, 0};
6547 float fact = reverse ? -1.0 : 1.0;
6563 sb[affected[0]].org_idx =
i;
6564 sb[affected[0]++].srt = co[coidx] * fact;
6583 sb[affected[1]].org_idx =
i;
6584 sb[affected[1]++].srt = co[coidx] * fact;
6603 sb[affected[2]].org_idx =
i;
6604 sb[affected[2]++].srt = co[coidx] * fact;
6616 float fact = reverse ? -1.0 : 1.0;
6630 sb[affected[0]].org_idx =
i;
6649 sb[affected[1]].org_idx =
i;
6668 sb[affected[2]].org_idx =
i;
6689 sb[affected[2]].org_idx =
i;
6692 sb[affected[2]++].srt = srt * float(totelem[2]) + float(
i);
6702 uint *tbuf[3] = {
nullptr,
nullptr,
nullptr}, *tb;
6710 mp[affected[0]++] =
i;
6725 mp[affected[1]++] =
i;
6740 mp[affected[2]++] =
i;
6750 int tot = totelem[j];
6751 int aff = affected[j];
6757 if (
ELEM(aff, 0, tot)) {
6764 memcpy(tb + (tot - aff), mp, aff *
sizeof(
int));
6767 memcpy(mp + aff, tb, (tot - aff) *
sizeof(
int));
6769 mp = map[j] = tbuf[j];
6774 for (
i = tot, tb = tbuf[j] + tot - 1;
i--; tb--) {
6792 sb[affected[0]].org_idx =
i;
6811 sb[affected[1]].org_idx =
i;
6830 sb[affected[2]].org_idx =
i;
6850 sb[affected[0]].org_idx =
i;
6851 sb[affected[0]++].srt = float(-
i);
6866 sb[affected[1]].org_idx =
i;
6867 sb[affected[1]++].srt = float(-
i);
6882 sb[affected[2]].org_idx =
i;
6883 sb[affected[2]++].srt = float(-
i);
6895 if (affected[0] == 0 && affected[1] == 0 && affected[2] == 0) {
6914 if (pb && sb && !map[j]) {
6917 int tot = totelem[j];
6918 int aff = affected[j];
6923 p_blk = pb + tot - 1;
6924 s_blk = sb + aff - 1;
6925 for (
i = tot;
i--; p_blk--) {
6946 params.calc_looptris = (totelem[2] != 0);
6947 params.calc_normals =
false;
6948 params.is_destructive =
true;
6977 if (rv3d ==
nullptr) {
7004 for (
uint ob_index = 0; ob_index < objects.
size(); ob_index++) {
7005 Object *ob = objects[ob_index];
7009 if (!((elem_types &
BM_VERT &&
bm->totvertsel > 0) ||
7010 (elem_types &
BM_EDGE &&
bm->totedgesel > 0) ||
7011 (elem_types &
BM_FACE &&
bm->totfacesel > 0)))
7016 int seed_iter =
seed;
7024 C, scene, ob, rv3d, elem_types,
BM_ELEM_SELECT, action, use_reverse, seed_iter);
7037 if (
STREQ(prop_id,
"seed")) {
7045 if (
STREQ(prop_id,
"reverse")) {
7062 "Sort selected elements from farthest to nearest one in current view"},
7067 "Sort selected elements from left to right one in current view"},
7072 "Sort selected elements from nearest to farthest from 3D cursor"},
7077 "Sort selected faces from smallest to greatest material index"},
7082 "Move all selected elements in first places, preserving their relative order.\n"
7083 "Warning: This will affect unselected elements' indices as well"},
7084 {
SRT_RANDOMIZE,
"RANDOMIZE", 0,
"Randomize",
"Randomize order of selected elements"},
7085 {
SRT_REVERSE,
"REVERSE", 0,
"Reverse",
"Reverse current order of selected elements"},
7086 {0,
nullptr, 0,
nullptr,
nullptr},
7090 {
BM_VERT,
"VERT", 0,
"Vertices",
""},
7091 {
BM_EDGE,
"EDGE", 0,
"Edges",
""},
7092 {
BM_FACE,
"FACE", 0,
"Faces",
""},
7093 {0,
nullptr, 0,
nullptr,
nullptr},
7097 ot->name =
"Sort Mesh Elements";
7099 "The order of selected vertices/edges/faces is modified, based on a given method";
7100 ot->idname =
"MESH_OT_sort_elements";
7117 "Type of reordering operation to apply");
7123 "Which elements to affect (vertices, edges and/or faces)");
7124 RNA_def_boolean(
ot->srna,
"reverse",
false,
"Reverse",
"Reverse the sorting effect");
7125 RNA_def_int(
ot->srna,
"seed", 0, 0, INT_MAX,
"Seed",
"Seed for random-based operations", 0, 255);
7146 int totface_del = 0;
7157 bool is_all_sel =
true;
7172 if (is_all_sel ==
false) {
7185 const bool use_pairs,
7186 const bool use_cyclic,
7187 const bool use_merge,
7188 const float merge_factor,
7189 const int twist_offset)
7193 int totface_del = 0;
7194 BMFace **totface_del_arr =
nullptr;
7196 bool changed =
false;
7213 totface_del_arr =
static_cast<BMFace **
>(
7214 MEM_mallocN(
sizeof(*totface_del_arr) * totface_del, __func__));
7219 totface_del_arr[
i++] = f;
7231 "bridge_loops edges=%he use_pairs=%b use_cyclic=%b use_merge=%b merge_factor=%f "
7240 if (use_faces && totface_del) {
7243 for (
i = 0;
i < totface_del;
i++) {
7248 "delete geom=%hf context=%i",
7258 if (use_merge ==
false) {
7266 if (use_merge ==
false) {
7270 if (op_props.
cuts) {
7278 "subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
7279 "profile_shape=%i profile_shape_factor=%f",
7297 if (totface_del_arr) {
7307 params.calc_looptris =
true;
7308 params.calc_normals =
false;
7309 params.is_destructive =
true;
7330 for (
Object *obedit : objects) {
7339 static_cast<Mesh *
>(obedit->data),
7355 {0,
nullptr, 0,
nullptr,
nullptr},
7359 ot->name =
"Bridge Edge Loops";
7360 ot->description =
"Create a bridge of faces between two or more selected edge loops";
7361 ot->idname =
"MESH_OT_bridge_edge_loops";
7375 "Method of bridging multiple loops");
7377 RNA_def_boolean(
ot->srna,
"use_merge",
false,
"Merge",
"Merge rather than creating faces");
7378 RNA_def_float(
ot->srna,
"merge_factor", 0.5f, 0.0f, 1.0f,
"Merge Factor",
"", 0.0f, 1.0f);
7385 "Twist offset for closed loops",
7413 for (
Object *obedit : objects) {
7425 "wireframe faces=%hf use_replace=%b use_boundary=%b use_even_offset=%b "
7426 "use_relative_offset=%b "
7427 "use_crease=%b crease_weight=%f thickness=%f offset=%f",
7432 use_relative_offset,
7449 params.calc_looptris =
true;
7450 params.calc_normals =
false;
7451 params.is_destructive =
true;
7463 ot->name =
"Wireframe";
7464 ot->idname =
"MESH_OT_wireframe";
7465 ot->description =
"Create a solid wireframe from faces";
7475 RNA_def_boolean(
ot->srna,
"use_boundary",
true,
"Boundary",
"Inset face boundaries");
7480 "Scale the offset to give more even thickness");
7482 "use_relative_offset",
7485 "Scale the offset by surrounding geometry");
7486 RNA_def_boolean(
ot->srna,
"use_replace",
true,
"Replace",
"Remove original faces");
7488 ot->srna,
"thickness", 0.01f, 0.0f, 1e4f,
"Thickness",
"", 0.0f, 10.0f);
7496 "Crease hub edges for an improved subdivision surface");
7498 ot->srna,
"crease_weight", 0.01f, 0.0f, 1e3f,
"Crease Weight",
"", 0.0f, 1.0f);
7511 bool changed_multi =
false;
7516 for (
Base *base : bases) {
7517 Object *obedit = base->object;
7528 "offset_edgeloops edges=%he use_cap_endpoint=%b",
7541 params.calc_looptris =
true;
7542 params.calc_normals =
false;
7543 params.is_destructive =
true;
7545 changed_multi =
true;
7549 if (changed_multi) {
7566 ot->name =
"Offset Edge Loop";
7567 ot->idname =
"MESH_OT_offset_edge_loops";
7568 ot->description =
"Create offset edge loop from the current selection";
7581 ot->srna,
"use_cap_endpoint",
false,
"Cap Endpoint",
"Extend loop around end-points");
7605 for (
Object *obedit : objects) {
7617 "convex_hull input=%hvef "
7618 "use_existing_faces=%b",
7620 use_existing_faces);
7633 if (delete_unused) {
7635 em, op,
"delete geom=%S context=%i", &bmop,
"geom_unused.out",
DEL_ONLYTAGGED))
7645 em, op,
"delete geom=%S context=%i", &bmop,
"geom_holes.out",
DEL_ONLYTAGGED))
7653 if (join_triangles) {
7658 "join_triangles faces=%S "
7659 "angle_face_threshold=%f angle_shape_threshold=%f",
7662 angle_face_threshold,
7663 angle_shape_threshold))
7675 params.calc_looptris =
true;
7676 params.calc_normals =
false;
7677 params.is_destructive =
true;
7688 ot->name =
"Convex Hull";
7689 ot->description =
"Enclose selected vertices in a convex polyhedron";
7690 ot->idname =
"MESH_OT_convex_hull";
7693 ot->exec = edbm_convex_hull_exec;
7704 "Delete selected elements that are not used by the hull");
7707 "use_existing_faces",
7709 "Use Existing Faces",
7710 "Skip hull triangles that are covered by a pre-existing face");
7716 "Delete selected faces that are used by the hull");
7719 ot->srna,
"join_triangles",
true,
"Join Triangles",
"Merge adjacent triangles into quads");
7739 for (
Object *obedit : objects) {
7750 "symmetrize input=%hvef direction=%i dist=%f",
7765 params.calc_looptris =
true;
7766 params.calc_normals =
false;
7767 params.is_destructive =
true;
7778 ot->name =
"Symmetrize";
7779 ot->description =
"Enforce symmetry (both form and topological) across an axis";
7780 ot->idname =
"MESH_OT_symmetrize";
7794 "Which sides to copy from and to");
7801 "Limit for snap middle vertices to the axis center",
7814 const float eps = 0.00001f;
7815 const float eps_sq =
eps *
eps;
7816 const bool use_topology =
false;
7824 int totvertfound = 0, totvertmirr = 0, totvertfail = 0, totobjects = 0;
7827 int axis = axis_dir % 3;
7828 bool axis_sign = axis != axis_dir;
7835 for (
Object *obedit : objects) {
7867 int i_mirr = index[
i];
7873 float co[3], co_mirr[3];
7875 if ((
v->co[axis] > v_mirr->
co[axis]) == axis_sign) {
7876 std::swap(
v, v_mirr);
7880 co_mirr[axis] *= -1.0f;
7916 params.calc_looptris =
false;
7917 params.calc_normals =
false;
7918 params.is_destructive =
false;
7928 "%d already symmetrical, %d pairs mirrored, %d failed",
7929 totvertfound - totvertmirr,
7933 else if (totobjects) {
7936 "%d already symmetrical, %d pairs mirrored",
7937 totvertfound - totvertmirr,
7947 ot->name =
"Snap to Symmetry";
7948 ot->description =
"Snap vertex pairs to their mirrored locations";
7949 ot->idname =
"MESH_OT_symmetry_snap";
7963 "Which sides to copy from and to");
7970 "Distance within which matching vertices are searched",
7979 "Mix factor of the locations of the vertices",
7983 ot->srna,
"use_center",
true,
"Center",
"Snap middle vertices to the axis center");
7988#if defined(WITH_FREESTYLE)
8005 for (
Object *obedit : objects) {
8008 if (em ==
nullptr) {
8014 if (
bm->totedgesel == 0) {
8053 ot->name =
"Mark Freestyle Edge";
8054 ot->description =
"(Un)mark selected edges as Freestyle feature edges";
8055 ot->idname =
"MESH_OT_mark_freestyle_edge";
8058 ot->exec = edbm_mark_freestyle_edge_exec;
8085 for (
Object *obedit : objects) {
8088 if (em ==
nullptr) {
8131 ot->name =
"Mark Freestyle Face";
8132 ot->description =
"(Un)mark selected faces for exclusion from Freestyle feature edge detection";
8133 ot->idname =
"MESH_OT_mark_freestyle_face";
8136 ot->exec = edbm_mark_freestyle_face_exec;
8187 "Toggle inversion of affected normals"},
8192 "Interpolate between new and original normals"},
8199 "Follow mouse cursor position"},
8204 "Use current rotation/scaling pivot point coordinates"},
8209 "Use current edited object's location"},
8213 "Set and Use 3D Cursor",
8214 "Set new 3D cursor position and use it"},
8218 "Select and Use Mesh Item",
8219 "Select new active mesh element and use its location"},
8220 {0,
nullptr, 0,
nullptr,
nullptr},
8222 static const char *keymap_name =
"Custom Normals Modal Map";
8238#define CLNORS_VALID_VEC_LEN (1e-4f)
8256 "Use static coordinates (defined by various means)"},
8258 {0,
nullptr, 0,
nullptr,
nullptr},
8273 return (lnors_ed_arr->
totloop != 0);
8361 if (do_align && !do_reset) {
8368 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
8372 else if (do_spherize) {
8376 float spherized_normal[3];
8387 else if (do_align) {
8394 if (do_invert && !do_reset) {
8423 int new_mode = mode;
8424 bool force_mousemove =
false;
8425 bool do_reset =
false;
8430 switch (event->
val) {
8476 force_mousemove =
true;
8563 if (new_mode != mode) {
8590 params.calc_looptris =
true;
8591 params.calc_normals =
false;
8592 params.is_destructive =
false;
8655 params.calc_looptris =
true;
8656 params.calc_normals =
false;
8657 params.is_destructive =
false;
8669 if (
STREQ(prop_id,
"spherize_strength")) {
8699 ot->name =
"Point Normals to Target";
8700 ot->description =
"Point selected custom normals to specified Target";
8701 ot->idname =
"MESH_OT_point_normals";
8719 "How to define coordinates to point custom normals to");
8722 RNA_def_boolean(
ot->srna,
"invert",
false,
"Invert",
"Invert affected normals");
8724 RNA_def_boolean(
ot->srna,
"align",
false,
"Align",
"Make all affected normals parallel");
8733 "Target location to which normals will point",
8738 ot->srna,
"spherize",
false,
"Spherize",
"Interpolate between original and new normals");
8741 "spherize_strength",
8745 "Spherize Strength",
8746 "Ratio of spherized normal to original normal",
8767 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
8778 float avg_normal[3] = {0.0f, 0.0f, 0.0f};
8781 for (; loops; loops = loops->
next) {
8831 bm->lnor_spacearr->lspacearr[loop_index], f->
no, clnors);
8837 const BMEdge *e_org = l_curr->
e;
8838 BMLoop *lfan_pivot, *lfan_pivot_next;
8840 lfan_pivot = l_curr;
8841 e_next = lfan_pivot->
e;
8842 float avg_normal[3] = {0.0f};
8846 if (lfan_pivot_next) {
8850 e_next = (lfan_pivot->
e == e_next) ? lfan_pivot->
prev->
e : lfan_pivot->
e;
8859 lfan_pivot = lfan_pivot_next;
8869 bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
8873 }
while ((l_curr = l_curr->
next) != l_first);
8884 for (
Object *obedit : objects) {
8922 params.calc_looptris =
true;
8923 params.calc_normals =
false;
8924 params.is_destructive =
false;
8939 ot->name =
"Merge Normals";
8940 ot->description =
"Merge custom normals of selected vertices";
8941 ot->idname =
"MESH_OT_merge_normals";
8959 ot->name =
"Split Normals";
8960 ot->description =
"Split custom normals of selected vertices";
8961 ot->idname =
"MESH_OT_split_normals";
8988 "Take average of vertex normals"},
8993 "Set all vertex normals by face area"},
8998 "Set all vertex normals by corner angle"},
8999 {0,
nullptr, 0,
nullptr,
nullptr},
9015 for (
uint ob_index = 0; ob_index < objects.
size(); ob_index++) {
9019 Object *obedit = objects[ob_index];
9032 float weight = absweight / 50.0f;
9033 if (absweight == 100.0f) {
9034 weight = float(SHRT_MAX);
9036 else if (absweight == 1.0f) {
9037 weight = 1 / float(SHRT_MAX);
9039 else if ((weight - 1) * 25 > 1) {
9040 weight = (weight - 1) * 25;
9058 bm->lnor_spacearr->lspacearr[loop_index], f->
no, clnors);
9064 const BMEdge *e_org = l_curr->
e;
9065 BMLoop *lfan_pivot, *lfan_pivot_next;
9067 lfan_pivot = l_curr;
9068 e_next = lfan_pivot->
e;
9072 if (lfan_pivot_next) {
9076 e_next = (lfan_pivot->
e == e_next) ? lfan_pivot->
prev->
e : lfan_pivot->
e;
9092 lfan_pivot = lfan_pivot_next;
9095 float wnor[3], avg_normal[3] = {0.0f},
count = 0;
9107 const float n_weight =
pow(weight,
count);
9113 bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
9118 mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
9130 bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
9134 }
while ((l_curr = l_curr->
next) != l_first);
9138 params.calc_looptris =
true;
9139 params.calc_normals =
false;
9140 params.is_destructive =
false;
9158 if (
STREQ(prop_id,
"weight")) {
9159 return !is_clor_average_loop;
9161 if (
STREQ(prop_id,
"threshold")) {
9162 return !is_clor_average_loop;
9191 ot->name =
"Average Normals";
9192 ot->description =
"Average custom normals of selected vertices";
9193 ot->idname =
"MESH_OT_average_normals";
9208 "Averaging method");
9210 RNA_def_int(
ot->srna,
"weight", 50, 1, 100,
"Weight",
"Weight applied per face", 1, 100);
9218 "Threshold value for different weights to be considered equal",
9243 "Paste normal from the internal clipboard"},
9249 "Multiply normal vector with selection"},
9254 "Reset the internal clipboard and/or normal of selected element"},
9255 {0,
nullptr, 0,
nullptr,
nullptr},
9267 bool done_copy =
false;
9269 for (
Object *obedit : objects) {
9273 if (
bm->totloop == 0) {
9283 if (
bm->totfacesel == 0 &&
bm->totvertsel == 0) {
9289 (
bm->totfacesel != 1 && lnors_ed_arr->
totloop != 1 &&
bm->totvertsel != 1))
9293 "Can only copy one custom normal, vertex normal or face normal");
9297 if (lnors_ed_arr->
totloop == 1) {
9300 else if (
bm->totfacesel == 1) {
9312 bool are_same_lnors =
true;
9313 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9315 are_same_lnors =
false;
9318 if (are_same_lnors) {
9332 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9334 float abs_normal[3];
9356 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9370 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9385 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9400 params.calc_looptris =
true;
9401 params.calc_normals =
false;
9402 params.is_destructive =
false;
9415 if (
STREQ(prop_id,
"absolute")) {
9443 ot->name =
"Normals Vector Tools";
9444 ot->description =
"Custom normals tools using Normal Vector of UI";
9445 ot->idname =
"MESH_OT_normals_tools";
9460 "Mode of tools taking input from interface");
9466 "Absolute Coordinates",
9467 "Copy Absolute coordinates of Normal vector");
9483 for (
Object *obedit : objects) {
9486 if (
bm->totfacesel == 0) {
9494 BMIter fiter, viter, eiter, liter;
9500 float(*vert_normals)[3] =
static_cast<float(*)[3]
>(
9501 MEM_mallocN(
sizeof(*vert_normals) *
bm->totvert, __func__));
9526 bm->lnor_spacearr->lspacearr[l_index], vert_normals[v_index], clnors);
9532 LinkNode *loops =
bm->lnor_spacearr->lspacearr[l_index]->loops;
9533 for (; loops; loops = loops->
next) {
9550 bm->lnor_spacearr->lspacearr[loop_index], vert_normals[v_index], clnors);
9558 params.calc_looptris =
true;
9559 params.calc_normals =
false;
9560 params.is_destructive =
false;
9570 ot->name =
"Set Normals from Faces";
9571 ot->description =
"Set the custom normals from the selected faces ones";
9572 ot->idname =
"MESH_OT_set_normals_from_faces";
9582 ot->srna,
"keep_sharp",
false,
"Keep Sharp Edges",
"Do not set sharp edges to face");
9598 for (
Object *obedit : objects) {
9608 float(*smooth_normal)[3] =
static_cast<float(*)[3]
>(
9619 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9621 float loop_normal[3];
9627 short *clnors =
static_cast<short *
>(
9630 bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
9639 for (
int i = 0;
i < lnors_ed_arr->
totloop;
i++, lnor_ed++) {
9640 float current_normal[3];
9652 mul_v3_fl(current_normal, 1.0f - factor);
9669 params.calc_looptris =
true;
9670 params.calc_normals =
false;
9671 params.is_destructive =
false;
9681 ot->name =
"Smooth Normals Vectors";
9682 ot->description =
"Smooth custom normals based on adjacent vertex normals";
9683 ot->idname =
"MESH_OT_smooth_normals";
9698 "Specifies weight of smooth vs original normal",
9716 for (
Object *obedit : objects) {
9728 if (cd_prop_int_index == -1) {
9742 *strength = face_strength;
9749 if (*strength == face_strength) {
9760 params.calc_looptris =
false;
9761 params.calc_normals =
false;
9762 params.is_destructive =
false;
9773 {0,
nullptr, 0,
nullptr,
nullptr},
9779 ot->name =
"Face Normals Strength";
9780 ot->description =
"Set/Get strength of face (used in Weighted Normal modifier)";
9781 ot->idname =
"MESH_OT_mod_weighted_strength";
9798 "Strength to use for assigning or selecting face influence for weighted normal modifier");
9804 ot->name =
"Flip Quad Tessellation";
9805 ot->description =
"Flips the tessellation of selected quads";
9806 ot->idname =
"MESH_OT_flip_quad_tessellation";
Generic geometry attributes built on CustomData.
int BKE_attribute_to_index(const AttributeOwner &owner, const CustomDataLayer *layer, AttrDomainMask domain_mask, eCustomDataMask layer_mask)
@ ATTR_DOMAIN_MASK_CORNER
const struct CustomDataLayer * BKE_attribute_search(const AttributeOwner &owner, blender::StringRef name, eCustomDataMask type, AttrDomainMask domain_mask)
#define CTX_DATA_BEGIN(C, Type, instance, member)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
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)
void * CustomData_bmesh_get_n(const CustomData *data, void *block, eCustomDataType type, int n)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_bmesh_get(const CustomData *data, void *block, eCustomDataType type)
int CustomData_get_layer_index(const CustomData *data, eCustomDataType type)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
void BKE_editmesh_lnorspace_update(BMEditMesh *em)
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
blender::Vector< Base * > BKE_view_layer_array_from_bases_in_edit_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
General operations, lookup, etc. for materials.
void BKE_objects_materials_sync_length_all(Main *bmain, ID *id)
short * BKE_object_material_len_p(Object *ob)
void BKE_id_material_clear(Main *bmain, ID *id)
short * BKE_id_material_len_p(ID *id)
Material *** BKE_id_material_array_p(ID *id)
void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user)
void BKE_object_material_array_assign(Main *bmain, Object *ob, Material ***matar, int totcol, bool to_object_only)
Material *** BKE_object_material_array_p(Object *ob)
void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
@ MLNOR_SPACEARR_BMLOOP_PTR
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_original_mesh(const Object *object)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_BITMAP_NEW(_num, _alloc_string)
#define BLI_BITMAP_TEST(_bitmap, _index)
#define BLI_BITMAP_ENABLE(_bitmap, _index)
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
BLI_LINKSTACK_*** wrapper macros for using a LinkNode to store a stack of pointers,...
#define BLI_SMALLSTACK_DECLARE(var, type)
#define BLI_SMALLSTACK_POP(var)
#define BLI_SMALLSTACK_PUSH(var, data)
#define BLI_SMALLSTACK_IS_EMPTY(var)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_listbase_rotate_first(ListBase *lb, void *vlink) ATTR_NONNULL(1
int BLI_listbase_count_at_most(const ListBase *listbase, int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findptr(const struct ListBase *listbase, const void *ptr, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int min_ii(int a, int b)
MINLINE int mod_i(int i, int n)
MINLINE int compare_ff(float a, float b, float max_diff)
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[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])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void negate_v3(float r[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
struct RNG * BLI_rng_new_srandom(unsigned int seed)
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_sortutil_cmp_float_reverse(const void *a_, const void *b_)
#define UNUSED_VARS_NDEBUG(...)
#define BLT_I18NCONTEXT_ID_CURVE_LEGACY
#define BLT_I18NCONTEXT_ID_MESH
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_GEOMETRY_ALL_MODES
@ MOD_TRIANGULATE_QUAD_BEAUTY
@ MOD_TRIANGULATE_NGON_BEAUTY
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID
Object is a sort of wrapper for general info.
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CENTER_MEDIAN
@ OP_IS_MODAL_GRAB_CURSOR
void EDBM_flag_disable_all(BMEditMesh *em, char hflag)
void EDBM_automerge(Object *obedit, bool update, char hflag, float dist)
void void EDBM_redo_state_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptris) ATTR_NONNULL(1
void EDBM_update(Mesh *mesh, const EDBMUpdate_Params *params)
BMVert * EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
void EDBM_verts_mirror_cache_begin(BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
void void void EDBM_redo_state_free(BMBackup *backup) ATTR_NONNULL(1)
void EDBM_mesh_normals_update(BMEditMesh *em)
bool EDBM_mesh_reveal(BMEditMesh *em, bool select)
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
void EDBM_mesh_stats_multi(blender::Span< Object * > objects, int totelem[3], int totelem_sel[3])
void ED_mesh_geometry_clear(Mesh *mesh)
void EDBM_verts_mirror_apply(BMEditMesh *em, int sel_from, int sel_to)
void EDBM_selectmode_flush(BMEditMesh *em)
BMBackup EDBM_redo_state_store(BMEditMesh *em)
void EDBM_selectmode_flush_ex(BMEditMesh *em, short selectmode)
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology, float maxdist, int *r_index)
void EDBM_verts_mirror_cache_end(BMEditMesh *em)
bool EDBM_selectmode_disable_multi_ex(Scene *scene, blender::Span< Base * > bases, short selectmode_disable, short selectmode_fallback)
void EDBM_select_flush(BMEditMesh *em)
bool EDBM_select_pick(bContext *C, const int mval[2], const SelectPick_Params ¶ms)
void ED_outliner_select_sync_from_object_tag(bContext *C)
bool ED_operator_scene_editable(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
bool ED_operator_editmesh(bContext *C)
void ED_uvedit_live_unwrap(const Scene *scene, blender::Span< Object * > objects)
RegionView3D * ED_view3d_context_rv3d(bContext *C)
void ED_view3d_win_to_3d_int(const View3D *v3d, const ARegion *region, const float depth_pt[3], const int mval[2], float r_out[3])
void ED_view3d_cursor3d_update(bContext *C, const int mval[2], bool use_depth, enum eV3DCursorOrient orientation)
void view3d_operator_needs_gpu(const bContext *C)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Read Guarded memory(de)allocation.
@ UI_BUT_LABEL_ALIGN_NONE
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr, bool(*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data, PropertyRNA *prop_activate_init, eButLabelAlign label_align, bool compact)
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, PointerRNA *searchptr, blender::StringRefNull searchpropname, std::optional< blender::StringRefNull > name, int icon)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
#define BM_elem_cb_check_hflag_disabled_simple(type, hflag_n)
#define BM_DISK_EDGE_NEXT(e, v)
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, BMesh *bm_src, const char htype, const BMAllocTemplate *allocsize)
void BM_vert_separate(BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select, BMVert ***r_vout, int *r_vout_len)
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill(BMesh *bm, BMFace *f)
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
void BM_mesh_decimate_collapse(BMesh *bm, float factor, float *vweights, float vweight_factor, bool do_triangulate, int symmetry_axis, float symmetry_eps)
BM_mesh_decimate.
void BM_mesh_delete_hflag_context(BMesh *bm, const char hflag, const int type)
void BM_mesh_edgeloops_free(ListBase *eloops)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
void BM_edgeloop_edges_get(BMEdgeLoopStore *el_store, BMEdge **e_arr)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_test_bool(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const StringRef name)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
Elem Iter Flag Count.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
BMesh const char void * data
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_select_history_clear(BMesh *bm)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test)
#define BM_select_history_store_notest(bm, ele)
#define BM_select_history_store_head_notest(bm, ele)
#define BM_select_history_store(bm, ele)
#define BM_SELECT_HISTORY_BACKUP(bm)
#define BM_SELECT_HISTORY_RESTORE(bm)
const BMAllocTemplate bm_mesh_allocsize_default
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
void BM_mesh_copy_arrays(BMesh *bm_src, BMesh *bm_dst, BMVert **verts_src, uint verts_src_len, BMEdge **edges_src, uint edges_src_len, BMFace **faces_src, uint faces_src_len)
void BM_lnorspace_update(BMesh *bm)
void BM_normals_loops_edges_tag(BMesh *bm, const bool do_edges)
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
void BM_mesh_normals_update(BMesh *bm)
BMLoopNorEditDataArray * BM_loop_normal_editdata_array_init(BMesh *bm, const bool do_all_loops_of_vert)
void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
bool BM_loop_check_cyclic_smooth_fan(BMLoop *l_curr)
void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int len)
@ BMO_SYMMETRIZE_NEGATIVE_X
@ DEL_FACES_KEEP_BOUNDARY
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.
void * BMO_iter_map_value_ptr(BMOIter *iter)
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag)
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_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int i)
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val)
void BM_mesh_esubdivide(BMesh *bm, char edge_hflag, float smooth, short smooth_falloff, bool use_smooth_even, float fractal, float along_normal, int numcuts, int seltype, int cornertype, short use_single_edge, short use_grid_fill, short use_only_quads, int seed)
@ SUBD_RING_INTERP_LINEAR
@ BMOP_POKE_MEDIAN_WEIGHTED
@ SUBD_CORNER_STRAIGHT_CUT
void BM_vert_normal_update(BMVert *v)
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
int BM_mesh_calc_edge_groups_as_arrays(BMesh *bm, BMVert **verts, BMEdge **edges, BMFace **faces, int(**r_groups)[3])
bool BM_vert_is_wire(const BMVert *v)
BMFace * BM_edge_pair_share_face_by_len(BMEdge *e_a, BMEdge *e_b, BMLoop **r_l_a, BMLoop **r_l_b, const bool allow_adjacent)
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
float BM_loop_calc_face_angle(const BMLoop *l)
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
bool BM_vert_pair_share_face_check_cb(BMVert *v_a, BMVert *v_b, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) 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 BMVert * v
btMatrix3x3 absolute() const
Return the matrix with all values non negative.
static unsigned long seed
static AttributeOwner from_id(ID *id)
void opmodal(std::string text, const wmOperatorType *ot, int propvalue, bool inverted=false)
IndexRange index_range() const
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt,...)
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt,...)
bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, const char *select_slot_out, const bool select_extend, const char *fmt,...)
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
#define CD_MASK_COLOR_ALL
BLI_INLINE float fb(float length, float L)
void * MEM_mallocN(size_t len, const char *str)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
void MESH_OT_convex_hull(wmOperatorType *ot)
static void clear(Message &msg)
bool shape_key_report_if_locked(const Object *obedit, ReportList *reports)
bool shape_key_report_if_any_locked(Object *ob, ReportList *reports)
void base_select(Base *base, eObjectSelect_Mode mode)
Base * add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, eDupli_ID_Flags dupflag)
bool calc_active_center_for_editmode(Object *obedit, bool select_only, float r_center[3])
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
const char * RNA_property_identifier(const PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_float_default(PropertyRNA *prop, float value)
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
PropertyRNA * RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_int_default(PropertyRNA *prop, int value)
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
PropertyRNA * RNA_def_enum_flag(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]
const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]
const EnumPropertyItem rna_enum_axis_xyz_items[]
const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]
const EnumPropertyItem rna_enum_dummy_NULL_items[]
const EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[]
const EnumPropertyItem rna_enum_symmetrize_direction_items[]
struct BMEditSelection * next
BMLoopNorEditData ** lidx_to_lnor_editdata
BMLoopNorEditData * lnor_editdata
int cd_custom_normal_offset
struct BMLoop * radial_next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
bool update_shapekey_indices
struct MLoopNorSpaceArray * lnor_spacearr
float profile_shape_factor
MeshRuntimeHandle * runtime
char * active_color_attribute
ObjectRuntimeHandle * runtime
struct ToolSettings * toolsettings
uiLayout & column(bool align)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct ReportList * reports
struct wmOperatorType * type
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
void WM_cursor_wait(bool val)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
#define ISMOUSE_MOTION(event_type)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)