[Bf-blender-cvs] [219e0155c27] soc-2021-knife-tools: Knife: Added undo functionality

Cian Jinks noreply at git.blender.org
Sun Jul 11 17:38:48 CEST 2021


Commit: 219e0155c270de6104fd07c2937a3ea28ab1b27c
Author: Cian Jinks
Date:   Sun Jul 11 16:33:24 2021 +0100
Branches: soc-2021-knife-tools
https://developer.blender.org/rB219e0155c270de6104fd07c2937a3ea28ab1b27c

Knife: Added undo functionality

Pressing ctrl-z will now undo the most recent cut segment made.
When drag cutting undo reverts each segment of the cut individually.
Currently this breaks visible distance and angle measurements after using undo but a fix will be committed soon.

===================================================================

M	release/scripts/presets/keyconfig/keymap_data/blender_default.py
M	source/blender/editors/mesh/editmesh_knife.c

===================================================================

diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 0d96455735a..25042e9884b 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5365,14 +5365,13 @@ def km_knife_tool_modal_map(_params):
         ("PANNING", {"type": 'MIDDLEMOUSE', "value": 'ANY', "any": True}, None),
         ("ADD_CUT_CLOSED", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "any": True}, None),
         ("ADD_CUT", {"type": 'LEFTMOUSE', "value": 'ANY', "any": True}, None),
