Merged changes in the trunk up to revision 55357.
[blender-staging.git] / source / blender / editors / mesh / editmesh_select.c
index 1c9fc75642645ea540c43bac48f7d954211e18bc..a1c302c6a63f102b1211673248e8772070cacd0f 100644 (file)
@@ -40,9 +40,9 @@
 
 #include "BKE_context.h"
 #include "BKE_displist.h"
-#include "BKE_depsgraph.h"
 #include "BKE_report.h"
 #include "BKE_paint.h"
+#include "BKE_mesh.h"
 #include "BKE_tessmesh.h"
 
 #include "IMB_imbuf_types.h"
@@ -56,9 +56,7 @@
 
 #include "ED_mesh.h"
 #include "ED_screen.h"
-#include "ED_util.h"
 #include "ED_uvedit.h"
-#include "ED_object.h"
 #include "ED_view3d.h"
 
 #include "BIF_gl.h"
@@ -66,6 +64,9 @@
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
 #include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "GPU_extensions.h"
 
 #include "mesh_intern.h"
 
@@ -107,21 +108,23 @@ void EDBM_select_mirrored(Object *UNUSED(obedit), BMEditMesh *em, int extend)
 
 void EDBM_automerge(Scene *scene, Object *obedit, int update)
 {
-       BMEditMesh *em;
        
        if ((scene->toolsettings->automerge) &&
            (obedit && obedit->type == OB_MESH))
        {
-               em = BMEdit_FromObject(obedit);
-               if (!em)
+               int ok;
+               BMEditMesh *em = BMEdit_FromObject(obedit);
+
+               if (!em) {
                        return;
+               }
 
-               BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
-                            "automerge verts=%hv dist=%f",
-                            BM_ELEM_SELECT, scene->toolsettings->doublimit);
-               if (update) {
-                       DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
-                       BMEdit_RecalcTessellation(em);
+               ok = BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
+                                 "automerge verts=%hv dist=%f",
+                                 BM_ELEM_SELECT, scene->toolsettings->doublimit);
+
+               if (LIKELY(ok) && update) {
+                       EDBM_update_generic(em, TRUE, TRUE);
                }
        }
 }
@@ -252,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);
        
@@ -269,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);
 
@@ -307,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);
@@ -573,7 +584,7 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *r_dist)
 
                        data.mval_fl[0] = vc->mval[0];
                        data.mval_fl[1] = vc->mval[1];
