diff options
Diffstat (limited to 'source/blender/editors/gpencil')
27 files changed, 1172 insertions, 569 deletions
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 4e2951c3571..751f8333aaa 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -171,7 +171,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, int totpoints = tgpw->gps->totpoints; const float viewport[2] = {(float)tgpw->winx, (float)tgpw->winy}; - float curpressure = points[0].pressure; + const float min_thickness = 0.05f; + float fpt[3]; /* if cyclic needs more vertex */ @@ -205,7 +206,6 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke); /* draw stroke curve */ - GPU_line_width(max_ff(curpressure * thickness, 1.0f)); immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2); const bGPDspoint *pt = points; @@ -215,18 +215,19 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, gpencil_set_point_varying_color(points, ink, attr_id.color, (bool)tgpw->is_fill_stroke); if ((cyclic) && (totpoints > 2)) { - immAttr1f(attr_id.thickness, max_ff((points + totpoints - 1)->pressure * thickness, 1.0f)); + immAttr1f(attr_id.thickness, + max_ff((points + totpoints - 1)->pressure * thickness, min_thickness)); mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x); } else { - immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f)); + immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, min_thickness)); mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x); } immVertex3fv(attr_id.pos, fpt); } /* set point */ gpencil_set_point_varying_color(pt, ink, attr_id.color, (bool)tgpw->is_fill_stroke); - immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, 1.0f)); + immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, min_thickness)); mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x); immVertex3fv(attr_id.pos, fpt); } diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index aae31b11025..166111c582c 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -276,7 +276,7 @@ void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl) bGPDframe *gpfd; /* duplicate frame, and deselect self */ - gpfd = BKE_gpencil_frame_duplicate(gpf); + gpfd = BKE_gpencil_frame_duplicate(gpf, true); gpf->flag &= ~GP_FRAME_SELECT; BLI_insertlinkafter(&gpl->frames, gpf, gpfd); @@ -361,7 +361,7 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) /* if frame is selected, make duplicate it and its strokes */ if (gpf->flag & GP_FRAME_SELECT) { /* make a copy of this frame */ - bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf); + bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf, true); BLI_addtail(&copied_frames, new_frame); /* extend extents for keyframes encountered */ diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 65141442237..d86bad7ef3c 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -29,16 +29,13 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" -#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 0c8cc621a3b..1e1a70f9c1d 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -29,16 +29,13 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" -#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 5cc5e7ecdcd..3271096c433 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -31,12 +31,9 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "BLT_translation.h" - #include "DNA_armature_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 09b57029350..ac75ae44c8a 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -178,7 +178,7 @@ static void gpencil_strokepoint_convertcoords(bContext *C, /* apply parent transform */ float fpt[3]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); mul_v3_m4v3(fpt, diff_mat, &source_pt->x); copy_v3_v3(&pt->x, fpt); @@ -370,7 +370,7 @@ static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd, static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *nbr_gaps, - float *tot_gaps_time) + float *r_tot_gaps_time) { float delta_time = 0.0f; @@ -387,10 +387,10 @@ static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, } gtd->tot_time -= delta_time; - *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; - gtd->tot_time += *tot_gaps_time; + *r_tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; + gtd->tot_time += *r_tot_gaps_time; if (G.debug & G_DEBUG) { - printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps); + printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *r_tot_gaps_time, *nbr_gaps); } if (gtd->gap_randomness > 0.0f) { BLI_rng_srandom(rng, gtd->seed); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index ad9b72b713e..3be913f342d 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -449,21 +449,32 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); } /* ********************* Duplicate Layer ************************** */ +enum { + GP_LAYER_DUPLICATE_ALL = 0, + GP_LAYER_DUPLICATE_EMPTY = 1, +}; -static int gpencil_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_layer_copy_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); bGPDlayer *new_layer; - + const int mode = RNA_enum_get(op->ptr, "mode"); + const bool dup_strokes = (bool)(mode == GP_LAYER_DUPLICATE_ALL); /* sanity checks */ if (ELEM(NULL, gpd, gpl)) { return OPERATOR_CANCELLED; } - /* make copy of layer, and add it immediately after the existing layer */ - new_layer = BKE_gpencil_layer_duplicate(gpl); - BLI_insertlinkafter(&gpd->layers, gpl, new_layer); + /* Make copy of layer, and add it immediately after or before the existing layer. */ + new_layer = BKE_gpencil_layer_duplicate(gpl, true, dup_strokes); + if (dup_strokes) { + BLI_insertlinkafter(&gpd->layers, gpl, new_layer); + } + else { + /* For empty strokes is better add below. */ + BLI_insertlinkbefore(&gpd->layers, gpl, new_layer); + } /* ensure new layer has a unique name, and is now the active layer */ BLI_uniquename(&gpd->layers, @@ -484,6 +495,12 @@ static int gpencil_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) { + static const EnumPropertyItem copy_mode[] = { + {GP_LAYER_DUPLICATE_ALL, "ALL", 0, "All Data", ""}, + {GP_LAYER_DUPLICATE_EMPTY, "EMPTY", 0, "Empty Keyframes", ""}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ ot->name = "Duplicate Layer"; ot->idname = "GPENCIL_OT_layer_duplicate"; @@ -495,6 +512,8 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_DUPLICATE_ALL, "Mode", ""); } /* ********************* Duplicate Layer in a new object ************************** */ @@ -1560,7 +1579,7 @@ static int gpencil_stroke_arrange_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } /* some stroke is already at front*/ @@ -1725,7 +1744,7 @@ static int gpencil_stroke_change_color_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } @@ -2849,12 +2868,12 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) mul_v3_m3v3(offset_local, imat, offset_global); LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { - bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src); + bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src, true, true); float diff_mat[4][4]; float inverse_diff_mat[4][4]; /* recalculate all stroke points */ - BKE_gpencil_parent_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat); invert_m4_m4_safe_ortho(inverse_diff_mat, diff_mat); Material *ma_src = NULL; @@ -3388,7 +3407,7 @@ static int gpencil_material_select_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index d1c8eca1be0..aeff2acb04d 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1867,7 +1867,7 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) } /* Check if the color is editable. */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } @@ -2610,7 +2610,7 @@ static int gpencil_delete_selected_points(bContext *C) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } @@ -2800,7 +2800,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) float diff_mat[4][4]; /* calculate difference matrix object */ - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ @@ -2808,7 +2808,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) { continue; } @@ -2935,7 +2935,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op) float diff_mat[4][4]; /* calculate difference matrix */ - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; @@ -2946,7 +2946,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) { continue; } /* only continue if this stroke is selected (editable doesn't guarantee this)... */ @@ -3039,7 +3039,7 @@ static bool gpencil_stroke_points_centroid(Depsgraph *depsgraph, float diff_mat[4][4]; /* calculate difference matrix */ - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; @@ -3050,7 +3050,7 @@ static bool gpencil_stroke_points_centroid(Depsgraph *depsgraph, continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) { continue; } /* only continue if this stroke is selected (editable doesn't guarantee this)... */ @@ -3565,7 +3565,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable. */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } elem = &strokes_list[tot_strokes]; @@ -3697,7 +3697,7 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } @@ -4516,7 +4516,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } /* Separate selected strokes. */ @@ -4717,7 +4717,7 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } /* Split selected strokes. */ @@ -4948,11 +4948,14 @@ static int gpencil_cutter_lasso_select(bContext *C, GPencilTestFn is_inside_fn, void *user_data) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *obact = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); ScrArea *area = CTX_wm_area(C); ToolSettings *ts = CTX_data_tool_settings(C); const float scale = ts->gp_sculpt.isect_threshold; const bool flat_caps = RNA_boolean_get(op->ptr, "flat_caps"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); bGPDspoint *pt; GP_SpaceConversion gsc = {NULL}; @@ -4979,57 +4982,87 @@ static int gpencil_cutter_lasso_select(bContext *C, } CTX_DATA_END; - /* select points */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - int tot_inside = 0; - const int oldtot = gps->totpoints; - for (int i = 0; i < gps->totpoints; i++) { - pt = &gps->points[i]; - if ((pt->flag & GP_SPOINT_SELECT) || (pt->flag & GP_SPOINT_TAG)) { - continue; - } - /* convert point coords to screen-space */ - const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data); - if (is_inside) { - tot_inside++; - changed = true; - pt->flag |= GP_SPOINT_SELECT; - gps->flag |= GP_STROKE_SELECT; - float r_hita[3], r_hitb[3]; - if (gps->totpoints > 1) { - ED_gpencil_select_stroke_segment(gpd, gpl, gps, pt, true, true, scale, r_hita, r_hitb); + /* Select points */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if ((gpl->flag & GP_LAYER_LOCKED) || ((gpl->flag & GP_LAYER_HIDE))) { + continue; + } + + float diff_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); + + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } /* check if the color is editable */ + if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) { + continue; + } + int tot_inside = 0; + const int oldtot = gps->totpoints; + for (int i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + if ((pt->flag & GP_SPOINT_SELECT) || (pt->flag & GP_SPOINT_TAG)) { + continue; + } + /* convert point coords to screen-space */ + const bool is_inside = is_inside_fn(gps, pt, &gsc, diff_mat, user_data); + if (is_inside) { + tot_inside++; + changed = true; + pt->flag |= GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + float r_hita[3], r_hitb[3]; + if (gps->totpoints > 1) { + ED_gpencil_select_stroke_segment( + gpd, gpl, gps, pt, true, true, scale, r_hita, r_hitb); + } + /* avoid infinite loops */ + if (gps->totpoints > oldtot) { + break; + } + } + } + /* if mark all points inside lasso set to remove all stroke */ + if ((tot_inside == oldtot) || ((tot_inside == 1) && (oldtot == 2))) { + for (int i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + pt->flag |= GP_SPOINT_SELECT; + } + } } - /* avoid infinite loops */ - if (gps->totpoints > oldtot) { + /* if not multiedit, exit loop. */ + if (!is_multiedit) { break; } } } - /* if mark all points inside lasso set to remove all stroke */ - if ((tot_inside == oldtot) || ((tot_inside == 1) && (oldtot == 2))) { - for (int i = 0; i < gps->totpoints; i++) { - pt = &gps->points[i]; - pt->flag |= GP_SPOINT_SELECT; - } - } } - GP_EDITABLE_STROKES_END(gpstroke_iter); - /* dissolve selected points */ + /* Dissolve selected points. */ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - if (gpl->flag & GP_LAYER_LOCKED) { - continue; - } - - bGPDframe *gpf = gpl->actframe; - if (gpf == NULL) { - continue; - } - LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - if (gps->flag & GP_STROKE_SELECT) { - gpencil_cutter_dissolve(gpd, gpl, gps, flat_caps); + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + bGPDframe *gpf_act = gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + gpl->actframe = gpf; + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_SELECT) { + gpencil_cutter_dissolve(gpd, gpl, gps, flat_caps); + } + } + /* if not multiedit, exit loop. */ + if (!is_multiedit) { + break; } } + gpl->actframe = gpf_act; } /* updates */ diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c index 60d1d2169b4..031bbd61173 100644 --- a/source/blender/editors/gpencil/gpencil_edit_curve.c +++ b/source/blender/editors/gpencil/gpencil_edit_curve.c @@ -28,13 +28,10 @@ #include <stdlib.h> #include <string.h> -#include "MEM_guardedalloc.h" - #include "DNA_gpencil_types.h" #include "DNA_view3d_types.h" #include "BKE_context.h" -#include "BKE_curve.h" #include "BKE_gpencil.h" #include "BKE_gpencil_curve.h" #include "BKE_gpencil_geom.h" diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 9b181866ccb..e68b7802532 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_stack.h" #include "BLI_utildefines.h" @@ -81,8 +82,18 @@ #define LEAK_HORZ 0 #define LEAK_VERT 1 +#define MIN_WINDOW_SIZE 128 -/* Temporary fill operation data (op->customdata) */ +/* Set to 1 to debug filling internal image. By default, the value must be 0. */ +#define FILL_DEBUG 0 + +/* Duplicated: etempFlags */ +enum { + GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */ + GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */ +}; + +/* Temporary fill operation data `op->customdata`. */ typedef struct tGPDfill { bContext *C; struct Main *bmain; @@ -101,7 +112,7 @@ typedef struct tGPDfill { struct View3D *v3d; /** region where painting originated */ struct ARegion *region; - /** current GP datablock */ + /** Current GP data-block. */ struct bGPdata *gpd; /** current material */ struct Material *mat; @@ -111,6 +122,8 @@ typedef struct tGPDfill { struct bGPDlayer *gpl; /** frame */ struct bGPDframe *gpf; + /** Temp mouse position stroke. */ + struct bGPDstroke *gps_mouse; /** flags */ short flag; @@ -118,9 +131,12 @@ typedef struct tGPDfill { short oldkey; /** send to back stroke */ bool on_back; - + /** Flag for render mode */ + bool is_render; + /** Flag to check something was done. */ + bool done; /** mouse fill center position */ - int center[2]; + int mouse[2]; /** windows width */ int sizex; /** window height */ @@ -137,7 +153,7 @@ typedef struct tGPDfill { /** boundary limits drawing mode */ int fill_draw_mode; /* scaling factor */ - short fill_factor; + float fill_factor; /* Frame to use. */ int active_cfra; @@ -156,14 +172,184 @@ typedef struct tGPDfill { /** handle for drawing strokes while operator is running 3d stuff */ void *draw_handle_3d; - /* tmp size x */ + /* Temporary size x. */ int bwinx; - /* tmp size y */ + /* Temporary size y. */ int bwiny; rcti brect; + /* Space Conversion Data */ + GP_SpaceConversion gsc; + + /** Zoom factor. */ + float zoom; + + /** Factor of extension. */ + float fill_extend_fac; + } tGPDfill; +bool skip_layer_check(short fill_layer_mode, int gpl_active_index, int gpl_index); +static void gpencil_draw_boundary_lines(const struct bContext *UNUSED(C), struct tGPDfill *tgpf); + +/* Delete any temporary stroke. */ +static void gpencil_delete_temp_stroke_extension(tGPDfill *tgpf, const bool all_frames) +{ + LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpf->gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + bGPDframe *init_gpf = (all_frames) ? gpl->frames.first : + BKE_gpencil_layer_frame_get( + gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); + if (init_gpf == NULL) { + continue; + } + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + /* free stroke */ + if ((gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG)) { + BLI_remlink(&gpf->strokes, gps); + BKE_gpencil_free_stroke(gps); + } + } + if (!all_frames) { + break; + } + } + } +} + +static void extrapolate_points_by_length(bGPDspoint *a, + bGPDspoint *b, + float length, + float r_point[3]) +{ + float ab[3]; + sub_v3_v3v3(ab, &b->x, &a->x); + normalize_v3(ab); + mul_v3_fl(ab, length); + add_v3_v3v3(r_point, &b->x, ab); +} + +/* Loop all layers create stroke extensions. */ +static void gpencil_create_extensions(tGPDfill *tgpf) +{ + Object *ob = tgpf->ob; + bGPdata *gpd = tgpf->gpd; + Brush *brush = tgpf->brush; + BrushGpencilSettings *brush_settings = brush->gpencil_settings; + + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); + BLI_assert(gpl_active != NULL); + + const int gpl_active_index = BLI_findindex(&gpd->layers, gpl_active); + BLI_assert(gpl_active_index >= 0); + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + /* Decide if the strokes of layers are included or not depending on the layer mode. */ + const int gpl_index = BLI_findindex(&gpd->layers, gpl); + bool skip = skip_layer_check(brush_settings->fill_layer_mode, gpl_active_index, gpl_index); + if (skip) { + continue; + } + + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); + if (gpf == NULL) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* Check if stroke can be drawn. */ + if ((gps->points == NULL) || (gps->totpoints < 2)) { + continue; + } + if (gps->flag & (GP_STROKE_NOFILL | GP_STROKE_TAG)) { + continue; + } + /* Check if the color is visible. */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE)) { + continue; + } + + /* Extend start. */ + bGPDspoint *pt0 = &gps->points[1]; + bGPDspoint *pt1 = &gps->points[0]; + bGPDstroke *gps_new = BKE_gpencil_stroke_new(gps->mat_nr, 2, gps->thickness); + gps_new->flag |= GP_STROKE_NOFILL | GP_STROKE_TAG; + BLI_addtail(&gpf->strokes, gps_new); + + bGPDspoint *pt = &gps_new->points[0]; + copy_v3_v3(&pt->x, &pt1->x); + pt->strength = 1.0f; + pt->pressure = 1.0f; + + pt = &gps_new->points[1]; + pt->strength = 1.0f; + pt->pressure = 1.0f; + extrapolate_points_by_length(pt0, pt1, tgpf->fill_extend_fac * 0.1f, &pt->x); + + /* Extend end. */ + pt0 = &gps->points[gps->totpoints - 2]; + pt1 = &gps->points[gps->totpoints - 1]; + gps_new = BKE_gpencil_stroke_new(gps->mat_nr, 2, gps->thickness); + gps_new->flag |= GP_STROKE_NOFILL | GP_STROKE_TAG; + BLI_addtail(&gpf->strokes, gps_new); + + pt = &gps_new->points[0]; + copy_v3_v3(&pt->x, &pt1->x); + pt->strength = 1.0f; + pt->pressure = 1.0f; + + pt = &gps_new->points[1]; + pt->strength = 1.0f; + pt->pressure = 1.0f; + extrapolate_points_by_length(pt0, pt1, tgpf->fill_extend_fac * 0.1f, &pt->x); + } + } +} + +static void gpencil_update_extend(tGPDfill *tgpf) +{ + gpencil_delete_temp_stroke_extension(tgpf, false); + + if (tgpf->fill_extend_fac > 0.0f) { + gpencil_create_extensions(tgpf); + } + WM_event_add_notifier(tgpf->C, NC_GPENCIL | NA_EDITED, NULL); +} + +static bool gpencil_stroke_is_drawable(tGPDfill *tgpf, bGPDstroke *gps) +{ + if (tgpf->is_render) { + return true; + } + + const bool show_help = (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) != 0; + const bool show_extend = (tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) != 0; + const bool is_extend = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG); + + if ((!show_help) && (show_extend)) { + if (!is_extend) { + return false; + } + } + + if ((show_help) && (!show_extend)) { + if (is_extend) { + return false; + } + } + + return true; +} + /* draw a given stroke using same thickness and color for all points */ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, bGPDstroke *gps, @@ -171,7 +357,8 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, const bool cyclic, const float ink[4], const int flag, - const float thershold) + const float thershold, + const float thickness) { bGPDspoint *points = gps->points; @@ -181,9 +368,19 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, int totpoints = gps->totpoints; float fpt[3]; float col[4]; + const float extend_col[4] = {0.0f, 1.0f, 1.0f, 1.0f}; + const bool is_extend = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG); - copy_v4_v4(col, ink); + if (!gpencil_stroke_is_drawable(tgpf, gps)) { + return; + } + if ((is_extend) && (!tgpf->is_render)) { + copy_v4_v4(col, extend_col); + } + else { + copy_v4_v4(col, ink); + } /* if cyclic needs more vertex */ int cyclic_add = (cyclic) ? 1 : 0; @@ -194,7 +391,7 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); /* draw stroke curve */ - GPU_line_width(1.0f); + GPU_line_width((!is_extend) ? thickness : thickness * 2.0f); immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add); const bGPDspoint *pt = points; @@ -225,15 +422,77 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, immUnbindProgram(); } -/* loop all layers */ -static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) +static void draw_mouse_position(tGPDfill *tgpf) { - /* duplicated: etempFlags */ - enum { - GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */ - GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */ - }; + if (tgpf->gps_mouse == NULL) { + return; + } + uchar mouse_color[4] = {0, 0, 255, 255}; + bGPDspoint *pt = &tgpf->gps_mouse->points[0]; + float point_size = (tgpf->zoom == 1.0f) ? 4.0f * tgpf->fill_factor : + (0.5f * tgpf->zoom) + tgpf->fill_factor; + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + /* Draw mouse click position in Blue. */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + GPU_point_size(point_size); + immBegin(GPU_PRIM_POINTS, 1); + immAttr4ubv(col, mouse_color); + immVertex3fv(pos, &pt->x); + immEnd(); + immUnbindProgram(); +} + +/* Helper: Check if must skip the layer */ +bool skip_layer_check(short fill_layer_mode, int gpl_active_index, int gpl_index) +{ + bool skip = false; + + switch (fill_layer_mode) { + case GP_FILL_GPLMODE_ACTIVE: { + if (gpl_index != gpl_active_index) { + skip = true; + } + break; + } + case GP_FILL_GPLMODE_ABOVE: { + if (gpl_index != gpl_active_index + 1) { + skip = true; + } + break; + } + case GP_FILL_GPLMODE_BELOW: { + if (gpl_index != gpl_active_index - 1) { + skip = true; + } + break; + } + case GP_FILL_GPLMODE_ALL_ABOVE: { + if (gpl_index <= gpl_active_index) { + skip = true; + } + break; + } + case GP_FILL_GPLMODE_ALL_BELOW: { + if (gpl_index >= gpl_active_index) { + skip = true; + } + break; + } + case GP_FILL_GPLMODE_VISIBLE: + default: + break; + } + + return skip; +} + +/* Loop all layers to draw strokes. */ +static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) +{ Object *ob = tgpf->ob; bGPdata *gpd = tgpf->gpd; Brush *brush = tgpf->brush; @@ -247,8 +506,8 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.gpd = gpd; tgpw.offsx = 0; tgpw.offsy = 0; - tgpw.winx = tgpf->region->winx; - tgpw.winy = tgpf->region->winy; + tgpw.winx = tgpf->sizex; + tgpw.winy = tgpf->sizey; tgpw.dflag = 0; tgpw.disable_fill = 1; tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS); @@ -261,54 +520,22 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) const int gpl_active_index = BLI_findindex(&gpd->layers, gpl_active); BLI_assert(gpl_active_index >= 0); - LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { - /* calculate parent position */ - BKE_gpencil_parent_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat); + /* Draw blue point where click with mouse. */ + draw_mouse_position(tgpf); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* do not draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) { continue; } + /* calculate parent position */ + BKE_gpencil_layer_transform_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat); + /* Decide if the strokes of layers are included or not depending on the layer mode. * Cannot skip the layer because it can use boundary strokes and must be used. */ - bool skip = false; const int gpl_index = BLI_findindex(&gpd->layers, gpl); - switch (brush_settings->fill_layer_mode) { - case GP_FILL_GPLMODE_ACTIVE: { - if (gpl_index != gpl_active_index) { - skip = true; - } - break; - } - case GP_FILL_GPLMODE_ABOVE: { - if (gpl_index != gpl_active_index + 1) { - skip = true; - } - break; - } - case GP_FILL_GPLMODE_BELOW: { - if (gpl_index != gpl_active_index - 1) { - skip = true; - } - break; - } - case GP_FILL_GPLMODE_ALL_ABOVE: { - if (gpl_index <= gpl_active_index) { - skip = true; - } - break; - } - case GP_FILL_GPLMODE_ALL_BELOW: { - if (gpl_index >= gpl_active_index) { - skip = true; - } - break; - } - case GP_FILL_GPLMODE_VISIBLE: - default: - break; - } + bool skip = skip_layer_check(brush_settings->fill_layer_mode, gpl_active_index, gpl_index); /* if active layer and no keyframe, create a new one */ if (gpl == tgpf->gpl) { @@ -351,17 +578,19 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.gpf = gpf; tgpw.t_gpf = gpf; - /* reduce thickness to avoid gaps */ tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true; + /* Reduce thickness to avoid gaps. */ tgpw.lthick = gpl->line_change; tgpw.opacity = 1.0; copy_v4_v4(tgpw.tintcolor, ink); tgpw.onion = true; tgpw.custonion = true; - /* normal strokes */ + /* Normal strokes. */ if (ELEM(tgpf->fill_draw_mode, GP_FILL_DMODE_STROKE, GP_FILL_DMODE_BOTH)) { - ED_gpencil_draw_fill(&tgpw); + if (gpencil_stroke_is_drawable(tgpf, gps) && ((gps->flag & GP_STROKE_TAG) == 0)) { + ED_gpencil_draw_fill(&tgpw); + } } /* 3D Lines with basic shapes and invisible lines */ @@ -372,7 +601,8 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) gps->flag & GP_STROKE_CYCLIC, ink, tgpf->flag, - tgpf->fill_threshold); + tgpf->fill_threshold, + 1.0f); } } } @@ -380,7 +610,7 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) GPU_blend(GPU_BLEND_NONE); } -/* draw strokes in offscreen buffer */ +/* Draw strokes in off-screen buffer. */ static bool gpencil_render_offscreen(tGPDfill *tgpf) { bool is_ortho = false; @@ -391,15 +621,15 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) } /* set temporary new size */ - tgpf->bwinx = tgpf->region->winx; - tgpf->bwiny = tgpf->region->winy; + tgpf->bwinx = tgpf->region->sizex; + tgpf->bwiny = tgpf->region->sizey; tgpf->brect = tgpf->region->winrct; /* resize region */ tgpf->region->winrct.xmin = 0; tgpf->region->winrct.ymin = 0; - tgpf->region->winrct.xmax = (int)tgpf->region->winx * tgpf->fill_factor; - tgpf->region->winrct.ymax = (int)tgpf->region->winy * tgpf->fill_factor; + tgpf->region->winrct.xmax = max_ii((int)tgpf->region->winx * tgpf->fill_factor, MIN_WINDOW_SIZE); + tgpf->region->winrct.ymax = max_ii((int)tgpf->region->winy * tgpf->fill_factor, MIN_WINDOW_SIZE); tgpf->region->winx = (short)abs(tgpf->region->winrct.xmax - tgpf->region->winrct.xmin); tgpf->region->winy = (short)abs(tgpf->region->winrct.ymax - tgpf->region->winrct.ymin); @@ -407,12 +637,6 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) tgpf->sizex = (int)tgpf->region->winx; tgpf->sizey = (int)tgpf->region->winy; - /* adjust center */ - float center[2]; - center[0] = (float)tgpf->center[0] * ((float)tgpf->region->winx / (float)tgpf->bwinx); - center[1] = (float)tgpf->center[1] * ((float)tgpf->region->winy / (float)tgpf->bwiny); - round_v2i_v2fl(tgpf->center, center); - char err_out[256] = "unknown"; GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, true, false, err_out); if (offscreen == NULL) { @@ -421,7 +645,7 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) } GPU_offscreen_bind(offscreen, true); - uint flag = IB_rect | IB_rectfloat; + uint flag = IB_rectfloat; ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag); rctf viewplane; @@ -436,6 +660,21 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) &clip_start, &clip_end, NULL); + + /* Rescale `viewplane` to fit all strokes. */ + float width = viewplane.xmax - viewplane.xmin; + float height = viewplane.ymax - viewplane.ymin; + + float width_new = width * tgpf->zoom; + float height_new = height * tgpf->zoom; + float scale_x = (width_new - width) / 2.0f; + float scale_y = (height_new - height) / 2.0f; + + viewplane.xmin -= scale_x; + viewplane.xmax += scale_x; + viewplane.ymin -= scale_y; + viewplane.ymax += scale_y; + if (is_ortho) { orthographic_m4(winmat, viewplane.xmin, @@ -456,7 +695,7 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) } GPU_matrix_push_projection(); - GPU_matrix_identity_set(); + GPU_matrix_identity_projection_set(); GPU_matrix_push(); GPU_matrix_identity_set(); @@ -495,45 +734,33 @@ static bool gpencil_render_offscreen(tGPDfill *tgpf) BKE_image_release_ibuf(tgpf->ima, ibuf, NULL); - /* switch back to window-system-provided framebuffer */ + /* Switch back to window-system-provided frame-buffer. */ GPU_offscreen_unbind(offscreen, true); GPU_offscreen_free(offscreen); return true; } -/* return pixel data (rgba) at index */ +/* Return pixel data (RGBA) at index. */ static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4]) { - if (ibuf->rect_float) { - const float *frgba = &ibuf->rect_float[idx * 4]; - copy_v4_v4(r_col, frgba); - } - else { - /* XXX: This case probably doesn't happen, as we only write to the float buffer, - * but we get compiler warnings about uninitialized vars otherwise - */ - BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!"); - zero_v4(r_col); - } + BLI_assert(ibuf->rect_float != NULL); + memcpy(r_col, &ibuf->rect_float[idx * 4], sizeof(float[4])); } -/* set pixel data (rgba) at index */ +/* Set pixel data (RGBA) at index. */ static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) { - // BLI_assert(idx <= ibuf->x * ibuf->y); - if (ibuf->rect) { - uint *rrect = &ibuf->rect[idx]; - uchar ccol[4]; - - rgba_float_to_uchar(ccol, col); - *rrect = *((uint *)ccol); - } + BLI_assert(ibuf->rect_float != NULL); + float *rrectf = &ibuf->rect_float[idx * 4]; + copy_v4_v4(rrectf, col); +} - if (ibuf->rect_float) { - float *rrectf = &ibuf->rect_float[idx * 4]; - copy_v4_v4(rrectf, col); - } +/* Helper: Check if one image row is empty. */ +static bool is_row_filled(const ImBuf *ibuf, const int row_index) +{ + float *row = &ibuf->rect_float[ibuf->x * 4 * row_index]; + return (row[0] == 0.0f && memcmp(row, row + 1, ((ibuf->x * 4) - 1) * sizeof(float)) != 0); } /** @@ -541,6 +768,9 @@ static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) * this is used for strokes with small gaps between them to get a full fill * and do not get a full screen fill. * + * This function assumes that if the furthest pixel is occupied, + * the other pixels are occupied. + * * \param ibuf: Image pixel data. * \param maxpixel: Maximum index. * \param limit: Limit of pixels to analyze. @@ -550,10 +780,10 @@ static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type) { float rgba[4]; - int i; int pt; bool t_a = false; bool t_b = false; + const int extreme = limit - 1; /* Horizontal leak (check vertical pixels) * X @@ -564,37 +794,29 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index */ if (type == LEAK_HORZ) { /* pixels on top */ - for (i = 1; i <= limit; i++) { - pt = index + (ibuf->x * i); - if (pt <= maxpixel) { - get_pixel(ibuf, pt, rgba); - if (rgba[0] == 1.0f) { - t_a = true; - break; - } - } - else { - /* edge of image*/ + pt = index + (ibuf->x * extreme); + if (pt <= maxpixel) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { t_a = true; - break; } } + else { + /* edge of image*/ + t_a = true; + } /* pixels on bottom */ - for (i = 1; i <= limit; i++) { - pt = index - (ibuf->x * i); - if (pt >= 0) { - get_pixel(ibuf, pt, rgba); - if (rgba[0] == 1.0f) { - t_b = true; - break; - } - } - else { - /* edge of image*/ + pt = index - (ibuf->x * extreme); + if (pt >= 0) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { t_b = true; - break; } } + else { + /* edge of image*/ + t_b = true; + } } /* Vertical leak (check horizontal pixels) @@ -608,35 +830,27 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index int higpix = lowpix + ibuf->x - 1; /* pixels to right */ - for (i = 0; i < limit; i++) { - pt = index - (limit - i); - if (pt >= lowpix) { - get_pixel(ibuf, pt, rgba); - if (rgba[0] == 1.0f) { - t_a = true; - break; - } - } - else { - t_a = true; /* edge of image*/ - break; + pt = index - extreme; + if (pt >= lowpix) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_a = true; } } + else { + t_a = true; /* edge of image*/ + } /* pixels to left */ - for (i = 0; i < limit; i++) { - pt = index + (limit - i); - if (pt <= higpix) { - get_pixel(ibuf, pt, rgba); - if (rgba[0] == 1.0f) { - t_b = true; - break; - } - } - else { - t_b = true; /* edge of image */ - break; + pt = index + extreme; + if (pt <= higpix) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_b = true; } } + else { + t_b = true; /* edge of image */ + } } return (bool)(t_a && t_b); } @@ -659,23 +873,37 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); - /* calculate index of the seed point using the position of the mouse */ - int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0]; + /* Calculate index of the seed point using the position of the mouse looking + * for a blue pixel. */ + int index = -1; + for (int i = 0; i < maxpixel; i++) { + get_pixel(ibuf, i, rgba); + if (rgba[2] == 1.0f) { + index = i; + break; + } + } + if ((index >= 0) && (index <= maxpixel)) { - BLI_stack_push(stack, &index); + if (!FILL_DEBUG) { + BLI_stack_push(stack, &index); + } } - /* the fill use a stack to save the pixel list instead of the common recursive + /** + * The fill use a stack to save the pixel list instead of the common recursive * 4-contact point method. * The problem with recursive calls is that for big fill areas, we can get max limit * of recursive calls and STACK_OVERFLOW error. * * The 4-contact point analyze the pixels to the left, right, bottom and top - * ----------- - * | X | - * | XoX | - * | X | - * ----------- + * <pre> + * ----------- + * | X | + * | XoX | + * | X | + * ----------- + * </pre> */ while (!BLI_stack_is_empty(stack)) { int v; @@ -763,7 +991,7 @@ static void gpencil_set_borders(tGPDfill *tgpf, const bool transparent) tgpf->ima->id.tag |= LIB_TAG_DOIT; } -/* Invert image to paint invese area. */ +/* Invert image to paint inverse area. */ static void gpencil_invert_image(tGPDfill *tgpf) { ImBuf *ibuf; @@ -773,18 +1001,24 @@ static void gpencil_invert_image(tGPDfill *tgpf) ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); const int maxpixel = (ibuf->x * ibuf->y) - 1; + const int center = ibuf->x / 2; for (int v = maxpixel; v != 0; v--) { float color[4]; get_pixel(ibuf, v, color); - /* Green. */ + /* Green->Red. */ if (color[1] == 1.0f) { set_pixel(ibuf, v, fill_col[0]); } + /* Red->Green */ else if (color[0] == 1.0f) { set_pixel(ibuf, v, fill_col[1]); + /* Add thickness of 2 pixels to avoid too thin lines. */ + int offset = (v % ibuf->x < center) ? 1 : -1; + set_pixel(ibuf, v + offset, fill_col[1]); } else { + /* Set to Transparent. */ set_pixel(ibuf, v, fill_col[2]); } } @@ -821,21 +1055,37 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf) float rgba[4]; for (int idy = 0; idy < ibuf->y; idy++) { - bool clear = false; + int init = -1; + int end = -1; for (int idx = 0; idx < ibuf->x; idx++) { int image_idx = ibuf->x * idy + idx; get_pixel(ibuf, image_idx, rgba); /* Blue. */ if (rgba[2] == 1.0f) { - clear = true; + if (init < 0) { + init = image_idx; + } + else { + end = image_idx; + } } /* Red. */ else if (rgba[0] == 1.0f) { - clear = false; + if (init > -1) { + for (int i = init; i <= max_ii(init, end); i++) { + set_pixel(ibuf, i, clear_col); + } + init = -1; + end = -1; + } } - if (clear) { - set_pixel(ibuf, image_idx, clear_col); + } + /* Check last segment. */ + if (init > -1) { + for (int i = init; i <= max_ii(init, end); i++) { + set_pixel(ibuf, i, clear_col); } + set_pixel(ibuf, init, clear_col); } } @@ -845,98 +1095,112 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf) tgpf->ima->id.tag |= LIB_TAG_DOIT; } -/* Naive dilate +/** + * Naive dilate * * Expand green areas into enclosing red areas. * Using stack prevents creep when replacing colors directly. + * <pre> * ----------- * XXXXXXX * XoooooX * XXooXXX * XXXX * ----------- + * </pre> */ -static void dilate_shape(ImBuf *ibuf) +static bool dilate_shape(ImBuf *ibuf) { + bool done = false; + BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); const float green[4] = {0.0f, 1.0f, 0.0f, 1.0f}; - const int maxpixel = (ibuf->x * ibuf->y) - 1; + // const int maxpixel = (ibuf->x * ibuf->y) - 1; /* detect pixels and expand into red areas */ - for (int v = maxpixel; v != 0; v--) { - float color[4]; - int index; - int tp = 0; - int bm = 0; - int lt = 0; - int rt = 0; - get_pixel(ibuf, v, color); - if (color[1] == 1.0f) { - /* pixel left */ - if (v - 1 >= 0) { - index = v - 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); - lt = index; + for (int row = 0; row < ibuf->y; row++) { + if (!is_row_filled(ibuf, row)) { + continue; + } + int maxpixel = (ibuf->x * (row + 1)) - 1; + int minpixel = ibuf->x * row; + + for (int v = maxpixel; v != minpixel; v--) { + float color[4]; + int index; + get_pixel(ibuf, v, color); + if (color[1] == 1.0f) { + int tp = 0; + int bm = 0; + int lt = 0; + int rt = 0; + + /* pixel left */ + if (v - 1 >= 0) { + index = v - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + lt = index; + } } - } - /* pixel right */ - if (v + 1 <= maxpixel) { - index = v + 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); - rt = index; + /* pixel right */ + if (v + 1 <= maxpixel) { + index = v + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + rt = index; + } } - } - /* pixel top */ - if (v + ibuf->x <= maxpixel) { - index = v + ibuf->x; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); - tp = index; + /* pixel top */ + if (v + (ibuf->x * 1) <= maxpixel) { + index = v + (ibuf->x * 1); + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + tp = index; + } } - } - /* pixel bottom */ - if (v - ibuf->x >= 0) { - index = v - ibuf->x; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); - bm = index; + /* pixel bottom */ + if (v - (ibuf->x * 1) >= 0) { + index = v - (ibuf->x * 1); + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + bm = index; + } } - } - /* pixel top-left */ - if (tp && lt) { - index = tp - 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); + /* pixel top-left */ + if (tp && lt) { + index = tp - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } } - } - /* pixel top-right */ - if (tp && rt) { - index = tp + 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); + /* pixel top-right */ + if (tp && rt) { + index = tp + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } } - } - /* pixel bottom-left */ - if (bm && lt) { - index = bm - 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); + /* pixel bottom-left */ + if (bm && lt) { + index = bm - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } } - } - /* pixel bottom-right */ - if (bm && rt) { - index = bm + 1; - get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { - BLI_stack_push(stack, &index); + /* pixel bottom-right */ + if (bm && rt) { + index = bm + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } } } } @@ -946,8 +1210,11 @@ static void dilate_shape(ImBuf *ibuf) int v; BLI_stack_pop(stack, &v); set_pixel(ibuf, v, green); + done = true; } BLI_stack_free(stack); + + return done; } /* Get the outline points of a shape using Moore Neighborhood algorithm @@ -963,11 +1230,12 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate) int v[2]; int boundary_co[2]; int start_co[2]; + int first_co[2] = {-1, -1}; int backtracked_co[2]; int current_check_co[2]; int prev_check_co[2]; int backtracked_offset[1][2] = {{0, 0}}; - // bool boundary_found = false; + bool first_pixel = false; bool start_found = false; const int NEIGHBOR_COUNT = 8; @@ -992,7 +1260,6 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate) dilate_shape(ibuf); } - /* find the initial point to start outline analysis */ for (int idx = imagesize - 1; idx != 0; idx--) { get_pixel(ibuf, idx, rgba); if (rgba[1] == 1.0f) { @@ -1015,7 +1282,7 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate) int cur_back_offset = -1; for (int i = 0; i < NEIGHBOR_COUNT; i++) { if (backtracked_offset[0][0] == offset[i][0] && backtracked_offset[0][1] == offset[i][1]) { - /* Finding the bracktracked pixel offset index */ + /* Finding the back-tracked pixel offset index */ cur_back_offset = i; break; } @@ -1045,19 +1312,24 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate) cur_back_offset++; loop++; } - /* current pixel is equal to starting pixel */ - if (boundary_co[0] == start_co[0] && boundary_co[1] == start_co[1]) { + /* Current pixel is equal to starting or first pixel. */ + if ((boundary_co[0] == start_co[0] && boundary_co[1] == start_co[1]) || + (boundary_co[0] == first_co[0] && boundary_co[1] == first_co[1])) { BLI_stack_pop(tgpf->stack, &v); - // boundary_found = true; break; } + + if (!first_pixel) { + first_pixel = true; + copy_v2_v2_int(first_co, boundary_co); + } } /* release ibuf */ BKE_image_release_ibuf(tgpf->ima, ibuf, lock); } -/* get z-depth array to reproject on surface */ +/* Get z-depth array to reproject on surface. */ static void gpencil_get_depth_array(tGPDfill *tgpf) { tGPspoint *ptc; @@ -1108,7 +1380,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) } if (found_depth == false) { - /* eeh... not much we can do.. :/, ignore depth in this case */ + /* Sigh! not much we can do here. Ignore depth in this case. */ for (i = totpoints - 1; i >= 0; i--) { tgpf->depth_arr[i] = 0.9999f; } @@ -1171,6 +1443,9 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) return; } + /* Set as done. */ + tgpf->done = true; + /* Get frame or create a new one. */ tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); @@ -1275,7 +1550,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) float origin[3]; ED_gpencil_drawing_reference_get(tgpf->scene, tgpf->ob, ts->gpencil_v3d_align, origin); ED_gpencil_project_stroke_to_plane( - tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1); + tgpf->scene, tgpf->ob, tgpf->rv3d, tgpf->gpl, gps, origin, tgpf->lock_axis - 1); } /* if parented change position relative to parent object */ @@ -1326,7 +1601,6 @@ static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(region), voi if (region != tgpf->region) { return; } - gpencil_draw_boundary_lines(C, tgpf); } @@ -1377,6 +1651,10 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op)) tgpf->win = CTX_wm_window(C); tgpf->active_cfra = CFRA; + /* Setup space conversions. */ + gpencil_point_conversion_init(C, &tgpf->gsc); + tgpf->zoom = 1.0f; + /* set GP datablock */ tgpf->gpd = gpd; tgpf->gpl = BKE_gpencil_layer_active_get(gpd); @@ -1387,6 +1665,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op)) tgpf->lock_axis = ts->gp_sculpt.lock_axis; tgpf->oldkey = -1; + tgpf->is_render = false; tgpf->sbuffer_used = 0; tgpf->sbuffer = NULL; tgpf->depth_arr = NULL; @@ -1395,11 +1674,13 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op)) Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); tgpf->brush = brush; tgpf->flag = brush->gpencil_settings->flag; - tgpf->fill_leak = brush->gpencil_settings->fill_leak; tgpf->fill_threshold = brush->gpencil_settings->fill_threshold; tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl; tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode; - tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor, 8)); + tgpf->fill_extend_fac = brush->gpencil_settings->fill_extend_fac; + tgpf->fill_factor = max_ff(GPENCIL_MIN_FILL_FAC, + min_ff(brush->gpencil_settings->fill_factor, GPENCIL_MAX_FILL_FAC)); + tgpf->fill_leak = (int)ceil((float)brush->gpencil_settings->fill_leak * tgpf->fill_factor); int totcol = tgpf->ob->totcol; @@ -1424,7 +1705,6 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *UNUSED(op)) /* end operator */ static void gpencil_fill_exit(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); /* clear undo stack */ @@ -1443,16 +1723,14 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op) MEM_SAFE_FREE(tgpf->sbuffer); MEM_SAFE_FREE(tgpf->depth_arr); + /* Remove any temp stroke. */ + gpencil_delete_temp_stroke_extension(tgpf, true); + /* remove drawing handler */ if (tgpf->draw_handle_3d) { ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d); } - /* Delete temp image. */ - if (tgpf->ima) { - BKE_id_free(bmain, tgpf->ima); - } - /* finally, free memory used by temp data */ MEM_freeN(tgpf); } @@ -1536,7 +1814,11 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE tgpf = op->customdata; /* Enable custom drawing handlers to show help lines */ - if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) { + const bool do_extend = (tgpf->fill_extend_fac > 0.0f); + const bool help_lines = ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || + ((tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) && (do_extend))); + + if (help_lines) { tgpf->draw_handle_3d = ED_region_draw_cb_activate( tgpf->region->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW); } @@ -1554,17 +1836,210 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE return OPERATOR_RUNNING_MODAL; } +/* Helper: Calc the maximum bounding box size of strokes to get the zoom level of the viewport. + * For each stroke, the 2D projected bounding box is calculated and using this data, the total + * object bounding box (all strokes) is calculated. */ +static void gpencil_zoom_level_set(tGPDfill *tgpf) +{ + Brush *brush = tgpf->brush; + if (brush->gpencil_settings->flag & GP_BRUSH_FILL_FIT_DISABLE) { + tgpf->zoom = 1.0f; + return; + } + + Object *ob = tgpf->ob; + bGPdata *gpd = tgpf->gpd; + BrushGpencilSettings *brush_settings = tgpf->brush->gpencil_settings; + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); + BLI_assert(gpl_active != NULL); + + const int gpl_active_index = BLI_findindex(&gpd->layers, gpl_active); + BLI_assert(gpl_active_index >= 0); + + /* Init maximum boundbox size. */ + rctf rect_max; + const float winx_half = tgpf->region->winx / 2.0f; + const float winy_half = tgpf->region->winy / 2.0f; + BLI_rctf_init(&rect_max, + 0.0f - winx_half, + tgpf->region->winx + winx_half, + 0.0f - winy_half, + tgpf->region->winy + winy_half); + + float objectbox_min[2], objectbox_max[2]; + INIT_MINMAX2(objectbox_min, objectbox_max); + rctf rect_bound; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + float diff_mat[4][4]; + /* calculate parent matrix */ + BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, ob, gpl, diff_mat); + + /* Decide if the strokes of layers are included or not depending on the layer mode. + * Cannot skip the layer because it can use boundary strokes and must be used. */ + const int gpl_index = BLI_findindex(&gpd->layers, gpl); + bool skip = skip_layer_check(brush_settings->fill_layer_mode, gpl_active_index, gpl_index); + + /* Get frame to check. */ + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); + if (gpf == NULL) { + continue; + } + + /* Read all strokes. */ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + /* check if stroke can be drawn */ + if ((gps->points == NULL) || (gps->totpoints < 2)) { + continue; + } + /* check if the color is visible */ + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE)) { + continue; + } + + /* If the layer must be skipped, but the stroke is not boundary, skip stroke. */ + if ((skip) && ((gps->flag & GP_STROKE_NOFILL) == 0)) { + continue; + } + + float boundbox_min[2]; + float boundbox_max[2]; + ED_gpencil_projected_2d_bound_box(&tgpf->gsc, gps, diff_mat, boundbox_min, boundbox_max); + minmax_v2v2_v2(objectbox_min, objectbox_max, boundbox_min); + minmax_v2v2_v2(objectbox_min, objectbox_max, boundbox_max); + } + } + /* Clamp max bound box. */ + BLI_rctf_init( + &rect_bound, objectbox_min[0], objectbox_max[0], objectbox_min[1], objectbox_max[1]); + float r_xy[2]; + BLI_rctf_clamp(&rect_bound, &rect_max, r_xy); + + /* Calculate total width used. */ + float width = tgpf->region->winx; + if (rect_bound.xmin < 0.0f) { + width -= rect_bound.xmin; + } + if (rect_bound.xmax > tgpf->region->winx) { + width += rect_bound.xmax - tgpf->region->winx; + } + /* Calculate total height used. */ + float height = tgpf->region->winy; + if (rect_bound.ymin < 0.0f) { + height -= rect_bound.ymin; + } + if (rect_bound.ymax > tgpf->region->winy) { + height += rect_bound.ymax - tgpf->region->winy; + } + + width = ceilf(width); + height = ceilf(height); + + float zoomx = (width > tgpf->region->winx) ? width / (float)tgpf->region->winx : 1.0f; + float zoomy = (height > tgpf->region->winy) ? height / (float)tgpf->region->winy : 1.0f; + if ((zoomx != 1.0f) || (zoomy != 1.0f)) { + tgpf->zoom = min_ff(max_ff(zoomx, zoomy) * 1.5f, 5.0f); + } +} + +static bool gpencil_do_frame_fill(tGPDfill *tgpf, const bool is_inverted) +{ + wmWindow *win = CTX_wm_window(tgpf->C); + + /* render screen to temp image */ + int totpoints = 1; + if (gpencil_render_offscreen(tgpf)) { + + /* Set red borders to create a external limit. */ + gpencil_set_borders(tgpf, true); + + /* apply boundary fill */ + gpencil_boundaryfill_area(tgpf); + + /* Invert direction if press Ctrl. */ + if (is_inverted) { + gpencil_invert_image(tgpf); + } + + /* Clean borders to avoid infinite loops. */ + gpencil_set_borders(tgpf, false); + WM_cursor_time(win, 50); + int totpoints_prv = 0; + int loop_limit = 0; + while (totpoints > 0) { + /* analyze outline */ + gpencil_get_outline_points(tgpf, (totpoints == 1) ? true : false); + + /* create array of points from stack */ + totpoints = gpencil_points_from_stack(tgpf); + + /* create z-depth array for reproject */ + gpencil_get_depth_array(tgpf); + + /* create stroke and reproject */ + gpencil_stroke_from_buffer(tgpf); + + if (is_inverted) { + gpencil_erase_processed_area(tgpf); + } + else { + /* Exit of the loop. */ + totpoints = 0; + } + + /* free temp stack data */ + if (tgpf->stack) { + BLI_stack_free(tgpf->stack); + } + WM_cursor_time(win, 100); + + /* Free memory. */ + MEM_SAFE_FREE(tgpf->sbuffer); + MEM_SAFE_FREE(tgpf->depth_arr); + + /* Limit very small areas. */ + if (totpoints < 3) { + break; + } + /* Limit infinite loops is some corner cases. */ + if (totpoints_prv == totpoints) { + loop_limit++; + if (loop_limit > 3) { + break; + } + } + totpoints_prv = totpoints; + } + + /* Delete temp image. */ + if ((tgpf->ima) && (!FILL_DEBUG)) { + BKE_id_free(tgpf->bmain, tgpf->ima); + } + + return true; + } + + return false; +} + /* events handling during interactive part of operator */ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGPDfill *tgpf = op->customdata; - Scene *scene = tgpf->scene; Brush *brush = tgpf->brush; BrushGpencilSettings *brush_settings = brush->gpencil_settings; + tgpf->on_back = RNA_boolean_get(op->ptr, "on_back"); + const bool is_brush_inv = brush_settings->fill_direction == BRUSH_DIR_IN; const bool is_inverted = (is_brush_inv && !event->ctrl) || (!is_brush_inv && event->ctrl); - - int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */ + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(tgpf->gpd); + const bool do_extend = (tgpf->fill_extend_fac > 0.0f); + const bool help_lines = ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || + ((tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) && (do_extend))); + int estate = OPERATOR_RUNNING_MODAL; switch (event->type) { case EVT_ESCKEY: @@ -1572,82 +2047,104 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_CANCELLED; break; case LEFTMOUSE: - tgpf->on_back = RNA_boolean_get(op->ptr, "on_back"); /* first time the event is not enabled to show help lines. */ - if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) { + if ((tgpf->oldkey != -1) || (!help_lines)) { ARegion *region = BKE_area_find_region_xy( CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y); if (region) { bool in_bounds = false; - /* Perform bounds check */ in_bounds = BLI_rcti_isect_pt(®ion->winrct, event->x, event->y); if ((in_bounds) && (region->regiontype == RGN_TYPE_WINDOW)) { - tgpf->center[0] = event->mval[0]; - tgpf->center[1] = event->mval[1]; - - /* Set active frame as current for filling. */ - tgpf->active_cfra = CFRA; + tgpf->mouse[0] = event->mval[0]; + tgpf->mouse[1] = event->mval[1]; + tgpf->is_render = true; + /* Define Zoom level. */ + gpencil_zoom_level_set(tgpf); + + /* Create Temp stroke. */ + tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f); + tGPspoint point2D; + bGPDspoint *pt = &tgpf->gps_mouse->points[0]; + copy_v2fl_v2i(&point2D.x, tgpf->mouse); + gpencil_stroke_convertcoords_tpoint( + tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x); + + /* If not multiframe and there is no frame in CFRA for the active layer, create + * a new frame before to make the hash function can find something. */ + if (!is_multiedit) { + tgpf->gpf = BKE_gpencil_layer_frame_get( + tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + tgpf->gpf->flag |= GP_FRAME_SELECT; + } - /* render screen to temp image */ - int totpoints = 1; - if (gpencil_render_offscreen(tgpf)) { + /* Hash of selected frames.*/ + GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); + BKE_gpencil_frame_selected_hash(tgpf->gpd, frame_list); - /* Set red borders to create a external limit. */ - gpencil_set_borders(tgpf, true); + /* Loop all frames. */ + wmWindow *win = CTX_wm_window(C); - /* apply boundary fill */ - gpencil_boundaryfill_area(tgpf); + GHashIterator gh_iter; + int total = BLI_ghash_len(frame_list); + int i = 1; + GHASH_ITER (gh_iter, frame_list) { + /* Set active frame as current for filling. */ + tgpf->active_cfra = POINTER_AS_INT(BLI_ghashIterator_getKey(&gh_iter)); + int step = ((float)i / (float)total) * 100.0f; + WM_cursor_time(win, step); - /* Invert direction if press Ctrl. */ - if (is_inverted) { - gpencil_invert_image(tgpf); + if (do_extend) { + gpencil_update_extend(tgpf); } - /* Clean borders to avoid infinite loops. */ - gpencil_set_borders(tgpf, false); - - while (totpoints > 0) { - /* analyze outline */ - gpencil_get_outline_points(tgpf, (totpoints == 1) ? true : false); - - /* create array of points from stack */ - totpoints = gpencil_points_from_stack(tgpf); - - /* create z-depth array for reproject */ - gpencil_get_depth_array(tgpf); - - /* create stroke and reproject */ - gpencil_stroke_from_buffer(tgpf); - - if (is_inverted) { - gpencil_erase_processed_area(tgpf); - } - else { - /* Exit of the loop. */ - totpoints = 0; - } - - /* free temp stack data */ - if (tgpf->stack) { - BLI_stack_free(tgpf->stack); + /* Repeat loop until get something. */ + tgpf->done = false; + int loop_limit = 0; + while ((!tgpf->done) && (loop_limit < 2)) { + WM_cursor_time(win, loop_limit + 1); + /* Render screen to temp image and do fill. */ + gpencil_do_frame_fill(tgpf, is_inverted); + + /* restore size */ + tgpf->region->winx = (short)tgpf->bwinx; + tgpf->region->winy = (short)tgpf->bwiny; + tgpf->region->winrct = tgpf->brect; + if (!tgpf->done) { + /* If the zoom was not set before, avoid a loop. */ + if (tgpf->zoom == 1.0f) { + loop_limit++; + } + else { + tgpf->zoom = 1.0f; + tgpf->fill_factor = max_ff( + GPENCIL_MIN_FILL_FAC, + min_ff(brush->gpencil_settings->fill_factor, GPENCIL_MAX_FILL_FAC)); + } } + loop_limit++; + } - /* Free memory. */ - MEM_SAFE_FREE(tgpf->sbuffer); - MEM_SAFE_FREE(tgpf->depth_arr); + if (do_extend) { + gpencil_delete_temp_stroke_extension(tgpf, true); } + + i++; } + WM_cursor_modal_restore(win); + /* Free hash table. */ + BLI_ghash_free(frame_list, NULL, NULL); - /* restore size */ - tgpf->region->winx = (short)tgpf->bwinx; - tgpf->region->winy = (short)tgpf->bwiny; - tgpf->region->winrct = tgpf->brect; + /* Free temp stroke. */ + BKE_gpencil_free_stroke(tgpf->gps_mouse); /* push undo data */ gpencil_undo_push(tgpf->gpd); + /* Save extend value for next operation. */ + brush_settings->fill_extend_fac = tgpf->fill_extend_fac; + estate = OPERATOR_FINISHED; } else { @@ -1658,8 +2155,29 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_CANCELLED; } } + else if (do_extend) { + gpencil_update_extend(tgpf); + } tgpf->oldkey = event->type; break; + case EVT_PAGEUPKEY: + case WHEELUPMOUSE: + if (tgpf->oldkey == 1) { + tgpf->fill_extend_fac -= (event->shift) ? 0.01f : 0.1f; + CLAMP_MIN(tgpf->fill_extend_fac, 0.0f); + gpencil_update_extend(tgpf); + } + break; + case EVT_PAGEDOWNKEY: + case WHEELDOWNMOUSE: + if (tgpf->oldkey == 1) { + tgpf->fill_extend_fac += (event->shift) ? 0.01f : 0.1f; + CLAMP_MAX(tgpf->fill_extend_fac, 100.0f); + gpencil_update_extend(tgpf); + } + break; + default: + break; } /* process last operations before exiting */ switch (estate) { @@ -1672,7 +2190,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_fill_exit(C, op); break; - case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: + default: break; } diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 4a908eff92e..5fea46626d5 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -667,7 +667,8 @@ struct GP_EditableStrokes_Iter { bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ - BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ + BKE_gpencil_layer_transform_matrix_get( \ + depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* loop over strokes */ \ bGPDstroke *gpsn_; \ @@ -678,7 +679,7 @@ struct GP_EditableStrokes_Iter { continue; \ } \ /* check if the color is editable */ \ - if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) { \ + if (ED_gpencil_stroke_material_editable(obact_, gpl, gps) == false) { \ continue; \ } \ /* ... Do Stuff With Strokes ... */ @@ -718,7 +719,8 @@ struct GP_EditableStrokes_Iter { bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ - BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ + BKE_gpencil_layer_transform_matrix_get( \ + depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* loop over strokes */ \ bGPDstroke *gpsn_; \ @@ -767,8 +769,10 @@ struct GP_EditableStrokes_Iter { bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ - BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ - invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ + BKE_gpencil_layer_transform_matrix_get( \ + depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ + /* Undo layer transform. */ \ + mul_m4_m4m4(gpstroke_iter.diff_mat, gpstroke_iter.diff_mat, gpl->layer_invmat); \ /* loop over strokes */ \ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \ /* skip strokes that are invalid for current view */ \ @@ -776,7 +780,7 @@ struct GP_EditableStrokes_Iter { continue; \ } \ /* check if the color is editable */ \ - if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) { \ + if (ED_gpencil_stroke_material_editable(obact_, gpl, gps) == false) { \ continue; \ } \ /* ... Do Stuff With Strokes ... */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index c666fcb67b7..ecd243ed595 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -48,31 +48,22 @@ #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_report.h" #include "UI_interface.h" -#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "UI_view2d.h" #include "ED_gpencil.h" -#include "ED_object.h" #include "ED_screen.h" -#include "ED_space_api.h" -#include "ED_view3d.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" @@ -229,7 +220,7 @@ static bool gpencil_interpolate_check_todo(bContext *C, bGPdata *gpd) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps_from) == false) { continue; } @@ -283,8 +274,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; - tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); - tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); + tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe, true); + tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next, true); BLI_addtail(&tgpi->ilayers, tgpil); @@ -315,7 +306,7 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) { + if (ED_gpencil_stroke_material_editable(ob, tgpil->gpl, gps_from) == false) { valid = false; } @@ -734,7 +725,7 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; /* properties */ - RNA_def_float_percentage( + RNA_def_float_factor( ot->srna, "shift", 0.0f, @@ -1008,8 +999,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* store extremes */ - prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); - nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); + prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe, true); + nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next, true); /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) { @@ -1048,7 +1039,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps_from) == false) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 272dff56291..435bff34998 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -48,12 +48,9 @@ #include "RNA_define.h" #include "ED_gpencil.h" -#include "ED_object.h" #include "ED_screen.h" -#include "ED_view3d.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index 53beaeaa6a0..ffe676f0520 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -36,8 +36,6 @@ #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_duplilist.h" -#include "BKE_global.h" -#include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" #include "BKE_layer.h" #include "BKE_main.h" diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 0a29b83bc4f..1a6cb5670c4 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -27,9 +27,7 @@ #include "BLI_sys_types.h" -#include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_gpencil.h" #include "BKE_paint.h" #include "DNA_brush_types.h" @@ -45,9 +43,6 @@ #include "RNA_access.h" #include "ED_gpencil.h" -#include "ED_object.h" -#include "ED_select_utils.h" -#include "ED_transform.h" #include "gpencil_intern.h" diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 815bbbaa254..45842c28dff 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -34,16 +34,12 @@ #include "DNA_gpencil_types.h" #include "DNA_material_types.h" -#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_main.h" -#include "BKE_material.h" #include "BKE_object.h" #include "WM_api.h" @@ -53,7 +49,6 @@ #include "RNA_define.h" #include "ED_gpencil.h" -#include "ED_object.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 889aea84c97..126de952e99 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -426,7 +426,7 @@ static void gpencil_reproject_toplane(tGPsdata *p, bGPDstroke *gps) /* get drawing origin */ gpencil_get_3d_reference(p, origin); - ED_gpencil_project_stroke_to_plane(p->scene, obact, rv3d, gps, origin, p->lock_axis - 1); + ED_gpencil_project_stroke_to_plane(p->scene, obact, rv3d, p->gpl, gps, origin, p->lock_axis - 1); } /* convert screen-coordinates to buffer-coordinates */ @@ -887,11 +887,13 @@ static short gpencil_stroke_addpoint(tGPsdata *p, gpencil_get_3d_reference(p, origin); /* reproject current */ ED_gpencil_tpoint_to_point(p->region, origin, pt, &spt); - ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt); + ED_gpencil_project_point_to_plane( + p->scene, obact, p->gpl, rv3d, origin, p->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(p->region, origin, ptb, &spt2); - ED_gpencil_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2); + ED_gpencil_project_point_to_plane( + p->scene, obact, p->gpl, rv3d, origin, p->lock_axis - 1, &spt2); p->totpixlen += len_v3v3(&spt.x, &spt2.x); pt->uv_fac = p->totpixlen; } @@ -1304,6 +1306,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gpd, gps); + /* In Multiframe mode, duplicate the stroke in other frames. */ + if (GPENCIL_MULTIEDIT_SESSIONS_ON(p->gpd)) { + const bool tail = (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK); + BKE_gpencil_stroke_copy_to_keyframes(gpd, gpl, p->gpf, gps, tail); + } + gpencil_stroke_added_enable(p); } @@ -1321,10 +1329,8 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) } /* only erase stroke points that are visible */ -static bool gpencil_stroke_eraser_is_occluded(tGPsdata *p, - const bGPDspoint *pt, - const int x, - const int y) +static bool gpencil_stroke_eraser_is_occluded( + tGPsdata *p, bGPDlayer *gpl, const bGPDspoint *pt, const int x, const int y) { Object *obact = (Object *)p->ownerPtr.data; Brush *brush = p->brush; @@ -1341,7 +1347,6 @@ static bool gpencil_stroke_eraser_is_occluded(tGPsdata *p, if ((gp_settings != NULL) && (p->area->spacetype == SPACE_VIEW3D) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) { RegionView3D *rv3d = p->region->regiondata; - bGPDlayer *gpl = p->gpl; const int mval_i[2] = {x, y}; float mval_3d[3]; @@ -1349,7 +1354,7 @@ static bool gpencil_stroke_eraser_is_occluded(tGPsdata *p, float diff_mat[4][4]; /* calculate difference matrix if parent object */ - BKE_gpencil_parent_matrix_get(p->depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(p->depsgraph, obact, gpl, diff_mat); if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) { const float depth_mval = view3d_point_depth(rv3d, mval_3d); @@ -1452,6 +1457,7 @@ static void gpencil_stroke_soft_refine(bGPDstroke *gps) /* eraser tool - evaluation per stroke */ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, + bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, const float mval[2], @@ -1577,9 +1583,9 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, * - this assumes that linewidth is irrelevant */ if (gpencil_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) { - if ((gpencil_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) || - (gpencil_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || - (gpencil_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) { + if ((gpencil_stroke_eraser_is_occluded(p, gpl, pt0, pc0[0], pc0[1]) == false) || + (gpencil_stroke_eraser_is_occluded(p, gpl, pt1, pc1[0], pc1[1]) == false) || + (gpencil_stroke_eraser_is_occluded(p, gpl, pt2, pc2[0], pc2[1]) == false)) { /* Point is affected: */ /* Adjust thickness * - Influence of eraser falls off with distance from the middle of the eraser @@ -1681,6 +1687,8 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, /* erase strokes which fall under the eraser strokes */ static void gpencil_stroke_doeraser(tGPsdata *p) { + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(p->gpd); + rcti rect; Brush *brush = p->brush; Brush *eraser = p->eraser; @@ -1721,40 +1729,53 @@ static void gpencil_stroke_doeraser(tGPsdata *p) * on multiple layers... */ LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) { - bGPDframe *gpf = gpl->actframe; - /* only affect layer if it's editable (and visible) */ if (BKE_gpencil_layer_is_editable(gpl) == false) { continue; } - if (gpf == NULL) { + + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + if (init_gpf == NULL) { continue; } - /* calculate difference matrix */ - BKE_gpencil_parent_matrix_get(p->depsgraph, p->ob, gpl, p->diff_mat); - /* loop over strokes, checking segments for intersections */ - LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) { - continue; - } + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + /* calculate difference matrix */ + BKE_gpencil_layer_transform_matrix_get(p->depsgraph, p->ob, gpl, p->diff_mat); + + /* loop over strokes, checking segments for intersections */ + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + /* check if the color is editable */ + if (ED_gpencil_stroke_material_editable(p->ob, gpl, gps) == false) { + continue; + } - /* Check if the stroke collide with mouse. */ - if (!ED_gpencil_stroke_check_collision(&p->gsc, gps, p->mval, calc_radius, p->diff_mat)) { - continue; - } + /* Check if the stroke collide with mouse. */ + if (!ED_gpencil_stroke_check_collision( + &p->gsc, gps, p->mval, calc_radius, p->diff_mat)) { + continue; + } - /* Not all strokes in the datablock may be valid in the current editor/context - * (e.g. 2D space strokes in the 3D view, if the same datablock is shared) - */ - if (ED_gpencil_stroke_can_use_direct(p->area, gps)) { - gpencil_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect); + /* Not all strokes in the datablock may be valid in the current editor/context + * (e.g. 2D space strokes in the 3D view, if the same datablock is shared) + */ + if (ED_gpencil_stroke_can_use_direct(p->area, gps)) { + gpencil_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, calc_radius, &rect); + } + } + + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } } } } } - /* ******************************************* */ /* Sketching Operator */ @@ -2103,6 +2124,11 @@ static void gpencil_paint_initstroke(tGPsdata *p, copy_v3_v3(p->gpl->color, p->custom_color); } } + + /* Recalculate layer transform matrix to avoid problems if props are animated. */ + loc_eul_size_to_mat4(p->gpl->layer_mat, p->gpl->location, p->gpl->rotation, p->gpl->scale); + invert_m4_m4(p->gpl->layer_invmat, p->gpl->layer_mat); + if ((paintmode != GP_PAINTMODE_ERASER) && (p->gpl->flag & GP_LAYER_LOCKED)) { p->status = GP_STATUS_ERROR; if (G.debug & G_DEBUG) { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 622680e5fb9..89c6b1dcc75 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -317,6 +317,10 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) } tgpi->gpl = gpl; + /* Recalculate layer transform matrix to avoid problems if props are animated. */ + loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); + /* create a new temporary frame */ tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe"); tgpi->gpf->framenum = tgpi->cframe = cfra; @@ -1004,12 +1008,12 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* reproject current */ ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt); ED_gpencil_project_point_to_plane( - tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt); + tgpi->scene, tgpi->ob, tgpi->gpl, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(tgpi->region, origin, tptb, &spt2); ED_gpencil_project_point_to_plane( - tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2); + tgpi->scene, tgpi->ob, tgpi->gpl, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2); tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x); tpt->uv_fac = tgpi->totpixlen; } @@ -1068,7 +1072,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) float origin[3]; ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin); ED_gpencil_project_stroke_to_plane( - tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1); + tgpi->scene, tgpi->ob, tgpi->rv3d, tgpi->gpl, gps, origin, ts->gp_sculpt.lock_axis - 1); } /* if parented change position relative to parent object */ @@ -1373,6 +1377,12 @@ static void gpencil_primitive_interaction_end(bContext *C, BKE_gpencil_stroke_geometry_update(tgpi->gpd, gps); } + /* In Multiframe mode, duplicate the stroke in other frames. */ + if (GPENCIL_MULTIEDIT_SESSIONS_ON(tgpi->gpd)) { + const bool tail = (ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK); + BKE_gpencil_stroke_copy_to_keyframes(tgpi->gpd, tgpi->gpl, gpf, gps, tail); + } + DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index bb9dd8cac5d..0d3ab9011d6 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1441,11 +1441,6 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, bool changed = false; float rot_eval = 0.0f; - /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { - return false; - } - if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; @@ -1577,6 +1572,13 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, Object *ob = gso->object; bGPdata *gpd = ob->data; char tool = gso->brush->gpencil_sculpt_tool; + GP_SpaceConversion *gsc = &gso->gsc; + Brush *brush = gso->brush; + const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : + gso->brush->size; + /* Calc bound box matrix. */ + float bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat); LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ @@ -1584,7 +1586,12 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + continue; + } + + /* Check if the stroke collide with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { continue; } @@ -1742,7 +1749,8 @@ static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData * /* calculate difference matrix */ float diff_mat[4][4]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 281ab8c5adc..a00d21bf88a 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -2473,7 +2473,7 @@ static void gpencil_selected_hue_table(bContext *C, if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } if ((gps->flag & GP_STROKE_SELECT) == 0) { diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c index 0be9d74278e..0f344909692 100644 --- a/source/blender/editors/gpencil/gpencil_trace_ops.c +++ b/source/blender/editors/gpencil/gpencil_trace_ops.c @@ -23,7 +23,6 @@ #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -31,34 +30,26 @@ #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_duplilist.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_material.h" #include "BKE_object.h" #include "BKE_report.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -#include "UI_interface.h" -#include "UI_resources.h" - #include "WM_api.h" #include "WM_types.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" -#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "ED_gpencil.h" @@ -66,7 +57,6 @@ #include "gpencil_intern.h" #include "gpencil_trace.h" -#include "potracelib.h" typedef struct TraceJob { /* from wmJob */ @@ -87,6 +77,7 @@ typedef struct TraceJob { bGPDlayer *gpl; bool was_ob_created; + bool use_current_frame; int32_t frame_target; float threshold; @@ -228,15 +219,17 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo trace_job->do_update = do_update; trace_job->progress = progress; trace_job->was_canceled = false; + const int init_frame = max_ii((trace_job->use_current_frame) ? trace_job->frame_target : 0, 0); G.is_break = false; /* Single Image. */ - if ((trace_job->image->source == IMA_SRC_FILE) || (trace_job->mode == GPENCIL_TRACE_MODE_SINGLE)) { void *lock; - ImBuf *ibuf = BKE_image_acquire_ibuf(trace_job->image, NULL, &lock); + ImageUser *iuser = trace_job->ob_active->iuser; + iuser->framenr = init_frame; + ImBuf *ibuf = BKE_image_acquire_ibuf(trace_job->image, iuser, &lock); if (ibuf) { /* Create frame. */ bGPDframe *gpf = BKE_gpencil_layer_frame_get( @@ -249,7 +242,7 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo /* Image sequence. */ else if (trace_job->image->type == IMA_TYPE_IMAGE) { ImageUser *iuser = trace_job->ob_active->iuser; - for (int i = 0; i < iuser->frames; i++) { + for (int i = init_frame; i < iuser->frames; i++) { if (G.is_break) { trace_job->was_canceled = true; break; @@ -320,6 +313,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op) job->ob_active = job->base_active->object; job->image = (Image *)job->ob_active->data; job->frame_target = CFRA; + job->use_current_frame = RNA_boolean_get(op->ptr, "use_current_frame"); /* Create a new grease pencil object or reuse selected. */ eGP_TargetObjectMode target = RNA_enum_get(op->ptr, "target"); @@ -493,4 +487,9 @@ void GPENCIL_OT_trace_image(wmOperatorType *ot) GPENCIL_TRACE_MODE_SINGLE, "Mode", "Determines if trace simple image or full sequence"); + RNA_def_boolean(ot->srna, + "use_current_frame", + true, + "Start At Current Frame", + "Trace Image starting in current image frame"); } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index c2504ce329e..4e172104ce7 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -36,6 +36,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_undo_system.h" #include "ED_gpencil.h" @@ -61,28 +62,22 @@ int ED_gpencil_session_active(void) return (BLI_listbase_is_empty(&undo_nodes) == false); } -int ED_undo_gpencil_step(bContext *C, int step, const char *name) +int ED_undo_gpencil_step(bContext *C, const eUndoStepDir step) { bGPdata **gpd_ptr = NULL, *new_gpd = NULL; gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - if (step == 1) { /* undo */ - // printf("\t\tGP - undo step\n"); + if (step == STEP_UNDO) { if (cur_node->prev) { - if (!name || STREQ(cur_node->name, name)) { - cur_node = cur_node->prev; - new_gpd = cur_node->gpd; - } + cur_node = cur_node->prev; + new_gpd = cur_node->gpd; } } - else if (step == -1) { - // printf("\t\tGP - redo step\n"); + else if (step == STEP_REDO) { if (cur_node->next) { - if (!name || STREQ(cur_node->name, name)) { - cur_node = cur_node->next; - new_gpd = cur_node->gpd; - } + cur_node = cur_node->next; + new_gpd = cur_node->gpd; } } @@ -99,7 +94,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* make a copy of source layer and its data */ - gpld = BKE_gpencil_layer_duplicate(gpl); + gpld = BKE_gpencil_layer_duplicate(gpl, true, true); BLI_addtail(&gpd->layers, gpld); } } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 7c796f7b7a1..9b12772bc9b 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -579,7 +579,7 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps) } /* Check whether given stroke can be edited for the current color */ -bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps) +bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps) { /* check if the color is editable */ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); @@ -674,7 +674,7 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b float inverse_diff_mat[4][4]; float fpt[3]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); for (i = 0; i < gps->totpoints; i++) { @@ -697,10 +697,11 @@ void gpencil_apply_parent_point(Depsgraph *depsgraph, float inverse_diff_mat[4][4]; float fpt[3]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x); + copy_v3_v3(&pt->x, fpt); } @@ -997,6 +998,12 @@ void ED_gpencil_drawing_reference_get(const Scene *scene, else { /* use object location */ copy_v3_v3(r_vec, ob->obmat[3]); + /* Apply layer offset. */ + bGPdata *gpd = ob->data; + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); + if (gpl != NULL) { + add_v3_v3(r_vec, gpl->layer_mat[3]); + } } } } @@ -1021,7 +1028,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * /* init space conversion stuff */ gpencil_point_conversion_init(C, &gsc); - BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); /* Adjust each point */ @@ -1046,6 +1053,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * void ED_gpencil_project_stroke_to_plane(const Scene *scene, const Object *ob, const RegionView3D *rv3d, + bGPDlayer *gpl, bGPDstroke *gps, const float origin[3], const int axis) @@ -1058,6 +1066,10 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene, float ray[3]; float rpoint[3]; + /* Recalculate layer transform matrix. */ + loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); + /* normal vector for a plane locked to axis */ zero_v3(plane_normal); if (axis < 0) { @@ -1074,24 +1086,27 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene, copy_m4_m4(mat, ob->obmat); /* move origin to cursor */ + if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { + if (gpl != NULL) { + add_v3_v3(mat[3], gpl->location); + } + } if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { copy_v3_v3(mat[3], cursor->location); } mul_mat3_m4_v3(mat, plane_normal); } + + if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) { + mul_mat3_m4_v3(gpl->layer_mat, plane_normal); + } } else { const float scale[3] = {1.0f, 1.0f, 1.0f}; plane_normal[2] = 1.0f; float mat[4][4]; loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale); - - /* move origin to object */ - if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { - copy_v3_v3(mat[3], ob->obmat[3]); - } - mul_mat3_m4_v3(mat, plane_normal); } @@ -1127,8 +1142,12 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, ARegion *region = gsc->region; RegionView3D *rv3d = region->regiondata; + /* Recalculate layer transform matrix. */ + loc_eul_size_to_mat4(gpl->layer_mat, gpl->location, gpl->rotation, gpl->scale); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); + float diff_mat[4][4], inverse_diff_mat[4][4]; - BKE_gpencil_parent_matrix_get(depsgraph, gsc->ob, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, gsc->ob, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); float origin[3]; @@ -1194,7 +1213,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, } } - ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, rv3d, origin, axis, &pt2); + ED_gpencil_project_point_to_plane(gsc->scene, gsc->ob, gpl, rv3d, origin, axis, &pt2); copy_v3_v3(&pt->x, &pt2.x); @@ -1250,6 +1269,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, */ void ED_gpencil_project_point_to_plane(const Scene *scene, const Object *ob, + bGPDlayer *gpl, const RegionView3D *rv3d, const float origin[3], const int axis, @@ -1277,6 +1297,11 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, if (ob && (ob->type == OB_GPENCIL)) { float mat[4][4]; copy_m4_m4(mat, ob->obmat); + if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { + if (gpl != NULL) { + add_v3_v3(mat[3], gpl->location); + } + } /* move origin to cursor */ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { @@ -1284,6 +1309,10 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, } mul_mat3_m4_v3(mat, plane_normal); + /* Apply layer rotation (local transform). */ + if ((gpl != NULL) && (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_CURSOR)) { + mul_mat3_m4_v3(gpl->layer_mat, plane_normal); + } } } else { @@ -1449,7 +1478,7 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata /* only redo if any change */ if (!equals_m4m4(gpl->inverse, cur_mat)) { /* first apply current transformation to all strokes */ - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); /* undo local object */ sub_v3_v3(diff_mat[3], gpl_loc); @@ -2144,7 +2173,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat) LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if it is editable */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1); @@ -3003,12 +3032,12 @@ void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph, } } -/* Helper to get the bigger 2D bound box points. */ -static void gpencil_projected_2d_bound_box(GP_SpaceConversion *gsc, - bGPDstroke *gps, - const float diff_mat[4][4], - float r_min[2], - float r_max[2]) +/* Get the bigger 2D bound box points. */ +void ED_gpencil_projected_2d_bound_box(GP_SpaceConversion *gsc, + bGPDstroke *gps, + const float diff_mat[4][4], + float r_min[2], + float r_max[2]) { float bounds[8][2]; BoundBox bb; @@ -3053,7 +3082,7 @@ bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, BKE_gpencil_stroke_boundingbox_calc(gps); } - gpencil_projected_2d_bound_box(gsc, gps, diff_mat, boundbox_min, boundbox_max); + ED_gpencil_projected_2d_bound_box(gsc, gps, diff_mat, boundbox_min, boundbox_max); rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]}; @@ -3126,7 +3155,7 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C, /* calculate difference matrix object */ float diff_mat[4][4]; - BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); /* Calculate the extremes of the stroke in 2D. */ bGPDspoint pt_parent; @@ -3144,15 +3173,13 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C, float dist_min = FLT_MAX; LISTBASE_FOREACH (bGPDstroke *, gps_target, &gpf->strokes) { /* Check if the color is editable. */ - if ((gps_target == gps) || (ED_gpencil_stroke_color_use(ob, gpl, gps) == false)) { + if ((gps_target == gps) || (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false)) { continue; } /* Check if one of the ends is inside target stroke bounding box. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_start, radius, diff_mat)) { - continue; - } - if (!ED_gpencil_stroke_check_collision(gsc, gps, pt2d_end, radius, diff_mat)) { + if ((!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_start, radius, diff_mat)) && + (!ED_gpencil_stroke_check_collision(gsc, gps_target, pt2d_end, radius, diff_mat))) { continue; } /* Check the distance of the ends with the ends of target stroke to avoid middle contact. diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index ec2ccabddfe..677451eaabc 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -31,7 +31,6 @@ #include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_gpencil_geom.h" -#include "BKE_unit.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index b212872b607..bf46fa2544f 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -28,16 +28,11 @@ #include "BLI_ghash.h" #include "BLI_math.h" -#include "BLT_translation.h" - #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_material_types.h" -#include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_paint.h" @@ -48,16 +43,11 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "UI_view2d.h" #include "ED_gpencil.h" #include "ED_screen.h" -#include "ED_view3d.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" @@ -674,7 +664,7 @@ static bool gpencil_extract_palette_from_vertex(bContext *C, if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); @@ -859,7 +849,7 @@ static int gpencil_material_to_vertex_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index e2c81d53fba..a05cc3c4dbd 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -151,7 +151,7 @@ typedef struct tGP_BrushVertexpaintData { tGP_Grid *grid; /** Total number of rows/cols. */ int grid_size; - /** Total number of cells elments in the grid array. */ + /** Total number of cells elements in the grid array. */ int grid_len; /** Grid sample position (used to determine distance of falloff) */ int grid_sample[2]; @@ -825,7 +825,8 @@ static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso, static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, const char tool, - const float diff_mat[4][4]) + const float diff_mat[4][4], + const float bound_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; @@ -853,7 +854,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, } /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { return false; } @@ -998,7 +999,8 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C, tGP_BrushVertexpaintData *gso, bGPDlayer *gpl, bGPDframe *gpf, - const float diff_mat[4][4]) + const float diff_mat[4][4], + const float bound_mat[4][4]) { Object *ob = CTX_data_active_object(C); const char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool : @@ -1020,12 +1022,12 @@ static bool gpencil_vertexpaint_brush_do_frame(bContext *C, continue; } /* Check if the color is editable. */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } /* Check points below the brush. */ - bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat); + bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat, bound_mat); /* If stroke was hit and has an editcurve the curve needs an update. */ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; @@ -1130,9 +1132,11 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert continue; } - /* calculate difference matrix */ - float diff_mat[4][4]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + /* Calculate transform matrix. */ + float diff_mat[4][4], bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); + copy_m4_m4(bound_mat, diff_mat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { @@ -1159,7 +1163,7 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert } /* affect strokes in this frame */ - changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); + changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat); } } } @@ -1167,7 +1171,8 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert /* Apply to active frame's strokes */ if (gpl->actframe != NULL) { gso->mf_falloff = 1.0f; - changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + changed |= gpencil_vertexpaint_brush_do_frame( + C, gso, gpl, gpl->actframe, diff_mat, bound_mat); } } } diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 7fa71fcce3c..a3e5ece5862 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -383,7 +383,8 @@ static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso, /* Select points in this stroke and add to an array to be used later. */ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, - const float diff_mat[4][4]) + const float diff_mat[4][4], + const float bound_mat[4][4]) { GP_SpaceConversion *gsc = &gso->gsc; rcti *rect = &gso->brush_rect; @@ -402,7 +403,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, bool include_last = false; /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { return; } @@ -505,7 +506,8 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, tGP_BrushWeightpaintData *gso, bGPDlayer *gpl, bGPDframe *gpf, - const float diff_mat[4][4]) + const float diff_mat[4][4], + const float bound_mat[4][4]) { Object *ob = CTX_data_active_object(C); char tool = gso->brush->gpencil_weight_tool; @@ -526,12 +528,12 @@ static bool gpencil_weightpaint_brush_do_frame(bContext *C, continue; } /* Check if the color is editable. */ - if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { continue; } /* Check points below the brush. */ - gpencil_weightpaint_select_stroke(gso, gps, diff_mat); + gpencil_weightpaint_select_stroke(gso, gps, diff_mat, bound_mat); } /*--------------------------------------------------------------------- @@ -578,9 +580,11 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig continue; } - /* calculate difference matrix */ - float diff_mat[4][4]; - BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); + /* Calculate transform matrix. */ + float diff_mat[4][4], bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); + copy_m4_m4(bound_mat, diff_mat); + mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { @@ -608,7 +612,7 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig } /* affect strokes in this frame */ - changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat); + changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat); } } } @@ -616,7 +620,8 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig if (gpl->actframe != NULL) { /* Apply to active frame's strokes */ gso->mf_falloff = 1.0f; - changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + changed |= gpencil_weightpaint_brush_do_frame( + C, gso, gpl, gpl->actframe, diff_mat, bound_mat); } } } |