Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2020-09-01 20:35:14 +0300
committerHans Goudey <h.goudey@me.com>2020-09-01 20:38:05 +0300
commitbaca8611e5fe4b3dcd6f5065fb125bc0a9d65934 (patch)
treebb1230387cd53b15f9621f10c4d0e5e2050b5580 /source/blender/editors/mesh
parent31705201dddebf7e3be5c4533b89f380aad1ede1 (diff)
parent2930d4fcea405985f2212c5f28c061af7c4849f8 (diff)
Merge branch 'master' into active-fcurve-keyframeactive-fcurve-keyframe
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt4
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c177
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c18
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c16
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_edgering.c4
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c4
-rw-r--r--source/blender/editors/mesh/editmesh_select.c36
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c6
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c73
-rw-r--r--source/blender/editors/mesh/mesh_data.c4
-rw-r--r--source/blender/editors/mesh/meshtools.c6
11 files changed, 237 insertions, 111 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index e41445aef09..589b51ce942 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -93,6 +93,10 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+if(WITH_GMP)
+ add_definitions(-DWITH_GMP)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 97bd6ee0039..1b5e374b2a7 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -39,6 +39,9 @@
#include "WM_types.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -46,6 +49,7 @@
#include "mesh_intern.h" /* own include */
+#include "tools/bmesh_boolean.h"
#include "tools/bmesh_intersect.h"
#include "tools/bmesh_separate.h"
@@ -134,6 +138,11 @@ enum {
ISECT_SEPARATE_NONE = 2,
};
+enum {
+ ISECT_SOLVER_FAST = 0,
+ ISECT_SOLVER_EXACT = 1,
+};
+
static int edbm_intersect_exec(bContext *C, wmOperator *op)
{
const int mode = RNA_enum_get(op->ptr, "mode");
@@ -142,6 +151,14 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
bool use_separate_cut = false;
const int separate_mode = RNA_enum_get(op->ptr, "separate_mode");
const float eps = RNA_float_get(op->ptr, "threshold");
+#ifdef WITH_GMP
+ const bool exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
+#else
+ if (RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT) {
+ BKE_report(op->reports, RPT_WARNING, "Compiled without GMP, using fast solver");
+ }
+ const bool exact = false;
+#endif
bool use_self;
bool has_isect;
@@ -186,19 +203,25 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
continue;
}
- has_isect = BM_mesh_intersect(em->bm,
- em->looptris,
- em->tottri,
- test_fn,
- NULL,
- use_self,
- use_separate_all,
- true,
- true,
- true,
- true,
- -1,
- eps);
+ if (exact) {
+ has_isect = BM_mesh_boolean_knife(
+ em->bm, em->looptris, em->tottri, test_fn, NULL, use_self, use_separate_all);
+ }
+ else {
+ has_isect = BM_mesh_intersect(em->bm,
+ em->looptris,
+ em->tottri,
+ test_fn,
+ NULL,
+ use_self,
+ use_separate_all,
+ true,
+ true,
+ true,
+ true,
+ -1,
+ eps);
+ }
if (use_separate_cut) {
/* detach selected/un-selected faces */
@@ -220,6 +243,34 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void edbm_intersect_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *row;
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemS(layout);
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &ptr, "separate_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemS(layout);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemS(layout);
+
+ if (!use_exact) {
+ uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ }
+}
+
void MESH_OT_intersect(struct wmOperatorType *ot)
{
static const EnumPropertyItem isect_mode_items[] = {
@@ -243,6 +294,12 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem isect_intersect_solver_items[] = {
+ {ISECT_SOLVER_FAST, "FAST", 0, "Fast", "Faster Solver, some limitations"},
+ {ISECT_SOLVER_EXACT, "EXACT", 0, "Exact", "Exact Solver, slower, handles more cases"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Intersect (Knife)";
ot->description = "Cut an intersection into faces";
@@ -251,6 +308,7 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = edbm_intersect_exec;
ot->poll = ED_operator_editmesh;
+ ot->ui = edbm_intersect_ui;
/* props */
RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", "");
@@ -258,6 +316,12 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
ot->srna, "separate_mode", isect_separate_items, ISECT_SEPARATE_CUT, "Separate Mode", "");
RNA_def_float_distance(
ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
+ RNA_def_enum(ot->srna,
+ "solver",
+ isect_intersect_solver_items,
+ ISECT_SOLVER_EXACT,
+ "Solver",
+ "Which Intersect solver to use");
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -280,6 +344,15 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
{
const int boolean_operation = RNA_enum_get(op->ptr, "operation");
bool use_swap = RNA_boolean_get(op->ptr, "use_swap");
+ bool use_self = RNA_boolean_get(op->ptr, "use_self");
+#ifdef WITH_GMP
+ const bool use_exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
+#else
+ if (RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT) {
+ BKE_report(op->reports, RPT_WARNING, "Compiled without GMP, using fast solver");
+ }
+ const bool use_exact = false;
+#endif
const float eps = RNA_float_get(op->ptr, "threshold");
int (*test_fn)(BMFace *, void *);
bool has_isect;
@@ -298,19 +371,25 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
continue;
}
- has_isect = BM_mesh_intersect(em->bm,
- em->looptris,
- em->tottri,
- test_fn,
- NULL,
- false,
- false,
- true,
- true,
- false,
- true,
- boolean_operation,
- eps);
+ if (use_exact) {
+ has_isect = BM_mesh_boolean(
+ em->bm, em->looptris, em->tottri, test_fn, NULL, use_self, boolean_operation);
+ }
+ else {
+ has_isect = BM_mesh_intersect(em->bm,
+ em->looptris,
+ em->tottri,
+ test_fn,
+ NULL,
+ false,
+ false,
+ true,
+ true,
+ false,
+ true,
+ boolean_operation,
+ eps);
+ }
edbm_intersect_select(em, obedit->data, has_isect);
@@ -326,6 +405,34 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void edbm_intersect_boolean_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *row;
+ PointerRNA ptr;
+
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+
+ bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemS(layout);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemS(layout);
+
+ uiItemR(layout, &ptr, "use_swap", 0, NULL, ICON_NONE);
+ uiItemR(layout, &ptr, "use_self", 0, NULL, ICON_NONE);
+ if (!use_exact) {
+ uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ }
+}
+
void MESH_OT_intersect_boolean(struct wmOperatorType *ot)
{
static const EnumPropertyItem isect_boolean_operation_items[] = {
@@ -335,6 +442,12 @@ void MESH_OT_intersect_boolean(struct wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem isect_boolean_solver_items[] = {
+ {ISECT_SOLVER_FAST, "FAST", 0, "Fast", "Faster Solver, some limitations"},
+ {ISECT_SOLVER_EXACT, "EXACT", 0, "Exact", "Exact Solver, slower, handles more cases"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
/* identifiers */
ot->name = "Intersect (Boolean)";
ot->description = "Cut solid geometry from selected to unselected";
@@ -343,21 +456,29 @@ void MESH_OT_intersect_boolean(struct wmOperatorType *ot)
/* api callbacks */
ot->exec = edbm_intersect_boolean_exec;
ot->poll = ED_operator_editmesh;
+ ot->ui = edbm_intersect_boolean_ui;
/* props */
RNA_def_enum(ot->srna,
"operation",
isect_boolean_operation_items,
BMESH_ISECT_BOOLEAN_DIFFERENCE,
- "Boolean",
- "");
+ "Boolean operation",
+ "Which boolean operation to apply");
RNA_def_boolean(ot->srna,
"use_swap",
false,
"Swap",
"Use with difference intersection to swap which side is kept");
+ RNA_def_boolean(ot->srna, "use_self", false, "Self", "Do self-union or self-intersection");
RNA_def_float_distance(
ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
+ RNA_def_enum(ot->srna,
+ "solver",
+ isect_boolean_solver_items,
+ ISECT_SOLVER_EXACT,
+ "Solver",
+ "Which Boolean solver to use");
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 6f4f75e802a..6facee77c1e 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1051,7 +1051,7 @@ static void knife_init_colors(KnifeColors *colors)
static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
{
const KnifeTool_OpData *kcd = arg;
- GPU_depth_test(false);
+ GPU_depth_test(GPU_DEPTH_NONE);
GPU_matrix_push_projection();
GPU_polygon_offset(1.0f, 1.0f);
@@ -1128,9 +1128,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
int i, snapped_verts_count, other_verts_count;
float fcol[4];
- GPU_blend(true);
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+ GPU_blend(GPU_BLEND_ALPHA);
GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(vert, kcd->totlinehit);
@@ -1147,16 +1145,13 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO);
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
- GPU_batch_bind(batch);
/* draw any snapped verts first */
rgba_uchar_to_float(fcol, kcd->colors.point_a);
GPU_batch_uniform_4fv(batch, "color", fcol);
- GPU_matrix_bind(batch->interface);
- GPU_shader_set_srgb_uniform(batch->interface);
GPU_point_size(11);
if (snapped_verts_count > 0) {
- GPU_batch_draw_advanced(batch, 0, snapped_verts_count, 0, 0);
+ GPU_batch_draw_range(batch, 0, snapped_verts_count);
}
/* now draw the rest */
@@ -1164,13 +1159,12 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
GPU_batch_uniform_4fv(batch, "color", fcol);
GPU_point_size(7);
if (other_verts_count > 0) {
- GPU_batch_draw_advanced(batch, snapped_verts_count, other_verts_count, 0, 0);
+ GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count);
}
- GPU_batch_program_use_end(batch);
GPU_batch_discard(batch);
- GPU_blend(false);
+ GPU_blend(GPU_BLEND_NONE);
}
if (kcd->totkedge > 0) {
@@ -1228,7 +1222,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
GPU_matrix_pop_projection();
/* Reset default */
- GPU_depth_test(true);
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
/**
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8eeba5007e1..34fcee779de 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -354,10 +354,6 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_begin(ob, "mask slice");
- /* TODO: The ideal functionality would be to preserve the current face sets and add a new one
- * for the new triangles, but this data-layer needs to be rebuild in order to make sculpt mode
- * not crash when modifying the geometry. */
- CustomData_free_layers(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly);
}
BMesh *bm;
@@ -429,14 +425,14 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
BKE_mesh_calc_normals(ob->data);
if (ob->mode == OB_MODE_SCULPT) {
- ED_sculpt_undo_geometry_end(ob);
SculptSession *ss = ob->sculpt;
- /* Rebuild a new valid Face Set layer for the object. */
- ss->face_sets = CustomData_add_layer(
- &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly);
- for (int i = 0; i < mesh->totpoly; i++) {
- ss->face_sets[i] = 1;
+ ss->face_sets = CustomData_get_layer(&((Mesh *)ob->data)->pdata, CD_SCULPT_FACE_SETS);
+ if (ss->face_sets) {
+ /* Assign a new Face Set ID to the new faces created by the slice operation. */
+ const int next_face_set_id = ED_sculpt_face_sets_find_next_available_id(ob->data);
+ ED_sculpt_face_sets_initialize_none_to_id(ob->data, next_face_set_id);
}
+ ED_sculpt_undo_geometry_end(ob);
}
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
diff --git a/source/blender/editors/mesh/editmesh_preselect_edgering.c b/source/blender/editors/mesh/editmesh_preselect_edgering.c
index d9bd63ef35f..aa1df3d76fc 100644
--- a/source/blender/editors/mesh/editmesh_preselect_edgering.c
+++ b/source/blender/editors/mesh/editmesh_preselect_edgering.c
@@ -159,7 +159,7 @@ void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const fl
return;
}
- GPU_depth_test(false);
+ GPU_depth_test(GPU_DEPTH_NONE);
GPU_matrix_push();
GPU_matrix_mul(matrix);
@@ -197,7 +197,7 @@ void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const fl
GPU_matrix_pop();
/* Reset default */
- GPU_depth_test(true);
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
static void view3d_preselect_mesh_edgering_update_verts_from_edge(
diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c
index d53a1e2b55c..dfd646c767f 100644
--- a/source/blender/editors/mesh/editmesh_preselect_elem.c
+++ b/source/blender/editors/mesh/editmesh_preselect_elem.c
@@ -133,7 +133,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
return;
}
- GPU_depth_test(false);
+ GPU_depth_test(GPU_DEPTH_NONE);
GPU_matrix_push();
GPU_matrix_mul(matrix);
@@ -204,7 +204,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr
GPU_matrix_pop();
/* Reset default */
- GPU_depth_test(true);
+ GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
}
static void view3d_preselect_mesh_elem_update_from_vert(struct EditMesh_PreSelElem *psel,
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index d2e9b57e950..52c109b3854 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -110,7 +110,7 @@ void EDBM_select_mirrored(BMEditMesh *em,
}
}
- EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology);
+ EDBM_verts_mirror_cache_begin(em, axis, true, true, false, use_topology);
if (!extend) {
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -1423,15 +1423,13 @@ void MESH_OT_select_mode(wmOperatorType *ot)
static void walker_select_count(BMEditMesh *em,
int walkercode,
void *start,
- const bool select,
- const bool select_mix,
- int *r_totsel,
- int *r_totunsel)
+ int r_count_by_select[2])
{
BMesh *bm = em->bm;
BMElem *ele;
BMWalker walker;
- int tot[2] = {0, 0};
+
+ r_count_by_select[0] = r_count_by_select[1] = 0;
BMW_init(&walker,
bm,
@@ -1443,17 +1441,15 @@ static void walker_select_count(BMEditMesh *em,
BMW_NIL_LAY);
for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
- tot[(BM_elem_flag_test_bool(ele, BM_ELEM_SELECT) != select)] += 1;
+ r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 1;
- if (!select_mix && tot[0] && tot[1]) {
- tot[0] = tot[1] = -1;
+ /* Early exit when mixed (could be optional if needed. */
+ if (r_count_by_select[0] && r_count_by_select[1]) {
+ r_count_by_select[0] = r_count_by_select[1] = -1;
break;
}
}
- *r_totsel = tot[0];
- *r_totunsel = tot[1];
-
BMW_end(&walker);
}
@@ -1590,18 +1586,18 @@ static void mouse_mesh_loop_edge(
{
bool edge_boundary = false;
- /* cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY */
+ /* Cycle between BMW_EDGELOOP / BMW_EDGEBOUNDARY. */
if (select_cycle && BM_edge_is_boundary(eed)) {
- int tot[2];
+ int count_by_select[2];
- /* if the loops selected toggle the boundaries */
- walker_select_count(em, BMW_EDGELOOP, eed, select, false, &tot[0], &tot[1]);
- if (tot[select] == 0) {
+ /* If the loops selected toggle the boundaries. */
+ walker_select_count(em, BMW_EDGELOOP, eed, count_by_select);
+ if (count_by_select[!select] == 0) {
edge_boundary = true;
- /* if the boundaries selected, toggle back to the loop */
- walker_select_count(em, BMW_EDGEBOUNDARY, eed, select, false, &tot[0], &tot[1]);
- if (tot[select] == 0) {
+ /* If the boundaries selected, toggle back to the loop. */
+ walker_select_count(em, BMW_EDGEBOUNDARY, eed, count_by_select);
+ if (count_by_select[!select] == 0) {
edge_boundary = false;
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 1e4144db47e..4e1a56b3b55 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -2513,7 +2513,7 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
/* mirror before smooth */
if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
+ EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
}
/* if there is a mirror modifier with clipping, flag the verts that
@@ -2658,7 +2658,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
/* Mirror before smooth. */
if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- EDBM_verts_mirror_cache_begin(em, 0, false, true, use_topology);
+ EDBM_verts_mirror_cache_begin(em, 0, false, true, false, use_topology);
}
bool failed_repeat_loop = false;
@@ -7600,7 +7600,7 @@ static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
BMVert *v;
int i;
- EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, use_topology, thresh, index);
+ EDBM_verts_mirror_cache_begin_ex(em, axis, true, true, false, use_topology, thresh, index);
BM_mesh_elem_table_ensure(bm, BM_VERT);
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 46c63d2e057..a90c8dea87b 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -523,7 +523,7 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
* \{ */
/**
- * Return a new UVVertMap from the editmesh
+ * Return a new #UvVertMap from the edit-mesh.
*/
UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
{
@@ -1059,6 +1059,7 @@ static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int ind
* \param em: Editmesh.
* \param use_self: Allow a vertex to point to its self (middle verts).
* \param use_select: Restrict to selected verts.
+ * \param respecthide: Skip hidden vertices.
* \param use_topology: Use topology mirror.
* \param maxdist: Distance for close point test.
* \param r_index: Optional array to write into, as an alternative to a customdata layer
@@ -1068,6 +1069,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
const int axis,
const bool use_self,
const bool use_select,
+ const bool respecthide,
/* extra args */
const bool use_topology,
float maxdist,
@@ -1110,6 +1112,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
else {
tree = BLI_kdtree_3d_new(bm->totvert);
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
BLI_kdtree_3d_insert(tree, i, v->co);
}
BLI_kdtree_3d_balance(tree);
@@ -1118,44 +1124,45 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em,
#define VERT_INTPTR(_v, _i) (r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset))
BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- BLI_assert(BM_elem_index_get(v) == i);
+ if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ continue;
+ }
- /* temporary for testing, check for selection */
if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- /* do nothing */
+ continue;
}
- else {
- BMVert *v_mirr;
- int *idx = VERT_INTPTR(v, i);
- if (use_topology) {
- v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
- }
- else {
- int i_mirr;
- float co[3];
- copy_v3_v3(co, v->co);
- co[axis] *= -1.0f;
-
- v_mirr = NULL;
- i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL);
- if (i_mirr != -1) {
- BMVert *v_test = BM_vert_at_index(bm, i_mirr);
- if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
- v_mirr = v_test;
- }
+ BLI_assert(BM_elem_index_get(v) == i);
+ BMVert *v_mirr;
+ int *idx = VERT_INTPTR(v, i);
+
+ if (use_topology) {
+ v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i);
+ }
+ else {
+ int i_mirr;
+ float co[3];
+ copy_v3_v3(co, v->co);
+ co[axis] *= -1.0f;
+
+ v_mirr = NULL;
+ i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL);
+ if (i_mirr != -1) {
+ BMVert *v_test = BM_vert_at_index(bm, i_mirr);
+ if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
+ v_mirr = v_test;
}
}
+ }
- if (v_mirr && (use_self || (v_mirr != v))) {
- const int i_mirr = BM_elem_index_get(v_mirr);
- *idx = i_mirr;
- idx = VERT_INTPTR(v_mirr, i_mirr);
- *idx = i;
- }
- else {
- *idx = -1;
- }
+ if (v_mirr && (use_self || (v_mirr != v))) {
+ const int i_mirr = BM_elem_index_get(v_mirr);
+ *idx = i_mirr;
+ idx = VERT_INTPTR(v_mirr, i_mirr);
+ *idx = i;
+ }
+ else {
+ *idx = -1;
}
}
@@ -1173,12 +1180,14 @@ void EDBM_verts_mirror_cache_begin(BMEditMesh *em,
const int axis,
const bool use_self,
const bool use_select,
+ const bool respecthide,
const bool use_topology)
{
EDBM_verts_mirror_cache_begin_ex(em,
axis,
use_self,
use_select,
+ respecthide,
/* extra args */
use_topology,
BM_SEARCH_MAXDIST_MIRR,
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index f608e5ce6a5..22ea222cf01 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -1014,6 +1014,10 @@ static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperato
Mesh *me = ED_mesh_context(C);
if (BKE_mesh_has_custom_loop_normals(me)) {
+ BMEditMesh *em = me->edit_mesh;
+ if (em != NULL && em->bm->lnor_spacearr != NULL) {
+ BKE_lnor_spacearr_clear(em->bm->lnor_spacearr);
+ }
return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL);
}
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 5278da67777..bd14919d1d7 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -590,8 +590,9 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
loopofs = 0;
polyofs = 0;
- /* inverse transform for all selected meshes in this object */
- invert_m4_m4(imat, ob->obmat);
+ /* Inverse transform for all selected meshes in this object,
+ * See #object_join_exec for detailed comment on why the safe version is used. */
+ invert_m4_m4_safe_ortho(imat, ob->obmat);
/* Add back active mesh first.
* This allows to keep things similar as they were, as much as possible
@@ -741,6 +742,7 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
return OPERATOR_FINISHED;
}