Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/gpencil')
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c11
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c39
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c139
-rw-r--r--source/blender/editors/gpencil/gpencil_edit_curve.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c1142
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h16
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c5
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c92
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c22
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_ops.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c81
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c14
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c25
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(&region->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);
}
}
}