-                       data.dist = 0x7FFF;     /* largest short */
+                       data.dist = FLT_MAX;
                        data.toFace = efa;
 
                        mesh_foreachScreenFace(vc, findnearestface__getDistance, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -681,6 +692,9 @@ static EnumPropertyItem prop_similar_types[] = {
        {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
        {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
        {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+#ifdef WITH_FREESTYLE
+       {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
+#endif
 
        {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
        {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
@@ -689,6 +703,9 @@ static EnumPropertyItem prop_similar_types[] = {
        {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
        {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
        {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+#ifdef WITH_FREESTYLE
+       {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
+#endif
 
        {0, NULL, 0, NULL, NULL}
 };
@@ -725,7 +742,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       EDBM_update_generic(C, em, FALSE);
+       EDBM_update_generic(em, FALSE, FALSE);
 
        /* we succeeded */
        return OPERATOR_FINISHED;
@@ -767,7 +784,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       EDBM_update_generic(C, em, FALSE);
+       EDBM_update_generic(em, FALSE, FALSE);
 
        /* we succeeded */
        return OPERATOR_FINISHED;
@@ -812,7 +829,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
 
        EDBM_selectmode_flush(em);
 
-       EDBM_update_generic(C, em, FALSE);
+       EDBM_update_generic(em, FALSE, FALSE);
 
        /* we succeeded */
        return OPERATOR_FINISHED;
@@ -863,7 +880,11 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS
                        }
                }
                else if (em->selectmode & SCE_SELECT_FACE) {
+#ifdef WITH_FREESTYLE
+                       for (a = SIMFACE_MATERIAL; a <= SIMFACE_FREESTYLE; a++) {
+#else
                        for (a = SIMFACE_MATERIAL; a <= SIMFACE_COPLANAR; a++) {
+#endif
                                RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
                        }
                }
@@ -921,11 +942,15 @@ 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)
 {
-       // RNA_enum_set(op->ptr, "type");  /* type must be set already */
-       RNA_boolean_set(op->ptr, "use_extend", event->shift);
-       RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+       /* detecting these options based on shift/ctrl here is weak, but it's done
+        * to make this work when clicking buttons or menus */
+       if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
+               RNA_boolean_set(op->ptr, "use_extend", event->shift);
+       if (!RNA_struct_property_is_set(op->ptr, "use_expand"))
+               RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+
        return edbm_select_mode_exec(C, op);
 }
 
@@ -985,8 +1010,8 @@ static void walker_select(BMEditMesh *em, int walkercode, void *start, int selec
                 BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
                 BMW_FLAG_TEST_HIDDEN,
                 BMW_NIL_LAY);
-       ele = BMW_begin(&walker, start);
-       for (; ele; ele = BMW_step(&walker)) {
+
+       for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) {
                if (!select) {
                        BM_select_history_remove(bm, ele);
                }
@@ -1069,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;
@@ -1136,11 +1161,11 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele
                                /* We can't be sure this has already been set... */
                                ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
 
-                               if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                               if (ED_view3d_project_float_object(vc.ar, eed->v1->co, v1_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
                                        length_1 = len_squared_v2v2(mvalf, v1_co);
                                }
 
-                               if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                               if (ED_view3d_project_float_object(vc.ar, eed->v2->co, v2_co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
                                        length_2 = len_squared_v2v2(mvalf, v2_co);
                                }
 #if 0
@@ -1156,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);
@@ -1167,7 +1192,7 @@ static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short desele
                                                float co[2], tdist;
 
                                                BM_face_calc_center_mean(f, cent);
-                                               if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+                                               if (ED_view3d_project_float_object(vc.ar, cent, co, V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) {
                                                        tdist = len_squared_v2v2(mvalf, co);
                                                        if (tdist < best_dist) {
 /*                                                             printf("Best face: %p (%f)\n", f, tdist);*/
@@ -1188,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);
@@ -1319,6 +1344,23 @@ static void edgetag_context_set(BMesh *bm, Scene *scene, BMEdge *e, int val)
                case EDGE_MODE_TAG_BEVEL:
                        BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
                        break;
+#ifdef WITH_FREESTYLE
+               case EDGE_MODE_TAG_FREESTYLE:
+                       {
+                               FreestyleEdge *fed;
+
+                               if (!CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE)) {
+                                       BM_data_layer_add(bm, &bm->pdata, CD_FREESTYLE_FACE);
+                               }
+
+                               fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
+                               if (!val)
+                                       fed->flag &= ~FREESTYLE_EDGE_MARK;
+                               else
+                                       fed->flag |= FREESTYLE_EDGE_MARK;
+                       }
+                       break;
+#endif
        }
 }
 
@@ -1335,10 +1377,34 @@ static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
                        return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? TRUE : FALSE;
                case EDGE_MODE_TAG_BEVEL:
                        return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? TRUE : FALSE;
+#ifdef WITH_FREESTYLE
+               case EDGE_MODE_TAG_FREESTYLE:
+                       {
+                               FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
+                               return (!fed) ? FALSE : (fed->flag & FREESTYLE_EDGE_MARK) ? TRUE : FALSE;
+                       }
+                       break;
+#endif
        }
        return 0;
 }
 
+static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
+{
+       BMesh *bm = me->edit_btmesh->bm;
+
+       switch (scene->toolsettings->edge_mode) {
+               case EDGE_MODE_TAG_CREASE:
+                       BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
+                       break;
+               case EDGE_MODE_TAG_BEVEL:
+                       BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+                       break;
+               default:
+                       break;
+       }
+}
+
 static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst)
 {
        /* BM_ELEM_TAG flag is used to store visited edges */
@@ -1352,6 +1418,8 @@ static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge
        /* note, would pass BM_EDGE except we are looping over all edges anyway */
        BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
 
+       edgetag_ensure_cd_flag(scene, OBACT->data);
+
        BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
                if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) {
                        BM_elem_flag_disable(e, BM_ELEM_TAG);
@@ -1431,7 +1499,7 @@ static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge
 /* ******************* mesh shortest path select, uses prev-selected edge ****************** */
 
 /* since you want to create paths with multiple selects, it doesn't have extend option */
-static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
+static int mouse_mesh_shortest_path_edge(ViewContext *vc)
 {
        BMEditMesh *em = vc->em;
        BMEdge *e_dst;
@@ -1440,7 +1508,7 @@ static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
        e_dst = EDBM_edge_find_nearest(vc, &dist);
        if (e_dst) {
                Mesh *me = vc->obedit->data;
-               int path = 0;
+               bool is_path = false;
                
                if (em->bm->selected.last) {
                        BMEditSelection *ese = em->bm->selected.last;
@@ -1451,13 +1519,14 @@ static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
                                if (e_act != e_dst) {
                                        if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) {
                                                BM_select_history_remove(em->bm, e_act);
-                                               path = 1;
+                                               is_path = true;
                                        }
                                }
                        }
                }
-               if (path == 0) {
+               if (is_path == false) {
                        int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0);
+                       edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
                        edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */
                }
                
@@ -1470,7 +1539,7 @@ static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
                        BM_select_history_store(em->bm, e_dst);
        
                /* force drawmode for mesh */
-               switch (CTX_data_tool_settings(C)->edge_mode) {
+               switch (vc->scene->toolsettings->edge_mode) {
                        
                        case EDGE_MODE_TAG_SEAM:
                                me->drawflag |= ME_DRAWSEAMS;
@@ -1485,9 +1554,14 @@ static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc)
                        case EDGE_MODE_TAG_BEVEL:
                                me->drawflag |= ME_DRAWBWEIGHTS;
                                break;
+#ifdef WITH_FREESTYLE
+                       case EDGE_MODE_TAG_FREESTYLE:
+                               me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+                               break;
+#endif
                }
                
-               EDBM_update_generic(C, em, FALSE);
+               EDBM_update_generic(em, FALSE, FALSE);
 
                return TRUE;
        }
@@ -1644,7 +1718,7 @@ static int facetag_shortest_path(Scene *scene, BMesh *bm, BMFace *f_src, BMFace
        return 1;
 }
 
-static int mouse_mesh_shortest_path_face(bContext *C, ViewContext *vc)
+static int mouse_mesh_shortest_path_face(ViewContext *vc)
 {
        BMEditMesh *em = vc->em;
        BMFace *f_dst;
@@ -1678,7 +1752,7 @@ static int mouse_mesh_shortest_path_face(bContext *C, ViewContext *vc)
 
                BM_active_face_set(em->bm, f_dst);
 
-               EDBM_update_generic(C, em, FALSE);
+               EDBM_update_generic(em, FALSE, FALSE);
 
                return TRUE;
        }
@@ -1690,7 +1764,7 @@ static int mouse_mesh_shortest_path_face(bContext *C, 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;
@@ -1703,7 +1777,7 @@ static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op),
        em = vc.em;
 
        if (em->selectmode & SCE_SELECT_EDGE) {
-               if (mouse_mesh_shortest_path_edge(C, &vc)) {
+               if (mouse_mesh_shortest_path_edge(&vc)) {
                        return OPERATOR_FINISHED;
                }
                else {
@@ -1711,7 +1785,7 @@ static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op),
                }
        }
        else if (em->selectmode & SCE_SELECT_FACE) {
-               if (mouse_mesh_shortest_path_face(C, &vc)) {
+               if (mouse_mesh_shortest_path_face(&vc)) {
                        return OPERATOR_FINISHED;
                }
                else {
@@ -1747,7 +1821,7 @@ void MESH_OT_select_shortest_path(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
        /* properties */
-       RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+       RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
 }
 
 /* ************************************************** */
@@ -2188,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;
@@ -2251,8 +2325,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *
                         BMW_FLAG_TEST_HIDDEN,
                         BMW_NIL_LAY);
 
-               e = BMW_begin(&walker, efa);
-               for (; efa; efa = BMW_step(&walker)) {
+               for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
                        BM_face_select_set(bm, efa, sel);
                }
                BMW_end(&walker);
@@ -2273,8 +2346,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *
                         BMW_FLAG_TEST_HIDDEN,
                         BMW_NIL_LAY);
 
-               e = BMW_begin(&walker, eed->v1);
-               for (; e; e = BMW_step(&walker)) {
+               for (e = BMW_begin(&walker, eed->v1); e; e = BMW_step(&walker)) {
                        BM_edge_select_set(bm, e, sel);
                }
                BMW_end(&walker);
@@ -2345,8 +2417,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
 
                BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
                        if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
-                               e = BMW_begin(&walker, efa);
-                               for (; efa; efa = BMW_step(&walker)) {
+                               for (efa = BMW_begin(&walker, efa); efa; efa = BMW_step(&walker)) {
                                        BM_face_select_set(bm, efa, TRUE);
                                }
                        }
@@ -2374,16 +2445,15 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
 
                BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
                        if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
-                               e = BMW_begin(&walker, v);
-                               for (; e; e = BMW_step(&walker)) {
-                                       BM_vert_select_set(em->bm, e->v1, TRUE);
-                                       BM_vert_select_set(em->bm, e->v2, TRUE);
+                               for (e = BMW_begin(&walker, v); e; e = BMW_step(&walker)) {
+                                       BM_edge_select_set(em->bm, e, true);
                                }
                        }
                }
                BMW_end(&walker);
+
+               EDBM_selectmode_flush(em);
        }
-       EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
 
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
@@ -2628,14 +2698,15 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
        int nth = RNA_int_get(op->ptr, "nth");
        int offset = RNA_int_get(op->ptr, "offset");
 
-       offset = MIN2(nth, offset);
+       /* so input of offset zero ends up being (nth - 1) */
+       offset = (offset + (nth - 1)) % nth;
 
        if (edbm_deselect_nth(em, nth, offset) == 0) {
                BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
                return OPERATOR_CANCELLED;
        }
 
-       EDBM_update_generic(C, em, FALSE);
+       EDBM_update_generic(em, FALSE, FALSE);
 
        return OPERATOR_FINISHED;
 }
@@ -2646,7 +2717,7 @@ void MESH_OT_select_nth(wmOperatorType *ot)
        /* identifiers */
        ot->name = "Checker Deselect";
        ot->idname = "MESH_OT_select_nth";
-       ot->description = "Deselect every Nth element starting from a selected vertex, edge or face";
+       ot->description = "Deselect every Nth element starting from the active vertex, edge or face";
 
        /* api callbacks */
        ot->exec = edbm_select_nth_exec;
@@ -2822,6 +2893,9 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
        BMEdge *e;
        BMIter iter;
 
+       if (!RNA_boolean_get(op->ptr, "extend"))
+               EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+
        /* Selects isolated verts, and edges that do not have 2 neighboring
         * faces
         */
@@ -2861,6 +2935,9 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       /* props */
+       RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
 }
 
 static int edbm_select_random_exec(bContext *C, wmOperator *op)
@@ -2925,8 +3002,60 @@ void MESH_OT_select_random(wmOperatorType *ot)
        /* props */
        RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
                                 "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
-       RNA_def_boolean(ot->srna, "extend", 0,
-                       "Extend Selection", "Extend selection instead of deselecting everything first");
+       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))