diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-03-16 17:36:36 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-03-16 17:43:19 +0300 |
commit | 43d0943141cb745d69d36eb1cf177c22663def61 (patch) | |
tree | 9e1caaf5b466e8c7c5f3f4ba52bbb74d541cf068 /source | |
parent | 2816694b0502652ec484b50b4f4773a8a4ce6ff8 (diff) | |
parent | 5de9c8f6f0f5157251b8f9f103455ba7f3bf826a (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/editors/mesh/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/mesh/editface.c | 260 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_add.c | 7 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude.c | 119 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_path.c | 31 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_utils.c | 371 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_mirror.c | 377 | ||||
-rw-r--r-- | source/blender/editors/mesh/meshtools.c | 80 |
8 files changed, 719 insertions, 527 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 80e1187609c..3877838ec54 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -60,6 +60,7 @@ set(SRC editmesh_undo.c editmesh_utils.c mesh_data.c + mesh_mirror.c mesh_ops.c meshtools.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 113173c1c03..1b9ee70ccf5 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -24,7 +24,6 @@ * \ingroup edmesh */ - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -41,7 +40,6 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_context.h" -#include "BKE_editmesh.h" #include "BIF_gl.h" @@ -609,261 +607,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags) paintvert_flush_flags(ob); } } - -/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ -/* note, this is not the best place for the function to be but moved - * here for the purpose of syncing with bmesh */ - -typedef unsigned int MirrTopoHash_t; - -typedef struct MirrTopoVert_t { - MirrTopoHash_t hash; - int v_index; -} MirrTopoVert_t; - -static int mirrtopo_hash_sort(const void *l1, const void *l2) -{ - if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; - else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; - return 0; -} - -static int mirrtopo_vert_sort(const void *v1, const void *v2) -{ - if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; - else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; - return 0; -} - -bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store) -{ - const bool is_editmode = (me->edit_btmesh != NULL); - int totvert; - int totedge; - - if (dm) { - totvert = dm->getNumVerts(dm); - totedge = dm->getNumEdges(dm); - } - else if (me->edit_btmesh) { - totvert = me->edit_btmesh->bm->totvert; - totedge = me->edit_btmesh->bm->totedge; - } - else { - totvert = me->totvert; - totedge = me->totedge; - } - - if ((mesh_topo_store->index_lookup == NULL) || - (mesh_topo_store->prev_is_editmode != is_editmode) || - (totvert != mesh_topo_store->prev_vert_tot) || - (totedge != mesh_topo_store->prev_edge_tot)) - { - return true; - } - else { - return false; - } - -} - -void ED_mesh_mirrtopo_init( - Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init) -{ - const bool is_editmode = (me->edit_btmesh != NULL); - MEdge *medge = NULL, *med; - BMEditMesh *em = dm ? NULL : me->edit_btmesh; - - /* editmode*/ - BMEdge *eed; - BMIter iter; - - int a, last; - int totvert, totedge; - int tot_unique = -1, tot_unique_prev = -1; - int tot_unique_edges = 0, tot_unique_edges_prev; - - MirrTopoHash_t *topo_hash = NULL; - MirrTopoHash_t *topo_hash_prev = NULL; - MirrTopoVert_t *topo_pairs; - MirrTopoHash_t topo_pass = 1; - - intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ - - /* reallocate if needed */ - ED_mesh_mirrtopo_free(mesh_topo_store); - - mesh_topo_store->prev_is_editmode = is_editmode; - - if (em) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - totvert = em->bm->totvert; - } - else { - totvert = dm ? dm->getNumVerts(dm) : me->totvert; - } - - topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); - - /* Initialize the vert-edge-user counts used to detect unique topology */ - if (em) { - totedge = me->edit_btmesh->bm->totedge; - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1]++; - topo_hash[i2]++; - } - } - else { - totedge = dm ? dm->getNumEdges(dm) : me->totedge; - medge = dm ? dm->getEdgeArray(dm) : me->medge; - - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1]++; - topo_hash[i2]++; - } - } - - topo_hash_prev = MEM_dupallocN(topo_hash); - - tot_unique_prev = -1; - tot_unique_edges_prev = -1; - while (1) { - /* use the number of edges per vert to give verts unique topology IDs */ - - tot_unique_edges = 0; - - /* This can make really big numbers, wrapping around here is fine */ - if (em) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - else { - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - /* sort so we can count unique values */ - qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); - - tot_unique = 1; /* account for skiping the first value */ - for (a = 1; a < totvert; a++) { - if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { - tot_unique++; - } - } - - if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { - /* Finish searching for unique values when 1 loop dosnt give a - * higher number of unique values compared to the previous loop */ - break; - } - else { - tot_unique_prev = tot_unique; - tot_unique_edges_prev = tot_unique_edges; - } - /* Copy the hash calculated this iter, so we can use them next time */ - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - topo_pass++; - } - - /* Hash/Index pairs are needed for sorting to find index pairs */ - topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); - - /* since we are looping through verts, initialize these values here too */ - index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); - - if (em) { - if (skip_em_vert_array_init == false) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - } - - for (a = 0; a < totvert; a++) { - topo_pairs[a].hash = topo_hash[a]; - topo_pairs[a].v_index = a; - - /* initialize lookup */ - index_lookup[a] = -1; - } - - qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - - last = 0; - - /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, - * but you cant ever access the last 'a' index of MirrTopoPairs */ - if (em) { - BMVert **vtable = em->bm->vtable; - for (a = 1; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = (intptr_t)vtable[k]; - index_lookup[k] = (intptr_t)vtable[j]; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = (intptr_t)vtable[j]; - } - last = a; - } - } - } - else { - /* same as above, for mesh */ - for (a = 1; a <= totvert; a++) { - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = k; - index_lookup[k] = j; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = j; - } - last = a; - } - } - } - - MEM_freeN(topo_pairs); - topo_pairs = NULL; - - MEM_freeN(topo_hash); - MEM_freeN(topo_hash_prev); - - mesh_topo_store->index_lookup = index_lookup; - mesh_topo_store->prev_vert_tot = totvert; - mesh_topo_store->prev_edge_tot = totedge; -} - -void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) -{ - if (mesh_topo_store->index_lookup) { - MEM_freeN(mesh_topo_store->index_lookup); - } - mesh_topo_store->index_lookup = NULL; - mesh_topo_store->prev_vert_tot = -1; - mesh_topo_store->prev_edge_tot = -1; -} diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index a21fc2fffde..292b28c772c 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -65,9 +65,10 @@ typedef struct MakePrimitiveData { bool was_editmode; } MakePrimitiveData; -static Object *make_prim_init(bContext *C, const char *idname, - const float loc[3], const float rot[3], const unsigned int layer, - MakePrimitiveData *r_creation_data) +static Object *make_prim_init( + bContext *C, const char *idname, + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 18320ec65f5..aee9785ea83 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -66,6 +66,10 @@ #include "ED_util.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Extrude Internal Utilities + * \{ */ + static void edbm_extrude_edge_exclude_mirror( Object *obedit, BMEditMesh *em, const char hflag, @@ -154,7 +158,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch EDBM_flag_disable_all(em, BM_ELEM_SELECT); BMO_op_exec(em->bm, &bmop); - + BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) { BM_face_select_set(em->bm, f, true); @@ -254,7 +258,7 @@ static bool edbm_extrude_ex( BMOIter siter; BMOperator extop; BMElem *ele; - + /* needed to remove the faces left behind */ if (htype & BM_FACE) { htype |= BM_EDGE; @@ -276,7 +280,7 @@ static bool edbm_extrude_ex( BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); - + BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { BM_elem_select_set(bm, ele, true); } @@ -286,14 +290,20 @@ static bool edbm_extrude_ex( return true; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Repeat Operator + * \{ */ + static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); RegionView3D *rv3d = CTX_wm_region_view3d(C); - + const int steps = RNA_int_get(op->ptr, "steps"); - + const float offs = RNA_float_get(op->ptr, "offset"); float dvec[3], tmat[3][3], bmat[3][3]; short a; @@ -314,7 +324,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT); } - + EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); @@ -328,19 +338,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) ot->name = "Extrude Repeat Mesh"; ot->description = "Extrude selected vertices, edges or faces repeatedly"; ot->idname = "MESH_OT_extrude_repeat"; - + /* api callbacks */ ot->exec = edbm_extrude_repeat_exec; ot->poll = ED_operator_editmesh_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Operator + * \{ */ + /* generic extern called extruder */ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { @@ -377,7 +393,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); break; } - + if (changed) { return true; } @@ -392,7 +408,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + edbm_extrude_mesh(obedit, em, op); /* This normally happens when pushing undo but modal operators @@ -401,7 +417,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -411,27 +427,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot) ot->name = "Extrude Region"; ot->idname = "MESH_OT_extrude_region"; ot->description = "Extrude region of faces"; - + /* api callbacks */ //ot->invoke = mesh_extrude_region_invoke; ot->exec = edbm_extrude_region_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Verts Operator + * \{ */ + static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -441,11 +463,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) ot->name = "Extrude Only Vertices"; ot->idname = "MESH_OT_extrude_verts_indiv"; ot->description = "Extrude individual vertices only"; - + /* api callbacks */ ot->exec = edbm_extrude_verts_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -453,15 +475,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Edges Operator + * \{ */ + static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -471,11 +499,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) ot->name = "Extrude Only Edges"; ot->idname = "MESH_OT_extrude_edges_indiv"; ot->description = "Extrude individual edges only"; - + /* api callbacks */ ot->exec = edbm_extrude_edges_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -483,15 +511,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Faces Operator + * \{ */ + static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -501,18 +535,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) ot->name = "Extrude Individual Faces"; ot->idname = "MESH_OT_extrude_faces_indiv"; ot->description = "Extrude individual faces only"; - + /* api callbacks */ ot->exec = edbm_extrude_faces_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } -/* *************** add-click-mesh (extrude) operator ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dupli-Extrude Operator + * + * Add-click-mesh (extrude) operator. + * \{ */ + static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; @@ -533,7 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w zero_v3(center); verts_len = 0; - + BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) { add_v3_v3(center, v1->co); @@ -596,7 +637,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } - + /* center */ copy_v3_v3(ofs, center); @@ -605,7 +646,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w mul_m4_v3(vc.obedit->imat, ofs); // back in object space sub_v3_v3(ofs, center); - + /* calculate rotation */ unit_m3(mat); if (done) { @@ -628,7 +669,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w axis_angle_to_mat3(mat, axis, angle); } } - + if (rot_src) { EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, center, mat); @@ -653,7 +694,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); // back in object space - + EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center); BMO_op_exec(vc.em->bm, &bmop); @@ -685,17 +726,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) ot->name = "Duplicate or Extrude to Cursor"; ot->idname = "MESH_OT_dupli_extrude_cursor"; ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor"; - + /* api callbacks */ ot->invoke = edbm_dupli_extrude_cursor_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Spin Operator + * \{ */ static int edbm_spin_exec(bContext *C, wmOperator *op) { @@ -815,8 +861,7 @@ void MESH_OT_spin(wmOperatorType *ot) #ifdef USE_MANIPULATOR /* -------------------------------------------------------------------- */ - -/** \name Spin Manipulator +/** \name Screw Operator * \{ */ typedef struct ManipulatorSpinGroup { @@ -1315,3 +1360,5 @@ void MESH_OT_screw(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 795c7b6aa53..2ae48bee095 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -63,6 +63,10 @@ #include "mesh_intern.h" /* own include */ +/* -------------------------------------------------------------------- */ +/** \name Path Select Struct & Properties + * \{ */ + struct PathSelectParams { bool track_active; /* ensure the active element is the last selected item (handy for picking) */ bool use_topology_distance; @@ -102,8 +106,11 @@ struct UserData { const struct PathSelectParams *op_params; }; +/** \} */ + /* -------------------------------------------------------------------- */ -/* Vert Path */ +/** \name Vert Path + * \{ */ /* callbacks */ static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v)) @@ -205,10 +212,11 @@ static void mouse_mesh_shortest_path_vert( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Edge Path */ +/** \name Edge Path + * \{ */ /* callbacks */ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v)) @@ -427,10 +435,11 @@ static void mouse_mesh_shortest_path_edge( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Face Path */ +/** \name Face Path + * \{ */ /* callbacks */ static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v)) @@ -477,7 +486,6 @@ static void mouse_mesh_shortest_path_face( facetag_filter_cb, &user_data); } - if (f_act != f_dst) { if (path) { if (op_params->track_active) { @@ -538,10 +546,11 @@ static void mouse_mesh_shortest_path_face( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Main Operator for vert/edge/face tag */ +/** \name Main Operator for vert/edge/face tag + * \{ */ static bool edbm_shortest_path_pick_ex( Scene *scene, Object *obedit, const struct PathSelectParams *op_params, @@ -710,9 +719,11 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select path between existing selection */ +/** \name Select Path Between Existing Selection + * \{ */ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) { @@ -797,3 +808,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot) /* properties */ path_select_properties(ot); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 70ee1627537..312dc000a2b 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -64,8 +64,14 @@ #include "mesh_intern.h" /* own include */ -/* mesh backup implementation. This would greatly benefit from some sort of binary diffing - * just as the undo stack would. So leaving this as an interface for further work */ +/* -------------------------------------------------------------------- */ +/** \name Redo API + * \{ */ + +/* Mesh backup implementation. + * This would greatly benefit from some sort of binary diffing + * just as the undo stack would. + * So leaving this as an interface for further work */ BMBackup EDBM_redo_state_store(BMEditMesh *em) { @@ -77,8 +83,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em) void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) { BMesh *tmpbm; - if (!em || !backup.bmcopy) + if (!em || !backup.bmcopy) { return; + } BM_mesh_data_free(em->bm); tmpbm = BM_mesh_copy(backup.bmcopy); @@ -86,8 +93,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) MEM_freeN(tmpbm); tmpbm = NULL; - if (recalctess) + if (recalctess) { BKE_editmesh_tessface_calc(em); + } } void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) @@ -100,68 +108,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) BM_mesh_data_free(backup->bmcopy); } - if (backup->bmcopy) + if (backup->bmcopy) { MEM_freeN(backup->bmcopy); + } backup->bmcopy = NULL; - if (recalctess && em) + if (recalctess && em) { BKE_editmesh_tessface_calc(em); -} - -void EDBM_mesh_normals_update(BMEditMesh *em) -{ - BM_mesh_normals_update(em->bm); -} - -void EDBM_mesh_clear(BMEditMesh *em) -{ - /* clear bmesh */ - BM_mesh_clear(em->bm); - - /* free derived meshes */ - BKE_editmesh_free_derivedmesh(em); - - /* free tessellation data */ - em->tottri = 0; - if (em->looptris) { - MEM_freeN(em->looptris); - em->looptris = NULL; } } -void EDBM_stats_update(BMEditMesh *em) -{ - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; - - BMIter iter; - BMElem *ele; - int *tots[3]; - int i; +/** \} */ - tots[0] = &em->bm->totvertsel; - tots[1] = &em->bm->totedgesel; - tots[2] = &em->bm->totfacesel; - - em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; - - for (i = 0; i < 3; i++) { - ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); - for ( ; ele; ele = BM_iter_step(&iter)) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - (*tots[i])++; - } - } - } -} - -DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) -{ - return ((em->derivedFinal != NULL) && - (em->derivedFinal->type == DM_TYPE_EDITBMESH) && - (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; -} +/* -------------------------------------------------------------------- */ +/** \name BMesh Operator (BMO) API Wrapper + * \{ */ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...) { @@ -175,9 +136,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * va_end(list); return false; } - - if (!em->emcopy) + + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; va_end(list); @@ -185,12 +147,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * return true; } - /* returns 0 on error, 1 on success. executes and finishes a bmesh operator */ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report) { const char *errmsg; - + BMO_op_finish(em->bm, bmop); if (BMO_error_get(em->bm, &errmsg, NULL)) { @@ -245,8 +206,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -255,9 +217,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return EDBM_op_finish(em, &bmop, op, true); } -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_call_and_selectf( + BMEditMesh *em, wmOperator *op, + const char *select_slot_out, const bool select_extend, + const char *fmt, ...) { BMOpSlot *slot_select_out; BMesh *bm = em->bm; @@ -273,8 +236,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -306,8 +270,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -316,20 +281,13 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return EDBM_op_finish(em, &bmop, NULL, false); } -void EDBM_selectmode_to_scene(bContext *C) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (!em) - return; +/** \} */ - scene->toolsettings->selectmode = em->selectmode; - - /* Request redraw of header buttons (to show new select mode) */ - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); -} +/* -------------------------------------------------------------------- */ +/** \name Edit BMesh API + * + * Make/Clear/Free functions. + * \{ */ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) { @@ -413,6 +371,22 @@ void EDBM_mesh_load(Object *ob) #endif } +void EDBM_mesh_clear(BMEditMesh *em) +{ + /* clear bmesh */ + BM_mesh_clear(em->bm); + + /* free derived meshes */ + BKE_editmesh_free_derivedmesh(em); + + /* free tessellation data */ + em->tottri = 0; + if (em->looptris) { + MEM_freeN(em->looptris); + em->looptris = NULL; + } +} + /** * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free */ @@ -427,6 +401,28 @@ void EDBM_mesh_free(BMEditMesh *em) BKE_editmesh_free(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selection Utilities + * \{ */ + +void EDBM_selectmode_to_scene(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!em) { + return; + } + + scene->toolsettings->selectmode = em->selectmode; + + /* Request redraw of header buttons (to show new select mode) */ + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); +} + void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode) { BM_mesh_select_mode_flush_ex(em->bm, selectmode); @@ -444,7 +440,6 @@ void EDBM_deselect_flush(BMEditMesh *em) BM_mesh_deselect_flush(em->bm); } - void EDBM_select_flush(BMEditMesh *em) { /* function below doesnt use. just do this to keep the values in sync */ @@ -457,9 +452,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, false, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, false, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -473,9 +469,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, true, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, true, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -497,6 +494,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UV Vertex Map API + * \{ */ + /** * Return a new UVVertMap from the editmesh */ @@ -519,7 +522,7 @@ UvVertMap *BM_uv_vert_map_create( BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - + totfaces = bm->totface; totverts = bm->totvert; totuv = 0; @@ -549,7 +552,7 @@ UvVertMap *BM_uv_vert_map_create( BKE_mesh_uv_vert_map_free(vmap); return NULL; } - + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) { if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { float (*tf_uv)[2]; @@ -562,7 +565,7 @@ UvVertMap *BM_uv_vert_map_create( buf->tfindex = i; buf->f = a; buf->separate = 0; - + buf->next = vmap->vert[BM_elem_index_get(l->v)]; vmap->vert[BM_elem_index_get(l->v)] = buf; buf++; @@ -578,7 +581,7 @@ UvVertMap *BM_uv_vert_map_create( } } } - + /* sort individual uvs for each vert */ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) { UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; @@ -592,22 +595,21 @@ UvVertMap *BM_uv_vert_map_create( newvlist = v; efa = BM_face_at_index(bm, v->f); - + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv = luv->uv; - + lastv = NULL; iterv = vlist; while (iterv) { next = iterv->next; efa = BM_face_at_index(bm, iterv->f); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; - + sub_v2_v2v2(uvdiff, uv2, uv); if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && @@ -640,13 +642,11 @@ UvVertMap *BM_uv_vert_map_create( return vmap; } - UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v) { return vmap->vert[v]; } - /* A specialized vert map used by stitch operator */ UvElementMap *BM_uv_element_map_create( BMesh *bm, @@ -904,23 +904,30 @@ void BM_uv_element_map_free(UvElementMap *element_map) UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) { - UvElement *element; - - element = map->vert[BM_elem_index_get(l->v)]; - - for (; element; element = element->next) - if (element->l->f == efa) + for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; + element; + element = element->next) + { + if (element->l->f == efa) { return element; + } + } return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Layer Checks + * \{ */ + /* last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected) { BMFace *efa = NULL; - + if (!EDBM_uv_check(em)) { return NULL; } @@ -948,6 +955,12 @@ bool EDBM_vert_color_check(BMEditMesh *em) return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mirror Cache API + * \{ */ + static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) { intptr_t eve_i = index_lookup[index]; @@ -982,9 +995,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) * \param maxdist Distance for close point test. * \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts). */ -void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select, - /* extra args */ - const bool use_topology, float maxdist, int *r_index) +void EDBM_verts_mirror_cache_begin_ex( + BMEditMesh *em, const int axis, const bool use_self, const bool use_select, + /* extra args */ + const bool use_topology, float maxdist, int *r_index) { Mesh *me = (Mesh *)em->ob->data; BMesh *bm = em->bm; @@ -1008,8 +1022,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); } - cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT, - em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); + cd_vmirr_offset = CustomData_get_n_offset( + &bm->vdata, CD_PROP_INT, + em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY; } @@ -1082,14 +1097,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool } } -void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis, - const bool use_self, const bool use_select, - const bool use_topology) +void EDBM_verts_mirror_cache_begin( + BMEditMesh *em, const int axis, + const bool use_self, const bool use_select, + const bool use_topology) { - EDBM_verts_mirror_cache_begin_ex(em, axis, - use_self, use_select, - /* extra args */ - use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); + EDBM_verts_mirror_cache_begin_ex( + em, axis, + use_self, use_select, + /* extra args */ + use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); } BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v) @@ -1177,6 +1194,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide/Reveal API + * \{ */ /* swap is 0 or 1, if 1 it hides not selected */ void EDBM_mesh_hide(BMEditMesh *em, bool swap) @@ -1211,17 +1233,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap) */ } - void EDBM_mesh_reveal(BMEditMesh *em, bool select) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; const bool sels[3] = { - (em->selectmode & SCE_SELECT_VERTEX) != 0, - (em->selectmode & SCE_SELECT_EDGE) != 0, - (em->selectmode & SCE_SELECT_FACE) != 0, + (em->selectmode & SCE_SELECT_VERTEX) != 0, + (em->selectmode & SCE_SELECT_EDGE) != 0, + (em->selectmode & SCE_SELECT_FACE) != 0, }; int i; @@ -1261,6 +1284,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select) EDBM_mesh_normals_update(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update API + * \{ */ + +void EDBM_mesh_normals_update(BMEditMesh *em) +{ + BM_mesh_normals_update(em->bm); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; + + BMIter iter; + BMElem *ele; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i = 0; i < 3; i++) { + ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + (*tots[i])++; + } + } + } +} + /* so many tools call these that we better make it a generic function. */ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive) @@ -1296,15 +1359,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Access + * \{ */ + +DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) +{ + return ((em->derivedFinal != NULL) && + (em->derivedFinal->type == DM_TYPE_EDITBMESH) && + (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Helpers + * \{ */ + /* poll call for mesh operators requiring a view3d context */ int EDBM_view3d_poll(bContext *C) { - if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) + if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) { return 1; + } return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BMesh Element API + * \{ */ + BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa) { BMElem *ele = NULL; @@ -1369,22 +1458,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index) return NULL; } -/* -------------------------------------------------------------------- */ -/* BMBVH functions */ -// XXX -#if 0 //BMESH_TODO: not implemented yet -int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) -{ +/** \} */ -} -#endif +/* -------------------------------------------------------------------- */ +/** \name BMesh BVH API + * \{ */ static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); - if (f && BM_edge_in_face(e, f)) + if (f && BM_edge_in_face(e, f)) { return NULL; + } return f; } @@ -1405,8 +1491,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, float origin[3], invmat[4][4]; float epsilon = 0.01f; float end[3]; - const float mval_f[2] = {ar->winx / 2.0f, - ar->winy / 2.0f}; + const float mval_f[2] = { + ar->winx / 2.0f, + ar->winy / 2.0f, + }; ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); @@ -1442,12 +1530,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, /* do three samplings: left, middle, right */ f = edge_ray_cast(tree, co1, dir1, NULL, e); - if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) + if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) { return true; - else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) + } + else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) { return true; - else if (!f) + } + else if (!f) { return true; + } return false; } + +/** \} */ diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c new file mode 100644 index 00000000000..22bfd8eedea --- /dev/null +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -0,0 +1,377 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Foundation, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/mesh_mirror.c + * \ingroup edmesh + * + * Mirror calculation for edit-mode and object mode. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_bitmap.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BKE_DerivedMesh.h" +#include "BLI_kdtree.h" +#include "BKE_editmesh.h" + +#include "ED_mesh.h" + +/* -------------------------------------------------------------------- */ +/** \name Mesh Spatial Mirror API + * \{ */ + +#define KD_THRESH 0.00002f + +static struct { void *tree; } MirrKdStore = {NULL}; + +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) +{ + if (mode == 'u') { /* use table */ + if (MirrKdStore.tree == NULL) + ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); + + if (MirrKdStore.tree) { + KDTreeNearest nearest; + const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } + } + return -1; + } + else if (mode == 's') { /* start table */ + Mesh *me = ob->data; + const bool use_em = (!dm && em && me->edit_btmesh == em); + const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; + + if (MirrKdStore.tree) /* happens when entering this call without ending it */ + ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); + + MirrKdStore.tree = BLI_kdtree_new(totvert); + + if (use_em) { + BMVert *eve; + BMIter iter; + int i; + + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); + } + } + else { + MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; + int i; + + for (i = 0; i < totvert; i++, mvert++) { + BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); + } + } + + BLI_kdtree_balance(MirrKdStore.tree); + } + else if (mode == 'e') { /* end table */ + if (MirrKdStore.tree) { + BLI_kdtree_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; + } + } + else { + BLI_assert(0); + } + + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Topology Mirror API + * \{ */ + +typedef unsigned int MirrTopoHash_t; + +typedef struct MirrTopoVert_t { + MirrTopoHash_t hash; + int v_index; +} MirrTopoVert_t; + +static int mirrtopo_hash_sort(const void *l1, const void *l2) +{ + if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; + else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; + return 0; +} + +static int mirrtopo_vert_sort(const void *v1, const void *v2) +{ + if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; + else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; + return 0; +} + +bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + int totvert; + int totedge; + + if (dm) { + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + } + else if (me->edit_btmesh) { + totvert = me->edit_btmesh->bm->totvert; + totedge = me->edit_btmesh->bm->totedge; + } + else { + totvert = me->totvert; + totedge = me->totedge; + } + + if ((mesh_topo_store->index_lookup == NULL) || + (mesh_topo_store->prev_is_editmode != is_editmode) || + (totvert != mesh_topo_store->prev_vert_tot) || + (totedge != mesh_topo_store->prev_edge_tot)) + { + return true; + } + else { + return false; + } + +} + +void ED_mesh_mirrtopo_init( + Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + MEdge *medge = NULL, *med; + BMEditMesh *em = dm ? NULL : me->edit_btmesh; + + /* editmode*/ + BMEdge *eed; + BMIter iter; + + int a, last; + int totvert, totedge; + int tot_unique = -1, tot_unique_prev = -1; + int tot_unique_edges = 0, tot_unique_edges_prev; + + MirrTopoHash_t *topo_hash = NULL; + MirrTopoHash_t *topo_hash_prev = NULL; + MirrTopoVert_t *topo_pairs; + MirrTopoHash_t topo_pass = 1; + + intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ + + /* reallocate if needed */ + ED_mesh_mirrtopo_free(mesh_topo_store); + + mesh_topo_store->prev_is_editmode = is_editmode; + + if (em) { + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + totvert = em->bm->totvert; + } + else { + totvert = dm ? dm->getNumVerts(dm) : me->totvert; + } + + topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); + + /* Initialize the vert-edge-user counts used to detect unique topology */ + if (em) { + totedge = me->edit_btmesh->bm->totedge; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1]++; + topo_hash[i2]++; + } + } + else { + totedge = dm ? dm->getNumEdges(dm) : me->totedge; + medge = dm ? dm->getEdgeArray(dm) : me->medge; + + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1]++; + topo_hash[i2]++; + } + } + + topo_hash_prev = MEM_dupallocN(topo_hash); + + tot_unique_prev = -1; + tot_unique_edges_prev = -1; + while (1) { + /* use the number of edges per vert to give verts unique topology IDs */ + + tot_unique_edges = 0; + + /* This can make really big numbers, wrapping around here is fine */ + if (em) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + else { + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + /* sort so we can count unique values */ + qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); + + tot_unique = 1; /* account for skiping the first value */ + for (a = 1; a < totvert; a++) { + if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { + tot_unique++; + } + } + + if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { + /* Finish searching for unique values when 1 loop dosnt give a + * higher number of unique values compared to the previous loop */ + break; + } + else { + tot_unique_prev = tot_unique; + tot_unique_edges_prev = tot_unique_edges; + } + /* Copy the hash calculated this iter, so we can use them next time */ + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + topo_pass++; + } + + /* Hash/Index pairs are needed for sorting to find index pairs */ + topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); + + /* since we are looping through verts, initialize these values here too */ + index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); + + if (em) { + if (skip_em_vert_array_init == false) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + } + + for (a = 0; a < totvert; a++) { + topo_pairs[a].hash = topo_hash[a]; + topo_pairs[a].v_index = a; + + /* initialize lookup */ + index_lookup[a] = -1; + } + + qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); + + last = 0; + + /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, + * but you cant ever access the last 'a' index of MirrTopoPairs */ + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; + } + last = a; + } + } + } + + MEM_freeN(topo_pairs); + topo_pairs = NULL; + + MEM_freeN(topo_hash); + MEM_freeN(topo_hash_prev); + + mesh_topo_store->index_lookup = index_lookup; + mesh_topo_store->prev_vert_tot = totvert; + mesh_topo_store->prev_edge_tot = totedge; +} + +void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) +{ + if (mesh_topo_store->index_lookup) { + MEM_freeN(mesh_topo_store->index_lookup); + } + mesh_topo_store->index_lookup = NULL; + mesh_topo_store->prev_vert_tot = -1; + mesh_topo_store->prev_edge_tot = -1; +} + +/** \} */ diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index aebfd46a554..2e75276cd8f 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -47,8 +47,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" - -#include "BLI_kdtree.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" @@ -682,84 +680,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* -------------------------------------------------------------------- */ -/* Mesh Mirror (Spatial) */ - -/** \name Mesh Spatial Mirror API - * \{ */ - -#define KD_THRESH 0.00002f - -static struct { void *tree; } MirrKdStore = {NULL}; - -/* mode is 's' start, or 'e' end, or 'u' use */ -/* if end, ob can be NULL */ -int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) -{ - if (mode == 'u') { /* use table */ - if (MirrKdStore.tree == NULL) - ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); - - if (MirrKdStore.tree) { - KDTreeNearest nearest; - const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); - - if (i != -1) { - if (nearest.dist < KD_THRESH) { - return i; - } - } - } - return -1; - } - else if (mode == 's') { /* start table */ - Mesh *me = ob->data; - const bool use_em = (!dm && em && me->edit_btmesh == em); - const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; - - if (MirrKdStore.tree) /* happens when entering this call without ending it */ - ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); - - MirrKdStore.tree = BLI_kdtree_new(totvert); - - if (use_em) { - BMVert *eve; - BMIter iter; - int i; - - /* this needs to be valid for index lookups later (callers need) */ - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); - } - } - else { - MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; - int i; - - for (i = 0; i < totvert; i++, mvert++) { - BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); - } - } - - BLI_kdtree_balance(MirrKdStore.tree); - } - else if (mode == 'e') { /* end table */ - if (MirrKdStore.tree) { - BLI_kdtree_free(MirrKdStore.tree); - MirrKdStore.tree = NULL; - } - } - else { - BLI_assert(0); - } - - return 0; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /* Mesh Mirror (Topology) */ |