GPencil: Use evaluated data in selection
Now the selection is using the position after evaluating the modifiers and makes possible to select a stroke point that has been moved from the original location. Related to T66294
This commit is contained in:
parent
b1ed72f152
commit
091e7979d3
|
@ -639,6 +639,60 @@ struct GP_EditableStrokes_Iter {
|
|||
((flag & (GP_SCULPT_MASK_SELECTMODE_POINT | GP_SCULPT_MASK_SELECTMODE_STROKE | \
|
||||
GP_SCULPT_MASK_SELECTMODE_SEGMENT)))
|
||||
|
||||
/**
|
||||
* Iterate over all editable strokes using evaluated data in the current context,
|
||||
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
|
||||
* to perform some operations on the stroke.
|
||||
*
|
||||
* \param gpl: The identifier to use for the layer of the stroke being processed.
|
||||
* Choose a suitable value to avoid name clashes.
|
||||
* \param gps: The identifier to use for current stroke being processed.
|
||||
* Choose a suitable value to avoid name clashes.
|
||||
*/
|
||||
#define GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) \
|
||||
{ \
|
||||
struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
|
||||
Depsgraph *depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C); \
|
||||
Object *obact_ = CTX_data_active_object(C); \
|
||||
Object *obeval_ = DEG_get_evaluated_object(depsgraph_, obact_); \
|
||||
bGPdata *gpd_ = CTX_data_gpencil_data(C); \
|
||||
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
|
||||
int idx_eval = 0; \
|
||||
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { \
|
||||
if (gpencil_layer_is_editable(gpl)) { \
|
||||
bGPDframe *init_gpf_ = gpl->actframe; \
|
||||
if (is_multiedit_) { \
|
||||
init_gpf_ = gpl->frames.first; \
|
||||
} \
|
||||
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
|
||||
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
|
||||
ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
|
||||
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
|
||||
/* get evaluated frame with modifiers applied */ \
|
||||
bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \
|
||||
/* loop over strokes */ \
|
||||
for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
|
||||
/* skip strokes that are invalid for current view */ \
|
||||
if (ED_gpencil_stroke_can_use(C, gps) == false) \
|
||||
continue; \
|
||||
/* check if the color is editable */ \
|
||||
if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
|
||||
continue; \
|
||||
/* ... Do Stuff With Strokes ... */
|
||||
|
||||
#define GP_EVALUATED_STROKES_END(gpstroke_iter) \
|
||||
} \
|
||||
} \
|
||||
if (!is_multiedit_) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
idx_eval++; \
|
||||
} \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
#endif /* __GPENCIL_INTERN_H__ */
|
||||
|
|
|
@ -825,6 +825,7 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
|
|||
{
|
||||
bGPDspoint *pt1 = NULL;
|
||||
bGPDspoint *pt2 = NULL;
|
||||
bGPDstroke *gps_orig = gps->runtime.gps_orig;
|
||||
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||
int i;
|
||||
bool changed = false;
|
||||
|
@ -840,12 +841,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
|
|||
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
|
||||
/* change selection */
|
||||
if (select) {
|
||||
gps->points->flag |= GP_SPOINT_SELECT;
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
gps_orig->points->flag |= GP_SPOINT_SELECT;
|
||||
gps_orig->flag |= GP_STROKE_SELECT;
|
||||
}
|
||||
else {
|
||||
gps->points->flag &= ~GP_SPOINT_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
gps_orig->points->flag &= ~GP_SPOINT_SELECT;
|
||||
gps_orig->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -885,15 +886,21 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
|
|||
*/
|
||||
hit = true;
|
||||
if (select) {
|
||||
pt1->flag |= GP_SPOINT_SELECT;
|
||||
pt2->flag |= GP_SPOINT_SELECT;
|
||||
|
||||
if (pt1->runtime.pt_orig != NULL) {
|
||||
pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
if (pt2->runtime.pt_orig != NULL) {
|
||||
pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
pt1->flag &= ~GP_SPOINT_SELECT;
|
||||
pt2->flag &= ~GP_SPOINT_SELECT;
|
||||
|
||||
if (pt1->runtime.pt_orig != NULL) {
|
||||
pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
if (pt2->runtime.pt_orig != NULL) {
|
||||
pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@ -907,24 +914,28 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
|
|||
/* if stroke mode expand selection */
|
||||
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
|
||||
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
|
||||
if (select) {
|
||||
pt1->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
pt1->flag &= ~GP_SPOINT_SELECT;
|
||||
if (pt1->runtime.pt_orig != NULL) {
|
||||
if (select) {
|
||||
pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* expand selection to segment */
|
||||
if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select)) {
|
||||
if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
|
||||
(pt1->runtime.pt_orig != NULL)) {
|
||||
float r_hita[3], r_hitb[3];
|
||||
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
|
||||
ED_gpencil_select_stroke_segment(gpl, gps, pt1, hit_select, false, scale, r_hita, r_hitb);
|
||||
ED_gpencil_select_stroke_segment(
|
||||
gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
|
||||
}
|
||||
|
||||
/* Ensure that stroke selection is in sync with its points */
|
||||
BKE_gpencil_stroke_sync_selection(gps);
|
||||
BKE_gpencil_stroke_sync_selection(gps_orig);
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
@ -982,11 +993,12 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
|
|||
rect.ymax = my + radius;
|
||||
|
||||
/* find visible strokes, and select if hit */
|
||||
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
|
||||
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
|
||||
{
|
||||
changed |= gp_stroke_do_circle_sel(
|
||||
gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
|
||||
}
|
||||
GP_EDITABLE_STROKES_END(gpstroke_iter);
|
||||
GP_EVALUATED_STROKES_END(gpstroke_iter);
|
||||
|
||||
/* updates */
|
||||
if (changed) {
|
||||
|
@ -1090,27 +1102,38 @@ static int gpencil_generic_select_exec(bContext *C,
|
|||
}
|
||||
|
||||
/* select/deselect points */
|
||||
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
|
||||
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
|
||||
{
|
||||
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
bool hit = false;
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (pt->runtime.pt_orig == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* convert point coords to screenspace */
|
||||
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
|
||||
if (strokemode == false) {
|
||||
const bool is_select = (pt->flag & GP_SPOINT_SELECT) != 0;
|
||||
const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
|
||||
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
|
||||
if (sel_op_result != -1) {
|
||||
SET_FLAG_FROM_TEST(pt->flag, sel_op_result, GP_SPOINT_SELECT);
|
||||
SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
|
||||
changed = true;
|
||||
|
||||
/* expand selection to segment */
|
||||
if ((sel_op_result != -1) && (segmentmode)) {
|
||||
bool hit_select = (bool)(pt->flag & GP_SPOINT_SELECT);
|
||||
bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
|
||||
float r_hita[3], r_hitb[3];
|
||||
ED_gpencil_select_stroke_segment(
|
||||
gpl, gps, pt, hit_select, false, scale, r_hita, r_hitb);
|
||||
ED_gpencil_select_stroke_segment(gpl,
|
||||
gps->runtime.gps_orig,
|
||||
pt->runtime.pt_orig,
|
||||
hit_select,
|
||||
false,
|
||||
scale,
|
||||
r_hita,
|
||||
r_hitb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1124,16 +1147,19 @@ 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);
|
||||
const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig);
|
||||
const bool is_inside = hit;
|
||||
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++) {
|
||||
if (pt->runtime.pt_orig == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (sel_op_result) {
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
|
@ -1141,9 +1167,9 @@ static int gpencil_generic_select_exec(bContext *C,
|
|||
}
|
||||
|
||||
/* Ensure that stroke selection is in sync with its points */
|
||||
BKE_gpencil_stroke_sync_selection(gps);
|
||||
BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
|
||||
}
|
||||
GP_EDITABLE_STROKES_END(gpstroke_iter);
|
||||
GP_EVALUATED_STROKES_END(gpstroke_iter);
|
||||
|
||||
/* if paint mode,delete selected points */
|
||||
if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
|
||||
|
@ -1365,13 +1391,17 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
|
|||
|
||||
/* First Pass: Find stroke point which gets hit */
|
||||
/* XXX: maybe we should go from the top of the stack down instead... */
|
||||
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
|
||||
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* firstly, check for hit-point */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
int xy[2];
|
||||
if (pt->runtime.pt_orig == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bGPDspoint pt2;
|
||||
gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
|
||||
|
@ -1386,15 +1416,15 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
|
|||
/* only use this point if it is a better match than the current hit - T44685 */
|
||||
if (pt_distance < hit_distance) {
|
||||
hit_layer = gpl;
|
||||
hit_stroke = gps;
|
||||
hit_point = pt;
|
||||
hit_stroke = gps->runtime.gps_orig;
|
||||
hit_point = pt->runtime.pt_orig;
|
||||
hit_distance = pt_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GP_EDITABLE_STROKES_END(gpstroke_iter);
|
||||
GP_EVALUATED_STROKES_END(gpstroke_iter);
|
||||
|
||||
/* Abort if nothing hit... */
|
||||
if (ELEM(NULL, hit_stroke, hit_point)) {
|
||||
|
|
Loading…
Reference in New Issue