diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-03-18 04:48:59 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2013-03-18 04:48:59 +0400 |
commit | c1ceab1281ccf061f03f8000bf190a082a5385d8 (patch) | |
tree | 01b9a9cfca80432d316bdad6c18c74eb025e9eb0 /source/blender/editors/mesh | |
parent | 0d9c98c4bbfbc8c70c4772086dd09a51d01921ef (diff) | |
parent | 66a35e089a64d27bfc09c2225a530069eca05875 (diff) |
Merged changes in the trunk up to revision 55357.
Resolved conflicts:
release/datafiles/startup.blend
source/blender/editors/space_nla/nla_buttons.c
Also updated source/blender/blenkernel/intern/linestyle.c as a follow-up of
recent changes for the use of bool.
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r-- | source/blender/editors/mesh/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/editface.c | 39 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_add.c | 5 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 519 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife_project.c | 168 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_loopcut.c | 7 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_rip.c | 25 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 79 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 235 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_data.c | 5 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_intern.h | 7 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/meshtools.c | 4 |
13 files changed, 896 insertions, 201 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index b51d55aaf0e..a76872d6e30 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenlib ../../blenloader ../../bmesh + ../../gpu ../../imbuf ../../makesdna ../../makesrna @@ -43,6 +44,7 @@ set(SRC editmesh_add.c editmesh_bvh.c editmesh_knife.c + editmesh_knife_project.c editmesh_loopcut.c editmesh_rip.c editmesh_select.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 7ddf2b54a88..260d01d726a 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -294,7 +294,7 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind MEM_freeN(linkflag); } -void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2]), int mode) +void paintface_select_linked(bContext *UNUSED(C), Object *ob, const int UNUSED(mval[2]), int mode) { Mesh *me; unsigned int index = 0; @@ -525,7 +525,9 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in else mpoly_sel->flag |= ME_FACE_SEL; } - else mpoly_sel->flag |= ME_FACE_SEL; + else { + mpoly_sel->flag |= ME_FACE_SEL; + } /* image window redraw */ @@ -568,7 +570,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect); rt = ibuf->rect; - glReadPixels(rect->xmin + vc->ar->winrct.xmin, rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf); a = sx * sy; @@ -710,6 +712,37 @@ void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags) } } +void paintvert_select_ungrouped(Object *ob, short extend, short flush_flags) +{ + Mesh *me = BKE_mesh_from_object(ob); + MVert *mv; + MDeformVert *dv; + int a, tot; + + if (me == NULL || me->dvert == NULL) { + return; + } + + if (!extend) { + paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); + } + + dv = me->dvert; + tot = me->totvert; + + for (a = 0, mv = me->mvert; a < tot; a++, mv++, dv++) { + if ((mv->flag & ME_HIDE) == 0) { + if (dv->dw == NULL) { + /* if null weight then not grouped */ + mv->flag |= SELECT; + } + } + } + + if (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 diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index a356f9fca7f..174715495f6 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -32,15 +32,14 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "BLI_math.h" #include "BKE_context.h" #include "BKE_library.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index d7dbe3506b1..b5b6a92cbf5 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_array.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_smallhash.h" #include "BLI_memarena.h" @@ -90,7 +91,8 @@ typedef struct KnifeVert { ListBase faces; float co[3], cageco[3], sco[3]; /* sco is screen coordinates for cageco */ - short flag, draw, isface, inspace; + bool is_face, in_space; + bool draw; } KnifeVert; typedef struct Ref { @@ -102,9 +104,9 @@ typedef struct KnifeEdge { KnifeVert *v1, *v2; BMFace *basef; /* face to restrict face fill to */ ListBase faces; - int draw; - BMEdge *e, *oe; /* non-NULL if this is an original edge */ + BMEdge *e /* , *e_old */; /* non-NULL if this is an original edge */ + bool draw; } KnifeEdge; typedef struct BMEdgeHit { @@ -128,7 +130,7 @@ typedef struct KnifePosData { KnifeVert *vert; KnifeEdge *edge; BMFace *bmface; - int is_space; + bool is_space; float mval[2]; /* mouse screen position (may be non-integral if snapped to something) */ } KnifePosData; @@ -137,7 +139,8 @@ typedef struct KnifePosData { typedef struct KnifeTool_OpData { ARegion *ar; /* region that knifetool was activated in */ void *draw_handle; /* for drawing preview loop */ - ViewContext vc; + ViewContext vc; /* note: _don't_ use 'mval', instead use the one we define below */ + float mval[2]; /* mouse value with snapping applied */ //bContext *C; Object *ob; @@ -173,12 +176,15 @@ typedef struct KnifeTool_OpData { KnifeColors colors; + /* run by the UI or not */ + bool is_interactive; + /* operatpr options */ - char cut_through; /* preference, can be modified at runtime (that feature may go) */ - char only_select; /* set on initialization */ - char select_result; /* set on initialization */ + bool cut_through; /* preference, can be modified at runtime (that feature may go) */ + bool only_select; /* set on initialization */ + bool select_result; /* set on initialization */ - short is_ortho; + bool is_ortho; float ortho_extent; float clipsta, clipend; @@ -189,8 +195,10 @@ typedef struct KnifeTool_OpData { MODE_PANNING } mode; - int snap_midpoints, prevmode, extend; - int ignore_edge_snapping, ignore_vert_snapping; + int prevmode; + bool snap_midpoints, extend; + bool ignore_edge_snapping; + bool ignore_vert_snapping; enum { ANGLE_FREE, @@ -228,14 +236,16 @@ static void knife_update_header(bContext *C, KnifeTool_OpData *kcd) ED_area_headerprint(CTX_wm_area(C), header); } +#if 0 BLI_INLINE int round_ftoi(float x) { return x > 0.0f ? (int)(x + 0.5f) : (int)(x - 0.5f); } +#endif -static void knife_project_v3(KnifeTool_OpData *kcd, const float co[3], float sco[3]) +static void knife_project_v3(const KnifeTool_OpData *kcd, const float co[3], float sco[3]) { - ED_view3d_project_float_v3_m4(kcd->ar, co, sco, kcd->projmat); + ED_view3d_project_float_v3_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat); } static void knife_pos_data_clear(KnifePosData *kpd) @@ -245,8 +255,7 @@ static void knife_pos_data_clear(KnifePosData *kpd) kpd->vert = NULL; kpd->edge = NULL; kpd->bmface = NULL; - kpd->mval[0] = 0.0f; - kpd->mval[1] = 0.0f; + zero_v2(kpd->mval); } static ListBase *knife_empty_list(KnifeTool_OpData *kcd) @@ -494,7 +503,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) if (kcd->prev.edge && kcd->prev.edge == kcd->curr.edge) return; - kfe->draw = 1; + kfe->draw = true; if (kcd->prev.vert) { kfe->v1 = kcd->prev.vert; @@ -505,9 +514,9 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) else { kfe->v1 = new_knife_vert(kcd, kcd->prev.co, kcd->prev.co); kfe->v1->draw = kfe->draw = !kcd->prev.is_space; - kfe->v1->inspace = kcd->prev.is_space; + kfe->v1->in_space = kcd->prev.is_space; kfe->draw = !kcd->prev.is_space; - kfe->v1->isface = 1; + kfe->v1->is_face = true; if (kfe->v1->draw && kcd->prev.bmface) knife_append_list(kcd, &kfe->v1->faces, kcd->prev.bmface); } @@ -522,13 +531,13 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd) else { kfe->v2 = new_knife_vert(kcd, kcd->curr.co, kcd->curr.co); kfe->v2->draw = !kcd->curr.is_space; - kfe->v2->isface = 1; - kfe->v2->inspace = kcd->curr.is_space; + kfe->v2->is_face = true; + kfe->v2->in_space = kcd->curr.is_space; if (kfe->v2->draw && kcd->curr.bmface) knife_append_list(kcd, &kfe->v2->faces, kcd->curr.bmface); if (kcd->curr.is_space) - kfe->draw = 0; + kfe->draw = false; kcd->curr.vert = kfe->v2; } @@ -632,11 +641,10 @@ static void knife_add_single_cut_through(KnifeTool_OpData *kcd, KnifeVert *v1, K KnifeEdge *kfenew; kfenew = new_knife_edge(kcd); - kfenew->draw = 1; kfenew->basef = f; kfenew->v1 = v1; kfenew->v2 = v2; - kfenew->draw = 1; + kfenew->draw = true; knife_add_to_vert_edges(kcd, kfenew); @@ -650,7 +658,7 @@ static void knife_get_vert_faces(KnifeTool_OpData *kcd, KnifeVert *kfv, BMFace * BMFace *f; Ref *r; - if (kfv->isface && facef) { + if (kfv->is_face && facef) { knife_append_list(kcd, lst, facef); } else if (kfv->v) { @@ -689,7 +697,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd) ListBase firstfaces = {NULL, NULL}, lastfaces = {NULL, NULL}; Ref *r, *r2; KnifeEdge **splitkfe; - int i, j, found; + int i, j; if (!kcd->totlinehit) { /* if no linehits then no interesting back face stuff to do */ @@ -727,15 +735,15 @@ static void knife_cut_through(KnifeTool_OpData *kcd) /* For each face incident to firstv, * find the first following linehit (if any) sharing that face and connect */ for (r = firstfaces.first; r; r = r->next) { + bool found = false; f = r->ref; - found = 0; for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit && !found; j++, lh2++) { kfe2 = lh2->kfe; for (r2 = kfe2->faces.first; r2; r2 = r2->next) { if (r2->ref == f) { v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); knife_add_single_cut_through(kcd, firstv, v2, f); - found = 1; + found = true; break; } } @@ -757,8 +765,8 @@ static void knife_cut_through(KnifeTool_OpData *kcd) /* For each face attached to edge for this linehit, * find the first following linehit (if any) sharing that face and connect */ for (r = kfe->faces.first; r; r = r->next) { + bool found = false; f = r->ref; - found = 0; for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit && !found; j++, lh2++) { kfe2 = lh2->kfe; for (r2 = kfe2->faces.first; r2; r2 = r2->next) { @@ -766,7 +774,7 @@ static void knife_cut_through(KnifeTool_OpData *kcd) v1 = splitkfe[i] ? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); knife_add_single_cut_through(kcd, v1, v2, f); - found = 1; + found = true; break; } } @@ -890,7 +898,7 @@ static void knife_finish_cut(KnifeTool_OpData *UNUSED(kcd)) } -static void knifetool_draw_angle_snapping(KnifeTool_OpData *kcd) +static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) { bglMats mats; double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy; @@ -1006,7 +1014,7 @@ static void knife_init_colors(KnifeColors *colors) static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) { View3D *v3d = CTX_wm_view3d(C); - KnifeTool_OpData *kcd = arg; + const KnifeTool_OpData *kcd = arg; if (v3d->zbuf) glDisable(GL_DEPTH_TEST); @@ -1062,7 +1070,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) if (kcd->totlinehit > 0) { const float vthresh4 = kcd->vthresh / 4.0f; - const float vthresh4_squared = vthresh4 * vthresh4; + const float vthresh4_sq = vthresh4 * vthresh4; BMEdgeHit *lh; int i; @@ -1082,12 +1090,12 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) knife_project_v3(kcd, lh->kfe->v2->cageco, sv2); knife_project_v3(kcd, lh->cagehit, lh->schit); - if (len_squared_v2v2(lh->schit, sv1) < vthresh4_squared) { + if (len_squared_v2v2(lh->schit, sv1) < vthresh4_sq) { copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v1; } - else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_squared) { + else if (len_squared_v2v2(lh->schit, sv2) < vthresh4_sq) { copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco); glVertex3fv(lh->cagehit); lh->v = lh->kfe->v2; @@ -1179,7 +1187,7 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, /* for comparing distances, error of intersection depends on triangle scale. * need to scale down before squaring for accurate comparison */ const float depsilon = (FLT_EPSILON / 2.0f) * len_v3_tri_side_max(v1, v2, v3); - const float depsilon_squared = depsilon * depsilon; + const float depsilon_sq = depsilon * depsilon; copy_v3_v3(cos + 0, v1); copy_v3_v3(cos + 3, v2); @@ -1213,14 +1221,14 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda); - if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_squared) { + if (kcd->curr.vert && len_squared_v3v3(kcd->curr.vert->cageco, p) < depsilon_sq) { continue; } - if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_squared) { + if (kcd->prev.vert && len_squared_v3v3(kcd->prev.vert->cageco, p) < depsilon_sq) { continue; } - if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_squared || - len_squared_v3v3(kcd->curr.cage, p) < depsilon_squared) + if (len_squared_v3v3(kcd->prev.cage, p) < depsilon_sq || + len_squared_v3v3(kcd->curr.cage, p) < depsilon_sq) { continue; } @@ -1266,8 +1274,8 @@ static BMEdgeHit *knife_edge_tri_isect(KnifeTool_OpData *kcd, BMBVHTree *bmtree, if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) { BMEdgeHit hit; - if (len_squared_v3v3(p, kcd->curr.co) < depsilon_squared || - len_squared_v3v3(p, kcd->prev.co) < depsilon_squared) + if (len_squared_v3v3(p, kcd->curr.co) < depsilon_sq || + len_squared_v3v3(p, kcd->prev.co) < depsilon_sq) { continue; } @@ -1381,7 +1389,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) knife_project_v3(kcd, v1, s1); knife_project_v3(kcd, v2, s2); - if (len_v2v2(s1, s2) < 1) + if (len_squared_v2v2(s1, s2) < 1) return; /* unproject screen line */ @@ -1481,7 +1489,7 @@ static void knife_input_ray_segment(KnifeTool_OpData *kcd, const float mval[2], mul_m4_v3(kcd->ob->imat, r_origin_ofs); } -static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], int *is_space) +static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float cageco[3], bool *is_space) { BMFace *f; float dist = KMAXDIST; @@ -1499,13 +1507,15 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float *is_space = !f; if (!f) { - /* try to use backbuffer selection method if ray casting failed */ - f = EDBM_face_find_nearest(&kcd->vc, &dist); + if (kcd->is_interactive) { + /* try to use backbuffer selection method if ray casting failed */ + f = EDBM_face_find_nearest(&kcd->vc, &dist); - /* cheat for now; just put in the origin instead - * of a true coordinate on the face. - * This just puts a point 1.0f infront of the view. */ - add_v3_v3v3(co, origin, ray); + /* cheat for now; just put in the origin instead + * of a true coordinate on the face. + * This just puts a point 1.0f infront of the view. */ + add_v3_v3v3(co, origin, ray); + } } return f; @@ -1513,18 +1523,21 @@ static BMFace *knife_find_closest_face(KnifeTool_OpData *kcd, float co[3], float /* find the 2d screen space density of vertices within a radius. used to scale snapping * distance for picking edges/verts.*/ -static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) +static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius) { BMFace *f; - int is_space; + bool is_space; float co[3], cageco[3], sco[3]; + BLI_assert(kcd->is_interactive == true); + f = knife_find_closest_face(kcd, co, cageco, &is_space); if (f && !is_space) { + const float radius_sq = radius * radius; ListBase *lst; Ref *ref; - float dis; + float dis_sq; int c = 0; knife_project_v3(kcd, cageco, sco); @@ -1539,8 +1552,8 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) knife_project_v3(kcd, kfv->cageco, kfv->sco); - dis = len_v2v2(kfv->sco, sco); - if (dis < radius) { + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < radius_sq) { if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) { c++; @@ -1563,7 +1576,14 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, float radius) * surrounding mesh (in screen space)*/ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) { - float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + float density; + + if (kcd->is_interactive) { + density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f); + } + else { + density = 1.0f; + } if (density < 1.0f) density = 1.0f; @@ -1572,7 +1592,7 @@ static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize) } /* p is closest point on edge to the mouse cursor */ -static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, int *is_space) +static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, bool *is_space) { BMFace *f; float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh); @@ -1668,7 +1688,7 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo /* find a vertex near the mouse cursor, if it exists */ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], float cagep[3], BMFace **fptr, - int *is_space) + bool *is_space) { BMFace *f; float co[3], cageco[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh); @@ -1684,10 +1704,11 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo kcd->curr.bmface = f; if (f) { + const float maxdist_sq = maxdist * maxdist; ListBase *lst; Ref *ref; KnifeVert *curv = NULL; - float dis, curdis = FLT_MAX; + float dis_sq, curdis_sq = FLT_MAX; knife_project_v3(kcd, cageco, sco); @@ -1701,17 +1722,17 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo knife_project_v3(kcd, kfv->cageco, kfv->sco); - dis = len_v2v2(kfv->sco, sco); - if (dis < curdis && dis < maxdist) { + dis_sq = len_squared_v2v2(kfv->sco, sco); + if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, TRUE) == 0) { curv = kfv; - curdis = dis; + curdis_sq = dis_sq; } } else { curv = kfv; - curdis = dis; + curdis_sq = dis_sq; } } } @@ -1747,7 +1768,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo return NULL; } -/* update both kcd->curr.mval and kcd->vc.mval to snap to required angle */ +/* update both kcd->curr.mval and kcd->mval to snap to required angle */ static void knife_snap_angle(KnifeTool_OpData *kcd) { float dx, dy; @@ -1784,16 +1805,14 @@ static void knife_snap_angle(KnifeTool_OpData *kcd) kcd->curr.mval[0] = kcd->prev.mval[0]; } - kcd->vc.mval[0] = round_ftoi(kcd->curr.mval[0]); - kcd->vc.mval[1] = round_ftoi(kcd->curr.mval[1]); + copy_v2_v2(kcd->mval, kcd->curr.mval); } /* update active knife edge/vert pointers */ static int knife_update_active(KnifeTool_OpData *kcd) { knife_pos_data_clear(&kcd->curr); - kcd->curr.mval[0] = (float)kcd->vc.mval[0]; - kcd->curr.mval[1] = (float)kcd->vc.mval[1]; + copy_v2_v2(kcd->curr.mval, kcd->mval); if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) knife_snap_angle(kcd); @@ -1994,14 +2013,14 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) i++; if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) { - kfe->oe = kfe->e; + kfe->e_old = kfe->e; continue; } j++; if (kfe->e) { - kfe->oe = kfe->e; + kfe->e_old = kfe->e; BMO_elem_flag_enable(bm, kfe->e, DEL); BMO_elem_flag_disable(bm, kfe->e, BOUNDARY); @@ -2027,13 +2046,13 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace) continue; - if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2)) + if (!(kfe->e_old && kfe->v1->v == kfe->e_old->v1 && kfe->v2->v == kfe->e_old->v2)) continue; k++; BMO_elem_flag_enable(bm, kfe->e, BOUNDARY); - kfe->oe = kfe->e; + kfe->e_old = kfe->e; for (ref = kfe->faces.first; ref; ref = ref->next) { f = ref->ref; @@ -2096,7 +2115,7 @@ static void knifenet_fill_faces(KnifeTool_OpData *kcd) if (sf_vert->poly_nr > 1 && sf_vert_last->poly_nr > 1) { ScanFillEdge *sf_edge; sf_edge = BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert); - if (entry->kfe->oe) + if (entry->kfe->e_old) sf_edge->f = SF_EDGE_BOUNDARY; /* mark as original boundary edge */ BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL); @@ -2239,15 +2258,15 @@ static void sort_by_frac_along(ListBase *lst, BMEdge *e) /* The chain so far goes from an instantiated vertex to kfv (some may be reversed). * If possible, complete the chain to another instantiated vertex and return 1, else return 0. * The visited hash says which KnifeVert's have already been tried, not including kfv. */ -static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited, - ListBase *chain) +static bool find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited, + ListBase *chain) { Ref *r; KnifeEdge *kfe; KnifeVert *kfv_other; if (kfv->v) - return TRUE; + return true; BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL); /* Try all possible next edges. Could either go through fedges @@ -2264,22 +2283,22 @@ static int find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fe if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) { knife_append_list(kcd, chain, kfe); if (find_chain_search(kcd, kfv_other, fedges, visited, chain)) - return TRUE; + return true; BLI_remlink(chain, chain->last); } } - return FALSE; + return false; } static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges) { SmallHash visited_, *visited = &visited_; ListBase *ans; - int found; + bool found; ans = knife_empty_list(kcd); knife_append_list(kcd, ans, kfe); - found = 0; + found = false; BLI_smallhash_init(visited); if (kfe->v1->v == v) { BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL); @@ -2340,15 +2359,15 @@ static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges) /* The hole so far goes from kfvfirst to kfv (some may be reversed). * If possible, complete the hole back to kfvfirst and return 1, else return 0. * The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */ -static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges, - SmallHash *visited, ListBase *hole) +static bool find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges, + SmallHash *visited, ListBase *hole) { Ref *r; KnifeEdge *kfe, *kfelast; KnifeVert *kfv_other; if (kfv == kfvfirst) - return TRUE; + return true; BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL); kfelast = ((Ref *)hole->last)->ref; @@ -2366,11 +2385,11 @@ static int find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVer if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) { knife_append_list(kcd, hole, kfe); if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole)) - return TRUE; + return true; BLI_remlink(hole, hole->last); } } - return FALSE; + return false; } /* Find a hole (simple cycle with no instantiated vertices). @@ -2381,10 +2400,10 @@ static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges) Ref *r, *ref; KnifeEdge *kfe; SmallHash visited_, *visited = &visited_; - int found; + bool found; ans = NULL; - found = FALSE; + found = false; for (r = fedges->first; r && !found; r = r->next) { kfe = r->ref; @@ -2853,10 +2872,8 @@ static void knife_make_cuts(KnifeTool_OpData *kcd) #endif /* called on tool confirmation */ -static void knifetool_finish(wmOperator *op) +static void knifetool_finish_ex(KnifeTool_OpData *kcd) { - KnifeTool_OpData *kcd = op->customdata; - #if SCANFILL_CUTS knifenet_fill_faces(kcd); #else @@ -2866,19 +2883,10 @@ static void knifetool_finish(wmOperator *op) EDBM_mesh_normals_update(kcd->em); EDBM_update_generic(kcd->em, TRUE, TRUE); } - -/* copied from paint_image.c */ -static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) +static void knifetool_finish(wmOperator *op) { - int orth = ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); - - if (orth) { /* only needed for ortho */ - float fac = 2.0f / ((*clipend) - (*clipsta)); - *clipsta *= fac; - *clipend *= fac; - } - - return orth; + KnifeTool_OpData *kcd = op->customdata; + knifetool_finish_ex(kcd); } static void knife_recalc_projmat(KnifeTool_OpData *kcd) @@ -2887,22 +2895,22 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd) ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat); //mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat); - kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d, - &kcd->clipsta, &kcd->clipend); + kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d, + &kcd->clipsta, &kcd->clipend, true); } /* called when modal loop selection is done... */ -static void knifetool_exit(bContext *C, wmOperator *op) +static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd) { - KnifeTool_OpData *kcd = op->customdata; - if (!kcd) return; - WM_cursor_restore(CTX_wm_window(C)); + if (kcd->is_interactive) { + WM_cursor_restore(CTX_wm_window(C)); - /* deactivate the extra drawing stuff in 3D-View */ - ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + } /* free the custom data */ BLI_mempool_destroy(kcd->refs); @@ -2927,6 +2935,11 @@ static void knifetool_exit(bContext *C, wmOperator *op) /* destroy kcd itself */ MEM_freeN(kcd); +} +static void knifetool_exit(bContext *C, wmOperator *op) +{ + KnifeTool_OpData *kcd = op->customdata; + knifetool_exit_ex(C, kcd); op->customdata = NULL; } @@ -2944,35 +2957,36 @@ static void cage_mapped_verts_callback(void *userData, int index, const float co } } -static void knifetool_update_mval(KnifeTool_OpData *kcd, int mval_i[2]) +static void knifetool_update_mval(KnifeTool_OpData *kcd, const float mval[2]) { knife_recalc_projmat(kcd); - kcd->vc.mval[0] = mval_i[0]; - kcd->vc.mval[1] = mval_i[1]; + copy_v2_v2(kcd->mval, mval); if (knife_update_active(kcd)) { ED_region_tag_redraw(kcd->ar); } } +static void knifetool_update_mval_i(KnifeTool_OpData *kcd, const int mval_i[2]) +{ + float mval[2] = {UNPACK2(mval_i)}; + knifetool_update_mval(kcd, mval); +} + /* called when modal loop selection gets set up... */ -static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) +static void knifetool_init(bContext *C, KnifeTool_OpData *kcd, + const bool only_select, const bool cut_through, const bool is_interactive) { - KnifeTool_OpData *kcd; Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); DerivedMesh *cage, *final; SmallHash shash; void *data[3]; - const short only_select = RNA_boolean_get(op->ptr, "only_selected"); - - /* alloc new customdata */ - kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), "knifetool Modal Op Data"); /* assign the drawing handle for drawing preview line... */ kcd->ob = obedit; kcd->ar = CTX_wm_region(C); - kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); + em_setup_viewcontext(C, &kcd->vc); kcd->em = BMEdit_FromObject(kcd->ob); @@ -2998,7 +3012,7 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) kcd->vthresh = KMAXDIST - 1; kcd->ethresh = KMAXDIST; - kcd->extend = 1; + kcd->extend = true; knife_recalc_projmat(kcd); @@ -3013,7 +3027,8 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) kcd->kedgefacemap = BLI_ghash_ptr_new("knife origvertmap"); /* cut all the way through the mesh if use_occlude_geometry button not pushed */ - kcd->cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + kcd->is_interactive = is_interactive; + kcd->cut_through = cut_through; kcd->only_select = only_select; /* can't usefully select resulting edges in face mode */ @@ -3022,9 +3037,11 @@ static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) knife_pos_data_clear(&kcd->curr); knife_pos_data_clear(&kcd->prev); - knife_init_colors(&kcd->colors); + if (is_interactive) { + kcd->draw_handle = ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); - return 1; + knife_init_colors(&kcd->colors); + } } static int knifetool_cancel(bContext *C, wmOperator *op) @@ -3034,21 +3051,25 @@ static int knifetool_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int knifetool_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + const bool only_select = RNA_boolean_get(op->ptr, "only_selected"); + const bool cut_through = !RNA_boolean_get(op->ptr, "use_occlude_geometry"); + KnifeTool_OpData *kcd; view3d_operator_needs_opengl(C); - if (!knifetool_init(C, op, 0)) - return OPERATOR_CANCELLED; + /* alloc new customdata */ + kcd = op->customdata = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through, true); /* add a modal handler for this operator - handles loop selection */ WM_cursor_modal(CTX_wm_window(C), BC_KNIFECURSOR); WM_event_add_modal_handler(C, op); - kcd = op->customdata; - knifetool_update_mval(kcd, evt->mval); + knifetool_update_mval_i(kcd, event->mval); knife_update_header(C, kcd); @@ -3119,11 +3140,11 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) +static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); KnifeTool_OpData *kcd = op->customdata; - int do_refresh = FALSE; + bool do_refresh = false; if (!obedit || obedit->type != OB_MESH || BMEdit_FromObject(obedit) != kcd->em) { knifetool_exit(C, op); @@ -3158,7 +3179,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_FINISHED; case KNF_MODAL_MIDPOINT_ON: - kcd->snap_midpoints = 1; + kcd->snap_midpoints = true; knife_recalc_projmat(kcd); knife_update_active(kcd); @@ -3167,7 +3188,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) do_refresh = TRUE; break; case KNF_MODAL_MIDPOINT_OFF: - kcd->snap_midpoints = 0; + kcd->snap_midpoints = false; knife_recalc_projmat(kcd); knife_update_active(kcd); @@ -3177,13 +3198,13 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) break; case KNF_MODEL_IGNORE_SNAP_ON: ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1; + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = true; knife_update_header(C, kcd); do_refresh = TRUE; break; case KNF_MODEL_IGNORE_SNAP_OFF: ED_region_tag_redraw(kcd->ar); - kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0; + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = false; knife_update_header(C, kcd); do_refresh = TRUE; break; @@ -3241,7 +3262,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) case MOUSEMOVE: /* mouse moved somewhere to select another loop */ if (kcd->mode != MODE_PANNING) { - knifetool_update_mval(kcd, event->mval); + knifetool_update_mval_i(kcd, event->mval); } break; @@ -3251,7 +3272,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, wmEvent *event) if (do_refresh) { /* we don't really need to update mval, * but this happens to be the best way to refresh at the moment */ - knifetool_update_mval(kcd, event->mval); + knifetool_update_mval_i(kcd, event->mval); } /* keep going until the user confirms */ @@ -3277,3 +3298,229 @@ void MESH_OT_knife_tool(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry"); RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry"); } + + +/* -------------------------------------------------------------------- */ +/* Knife tool as a utility function + * that can be used for internal slicing operations */ + +/** + * Return a point inside the face. + * + * tessellation here seems way overkill, + * but without this its very hard to know of a point is inside the face + */ +static void edvm_mesh_knife_face_point(BMFace *f, float r_cent[3]) +{ + int tottri = f->len - 2; + BMLoop **loops = BLI_array_alloca(loops, f->len); + int (*index)[3] = BLI_array_alloca(index, tottri); + int j; + + float const *best_co[3] = {NULL}; + float best_area = -1.0f; + bool ok = false; + + tottri = BM_face_calc_tessellation(f, loops, index); + BLI_assert(tottri <= f->len - 2); + + for (j = 0; j < tottri; j++) { + const float *p1 = loops[index[j][0]]->v->co; + const float *p2 = loops[index[j][1]]->v->co; + const float *p3 = loops[index[j][2]]->v->co; + float area; + + float cross[3]; + cross_v3_v3v3(cross, p2, p3); + area = fabsf(dot_v3v3(p1, cross)); + if (area > best_area) { + best_co[0] = p1; + best_co[1] = p2; + best_co[2] = p3; + best_area = area; + ok = true; + } + } + + if (ok) { + mid_v3_v3v3v3(r_cent, best_co[0], best_co[1], best_co[2]); + } + else { + mid_v3_v3v3v3(r_cent, loops[0]->v->co, loops[1]->v->co, loops[2]->v->co); + } +} + +static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4]) +{ + float cent_ss[2]; + float cent[3]; + + edvm_mesh_knife_face_point(f, cent); + + ED_view3d_project_float_v2_m4(ar, cent, cent_ss, projmat); + + /* check */ + { + LinkNode *p = polys; + int isect = 0; + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + isect += (int)isect_point_poly_v2(cent_ss, mval_fl, mval_tot - 1); + p = p->next; + } + + if (isect % 2) { + return true; + } + } + + return false; +} + +/** + * \param use_tag When set, tag all faces inside the polylines. + */ +void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag) +{ + KnifeTool_OpData *kcd; + + view3d_operator_needs_opengl(C); + + /* init */ + { + const bool only_select = false; + const bool cut_through = false; + const bool is_interactive = false; /* can enable for testing */ + + kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__); + + knifetool_init(C, kcd, only_select, cut_through, is_interactive); + + kcd->ignore_edge_snapping = true; + kcd->ignore_vert_snapping = true; + + if (use_tag) { + BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false); + } + } + + /* execute */ + { + LinkNode *p = polys; + + knife_recalc_projmat(kcd); + + while (p) { + const float (*mval_fl)[2] = p->link; + const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl); + int i; + + for (i = 0; i < mval_tot; i++) { + knifetool_update_mval(kcd, mval_fl[i]); + if (i == 0) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + else { + knife_add_cut(kcd); + } + } + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + p = p->next; + } + } + + /* finish */ + { + knifetool_finish_ex(kcd); + + /* tag faces inside! */ + if (use_tag) { + BMesh *bm = kcd->em->bm; + float projmat[4][4]; + + BMEdge *e; + BMIter iter; + + bool keep_search; + + ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat); + + /* use face-loop tag to store if we have intersected */ +#define F_ISECT_IS_UNKNOWN(f) BM_elem_flag_test(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) +#define F_ISECT_SET_UNKNOWN(f) BM_elem_flag_enable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) +#define F_ISECT_SET_OUTSIDE(f) BM_elem_flag_disable(BM_FACE_FIRST_LOOP(f), BM_ELEM_TAG) + { + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + F_ISECT_SET_UNKNOWN(f); + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + } + + /* tag all faces linked to cut edges */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + /* check are we tagged?, then we are an original face */ + if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { + BMFace *f; + BMIter fiter; + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + } + } + } + + /* expand tags for faces which are not cut, but are inside the polys */ + do { + BMFace *f; + keep_search = false; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) { + /* am I connected to a tagged face via an un-tagged edge (ie, not across a cut) */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + bool found = false; + + do { + if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { + /* now check if the adjacent faces is tagged */ + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + found = true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && (found == false)); + } + } + } while ((l_iter = l_iter->next) != l_first && (found == false)); + + if (found) { + if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + keep_search = true; + } + else { + /* don't loose time on this face again, set it as outside */ + F_ISECT_SET_OUTSIDE(f); + } + } + } + } + } while (keep_search); + +#undef F_ISECT_IS_UNKNOWN +#undef F_ISECT_SET_UNKNOWN +#undef F_ISECT_SET_OUTSIDE + + } + + knifetool_exit_ex(C, kcd); + kcd = NULL; + } +} diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c new file mode 100644 index 00000000000..c581ce5a2e8 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -0,0 +1,168 @@ +/* + * ***** 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. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_knife_project.c + * \ingroup edmesh + */ + +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" + +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_tessmesh.h" +#include "BKE_report.h" + +#include "MEM_guardedalloc.h" + +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "mesh_intern.h" + + +static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys) +{ + DerivedMesh *dm; + bool dm_needsFree; + + if (ob->type == OB_MESH || ob->derivedFinal) { + dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); + dm_needsFree = false; + } + else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { + dm = CDDM_from_curve(ob); + dm_needsFree = true; + } + else { + dm = NULL; + } + + if (dm) { + ListBase nurbslist = {NULL, NULL}; + float projmat[4][4]; + + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */ + BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */ + + ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat); + + if (nurbslist.first) { + Nurb *nu; + for (nu = nurbslist.first; nu; nu = nu->next) { + if (nu->bp) { + int a; + BPoint *bp; + bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0; + float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__); + + for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) { + ED_view3d_project_float_v3_m4(ar, bp->vec, mval[a], projmat); + } + if (is_cyclic) { + copy_v2_v2(mval[a], mval[0]); + } + + BLI_linklist_prepend(&polys, mval); + } + } + } + + BKE_nurbList_free(&nurbslist); + + if (dm_needsFree) { + dm->release(dm); + } + } + + + return polys; +} + +static int knifeproject_exec(bContext *C, wmOperator *op) +{ + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + + LinkNode *polys = NULL; + + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + { + if (ob != obedit) { + polys = knifeproject_poly_from_object(ar, scene, ob, polys); + } + } + CTX_DATA_END; + + if (polys) { + EDBM_mesh_knife(C, polys, true); + + /* select only tagged faces */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG); + + BM_mesh_select_mode_flush(em->bm); + + BLI_linklist_freeN(polys); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection"); + return OPERATOR_CANCELLED; + } +} + +void MESH_OT_knife_project(wmOperatorType *ot) +{ + /* description */ + ot->name = "Knife Project"; + ot->idname = "MESH_OT_knife_project"; + ot->description = "Use other objects outlines & boundaries to project knife cuts"; + + /* callbacks */ + ot->exec = knifeproject_exec; + ot->poll = ED_operator_editmesh_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; +} + diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 83542915ec2..5b9864ca239 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -385,7 +385,7 @@ static int ringcut_cancel(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) +static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ScrArea *sa = CTX_wm_area(C); Object *obedit = CTX_data_edit_object(C); @@ -405,8 +405,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) WM_event_add_modal_handler(C, op); lcd = op->customdata; - lcd->vc.mval[0] = evt->mval[0]; - lcd->vc.mval[1] = evt->mval[1]; + copy_v2_v2_int(lcd->vc.mval, event->mval); edge = EDBM_edge_find_nearest(&lcd->vc, &dist); if (edge != lcd->eed) { @@ -419,7 +418,7 @@ static int ringcut_invoke(bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_RUNNING_MODAL; } -static int loopcut_modal(bContext *C, wmOperator *op, wmEvent *event) +static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event) { float smoothness = RNA_float_get(op->ptr, "smoothness"); int cuts = RNA_int_get(op->ptr, "number_cuts"); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 6cbf5e88cee..8198e088e5a 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -33,9 +33,6 @@ #include "DNA_object_types.h" -#include "RNA_define.h" -#include "RNA_access.h" - #include "BLI_math.h" #include "BLI_array.h" @@ -43,6 +40,9 @@ #include "BKE_report.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" + #include "WM_types.h" #include "ED_mesh.h" @@ -499,16 +499,9 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); } else { - if (v_shared == f_verts[0]) { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); - } - else { - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; - BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); - } + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next; + BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); } } @@ -538,7 +531,7 @@ static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op) /** * This is the main vert ripping function (rip when one vertex is selected) */ -static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *event) { const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; @@ -860,7 +853,7 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) /** * This is the main edge ripping function */ -static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, const wmEvent *event) { const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); UnorderedLoopPair *fill_uloop_pairs = NULL; @@ -988,7 +981,7 @@ static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) } /* based on mouse cursor position, it defines how is being ripped */ -static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 1016c08e1c4..a1c302c6a63 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -66,6 +66,8 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "GPU_extensions.h" + #include "mesh_intern.h" #include "UI_resources.h" @@ -253,6 +255,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short dr = buf->rect; + if (vc->rv3d->gpuoffscreen) + GPU_offscreen_bind(vc->rv3d->gpuoffscreen); + /* draw the mask */ glDisable(GL_DEPTH_TEST); @@ -270,6 +275,9 @@ int EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short glFinish(); /* to be sure readpixels sees mask */ + if (vc->rv3d->gpuoffscreen) + GPU_offscreen_unbind(vc->rv3d->gpuoffscreen); + /* grab mask */ bufmask = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); @@ -308,8 +316,10 @@ int EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads) return 0; } } - else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) return 0; - + else if (vc->v3d->drawtype < OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT) == 0) { + return 0; + } + xmin = xs - rads; xmax = xs + rads; ymin = ys - rads; ymax = ys + rads; buf = view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); @@ -932,7 +942,7 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op) } } -static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* detecting these options based on shift/ctrl here is weak, but it's done * to make this work when clicking buttons or menus */ @@ -1084,7 +1094,7 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot) /* ***************** loop select (non modal) ************** */ -static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short deselect, short toggle, short ring) +static void mouse_mesh_loop(bContext *C, const int mval[2], short extend, short deselect, short toggle, short ring) { ViewContext vc; BMEditMesh *em; @@ -1171,7 +1181,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele /* Select the face of eed which is the nearest of mouse. */ BMFace *f, *efa = NULL; BMIter iterf; - float best_dist = MAXFLOAT; + float best_dist = FLT_MAX; /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); @@ -1203,7 +1213,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele } } -static int edbm_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { view3d_operator_needs_opengl(C); @@ -1754,7 +1764,7 @@ static int mouse_mesh_shortest_path_face(ViewContext *vc) /* ******************* operator for edge and face tag ****************** */ -static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { ViewContext vc; BMEditMesh *em; @@ -2252,7 +2262,7 @@ static void linked_limit_default(bContext *C, wmOperator *op) } } -static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *obedit = CTX_data_edit_object(C); ViewContext vc; @@ -2995,6 +3005,59 @@ void MESH_OT_select_random(wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); } +static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + BMVert *eve; + BMIter iter; + + if (!em->selectmode == SCE_SELECT_VERTEX) { + BKE_report(op->reports, RPT_ERROR, "Does not work out of vertex selection mode"); + return OPERATOR_CANCELLED; + } + + if (obedit->defbase.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object"); + return OPERATOR_CANCELLED; + } + + if (!RNA_boolean_get(op->ptr, "extend")) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + /* no dv or dv set with no weight */ + if (dv == NULL || (dv && dv->dw == NULL)) { + BM_vert_select_set(em->bm, eve, true); + } + } + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_ungrouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Ungrouped"; + ot->idname = "MESH_OT_select_ungrouped"; + ot->description = "Select vertices without a group"; + + /* api callbacks */ + ot->exec = edbm_select_ungrouped_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection"); +} + static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index c35f942cf33..36a1d30c85e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -39,10 +39,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "RNA_define.h" -#include "RNA_access.h" -#include "RNA_enum_types.h" - #include "BLI_blenlib.h" #include "BLI_noise.h" #include "BLI_math.h" @@ -59,6 +55,10 @@ #include "BKE_main.h" #include "BKE_tessmesh.h" +#include "RNA_define.h" +#include "RNA_access.h" +#include "RNA_enum_types.h" + #include "WM_api.h" #include "WM_types.h" @@ -77,6 +77,8 @@ #include "mesh_intern.h" +#define USE_FACE_CREATE_SEL_EXTEND + #define MVAL_PIXEL_MARGIN 5.0f /* allow accumulated normals to form a new direction but don't @@ -333,10 +335,7 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, mult_m4_m4m4(mtx, imtx, obedit->obmat); } - for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); - edge; - edge = BM_iter_step(&iter)) - { + BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(edge, hflag) && BM_edge_is_boundary(edge) && BM_elem_flag_test(edge->l->f, hflag)) @@ -779,7 +778,7 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) } /* *************** add-click-mesh (extrude) operator ************** */ -static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; BMVert *v1; @@ -863,7 +862,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); /* view space */ - view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); + view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, true); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); @@ -912,7 +911,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent BMOIter oiter; copy_v3_v3(min, curs); - view3d_get_view_aligned_coordinate(&vc, min, event->mval, FALSE); + view3d_get_view_aligned_coordinate(vc.ar, min, event->mval, false); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); mul_m4_v3(vc.obedit->imat, min); // back in object space @@ -1099,6 +1098,140 @@ static int edbm_add_edge_face__smooth_get(BMesh *bm) return (vote_on_smooth[0] < vote_on_smooth[1]); } +#ifdef USE_FACE_CREATE_SEL_EXTEND +/** + * Function used to get a fixed number of edges linked to a vertex that passes a test function. + * This is used so we can request all boundary edges connected to a vertex for eg. + */ +static int edbm_add_edge_face_exec__vert_edge_lookup(BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len, + bool (* func)(BMEdge *)) +{ + BMIter iter; + BMEdge *e_iter; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) { + if ((e_used == NULL) || (e_used != e_iter)) { + if (func(e_iter)) { + e_arr[i++] = e_iter; + if (i >= e_arr_len) { + break; + } + } + } + } + } + return i; +} + +static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm) +{ + BMIter iter; + bool found = false; + + if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMVert *v; + + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + found = true; + break; + } + } + + if (found) { + BMEdge *ed_pair[3]; + if ( + ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) && + (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) + ) + { + BMEdge *e_other = BM_edge_exists(BM_edge_other_vert(ed_pair[0], v), + BM_edge_other_vert(ed_pair[1], v)); + BM_edge_select_set(bm, ed_pair[0], true); + BM_edge_select_set(bm, ed_pair[1], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)v; + } + } + } + else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) { + /* first look for 2 boundary edges */ + BMEdge *e; + + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + found = true; + break; + } + } + if (found) { + BMEdge *ed_pair_v1[2]; + BMEdge *ed_pair_v2[2]; + if ( + ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_wire) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_wire) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) || + + ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_v1, 2, BM_edge_is_boundary) == 1) && + (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_v2, 2, BM_edge_is_boundary) == 1) && + (BM_edge_share_face_check(e, ed_pair_v1[0]) == false) && + (BM_edge_share_face_check(e, ed_pair_v2[0]) == false)) + ) + { + BMVert *v1_other = BM_edge_other_vert(ed_pair_v1[0], e->v1); + BMVert *v2_other = BM_edge_other_vert(ed_pair_v2[0], e->v2); + BMEdge *e_other = (v1_other != v2_other) ? BM_edge_exists(v1_other, v2_other) : NULL; + BM_edge_select_set(bm, ed_pair_v1[0], true); + BM_edge_select_set(bm, ed_pair_v2[0], true); + if (e_other) { + BM_edge_select_set(bm, e_other, true); + } + return (BMElem *)e; + } + } + } + + return NULL; +} +static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f) +{ + /* now we need to find the edge that isnt connected to this element */ + BM_select_history_clear(bm); + + if (ele_desel->head.htype == BM_VERT) { + BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel); + BLI_assert(f->len == 3); + BM_face_select_set(bm, f, false); + BM_vert_select_set(bm, (BMVert *)ele_desel, false); + + BM_edge_select_set(bm, l->next->e, true); + BM_select_history_store(bm, l->next->e); + } + else { + BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel); + BLI_assert(f->len == 4 || f->len == 3); + BM_face_select_set(bm, f, false); + BM_edge_select_set(bm, (BMEdge *)ele_desel, false); + if (f->len == 4) { + BM_edge_select_set(bm, l->next->next->e, true); + BM_select_history_store(bm, l->next->next->e); + } + else { + BM_vert_select_set(bm, l->next->next->v, true); + BM_select_history_store(bm, l->next->next->v); + } + } +} +#endif /* USE_FACE_CREATE_SEL_EXTEND */ + static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) { BMOperator bmop; @@ -1107,6 +1240,15 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) const short use_smooth = edbm_add_edge_face__smooth_get(em->bm); /* when this is used to dissolve we could avoid this, but checking isnt too slow */ +#ifdef USE_FACE_CREATE_SEL_EXTEND + BMElem *ele_desel; + BMFace *ele_desel_face; + + /* be extra clever, figure out if a partial selection should be extended so we can create geometry + * with single vert or single edge selection */ + ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm); +#endif + if (!EDBM_op_init(em, &bmop, op, "contextual_create geom=%hfev mat_nr=%i use_smooth=%b", BM_ELEM_SELECT, em->mat_nr, use_smooth)) @@ -1115,8 +1257,22 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) } BMO_op_exec(em->bm, &bmop); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, TRUE); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, TRUE); + +#ifdef USE_FACE_CREATE_SEL_EXTEND + /* normally we would want to leave the new geometry selected, + * but being able to press F many times to add geometry is too useful! */ + if (ele_desel && + (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) && + (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out"))) + { + edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face); + } + else +#endif + { + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + } if (!EDBM_op_finish(em, &bmop, op, TRUE)) { return OPERATOR_CANCELLED; @@ -1355,7 +1511,7 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { WM_cursor_wait(1); edbm_duplicate_exec(C, op); @@ -2005,12 +2161,22 @@ static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *w BMVert *mergevert; BMEditSelection *ese; + /* operator could be called directly from shortcut or python, + * so do extra check for data here + */ + /* do sanity check in mergemenu in edit.c ?*/ if (first == 0) { + if (!em->bm->selected.last || ((BMEditSelection *)em->bm->selected.last)->htype != BM_VERT) + return OPERATOR_CANCELLED; + ese = em->bm->selected.last; mergevert = (BMVert *)ese->ele; } else { + if (!em->bm->selected.first || ((BMEditSelection *)em->bm->selected.first)->htype != BM_VERT) + return OPERATOR_CANCELLED; + ese = em->bm->selected.first; mergevert = (BMVert *)ese->ele; } @@ -2293,8 +2459,12 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) continue; - if (svert == NULL) svert = eve; - else if (evert == NULL) evert = eve; + if (svert == NULL) { + svert = eve; + } + else if (evert == NULL) { + evert = eve; + } else { /* more than two vertices are selected, * show warning message and cancel operator */ @@ -3225,6 +3395,16 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) Base *base = CTX_data_active_base(C); BMEditMesh *em = BMEdit_FromObject(base->object); + if (type == 0) { + if ((em->bm->totvertsel == 0) && + (em->bm->totedgesel == 0) && + (em->bm->totfacesel == 0)) + { + BKE_report(op->reports, RPT_ERROR, "Nothing selected"); + return OPERATOR_CANCELLED; + } + } + /* editmode separate */ if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm); else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm); @@ -3689,7 +3869,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) } /* get center and axis, in global coords */ -static int edbm_spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -3759,9 +3939,10 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) /* find two vertices with valence count == 1, more or less is wrong */ v1 = NULL; v2 = NULL; - for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter)) { + + BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { valence = 0; - for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve); eed; eed = BM_iter_step(&eiter)) { + BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { valence++; } @@ -3812,7 +3993,7 @@ static int edbm_screw_exec(bContext *C, wmOperator *op) } /* get center and axis, in global coords */ -static int edbm_screw_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +static int edbm_screw_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4505,7 +4686,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop int action = RNA_enum_get(ptr, "type"); /* Only show seed for randomize action! */ - if (strcmp(prop_id, "seed") == 0) { + if (STREQ(prop_id, "seed")) { if (action == SRT_RANDOMIZE) return TRUE; else @@ -4513,7 +4694,7 @@ static int edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop } /* Hide seed for reverse and randomize actions! */ - if (strcmp(prop_id, "reverse") == 0) { + if (STREQ(prop_id, "reverse")) { if (ELEM(action, SRT_RANDOMIZE, SRT_REVERSE)) return FALSE; else @@ -4804,7 +4985,7 @@ static int edbm_bevel_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* TODO make modal keymap (see fly mode) */ RegionView3D *rv3d = CTX_wm_region_view3d(C); @@ -4841,7 +5022,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) +static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int use_dist = TRUE; @@ -4880,7 +5061,7 @@ static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) return factor; } -static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { BevelData *opdata = op->customdata; int segments = RNA_int_get(op->ptr, "segments"); @@ -5186,7 +5367,7 @@ static int edbm_inset_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RegionView3D *rv3d = CTX_wm_region_view3d(C); InsetData *opdata; @@ -5216,7 +5397,7 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int edbm_inset_modal(bContext *C, wmOperator *op, wmEvent *event) +static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) { InsetData *opdata = op->customdata; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 0c9a5aab537..99f526f95f3 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -36,6 +36,7 @@ #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "BLI_utildefines.h" #include "BLI_path_util.h" #include "BLI_array.h" #include "BLI_math.h" @@ -570,7 +571,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event) +static int drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -884,7 +885,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface) } if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) - BKE_mesh_calc_edges(mesh, calc_edges); + BKE_mesh_calc_edges(mesh, calc_edges, true); if (calc_tessface) { if (tessface_input == FALSE) { diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index fe4917acdac..5dab022dd2f 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -48,6 +48,7 @@ struct wmKeyConfig; struct wmKeyMap; struct wmOperator; struct wmOperatorType; +struct LinkNode; /* ******************** editmesh_utils.c */ @@ -77,7 +78,6 @@ int EDBM_op_init(struct BMEditMesh *em, struct BMOperator *bmop, int EDBM_op_finish(struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, const int report); -void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); void EDBM_stats_update(struct BMEditMesh *em); /* ******************** editface.c */ @@ -128,6 +128,7 @@ void MESH_OT_select_shortest_path(struct wmOperatorType *ot); void MESH_OT_select_similar(struct wmOperatorType *ot); void MESH_OT_select_mode(struct wmOperatorType *ot); void MESH_OT_select_random(struct wmOperatorType *ot); +void MESH_OT_select_ungrouped(struct wmOperatorType *ot); void MESH_OT_loop_multi_select(struct wmOperatorType *ot); void MESH_OT_mark_seam(struct wmOperatorType *ot); void MESH_OT_mark_sharp(struct wmOperatorType *ot); @@ -211,6 +212,8 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); void MESH_OT_knife_tool(struct wmOperatorType *ot); +void MESH_OT_knife_project(wmOperatorType *ot); + void MESH_OT_bevel(struct wmOperatorType *ot); void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); @@ -228,4 +231,6 @@ void MESH_OT_navmesh_face_add(struct wmOperatorType *ot); void MESH_OT_navmesh_reset(struct wmOperatorType *ot); void MESH_OT_navmesh_clear(struct wmOperatorType *ot); +void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag); + #endif /* __MESH_INTERN_H__ */ diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 140681304b2..cf3877a8d93 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -59,6 +59,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_linked); WM_operatortype_append(MESH_OT_select_linked_pick); WM_operatortype_append(MESH_OT_select_random); + WM_operatortype_append(MESH_OT_select_ungrouped); WM_operatortype_append(MESH_OT_hide); WM_operatortype_append(MESH_OT_reveal); WM_operatortype_append(MESH_OT_select_face_by_sides); @@ -155,6 +156,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_nth); WM_operatortype_append(MESH_OT_vert_connect); WM_operatortype_append(MESH_OT_knife_tool); + WM_operatortype_append(MESH_OT_knife_project); WM_operatortype_append(MESH_OT_bevel); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 378f6374336..3d4d204299f 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -789,7 +789,9 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, const float c return (*bt)->index[a]; } } - else return -1; + else { + return -1; + } } if ( (*bt)->next) return mesh_octree_find_index(&(*bt)->next, mvert, co); |