+        ("UNDO", {"type": 'Z', "value": 'PRESS', "ctrl": True}, None),
         ("CONFIRM", {"type": 'RET', "value": 'PRESS', "any": True}, None),
         ("CONFIRM", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
         ("CONFIRM", {"type": 'SPACE', "value": 'PRESS', "any": True}, None),
         ("NEW_CUT", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
-        ("SNAP_MIDPOINTS_ON", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
-        ("SNAP_MIDPOINTS_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
-        ("SNAP_MIDPOINTS_ON", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
-        ("SNAP_MIDPOINTS_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
+        ("SNAP_MIDPOINTS_ON", {"type": 'TAB', "value": 'PRESS', "any": True}, None),
+        ("SNAP_MIDPOINTS_OFF", {"type": 'TAB', "value": 'RELEASE', "any": True}, None),
         ("IGNORE_SNAP_ON", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
         ("IGNORE_SNAP_OFF", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
         ("IGNORE_SNAP_ON", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 4ac11ac2af1..76ffb94d8ad 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -38,6 +38,7 @@
 #include "BLI_math.h"
 #include "BLI_memarena.h"
 #include "BLI_smallhash.h"
+#include "BLI_stack.h"
 #include "BLI_string.h"
 
 #include "BLT_translation.h"
@@ -115,6 +116,8 @@ typedef struct KnifeVert {
   float co[3], cageco[3];
   bool is_face, in_space;
   bool is_cut; /* Along a cut created by user input (will draw too). */
+  bool is_invalid;
+  bool is_splitting; /* Created when an edge was split. */
 } KnifeVert;
 
 typedef struct Ref {
@@ -129,6 +132,8 @@ typedef struct KnifeEdge {
 
   BMEdge *e;   /* Non-NULL if this is an original edge. */
   bool is_cut; /* Along a cut created by user input (will draw too). */
+  bool is_invalid;
+  int splits; /* Number of times this edge has been split. */
 } KnifeEdge;
 
 typedef struct KnifeLineHit {
@@ -163,6 +168,13 @@ typedef struct KnifePosData {
   float mval[2]; /* Mouse screen position (may be non-integral if snapped to something). */
 } KnifePosData;
 
+typedef struct KnifeUndoFrame {
+  int cuts;         /* Line hits cause multiple edges/cuts to be created at once. */
+  int splits;       /* Number of edges split. */
+  KnifePosData pos; /* Store previous KnifePosData. */
+
+} KnifeUndoFrame;
+
 /* struct for properties used while drawing */
 typedef struct KnifeTool_OpData {
   ARegion *region;   /* Region that knifetool was activated in. */
@@ -195,6 +207,9 @@ typedef struct KnifeTool_OpData {
   BLI_mempool *kverts;
   BLI_mempool *kedges;
 
+  BLI_Stack *undostack;
+  BLI_Stack *splitstack; /* Store edge splits by #knife_split_edge. */
+
   float vthresh;
   float ethresh;
 
@@ -274,11 +289,14 @@ typedef struct KnifeTool_OpData {
   bool old_stored;
   float corr_prev_cage[3]; /* "knife_start_cut" updates prev.cage breaking angle calculations,
                             * store correct version. */
+
+  KnifeUndoFrame *undo; /* Current undo frame. */
 } KnifeTool_OpData;
 
 enum {
   KNF_MODAL_CANCEL = 1,
   KNF_MODAL_CONFIRM,
+  KNF_MODAL_UNDO,
   KNF_MODAL_MIDPOINT_ON,
   KNF_MODAL_MIDPOINT_OFF,
   KNF_MODAL_NEW_CUT,
@@ -883,7 +901,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
 
     BLI_mempool_iternew(kcd->kedges, &iter);
     for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
-      if (!kfe->is_cut) {
+      if (!kfe->is_cut || kfe->is_invalid) {
         continue;
       }
 
@@ -908,7 +926,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
 
     BLI_mempool_iternew(kcd->kverts, &iter);
     for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
-      if (!kfv->is_cut) {
+      if (!kfv->is_cut || kfv->is_invalid) {
         continue;
       }
 
@@ -957,7 +975,7 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
   BLI_snprintf(
       header,
       sizeof(header),
-      TIP_("%s: confirm, %s: cancel, "
+      TIP_("%s: confirm, %s: cancel, %s: undo, "
            "%s: start/define cut, %s: close cut, %s: new cut, "
            "%s: midpoint snap (%s), %s: ignore snap (%s), "
            "%s: angle constraint %.2f(%.2f) (%s), %s: cut through (%s), "
@@ -965,6 +983,7 @@ static void knife_update_header(bContext *C, wmOperator *op, KnifeTool_OpData *k
            "%s: distance/angle measurements (%s)"),
       WM_MODALKEY(KNF_MODAL_CONFIRM),
       WM_MODALKEY(KNF_MODAL_CANCEL),
+      WM_MODALKEY(KNF_MODAL_UNDO),
       WM_MODALKEY(KNF_MODAL_ADD_CUT),
       WM_MODALKEY(KNF_MODAL_ADD_CUT_CLOSED),
       WM_MODALKEY(KNF_MODAL_NEW_CUT),
@@ -1359,6 +1378,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd,
   BLI_remlink(&kfe->v1->edges, ref);
 
   kfe->v1 = newkfe->v2;
+  kfe->v1->is_splitting = true;
   BLI_addtail(&kfe->v1->edges, ref);
 
   for (ref = kfe->faces.first; ref; ref = ref->next) {
@@ -1370,11 +1390,32 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd,
   newkfe->is_cut = kfe->is_cut;
   newkfe->e = kfe->e;
 
+  newkfe->splits++;
+  kfe->splits++;
+
+  kcd->undo->splits++;
+
+  BLI_stack_push(kcd->splitstack, (void *)&kfe);
+  BLI_stack_push(kcd->splitstack, (void *)&newkfe);
+
   *r_kfe = newkfe;
 
   return newkfe->v2;
 }
 
+/* Rejoin two edges split by #knife_split_edge. */
+static void knife_join_edge(KnifeTool_OpData *kcd, KnifeEdge *newkfe, KnifeEdge *kfe)
+{
+  newkfe->is_invalid = true;
+  newkfe->v2->is_invalid = true;
+
+  kfe->v1 = newkfe->v1;
+
+  kfe->splits--;
+  kfe->v1->is_splitting = false;
+  kfe->v2->is_splitting = false;
+}
+
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -1682,6 +1723,10 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
     bool is_new_edge = false;
     kfe = ref->ref;
 
+    if (kfe->is_invalid) {
+      continue;
+    }
+
     if (kfe->e == NULL) {
       if (kfe->v1->v && kfe->v2->v) {
         kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v);
@@ -1814,6 +1859,9 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
   /* Put list of cutting edges for a face into fhash, keyed by face. */
   BLI_mempool_iternew(kcd->kedges, &iter);
   for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) {
+    if (kfe->is_invalid) {
+      continue;
+    }
 
     /* Select edges that lie directly on the cut. */
     if (kcd->select_result) {
@@ -1837,7 +1885,7 @@ static void knife_make_cuts(KnifeTool_OpData *kcd)
   /* Put list of splitting vertices for an edge into ehash, keyed by edge. */
   BLI_mempool_iternew(kcd->kverts, &iter);
   for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) {
-    if (kfv->v) {
+    if (kfv->v || kfv->is_invalid) {
       continue; /* Already have a BMVert. */
     }
     for (ref = kfv->edges.first; ref; ref = ref->next) {
@@ -1898,6 +1946,12 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
   GHashIterator giter;
   ListBase *list;
 
+  /* Allocate new undo frame on stack. */
+  kcd->undo = BLI_stack_push_r(kcd->undostack);
+  kcd->undo->pos = kcd->prev;
+  kcd->undo->cuts = 0;
+  kcd->undo->splits = 0;
+
   /* Save values for angle drawing calculations. */
   copy_v3_v3(kcd->old_cage, kcd->corr_prev_cage);
   copy_v2_v2(kcd->old_mval, kcd->prev.mval);
@@ -1963,6 +2017,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
   BLI_ghash_free(facehits, NULL, NULL);
   MEM_freeN(kcd->linehits);
   kcd->linehits = NULL;
+  kcd->undo->cuts = kcd->totlinehit - 1;
   kcd->totlinehit = 0;
 }
 
@@ -2084,6 +2139,9 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
       list = knife_get_face_kedges(kcd, f);
       for (ref = list->first; ref; ref = ref->next) {
         kfe = ref->ref;
+        if (kfe->is_invalid) {
+          continue;
+        }
         knife_project_v2(kcd, kfe->v1->cageco, se1);
         knife_project_v2(kcd, kfe->v2->cageco, se2);
         d = dist_squared_to_line_segment_v2(s, se1, se2);
@@ -2401,6 +2459,9 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
     list = knife_get_face_kedges(kcd, f);
     for (ref = list->first; ref; ref = ref->next) {
       kfe = ref->ref;
+      if (kfe->is_invalid) {
+        continue;
+      }
       if (BLI_smallhash_haskey(&kfes, (uintptr_t)kfe)) {
         continue;
       }
@@ -2701,10 +2762,18 @@ static int knife_sample_screen_density_from_closest_face(KnifeTool_OpData *kcd,
     KnifeEdge *kfe = ref->ref;
     int i;
 
+    if (kfe->is_invalid) {
+      continue;
+    }
+
     for (i = 0; i < 2; i++) {
       KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
       float kfv_sco[2];
 
+      if (kfv->is_invalid) {
+        continue;
+      }
+
       knife_project_v2(kcd, kfv->cageco, kfv_sco);
 
       dis_sq = len_squared_v2v2(kfv_sco, sco);
@@ -2830,6 +2899,10 @@ static KnifeEdge *knife_find_closest_edge_of_face(KnifeTool_OpData *kcd,
     float kfv1_sco[2], kfv2_sco[2], test_cagep[3];
     float lambda;
 
+    if (kfe->is_invalid) {
+      continue;
+    }
+
     /* Project edge vertices into screen space. */
     knife_project_v2(kcd, kfe->v1->cageco, kfv1_sco);
     knife_project_v2(kcd, kfe->v2->cageco, kfv2_sco);
@@ -3254,6 +3327,73 @@ stat

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list