[Bf-blender-cvs] [65b78b63fcc] greasepencil-object: GPencil: Improve select to detect fill areas

Antonio Vazquez noreply at git.blender.org
Tue Mar 24 13:21:26 CET 2020


Commit: 65b78b63fcc1f613b5b01bf2b44d8bc49e01b6bf
Author: Antonio Vazquez
Date:   Tue Mar 24 13:20:23 2020 +0100
Branches: greasepencil-object
https://developer.blender.org/rB65b78b63fcc1f613b5b01bf2b44d8bc49e01b6bf

GPencil: Improve select to detect fill areas

Now if use Tweak, Box or Lasso select inside a filled area, the whole stroke is selected if no point is selected before.

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

M	source/blender/editors/gpencil/gpencil_select.c

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

diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 6194b82fed9..33c53914191 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -43,6 +43,7 @@
 
 #include "BKE_context.h"
 #include "BKE_gpencil.h"
+#include "BKE_material.h"
 #include "BKE_report.h"
 
 #include "UI_interface.h"
@@ -67,6 +68,45 @@
 /** \name Shared Utilities
  * \{ */
 
+/* Check if mouse inside stroke. */
+static bool gpencil_point_inside_stroke(bGPDstroke *gps,
+                                        GP_SpaceConversion *gsc,
+                                        int mouse[2],
+                                        const float diff_mat[4][4])
+{
+  bool hit = false;
+  if (gps->totpoints == 0) {
+    return hit;
+  }
+
+  int(*mcords)[2] = NULL;
+  int len = gps->totpoints;
+  mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__);
+
+  /* Convert stroke to 2D array of points. */
+  bGPDspoint *pt;
+  int i;
+  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+    bGPDspoint pt2;
+    gp_point_to_parent_space(pt, diff_mat, &pt2);
+    gp_point_to_xy(gsc, gps, &pt2, &mcords[i][0], &mcords[i][1]);
+  }
+
+  /* Compute boundbox of lasso (for faster testing later). */
+  rcti rect;
+  BLI_lasso_boundbox(&rect, mcords, len);
+
+  /* Test if point inside stroke. */
+  hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
+         BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
+         BLI_lasso_is_point_inside(mcords, len, mouse[0], mouse[1], INT_MAX));
+
+  /* Free memory. */
+  MEM_SAFE_FREE(mcords);
+
+  return hit;
+}
+
 /* Convert sculpt mask mode to Select mode */
 static int gpencil_select_mode_from_sculpt(eGP_Sculpt_SelectMaskFlag mode)
 {
@@ -1120,10 +1160,8 @@ typedef bool (*GPencilTestFn)(bGPDstroke *gps,
                               const float diff_mat[4][4],
                               void *user_data);
 
-static int gpencil_generic_select_exec(bContext *C,
-                                       wmOperator *op,
-                                       GPencilTestFn is_inside_fn,
-                                       void *user_data)
+static int gpencil_generic_select_exec(
+    bContext *C, wmOperator *op, GPencilTestFn is_inside_fn, rcti box, void *user_data)
 {
   Object *ob = CTX_data_active_object(C);
   bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -1183,6 +1221,7 @@ static int gpencil_generic_select_exec(bContext *C,
   GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
   {
     bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+    bool whole = false;
 
     bGPDspoint *pt;
     int i;
@@ -1219,10 +1258,25 @@ static int gpencil_generic_select_exec(bContext *C,
       }
     }
 
-    /* if stroke mode expand selection */
-    if (strokemode) {
-      const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
-      const bool is_inside = hit;
+    /* If nothing hit, check if the mouse is inside a filled stroke using the center or
+     * Box or lasso area. */
+    if (!hit) {
+      /* Only check filled strokes. */
+      MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+      if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+        continue;
+      }
+      int mval[2];
+      mval[0] = (box.xmax + box.xmin) / 2;
+      mval[1] = (box.ymax + box.ymin) / 2;
+
+      whole = gpencil_point_inside_stroke(gps_active, &gsc, mval, gpstroke_iter.diff_mat);
+    }
+
+    /* if stroke mode expand selection. */
+    if ((strokemode) || (whole)) {
+      const bool is_select = BKE_gpencil_stroke_select_check(gps_active) || whole;
+      const bool is_inside = hit || whole;
       const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
       if (sel_op_result != -1) {
         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
@@ -1247,7 +1301,7 @@ static int gpencil_generic_select_exec(bContext *C,
   }
   GP_EVALUATED_STROKES_END(gpstroke_iter);
 
-  /* if paint mode,delete selected points */
+  /* if paint mode, delete selected points */
   if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
     gp_delete_selected_point_wrap(C);
     changed = true;
@@ -1296,7 +1350,8 @@ static int gpencil_box_select_exec(bContext *C, wmOperator *op)
 {
   struct GP_SelectBoxUserData data = {0};
   WM_operator_properties_border_to_rcti(op, &data.rect);
-  return gpencil_generic_select_exec(C, op, gpencil_test_box, &data);
+  rcti rect = data.rect;
+  return gpencil_generic_select_exec(C, op, gpencil_test_box, rect, &data);
 }
 
 void GPENCIL_OT_select_box(wmOperatorType *ot)
@@ -1363,7 +1418,8 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
   /* Compute boundbox of lasso (for faster testing later). */
   BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
 
-  int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data);
+  rcti rect = data.rect;
+  int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, rect, &data);
 
   MEM_freeN((void *)data.mcords);
 
@@ -1472,7 +1528,6 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
   RNA_int_get_array(op->ptr, "location", mval);
 
   /* First Pass: Find stroke point which gets hit */
-  /* XXX: maybe we should go from the top of the stack down instead... */
   GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
   {
     bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
@@ -1509,8 +1564,31 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
   }
   GP_EVALUATED_STROKES_END(gpstroke_iter);
 
+  /* If nothing hit, check if the mouse is inside any filled stroke. */
+  if (ELEM(NULL, hit_stroke, hit_point)) {
+    GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+    {
+      bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+      /* Only check filled strokes. */
+      MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+      if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+        continue;
+      }
+
+      bool hit_fill = gpencil_point_inside_stroke(gps_active, &gsc, mval, gpstroke_iter.diff_mat);
+      if (hit_fill) {
+        hit_stroke = gps_active;
+        hit_point = &gps_active->points[0];
+        /* Extend selection to all stroke. */
+        whole = true;
+      }
+    }
+    GP_EVALUATED_STROKES_END(gpstroke_iter);
+  }
+
   /* Abort if nothing hit... */
   if (ELEM(NULL, hit_stroke, hit_point)) {
+
     if (deselect_all) {
       /* since left mouse select change, deselect all if click outside any hit */
       deselect_all_selected(C);



More information about the Bf-blender-cvs mailing list