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/annotate_paint.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c19
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.cc23
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c857
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h26
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.cc18
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c56
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c346
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_ops.c39
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_utils.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c120
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c16
22 files changed, 1311 insertions, 395 deletions
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 287dce1a509..2fd58a9cee0 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -13,9 +13,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -321,7 +318,7 @@ static void annotation_stroke_convertcoords(tGPsdata *p,
int mval_i[2];
round_v2i_v2fl(mval_i, mval);
if (annotation_project_check(p) &&
- (ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
+ ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth)) {
/* projecting onto 3D-Geometry
* - nothing more needs to be done here, since view_autodist_simple() has already done it
*/
@@ -1120,7 +1117,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* free stroke */
@@ -1162,8 +1159,8 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p,
gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
/* Check that point segment of the bound-box of the eraser stroke. */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1]) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that line-width is irrelevant.
@@ -2346,7 +2343,7 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev
return OPERATOR_RUNNING_MODAL;
}
-/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+/* gpencil modal operator stores area, which can be removed while using it (like full-screen). */
static bool annotation_area_exists(bContext *C, ScrArea *area_test)
{
bScreen *screen = CTX_wm_screen(C);
@@ -2520,7 +2517,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
* (Disabling RIGHTMOUSE case here results in bugs like T32647)
* also making sure we have a valid event value, to not exit too early
*/
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && ELEM(event->val, KM_PRESS, KM_RELEASE)) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
int sketch = 0;
@@ -2698,7 +2695,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ /* gpencil modal operator stores area, which can be removed while using it (like full-screen). */
if (0 == annotation_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index d389f7eb5dd..2b7e09b7f05 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -29,6 +29,7 @@
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -328,8 +329,8 @@ static void gpencil_add_verts_to_dgroups(
copy_v3_v3(tip[j], bone->arm_tail);
}
- mul_m4_v3(ob_arm->obmat, root[j]);
- mul_m4_v3(ob_arm->obmat, tip[j]);
+ mul_m4_v3(ob_arm->object_to_world, root[j]);
+ mul_m4_v3(ob_arm->object_to_world, tip[j]);
selected[j] = 1;
@@ -363,7 +364,7 @@ static void gpencil_add_verts_to_dgroups(
/* transform stroke points to global space */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
copy_v3_v3(verts[i], &pt->x);
- mul_m4_v3(ob->obmat, verts[i]);
+ mul_m4_v3(ob->object_to_world, verts[i]);
}
/* loop groups and assign weight */
@@ -528,6 +529,7 @@ static bool gpencil_generate_weights_poll(bContext *C)
return false;
}
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
bGPdata *gpd = (bGPdata *)ob->data;
@@ -536,7 +538,8 @@ static bool gpencil_generate_weights_poll(bContext *C)
}
/* need some armature in the view layer */
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) {
if (base->object->type == OB_ARMATURE) {
return true;
}
@@ -548,6 +551,7 @@ static bool gpencil_generate_weights_poll(bContext *C)
static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
@@ -566,7 +570,8 @@ static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
/* get armature */
const int arm_idx = RNA_enum_get(op->ptr, "armature");
if (arm_idx > 0) {
- Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1);
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ Base *base = BLI_findlink(BKE_view_layer_object_bases_get(view_layer), arm_idx - 1);
ob_arm = base->object;
}
else {
@@ -607,6 +612,7 @@ static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
EnumPropertyItem *item = NULL, item_tmp = {0};
int totitem = 0;
@@ -623,7 +629,8 @@ static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
i++;
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ BKE_view_layer_synced_ensure(scene, view_layer);
+ LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) {
Object *ob = base->object;
if (ob->type == OB_ARMATURE) {
item_tmp.identifier = item_tmp.name = ob->id.name + 2;
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc
index e480852a9bb..4ef2cf9ffd6 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.cc
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc
@@ -65,8 +65,8 @@ const EnumPropertyItem rna_gpencil_reproject_type_items[] = {
};
/* Check frame_end is always > start frame! */
-static void gpencil_bake_set_frame_end(struct Main *UNUSED(main),
- struct Scene *UNUSED(scene),
+static void gpencil_bake_set_frame_end(struct Main * /*main*/,
+ struct Scene * /*scene*/,
struct PointerRNA *ptr)
{
int frame_start = RNA_int_get(ptr, "frame_start");
@@ -86,7 +86,7 @@ static bool gpencil_bake_grease_pencil_animation_poll(bContext *C)
}
/* Check if grease pencil or empty for dupli groups. */
- if ((obact == nullptr) || (!ELEM(obact->type, OB_GPENCIL, OB_EMPTY))) {
+ if ((obact == nullptr) || !ELEM(obact->type, OB_GPENCIL, OB_EMPTY)) {
return false;
}
@@ -119,7 +119,7 @@ static void animdata_keyframe_list_get(ListBase *ob_list,
/* Keyframe number is x value of point. */
if ((bezt->f2 & SELECT) || (!only_selected)) {
/* Insert only one key for each keyframe number. */
- int key = (int)bezt->vec[1][0];
+ int key = int(bezt->vec[1][0]);
if (!BLI_ghash_haskey(r_keyframes, POINTER_FROM_INT(key))) {
BLI_ghash_insert(r_keyframes, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
}
@@ -222,7 +222,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
ob_gpencil = ED_gpencil_add_object(C, scene->cursor.location, local_view_bits);
float invmat[4][4];
- invert_m4_m4(invmat, ob_gpencil->obmat);
+ invert_m4_m4(invmat, ob_gpencil->object_to_world);
bGPdata *gpd_dst = (bGPdata *)ob_gpencil->data;
gpd_dst->draw_mode = GP_DRAWMODE_2D;
@@ -243,7 +243,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
/* Loop all frame range. */
- int oldframe = (int)DEG_get_ctime(depsgraph);
+ int oldframe = int(DEG_get_ctime(depsgraph));
int key = -1;
/* Get list of keyframes. */
@@ -260,7 +260,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
/* Check if frame is in the list of frames to be exported. */
- if ((only_selected) && (!BLI_ghash_haskey(keyframe_list, POINTER_FROM_INT(i)))) {
+ if ((only_selected) && !BLI_ghash_haskey(keyframe_list, POINTER_FROM_INT(i))) {
continue;
}
@@ -298,6 +298,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
BLI_addtail(&gpl_dst->frames, gpf_dst);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_dst->strokes) {
+ gps->runtime.gps_orig = nullptr;
/* Create material of the stroke. */
Material *ma_src = BKE_object_material_get(elem->ob, gps->mat_nr + 1);
bool found = false;
@@ -320,14 +321,16 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
/* Update point location to new object space. */
for (int j = 0; j < gps->totpoints; j++) {
bGPDspoint *pt = &gps->points[j];
- mul_m4_v3(ob_eval->obmat, &pt->x);
+ pt->runtime.idx_orig = 0;
+ pt->runtime.pt_orig = nullptr;
+ mul_m4_v3(ob_eval->object_to_world, &pt->x);
mul_m4_v3(invmat, &pt->x);
}
/* Reproject stroke. */
if (project_type != GP_REPROJECT_KEEP) {
ED_gpencil_stroke_reproject(
- depsgraph, &gsc, sctx, gpl_dst, gpf_dst, gps, project_type, false);
+ depsgraph, &gsc, sctx, gpl_dst, gpf_dst, gps, project_type, false, 0.0f);
}
else {
BKE_gpencil_stroke_geometry_update(gpd_dst, gps);
@@ -366,7 +369,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
static int gpencil_bake_grease_pencil_animation_invoke(bContext *C,
wmOperator *op,
- const wmEvent *UNUSED(event))
+ const wmEvent * /*event*/)
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index e02a82f4555..17ec33dc2bd 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -270,14 +270,13 @@ static void gpencil_timing_data_add_point(tGpTimingData *gtd,
}
else if (time < 0.0f) {
/* This is a gap, negative value! */
- gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time +
- gtd->offset_time);
+ gtd->times[cur_point] = -((float)(stroke_inittime - gtd->inittime) + time + gtd->offset_time);
delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
gtd->gap_tot_time += delta_time;
}
else {
- gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
+ gtd->times[cur_point] = ((float)(stroke_inittime - gtd->inittime) + time + gtd->offset_time);
delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
}
@@ -1303,6 +1302,7 @@ static void gpencil_layer_to_curve(bContext *C,
ob = BKE_object_add_only_object(bmain, OB_CURVES_LEGACY, gpl->info);
cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVES_LEGACY);
BKE_collection_object_add(bmain, collection, ob);
+ BKE_view_layer_synced_ensure(scene, view_layer);
base_new = BKE_view_layer_base_find(view_layer, ob);
DEG_relations_tag_update(bmain); /* added object */
@@ -1482,7 +1482,7 @@ static bool gpencil_convert_poll(bContext *C)
*/
return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
(gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) &&
- (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
+ (gpf->strokes.first) && !GPENCIL_ANY_EDIT_MODE(gpd));
}
static int gpencil_convert_layer_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 340288b2d74..0417694d7bd 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -623,6 +623,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
true,
"Only Active",
"Copy only active Layer, uncheck to append all layers");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
@@ -2913,8 +2914,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
float offset_global[3];
float offset_local[3];
- sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->obmat[3]);
- copy_m3_m4(bmat, ob_active->obmat);
+ sub_v3_v3v3(offset_global, ob_active->loc, ob_iter->object_to_world[3]);
+ copy_m3_m4(bmat, ob_active->object_to_world);
/* Inverse transform for all selected curves in this object,
* See #object_join_exec for detailed comment on why the safe version is used. */
@@ -3686,6 +3687,7 @@ void GPENCIL_OT_materials_copy_to_object(wmOperatorType *ot)
true,
"Only Active",
"Append only active material, uncheck to append all materials");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_GPENCIL);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index d53c0af2c54..f9b40a4c79b 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1618,7 +1618,7 @@ static bool gpencil_strokes_paste_poll(bContext *C)
* 2) Copy buffer must at least have something (though it may be the wrong sort...).
*/
return (ED_gpencil_data_get_active(C) != NULL) &&
- (!BLI_listbase_is_empty(&gpencil_strokes_copypastebuf));
+ !BLI_listbase_is_empty(&gpencil_strokes_copypastebuf);
}
typedef enum eGP_PasteMode {
@@ -2914,7 +2914,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
/* return data */
copy_v3_v3(&pt->x, fpt);
- gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
+ gpencil_world_to_object_space_point(depsgraph, obact, gpl, pt);
changed = true;
}
@@ -3015,7 +3015,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op)
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(&pt->x, cursor_global);
- gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
+ gpencil_world_to_object_space_point(depsgraph, obact, gpl, pt);
changed = true;
}
@@ -3848,7 +3848,12 @@ static int gpencil_stroke_start_set_exec(bContext *C, wmOperator *op)
for (int i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
if (pt->flag & GP_SPOINT_SELECT) {
- BKE_gpencil_stroke_start_set(gps, i);
+ if (i == gps->totpoints - 1) {
+ BKE_gpencil_stroke_flip(gps);
+ }
+ else {
+ BKE_gpencil_stroke_start_set(gps, i);
+ }
BKE_gpencil_stroke_geometry_update(gpd, gps);
changed = true;
break;
@@ -3905,6 +3910,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const float offset = RNA_float_get(op->ptr, "offset");
/* Init snap context for geometry projection. */
SnapObjectContext *sctx = NULL;
@@ -3944,7 +3950,8 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
BKE_scene_graph_update_for_newframe(depsgraph);
}
- ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf, gps, mode, keep_original);
+ ED_gpencil_stroke_reproject(
+ depsgraph, &gsc, sctx, gpl, gpf, gps, mode, keep_original, offset);
if (is_curve_edit && gps->editcurve != NULL) {
BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
@@ -3984,8 +3991,29 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void gpencil_strokes_reproject_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+ uiLayout *row;
+
+ const eGP_ReprojectModes type = RNA_enum_get(op->ptr, "type");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, op->ptr, "type", 0, NULL, ICON_NONE);
+
+ if (type == GP_REPROJECT_SURFACE) {
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, op->ptr, "offset", 0, NULL, ICON_NONE);
+ }
+ row = uiLayoutRow(layout, true);
+ uiItemR(row, op->ptr, "keep_original", 0, NULL, ICON_NONE);
+}
+
void GPENCIL_OT_reproject(wmOperatorType *ot)
{
+ PropertyRNA *prop;
static const EnumPropertyItem reproject_type[] = {
{GP_REPROJECT_FRONT, "FRONT", 0, "Front", "Reproject the strokes using the X-Z plane"},
{GP_REPROJECT_SIDE, "SIDE", 0, "Side", "Reproject the strokes using the Y-Z plane"},
@@ -4023,6 +4051,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->invoke = WM_menu_invoke;
ot->exec = gpencil_strokes_reproject_exec;
ot->poll = gpencil_strokes_edit3d_poll;
+ ot->ui = gpencil_strokes_reproject_ui;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -4031,12 +4060,15 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "type", reproject_type, GP_REPROJECT_VIEW, "Projection Type", "");
- RNA_def_boolean(
+ prop = RNA_def_boolean(
ot->srna,
"keep_original",
0,
"Keep Original",
"Keep original strokes and create a copy before reprojecting instead of reproject them");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
+
+ RNA_def_float(ot->srna, "offset", 0.0f, 0.0f, 10.0f, "Surface Offset", "", 0.0f, 10.0f);
}
static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
@@ -4130,7 +4162,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *cam_ob = scene->camera;
if (cam_ob != NULL) {
- invert_m4_m4(viewmat, cam_ob->obmat);
+ invert_m4_m4(viewmat, cam_ob->object_to_world);
}
break;
}
@@ -4197,7 +4229,7 @@ static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op)
/* Apply layer thickness change. */
gps_duplicate->thickness += gpl->line_change;
/* Apply object scale to thickness. */
- gps_duplicate->thickness *= mat4_to_scale(ob->obmat);
+ gps_duplicate->thickness *= mat4_to_scale(ob->object_to_world);
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
/* Stroke. */
@@ -4987,7 +5019,7 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if ((mode == GP_SEPARATE_LAYER) && (BLI_listbase_is_single(&gpd_src->layers))) {
+ if ((mode == GP_SEPARATE_LAYER) && BLI_listbase_is_single(&gpd_src->layers)) {
BKE_report(op->reports, RPT_ERROR, "Cannot separate an object with one layer only");
return OPERATOR_CANCELLED;
}
@@ -5194,7 +5226,9 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op)
for (int slot = 1; slot <= ob_dst->totcol; slot++) {
while (slot <= ob_dst->totcol && !BKE_object_material_slot_used(ob_dst, slot)) {
ob_dst->actcol = slot;
- BKE_object_material_slot_remove(bmain, ob_dst);
+ if (!BKE_object_material_slot_remove(bmain, ob_dst)) {
+ break;
+ }
if (actcol >= slot) {
actcol--;
}
@@ -5431,10 +5465,10 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
const struct GP_SelectLassoUserData *data = user_data;
bGPDspoint pt2;
int x0, y0;
- gpencil_point_to_parent_space(pt, diff_mat, &pt2);
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
gpencil_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso */
- return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
+ return (!ELEM(V2D_IS_CLIPPED, x0, y0) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
@@ -5559,7 +5593,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
/* Select points */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
- if ((gpl->flag & GP_LAYER_LOCKED) || ((gpl->flag & GP_LAYER_HIDE))) {
+ if ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE)) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 5305c764b3a..5c88e719b8c 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -67,6 +67,7 @@
#define LEAK_HORZ 0
#define LEAK_VERT 1
+#define FILL_LEAK 3.0f
#define MIN_WINDOW_SIZE 128
/* Set to 1 to debug filling internal image. By default, the value must be 0. */
@@ -78,6 +79,22 @@ enum {
GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */
};
+/* Temporary stroke data including stroke extensions. */
+typedef struct tStroke {
+ /* Referenced layer. */
+ bGPDlayer *gpl;
+ /** Referenced frame. */
+ bGPDframe *gpf;
+ /** Referenced stroke. */
+ bGPDstroke *gps;
+ /** Array of 2D points */
+ float (*points2d)[2];
+ /** Extreme Stroke A. */
+ bGPDstroke *gps_ext_a;
+ /** Extreme Stroke B. */
+ bGPDstroke *gps_ext_b;
+} tStroke;
+
/* Temporary fill operation data `op->customdata`. */
typedef struct tGPDfill {
bContext *C;
@@ -114,7 +131,7 @@ typedef struct tGPDfill {
/** For operations that require occlusion testing. */
struct ViewDepths *depths;
/** flags */
- short flag;
+ int flag;
/** avoid too fast events */
short oldkey;
/** send to back stroke */
@@ -140,12 +157,25 @@ typedef struct tGPDfill {
int fill_simplylvl;
/** boundary limits drawing mode */
int fill_draw_mode;
+ /** types of extensions **/
+ int fill_extend_mode;
/* scaling factor */
float fill_factor;
/* Frame to use. */
int active_cfra;
+ /** Center mouse position for extend length. */
+ float mouse_center[2];
+ /** Init mouse position for extend length. */
+ float mouse_init[2];
+ /** Last mouse position. */
+ float mouse_pos[2];
+ /** Use when mouse input is interpreted as spatial distance. */
+ float pixel_size;
+ /** Initial extend vector length. */
+ float initial_length;
+
/** number of elements currently in cache */
short sbuffer_used;
/** temporary points */
@@ -157,7 +187,7 @@ typedef struct tGPDfill {
Image *ima;
/** temp points data */
BLI_Stack *stack;
- /** handle for drawing strokes while operator is running 3d stuff */
+ /** handle for drawing strokes while operator is running 3d stuff. */
void *draw_handle_3d;
/* Temporary size x. */
@@ -174,11 +204,29 @@ typedef struct tGPDfill {
/** Factor of extension. */
float fill_extend_fac;
-
+ /** Size of stroke_array. */
+ int stroke_array_num;
+ /** Temp strokes array to handle strokes and stroke extensions. */
+ tStroke **stroke_array;
} 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);
+static void gpencil_fill_status_indicators(struct tGPDfill *tgpf);
+
+/* Free temp stroke array. */
+static void stroke_array_free(tGPDfill *tgpf)
+{
+ if (tgpf->stroke_array) {
+ for (int i = 0; i < tgpf->stroke_array_num; i++) {
+ tStroke *stroke = tgpf->stroke_array[i];
+ MEM_SAFE_FREE(stroke->points2d);
+ MEM_freeN(stroke);
+ }
+ MEM_SAFE_FREE(tgpf->stroke_array);
+ }
+ tgpf->stroke_array_num = 0;
+}
/* Delete any temporary stroke. */
static void gpencil_delete_temp_stroke_extension(tGPDfill *tgpf, const bool all_frames)
@@ -197,7 +245,8 @@ static void gpencil_delete_temp_stroke_extension(tGPDfill *tgpf, const bool all_
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)) {
+ if ((gps->flag & GP_STROKE_NOFILL) &&
+ (gps->flag & GP_STROKE_TAG || gps->flag & GP_STROKE_HELP)) {
BLI_remlink(&gpf->strokes, gps);
BKE_gpencil_free_stroke(gps);
}
@@ -209,6 +258,70 @@ static void gpencil_delete_temp_stroke_extension(tGPDfill *tgpf, const bool all_
}
}
+static bool extended_bbox_overlap(
+ float min1[3], float max1[3], float min2[3], float max2[3], float extend)
+{
+ for (int axis = 0; axis < 3; axis++) {
+ float intersection_min = max_ff(min1[axis], min2[axis]) - extend;
+ float intersection_max = min_ff(max1[axis], max2[axis]) + extend;
+ if (intersection_min > intersection_max) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static void add_stroke_extension(bGPDframe *gpf, bGPDstroke *gps, float p1[3], float p2[3])
+{
+ 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, p1);
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+
+ pt = &gps_new->points[1];
+ copy_v3_v3(&pt->x, p2);
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+}
+
+static void add_endpoint_radius_help(tGPDfill *tgpf,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ const float endpoint[3],
+ const float radius,
+ const bool focused)
+{
+ float circumference = 2.0f * M_PI * radius;
+ float vertex_spacing = 0.005f;
+ int num_vertices = min_ii(max_ii((int)ceilf(circumference / vertex_spacing), 3), 40);
+
+ bGPDstroke *gps_new = BKE_gpencil_stroke_new(gps->mat_nr, num_vertices, gps->thickness);
+ gps_new->flag |= GP_STROKE_NOFILL | GP_STROKE_CYCLIC | GP_STROKE_HELP;
+ if (focused) {
+ gps_new->flag |= GP_STROKE_TAG;
+ }
+ BLI_addtail(&gpf->strokes, gps_new);
+
+ for (int i = 0; i < num_vertices; i++) {
+ float angle = ((float)i / (float)num_vertices) * 2.0f * M_PI;
+ bGPDspoint *pt = &gps_new->points[i];
+ pt->x = endpoint[0] + radius * cosf(angle);
+ pt->y = endpoint[1];
+ pt->z = endpoint[2] + radius * sinf(angle);
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+
+ /* Rotate to object rotation. */
+ sub_v3_v3(&pt->x, endpoint);
+ mul_mat3_m4_v3(tgpf->ob->object_to_world, &pt->x);
+ add_v3_v3(&pt->x, endpoint);
+ }
+}
+
static void extrapolate_points_by_length(bGPDspoint *a,
bGPDspoint *b,
float length,
@@ -221,8 +334,42 @@ static void extrapolate_points_by_length(bGPDspoint *a,
add_v3_v3v3(r_point, &b->x, ab);
}
-/* Loop all layers create stroke extensions. */
-static void gpencil_create_extensions(tGPDfill *tgpf)
+/* Calculate the size of the array for strokes. */
+static void gpencil_strokes_array_size(tGPDfill *tgpf)
+{
+ 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);
+
+ tgpf->stroke_array_num = 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;
+ }
+ tgpf->stroke_array_num += BLI_listbase_count(&gpf->strokes);
+ }
+}
+
+/** Load all strokes to be processed by extend lines. */
+static void gpencil_load_array_strokes(tGPDfill *tgpf)
{
Object *ob = tgpf->ob;
bGPdata *gpd = tgpf->gpd;
@@ -235,6 +382,14 @@ static void gpencil_create_extensions(tGPDfill *tgpf)
const int gpl_active_index = BLI_findindex(&gpd->layers, gpl_active);
BLI_assert(gpl_active_index >= 0);
+ /* Create array of strokes. */
+ gpencil_strokes_array_size(tgpf);
+ if (tgpf->stroke_array_num == 0) {
+ return;
+ }
+
+ tgpf->stroke_array = MEM_callocN(sizeof(tStroke *) * tgpf->stroke_array_num, __func__);
+ int idx = 0;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (gpl->flag & GP_LAYER_HIDE) {
continue;
@@ -252,85 +407,489 @@ static void gpencil_create_extensions(tGPDfill *tgpf)
continue;
}
+ float diff_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, tgpf->ob, gpl, diff_mat);
+
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;
}
+ /* Don't include temp strokes. */
+ if ((gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG)) {
+ continue;
+ }
+
+ tStroke *stroke = MEM_callocN(sizeof(tStroke), __func__);
+ stroke->gpl = gpl;
+ stroke->gpf = gpf;
+ stroke->gps = gps;
+
+ /* Create the extension strokes only for Lines. */
+ if (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND) {
+ /* Convert all points to 2D to speed up collision checks and avoid convert in each
+ * iteration. */
+ stroke->points2d = (float(*)[2])MEM_mallocN(sizeof(*stroke->points2d) * gps->totpoints,
+ "GP Stroke temp 2d points");
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ bGPDspoint pt2;
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
+ gpencil_point_to_xy_fl(
+ &tgpf->gsc, gps, &pt2, &stroke->points2d[i][0], &stroke->points2d[i][1]);
+ }
+
+ /* Extend start. */
+ bGPDspoint *pt1 = &gps->points[0];
+ stroke->gps_ext_a = BKE_gpencil_stroke_new(gps->mat_nr, 2, gps->thickness);
+ stroke->gps_ext_a->flag |= GP_STROKE_NOFILL | GP_STROKE_TAG;
+ stroke->gps_ext_a->fill_opacity_fac = FLT_MAX;
+ BLI_addtail(&gpf->strokes, stroke->gps_ext_a);
+
+ bGPDspoint *pt = &stroke->gps_ext_a->points[0];
+ copy_v3_v3(&pt->x, &pt1->x);
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+
+ pt = &stroke->gps_ext_a->points[1];
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+
+ /* Extend end. */
+ pt1 = &gps->points[gps->totpoints - 1];
+ stroke->gps_ext_b = BKE_gpencil_stroke_new(gps->mat_nr, 2, gps->thickness);
+ stroke->gps_ext_b->flag |= GP_STROKE_NOFILL | GP_STROKE_TAG;
+ stroke->gps_ext_b->fill_opacity_fac = FLT_MAX;
+ BLI_addtail(&gpf->strokes, stroke->gps_ext_b);
+
+ pt = &stroke->gps_ext_b->points[0];
+ copy_v3_v3(&pt->x, &pt1->x);
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+
+ pt = &stroke->gps_ext_b->points[1];
+ pt->strength = 1.0f;
+ pt->pressure = 1.0f;
+ }
+ else {
+ stroke->gps_ext_a = NULL;
+ stroke->gps_ext_b = NULL;
+ }
+
+ tgpf->stroke_array[idx] = stroke;
+
+ idx++;
+ }
+ }
+ tgpf->stroke_array_num = idx;
+}
+
+static void set_stroke_collide(bGPDstroke *gps_a, bGPDstroke *gps_b, const float connection_dist)
+{
+ gps_a->flag |= GP_STROKE_COLLIDE;
+ gps_b->flag |= GP_STROKE_COLLIDE;
+
+ /* It uses `fill_opacity_fac` to store distance because this variable is never
+ * used by this type of strokes and can be used for these
+ * temp strokes without adding new variables to the bGPStroke struct. */
+ gps_a->fill_opacity_fac = connection_dist;
+ gps_b->fill_opacity_fac = connection_dist;
+ BKE_gpencil_stroke_boundingbox_calc(gps_a);
+ BKE_gpencil_stroke_boundingbox_calc(gps_b);
+}
+
+static void gpencil_stroke_collision(
+ tGPDfill *tgpf, bGPDlayer *gpl, bGPDstroke *gps_a, float a1xy[2], float a2xy[2])
+{
+ const float connection_dist = tgpf->fill_extend_fac * 0.1f;
+ float diff_mat[4][4], inv_mat[4][4];
+
+ /* Transform matrix for original stroke.*/
+ BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, tgpf->ob, gpl, diff_mat);
+ invert_m4_m4(inv_mat, diff_mat);
+
+ for (int idx = 0; idx < tgpf->stroke_array_num; idx++) {
+ tStroke *stroke = tgpf->stroke_array[idx];
+ bGPDstroke *gps_b = stroke->gps;
+
+ if (!extended_bbox_overlap(gps_a->boundbox_min,
+ gps_a->boundbox_max,
+ gps_b->boundbox_min,
+ gps_b->boundbox_max,
+ 1.1f)) {
+ continue;
+ }
+
+ /* Loop all segments of the stroke. */
+ for (int i = 0; i < gps_b->totpoints - 1; i++) {
+ /* Skip segments over same pixel. */
+ if (((int)a1xy[0] == (int)stroke->points2d[i + 1][0]) &&
+ ((int)a1xy[1] == (int)stroke->points2d[i + 1][1])) {
+ continue;
+ }
+
+ /* Check if extensions cross. */
+ if (isect_seg_seg_v2_simple(a1xy, a2xy, stroke->points2d[i], stroke->points2d[i + 1])) {
+ bGPDspoint *extreme_a = &gps_a->points[1];
+ float intersection2D[2];
+ isect_line_line_v2_point(
+ a1xy, a2xy, stroke->points2d[i], stroke->points2d[i + 1], intersection2D);
+
+ gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, intersection2D, &extreme_a->x);
+ mul_m4_v3(inv_mat, &extreme_a->x);
+ BKE_gpencil_stroke_boundingbox_calc(gps_a);
+
+ gps_a->flag |= GP_STROKE_COLLIDE;
+ gps_a->fill_opacity_fac = connection_dist;
+ return;
+ }
+ }
+ }
+}
+
+/* Cut the extended lines if collide. */
+static void gpencil_cut_extensions(tGPDfill *tgpf)
+{
+ const float connection_dist = tgpf->fill_extend_fac * 0.1f;
+ const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0;
+
+ bGPDlayer *gpl_prev = NULL;
+ bGPDframe *gpf_prev = NULL;
+ float diff_mat[4][4], inv_mat[4][4];
+
+ /* Allocate memory for all extend strokes. */
+ bGPDstroke **gps_array = MEM_callocN(sizeof(bGPDstroke *) * tgpf->stroke_array_num * 2,
+ __func__);
+
+ for (int idx = 0; idx < tgpf->stroke_array_num; idx++) {
+ tStroke *stroke = tgpf->stroke_array[idx];
+ bGPDframe *gpf = stroke->gpf;
+ if (stroke->gpl != gpl_prev) {
+ BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, tgpf->ob, stroke->gpl, diff_mat);
+ invert_m4_m4(inv_mat, diff_mat);
+ gpl_prev = stroke->gpl;
+ }
+
+ if (gpf == gpf_prev) {
+ continue;
+ }
+ gpf_prev = gpf;
+
+ /* Store all frame extend strokes in an array. */
+ int tot_idx = 0;
+ for (int i = 0; i < tgpf->stroke_array_num; i++) {
+ tStroke *s = tgpf->stroke_array[i];
+ if (s->gpf != gpf) {
+ continue;
+ }
+ if ((s->gps_ext_a) && ((s->gps_ext_a->flag & GP_STROKE_COLLIDE) == 0)) {
+ gps_array[tot_idx] = s->gps_ext_a;
+ tot_idx++;
+ }
+ if ((s->gps_ext_b) && ((s->gps_ext_b->flag & GP_STROKE_COLLIDE) == 0)) {
+ gps_array[tot_idx] = s->gps_ext_b;
+ tot_idx++;
+ }
+ }
+
+ /* Compare all strokes. */
+ for (int i = 0; i < tot_idx; i++) {
+ bGPDstroke *gps_a = gps_array[i];
+
+ bGPDspoint pt2;
+ float a1xy[2], a2xy[2];
+ float b1xy[2], b2xy[2];
+
+ /* First stroke. */
+ bGPDspoint *pt = &gps_a->points[0];
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
+ gpencil_point_to_xy_fl(&tgpf->gsc, gps_a, &pt2, &a1xy[0], &a1xy[1]);
+
+ pt = &gps_a->points[1];
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
+ gpencil_point_to_xy_fl(&tgpf->gsc, gps_a, &pt2, &a2xy[0], &a2xy[1]);
+ bGPDspoint *extreme_a = &gps_a->points[1];
+
+ /* Loop all other strokes and check the intersections. */
+ for (int z = 0; z < tot_idx; z++) {
+ bGPDstroke *gps_b = gps_array[z];
+ /* Don't check stroke with itself. */
+ if (i == z) {
+ continue;
+ }
+
+ /* Don't check strokes unless the bounding boxes of the strokes
+ * are close enough together that they can plausibly be connected. */
+ if (!extended_bbox_overlap(gps_a->boundbox_min,
+ gps_a->boundbox_max,
+ gps_b->boundbox_min,
+ gps_b->boundbox_max,
+ 1.1f)) {
+ continue;
+ }
+
+ pt = &gps_b->points[0];
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
+ gpencil_point_to_xy_fl(&tgpf->gsc, gps_b, &pt2, &b1xy[0], &b1xy[1]);
+
+ pt = &gps_b->points[1];
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
+ gpencil_point_to_xy_fl(&tgpf->gsc, gps_b, &pt2, &b2xy[0], &b2xy[1]);
+ bGPDspoint *extreme_b = &gps_b->points[1];
+
+ /* Check if extreme points are near. This case is when the
+ * extended lines are co-linear or parallel and close together. */
+ const float gap_pixsize_sq = 25.0f;
+ float intersection3D[3];
+ if (len_squared_v2v2(a2xy, b2xy) <= gap_pixsize_sq) {
+ gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, b2xy, intersection3D);
+ mul_m4_v3(inv_mat, intersection3D);
+ copy_v3_v3(&extreme_a->x, intersection3D);
+ copy_v3_v3(&extreme_b->x, intersection3D);
+ set_stroke_collide(gps_a, gps_b, connection_dist);
+ break;
+ }
+ /* Check if extensions cross. */
+ if (isect_seg_seg_v2_simple(a1xy, a2xy, b1xy, b2xy)) {
+ float intersection2D[2];
+ isect_line_line_v2_point(a1xy, a2xy, b1xy, b2xy, intersection2D);
+
+ gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, intersection2D, intersection3D);
+ mul_m4_v3(inv_mat, intersection3D);
+ copy_v3_v3(&extreme_a->x, intersection3D);
+ copy_v3_v3(&extreme_b->x, intersection3D);
+ set_stroke_collide(gps_a, gps_b, connection_dist);
+ break;
+ }
+ /* Check if extension extreme is near of the origin of any other extension. */
+ if (len_squared_v2v2(a2xy, b1xy) <= gap_pixsize_sq) {
+ gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, b1xy, &extreme_a->x);
+ mul_m4_v3(inv_mat, &extreme_a->x);
+ set_stroke_collide(gps_a, gps_b, connection_dist);
+ break;
+ }
+ if (len_squared_v2v2(a1xy, b2xy) <= gap_pixsize_sq) {
+ gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, a1xy, &extreme_b->x);
+ mul_m4_v3(inv_mat, &extreme_b->x);
+ set_stroke_collide(gps_a, gps_b, connection_dist);
+ break;
+ }
+ }
- /* Extend start. */
+ /* Check if collide with normal strokes. */
+ if (use_stroke_collide && (gps_a->flag & GP_STROKE_COLLIDE) == 0) {
+ gpencil_stroke_collision(tgpf, stroke->gpl, gps_a, a1xy, a2xy);
+ }
+ }
+ }
+ MEM_SAFE_FREE(gps_array);
+}
+
+/* Loop all strokes and update stroke line extensions. */
+static void gpencil_update_extensions_line(tGPDfill *tgpf)
+{
+ float connection_dist = tgpf->fill_extend_fac * 0.1f;
+
+ for (int idx = 0; idx < tgpf->stroke_array_num; idx++) {
+ tStroke *stroke = tgpf->stroke_array[idx];
+ bGPDstroke *gps = stroke->gps;
+ bGPDstroke *gps_a = stroke->gps_ext_a;
+ bGPDstroke *gps_b = stroke->gps_ext_b;
+
+ /* Extend start. */
+ if (((gps_a->flag & GP_STROKE_COLLIDE) == 0) || (gps_a->fill_opacity_fac > connection_dist)) {
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);
+ bGPDspoint *pt = &gps_a->points[1];
+ extrapolate_points_by_length(pt0, pt1, connection_dist, &pt->x);
+ gps_a->flag &= ~GP_STROKE_COLLIDE;
+ }
+
+ /* Extend end. */
+ if (((gps_b->flag & GP_STROKE_COLLIDE) == 0) || (gps_b->fill_opacity_fac > connection_dist)) {
+ bGPDspoint *pt0 = &gps->points[gps->totpoints - 2];
+ bGPDspoint *pt1 = &gps->points[gps->totpoints - 1];
+ bGPDspoint *pt = &gps_b->points[1];
+ extrapolate_points_by_length(pt0, pt1, connection_dist, &pt->x);
+ gps_b->flag &= ~GP_STROKE_COLLIDE;
}
}
+
+ /* Cut overlength strokes. */
+ gpencil_cut_extensions(tgpf);
+}
+
+/* Loop all strokes and create stroke radius extensions. */
+static void gpencil_create_extensions_radius(tGPDfill *tgpf)
+{
+ float connection_dist = tgpf->fill_extend_fac * 0.1f;
+ GSet *connected_endpoints = BLI_gset_ptr_new(__func__);
+
+ for (int idx = 0; idx < tgpf->stroke_array_num; idx++) {
+ tStroke *stroke = tgpf->stroke_array[idx];
+ bGPDframe *gpf = stroke->gpf;
+ bGPDstroke *gps = stroke->gps;
+
+ /* Find points of high curvature. */
+ float tan1[3];
+ float tan2[3];
+ float d1;
+ float d2;
+ float total_length = 0.f;
+ for (int i = 1; i < gps->totpoints; i++) {
+ if (i > 1) {
+ copy_v3_v3(tan1, tan2);
+ d1 = d2;
+ }
+ bGPDspoint *pt1 = &gps->points[i - 1];
+ bGPDspoint *pt2 = &gps->points[i];
+ sub_v3_v3v3(tan2, &pt2->x, &pt1->x);
+ d2 = normalize_v3(tan2);
+ total_length += d2;
+ if (i > 1) {
+ float curvature[3];
+ sub_v3_v3v3(curvature, tan2, tan1);
+ float k = normalize_v3(curvature);
+ k /= min_ff(d1, d2);
+ float radius = 1.f / k;
+ /*
+ * The smaller the radius of curvature, the sharper the corner.
+ * The thicker the line, the larger the radius of curvature it
+ * takes to be visually indistinguishable from an endpoint.
+ */
+ float min_radius = gps->thickness * 0.0001f;
+
+ if (radius < min_radius) {
+ /* Extend along direction of curvature. */
+ 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;
+ mul_v3_fl(curvature, -connection_dist);
+ add_v3_v3v3(&pt->x, &pt1->x, curvature);
+ }
+ }
+ }
+
+ /* Connect endpoints within a radius */
+ float *stroke1_start = &gps->points[0].x;
+ float *stroke1_end = &gps->points[gps->totpoints - 1].x;
+ /* Connect the start of the stroke to its own end if the whole stroke
+ * isn't already so short that it's within that distance
+ */
+ if (len_v3v3(stroke1_start, stroke1_end) < connection_dist && total_length > connection_dist) {
+ add_stroke_extension(gpf, gps, stroke1_start, stroke1_end);
+ BLI_gset_add(connected_endpoints, stroke1_start);
+ BLI_gset_add(connected_endpoints, stroke1_end);
+ }
+ for (bGPDstroke *gps2 = (bGPDstroke *)(((Link *)gps)->next); gps2 != NULL;
+ gps2 = (bGPDstroke *)(((Link *)gps2)->next)) {
+ /* Don't check distance to temporary extensions. */
+ if ((gps2->flag & GP_STROKE_NOFILL) && (gps2->flag & GP_STROKE_TAG)) {
+ continue;
+ }
+
+ /* Don't check endpoint distances unless the bounding boxes of the strokes
+ are close enough together that they can plausibly be connected. */
+ if (!extended_bbox_overlap(gps->boundbox_min,
+ gps->boundbox_max,
+ gps2->boundbox_min,
+ gps2->boundbox_max,
+ connection_dist)) {
+ continue;
+ }
+
+ float *stroke2_start = &gps2->points[0].x;
+ float *stroke2_end = &gps2->points[gps2->totpoints - 1].x;
+ if (len_v3v3(stroke1_start, stroke2_start) < connection_dist) {
+ add_stroke_extension(gpf, gps, stroke1_start, stroke2_start);
+ BLI_gset_add(connected_endpoints, stroke1_start);
+ BLI_gset_add(connected_endpoints, stroke2_start);
+ }
+ if (len_v3v3(stroke1_start, stroke2_end) < connection_dist) {
+ add_stroke_extension(gpf, gps, stroke1_start, stroke2_end);
+ BLI_gset_add(connected_endpoints, stroke1_start);
+ BLI_gset_add(connected_endpoints, stroke2_end);
+ }
+ if (len_v3v3(stroke1_end, stroke2_start) < connection_dist) {
+ add_stroke_extension(gpf, gps, stroke1_end, stroke2_start);
+ BLI_gset_add(connected_endpoints, stroke1_end);
+ BLI_gset_add(connected_endpoints, stroke2_start);
+ }
+ if (len_v3v3(stroke1_end, stroke2_end) < connection_dist) {
+ add_stroke_extension(gpf, gps, stroke1_end, stroke2_end);
+ BLI_gset_add(connected_endpoints, stroke1_end);
+ BLI_gset_add(connected_endpoints, stroke2_end);
+ }
+ }
+
+ bool start_connected = BLI_gset_haskey(connected_endpoints, stroke1_start);
+ bool end_connected = BLI_gset_haskey(connected_endpoints, stroke1_end);
+ add_endpoint_radius_help(tgpf, gpf, gps, stroke1_start, connection_dist, start_connected);
+ add_endpoint_radius_help(tgpf, gpf, gps, stroke1_end, connection_dist, end_connected);
+ }
+
+ BLI_gset_free(connected_endpoints, NULL);
}
static void gpencil_update_extend(tGPDfill *tgpf)
{
- gpencil_delete_temp_stroke_extension(tgpf, false);
+ if (tgpf->stroke_array == NULL) {
+ gpencil_load_array_strokes(tgpf);
+ }
- if (tgpf->fill_extend_fac > 0.0f) {
- gpencil_create_extensions(tgpf);
+ if (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND) {
+ gpencil_update_extensions_line(tgpf);
}
+ else {
+ gpencil_delete_temp_stroke_extension(tgpf, false);
+ gpencil_create_extensions_radius(tgpf);
+ }
+ gpencil_fill_status_indicators(tgpf);
WM_event_add_notifier(tgpf->C, NC_GPENCIL | NA_EDITED, NULL);
}
static bool gpencil_stroke_is_drawable(tGPDfill *tgpf, bGPDstroke *gps)
{
+ const bool is_line_mode = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND);
+ 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 use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0;
+ const bool is_extend_stroke = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG);
+ const bool is_help_stroke = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_HELP);
+ const bool stroke_collide = (gps->flag & GP_STROKE_COLLIDE) != 0;
+
+ if (is_line_mode && is_extend_stroke && tgpf->is_render && use_stroke_collide &&
+ !stroke_collide) {
+ return false;
+ }
+
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) {
+ if (!is_extend_stroke && !is_help_stroke) {
return false;
}
}
if ((show_help) && (!show_extend)) {
- if (is_extend) {
+ if (is_extend_stroke || is_help_stroke) {
return false;
}
}
@@ -357,14 +916,38 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf,
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);
+ const float help_col[4] = {1.0f, 0.0f, 0.5f, 1.0f};
+ const bool is_extend = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG) &&
+ !(gps->flag & GP_STROKE_HELP);
+ const bool is_help = gps->flag & GP_STROKE_HELP;
+ const bool is_line_mode = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND);
+ const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0;
+ const bool stroke_collide = (gps->flag & GP_STROKE_COLLIDE) != 0;
if (!gpencil_stroke_is_drawable(tgpf, gps)) {
return;
}
- if ((is_extend) && (!tgpf->is_render)) {
- copy_v4_v4(col, extend_col);
+ if (is_help && tgpf->is_render) {
+ /* Help strokes are for display only and shouldn't render. */
+ return;
+ }
+ else if (is_help) {
+ /* Color help strokes that won't affect fill or render separately from
+ * extended strokes, as they will affect them. */
+ copy_v4_v4(col, help_col);
+
+ /* If there is contact, hide the circles to avoid noise and keep the focus
+ * in the pending gaps. */
+ col[3] = (gps->flag & GP_STROKE_TAG) ? 0.0f : 0.5f;
+ }
+ else if ((is_extend) && (!tgpf->is_render)) {
+ if (stroke_collide || !use_stroke_collide || !is_line_mode) {
+ copy_v4_v4(col, extend_col);
+ }
+ else {
+ copy_v4_v4(col, help_col);
+ }
}
else {
copy_v4_v4(col, ink);
@@ -379,7 +962,7 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf,
immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
/* draw stroke curve */
- GPU_line_width((!is_extend) ? thickness : thickness * 2.0f);
+ GPU_line_width((!is_extend && !is_help) ? thickness : thickness * 2.0f);
immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
const bGPDspoint *pt = points;
@@ -390,7 +973,7 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf,
CLAMP(alpha, 0.0f, 1.0f);
col[3] = alpha <= thershold ? 0.0f : 1.0f;
}
- else {
+ else if (!is_help) {
col[3] = 1.0f;
}
/* set point */
@@ -486,6 +1069,7 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4])
Brush *brush = tgpf->brush;
BrushGpencilSettings *brush_settings = brush->gpencil_settings;
ToolSettings *ts = tgpf->scene->toolsettings;
+ const bool extend_lines = (tgpf->fill_extend_fac > 0.0f);
tGPDdraw tgpw;
tgpw.rv3d = tgpf->rv3d;
@@ -582,12 +1166,26 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4])
/* Normal strokes. */
if (ELEM(tgpf->fill_draw_mode, GP_FILL_DMODE_STROKE, GP_FILL_DMODE_BOTH)) {
- if (gpencil_stroke_is_drawable(tgpf, gps) && ((gps->flag & GP_STROKE_TAG) == 0)) {
+ if (gpencil_stroke_is_drawable(tgpf, gps) && ((gps->flag & GP_STROKE_TAG) == 0) &&
+ ((gps->flag & GP_STROKE_HELP) == 0)) {
ED_gpencil_draw_fill(&tgpw);
}
+ /* In stroke mode, still must draw the extend lines. */
+ if (extend_lines && (tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE)) {
+ if ((gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG)) {
+ gpencil_draw_basic_stroke(tgpf,
+ gps,
+ tgpw.diff_mat,
+ gps->flag & GP_STROKE_CYCLIC,
+ ink,
+ tgpf->flag,
+ tgpf->fill_threshold,
+ 1.0f);
+ }
+ }
}
- /* 3D Lines with basic shapes and invisible lines */
+ /* 3D Lines with basic shapes and invisible lines. */
if (ELEM(tgpf->fill_draw_mode, GP_FILL_DMODE_CONTROL, GP_FILL_DMODE_BOTH)) {
gpencil_draw_basic_stroke(tgpf,
gps,
@@ -1655,7 +2253,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* if parented change position relative to parent object */
for (int a = 0; a < tgpf->sbuffer_used; a++) {
pt = &gps->points[a];
- gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt);
+ gpencil_world_to_object_space_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt);
}
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
@@ -1675,10 +2273,22 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
/* ----------------------- */
/* Drawing */
/* Helper: Draw status message while the user is running the operator */
-static void gpencil_fill_status_indicators(bContext *C)
+static void gpencil_fill_status_indicators(tGPDfill *tgpf)
{
- const char *status_str = TIP_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
- ED_workspace_status_text(C, status_str);
+ const bool is_extend = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND);
+ const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0;
+
+ char status_str[UI_MAX_DRAW_STR];
+ BLI_snprintf(status_str,
+ sizeof(status_str),
+ TIP_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back, MMB Adjust Extend, S: "
+ "Switch Mode, D: "
+ "Stroke Collision | %s %s (%.3f)"),
+ (is_extend) ? TIP_("Extend") : TIP_("Radius"),
+ (is_extend && use_stroke_collide) ? TIP_("Stroke: ON") : TIP_("Stroke: OFF"),
+ tgpf->fill_extend_fac);
+
+ ED_workspace_status_text(tgpf->C, status_str);
}
/* draw boundary lines to see fill limits */
@@ -1770,6 +2380,11 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op)
tgpf->sbuffer = NULL;
tgpf->depth_arr = NULL;
+ /* Prepare extend handling for pen. */
+ tgpf->mouse_init[0] = -1.0f;
+ tgpf->mouse_init[1] = -1.0f;
+ tgpf->pixel_size = tgpf->rv3d ? ED_view3d_pixel_size(tgpf->rv3d, tgpf->ob->loc) : 1.0f;
+
/* save filling parameters */
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tgpf->brush = brush;
@@ -1777,13 +2392,17 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op)
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_extend_mode = brush->gpencil_settings->fill_extend_mode;
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);
+ tgpf->fill_leak = (int)ceil(FILL_LEAK * tgpf->fill_factor);
int totcol = tgpf->ob->totcol;
+ /* Extensions array */
+ tgpf->stroke_array = NULL;
+
/* get color info */
Material *ma = BKE_gpencil_object_material_ensure_from_active_input_brush(
bmain, tgpf->ob, brush);
@@ -1832,6 +2451,9 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
MEM_SAFE_FREE(tgpf->sbuffer);
MEM_SAFE_FREE(tgpf->depth_arr);
+ /* Clean temp strokes. */
+ stroke_array_free(tgpf);
+
/* Remove any temp stroke. */
gpencil_delete_temp_stroke_extension(tgpf, true);
@@ -1839,6 +2461,7 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
if (tgpf->draw_handle_3d) {
ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d);
}
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
/* Remove depth buffer in cache. */
if (tgpf->depths) {
@@ -1859,7 +2482,8 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
}
- WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void gpencil_fill_cancel(bContext *C, wmOperator *op)
@@ -1928,9 +2552,8 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
tgpf = op->customdata;
/* Enable custom drawing handlers to show help lines */
- 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)));
+ const bool do_extend = (tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES);
+ const bool help_lines = ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || (do_extend));
if (help_lines) {
tgpf->draw_handle_3d = ED_region_draw_cb_activate(
@@ -1939,7 +2562,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
- gpencil_fill_status_indicators(C);
+ gpencil_fill_status_indicators(tgpf);
DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@@ -2071,9 +2694,12 @@ static bool gpencil_find_and_mark_empty_areas(tGPDfill *tgpf)
get_pixel(ibuf, i, rgba);
if (rgba[3] == 0.0f) {
set_pixel(ibuf, i, blue_col);
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
return true;
}
}
+
+ BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
return false;
}
@@ -2099,6 +2725,9 @@ static bool gpencil_do_frame_fill(tGPDfill *tgpf, const bool is_inverted)
gpencil_invert_image(tgpf);
while (gpencil_find_and_mark_empty_areas(tgpf)) {
gpencil_boundaryfill_area(tgpf);
+ if (FILL_DEBUG) {
+ break;
+ }
}
}
@@ -2179,9 +2808,10 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
const bool is_inverted = (is_brush_inv && (event->modifier & KM_CTRL) == 0) ||
(!is_brush_inv && (event->modifier & KM_CTRL) != 0);
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)));
+ const bool extend_lines = (tgpf->fill_extend_fac > 0.0f);
+ const bool show_extend = ((tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) && !is_inverted);
+ const bool help_lines = (((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || show_extend) &&
+ !is_inverted);
int estate = OPERATOR_RUNNING_MODAL;
switch (event->type) {
@@ -2195,6 +2825,12 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_CANCELLED;
break;
}
+ /* if doing a extend transform with the pen, avoid false contacts of
+ * the pen with the tablet. */
+ if (tgpf->mouse_init[0] != -1.0f) {
+ break;
+ }
+ copy_v2fl_v2i(tgpf->mouse_center, event->mval);
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
@@ -2250,7 +2886,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
int step = ((float)i / (float)total) * 100.0f;
WM_cursor_time(win, step);
- if (do_extend) {
+ if (extend_lines) {
gpencil_update_extend(tgpf);
}
@@ -2281,7 +2917,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
loop_limit++;
}
- if (do_extend) {
+ if (extend_lines) {
gpencil_delete_temp_stroke_extension(tgpf, true);
}
@@ -2310,11 +2946,36 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
estate = OPERATOR_CANCELLED;
}
}
- else if (do_extend) {
+ else if (extend_lines) {
gpencil_update_extend(tgpf);
}
tgpf->oldkey = event->type;
break;
+ case EVT_SKEY:
+ if ((show_extend) && (event->val == KM_PRESS)) {
+ /* Clean temp strokes. */
+ stroke_array_free(tgpf);
+
+ /* Toggle mode. */
+ if (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND) {
+ tgpf->fill_extend_mode = GP_FILL_EMODE_RADIUS;
+ }
+ else {
+ tgpf->fill_extend_mode = GP_FILL_EMODE_EXTEND;
+ }
+ gpencil_delete_temp_stroke_extension(tgpf, true);
+ gpencil_update_extend(tgpf);
+ }
+ break;
+ case EVT_DKEY:
+ if ((show_extend) && (event->val == KM_PRESS)) {
+ tgpf->flag ^= GP_BRUSH_FILL_STROKE_COLLIDE;
+ /* Clean temp strokes. */
+ stroke_array_free(tgpf);
+ gpencil_delete_temp_stroke_extension(tgpf, true);
+ gpencil_update_extend(tgpf);
+ }
+ break;
case EVT_PAGEUPKEY:
case WHEELUPMOUSE:
if (tgpf->oldkey == 1) {
@@ -2327,10 +2988,60 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
case WHEELDOWNMOUSE:
if (tgpf->oldkey == 1) {
tgpf->fill_extend_fac += (event->modifier & KM_SHIFT) ? 0.01f : 0.1f;
- CLAMP_MAX(tgpf->fill_extend_fac, 100.0f);
+ CLAMP_MAX(tgpf->fill_extend_fac, 10.0f);
gpencil_update_extend(tgpf);
}
break;
+ case MIDDLEMOUSE: {
+ if (event->val == KM_PRESS) {
+ /* Consider initial offset as zero position. */
+ copy_v2fl_v2i(tgpf->mouse_init, event->mval);
+ float mlen[2];
+ sub_v2_v2v2(mlen, tgpf->mouse_init, tgpf->mouse_center);
+
+ /* Offset the center a little to get enough space to reduce the extend moving the pen. */
+ const float gap = 300.0f;
+ if (len_v2(mlen) < gap) {
+ tgpf->mouse_center[0] -= gap;
+ sub_v2_v2v2(mlen, tgpf->mouse_init, tgpf->mouse_center);
+ }
+
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_EW_ARROW);
+
+ tgpf->initial_length = len_v2(mlen);
+ }
+ if (event->val == KM_RELEASE) {
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
+
+ tgpf->mouse_init[0] = -1.0f;
+ tgpf->mouse_init[1] = -1.0f;
+ }
+ /* Update cursor line. */
+ WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ break;
+ }
+ case MOUSEMOVE: {
+ if (tgpf->mouse_init[0] == -1.0f) {
+ break;
+ }
+ copy_v2fl_v2i(tgpf->mouse_pos, event->mval);
+
+ float mlen[2];
+ sub_v2_v2v2(mlen, tgpf->mouse_pos, tgpf->mouse_center);
+ float delta = (len_v2(mlen) - tgpf->initial_length) * tgpf->pixel_size * 0.5f;
+ tgpf->fill_extend_fac += delta;
+ CLAMP(tgpf->fill_extend_fac, 0.0f, 10.0f);
+
+ /* Update cursor line and extend lines. */
+ WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ gpencil_update_extend(tgpf);
+
+ break;
+ }
default:
break;
}
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 4d62f834d86..4847e3eabf3 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -276,35 +276,35 @@ void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc,
float *r_y);
/**
- * Convert point to parent space
+ * Convert point to world space
*
* \param pt: Original point
- * \param diff_mat: Matrix with the difference between original parent matrix
+ * \param diff_mat: Matrix with the transformation
* \param[out] r_pt: Pointer to new point after apply matrix
*/
-void gpencil_point_to_parent_space(const bGPDspoint *pt,
- const float diff_mat[4][4],
- bGPDspoint *r_pt);
+void gpencil_point_to_world_space(const bGPDspoint *pt,
+ const float diff_mat[4][4],
+ bGPDspoint *r_pt);
/**
* Change points position relative to parent object
*/
/**
* Change position relative to parent object
*/
-void gpencil_apply_parent(struct Depsgraph *depsgraph,
- struct Object *obact,
- bGPDlayer *gpl,
- bGPDstroke *gps);
+void gpencil_world_to_object_space(struct Depsgraph *depsgraph,
+ struct Object *obact,
+ bGPDlayer *gpl,
+ bGPDstroke *gps);
/**
* Change point position relative to parent object
*/
/**
* Change point position relative to parent object
*/
-void gpencil_apply_parent_point(struct Depsgraph *depsgraph,
- struct Object *obact,
- bGPDlayer *gpl,
- bGPDspoint *pt);
+void gpencil_world_to_object_space_point(struct Depsgraph *depsgraph,
+ struct Object *obact,
+ bGPDlayer *gpl,
+ bGPDspoint *pt);
/**
* generic based on gpencil_point_to_xy_fl
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index dc63acf5136..cc25ed66b3d 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -167,20 +167,20 @@ static bool gpencil_stroke_need_flip(Depsgraph *depsgraph,
/* Line from start of strokes. */
pt = &gps_from->points[0];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_start[0], &v_from_start[1]);
pt = &gps_to->points[0];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_start[0], &v_to_start[1]);
/* Line from end of strokes. */
pt = &gps_from->points[gps_from->totpoints - 1];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_end[0], &v_from_end[1]);
pt = &gps_to->points[gps_to->totpoints - 1];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_end[0], &v_to_end[1]);
const bool isect_lines = (isect_seg_seg_v2(v_from_start, v_to_start, v_from_end, v_to_end) ==
@@ -690,7 +690,7 @@ static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGP
tgpi->flag, (RNA_enum_get(op->ptr, "layers") == 1), GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS);
SET_FLAG_FROM_TEST(
tgpi->flag,
- (GPENCIL_EDIT_MODE(tgpi->gpd) && (RNA_boolean_get(op->ptr, "interpolate_selected_only"))),
+ (GPENCIL_EDIT_MODE(tgpi->gpd) && RNA_boolean_get(op->ptr, "interpolate_selected_only")),
GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED);
tgpi->flipmode = RNA_enum_get(op->ptr, "flip");
diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc
index b27e1c75746..2b01fce5bf8 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.cc
+++ b/source/blender/editors/gpencil/gpencil_mesh.cc
@@ -43,8 +43,8 @@
#include "gpencil_intern.h"
/* Check frame_end is always > start frame! */
-static void gpencil_bake_set_frame_end(struct Main *UNUSED(main),
- struct Scene *UNUSED(scene),
+static void gpencil_bake_set_frame_end(struct Main * /*main*/,
+ struct Scene * /*scene*/,
struct PointerRNA *ptr)
{
int frame_start = RNA_int_get(ptr, "frame_start");
@@ -91,7 +91,7 @@ static void animdata_keyframe_list_get(ListBase *ob_list,
/* Keyframe number is x value of point. */
if ((bezt->f2 & SELECT) || (!only_selected)) {
/* Insert only one key for each keyframe number. */
- int key = (int)bezt->vec[1][0];
+ int key = int(bezt->vec[1][0]);
if (!BLI_ghash_haskey(r_keyframes, POINTER_FROM_INT(key))) {
BLI_ghash_insert(r_keyframes, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
}
@@ -213,7 +213,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
bool newob = false;
if (target == GP_TARGET_OB_SELECTED) {
- ob_gpencil = BKE_view_layer_non_active_selected_object(CTX_data_view_layer(C), v3d);
+ ob_gpencil = BKE_view_layer_non_active_selected_object(scene, CTX_data_view_layer(C), v3d);
if (ob_gpencil != nullptr) {
if (ob_gpencil->type != OB_GPENCIL) {
BKE_report(op->reports, RPT_WARNING, "Target object not a grease pencil, ignoring!");
@@ -261,7 +261,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Loop all frame range. */
- int oldframe = (int)DEG_get_ctime(depsgraph);
+ int oldframe = int(DEG_get_ctime(depsgraph));
int key = -1;
/* Get list of keyframes. */
@@ -278,7 +278,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Check if frame is in the list of frames to be exported. */
- if ((only_selected) && (!BLI_ghash_haskey(keyframe_list, POINTER_FROM_INT(i)))) {
+ if ((only_selected) && !BLI_ghash_haskey(keyframe_list, POINTER_FROM_INT(i))) {
continue;
}
@@ -299,7 +299,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
angle,
thickness,
offset,
- ob_eval->obmat,
+ ob_eval->object_to_world,
frame_offset,
use_seams,
use_faces,
@@ -315,7 +315,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if ((gps->flag & GP_STROKE_TAG) == 0) {
ED_gpencil_stroke_reproject(
- depsgraph, &gsc, sctx, gpl, gpf, gps, project_type, false);
+ depsgraph, &gsc, sctx, gpl, gpf, gps, project_type, false, 0.0f);
gps->flag |= GP_STROKE_TAG;
}
}
@@ -380,7 +380,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
static int gpencil_bake_mesh_animation_invoke(bContext *C,
wmOperator *op,
- const wmEvent *UNUSED(event))
+ const wmEvent * /*event*/)
{
/* Show popup dialog to allow editing. */
/* FIXME: hard-coded dimensions here are just arbitrary. */
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index 8119646137c..60b58b6f513 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -92,7 +92,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
if ((!is_annotation) && (view_layer != NULL)) {
Object *ob;
ob = BKE_object_add_for_data(
- bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
+ bmain, scene, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
zero_v3(ob->loc);
DEG_relations_tag_update(bmain); /* added object */
@@ -122,7 +122,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
+ if ((gps->colorname[0] != '\0') && STREQ(gps->colorname, palcolor->info)) {
gps->mat_nr = ob->totcol - 1;
gps->colorname[0] = '\0';
/* weights array */
@@ -160,7 +160,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
gpl->tintcolor[3] = 0.0f;
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) {
+ if ((gps->colorname[0] != '\0') && STREQ(gps->colorname, palcolor->info)) {
/* copy color settings */
copy_v4_v4(gpl->color, palcolor->color);
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 8e33a029229..d2ed1720bf8 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -434,8 +434,7 @@ static void gpencil_stroke_convertcoords(tGPsdata *p,
rmval[1] = mval[1] - 0.5f;
round_v2i_v2fl(mval_i, rmval);
- if (gpencil_project_check(p) &&
- (ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
+ if (gpencil_project_check(p) && ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth)) {
/* projecting onto 3D-Geometry
* - nothing more needs to be done here, since view_autodist_simple() has already done it
*/
@@ -937,7 +936,7 @@ static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps)
/* Apply layer thickness change. */
gps_duplicate->thickness += gpl->line_change;
/* Apply object scale to thickness. */
- gps_duplicate->thickness *= mat4_to_scale(p->ob->obmat);
+ gps_duplicate->thickness *= mat4_to_scale(p->ob->object_to_world);
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
/* Stroke. */
@@ -1134,11 +1133,9 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* reproject to plane (only in 3d space) */
gpencil_reproject_toplane(p, gps);
- pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* if parented change position relative to parent object */
- gpencil_apply_parent_point(depsgraph, obact, gpl, pt);
- }
+
+ /* Change position relative to object. */
+ gpencil_world_to_object_space(depsgraph, obact, gpl, gps);
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
if ((!is_depth) &&
@@ -1301,8 +1298,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* reproject to plane (only in 3d space) */
gpencil_reproject_toplane(p, gps);
- /* change position relative to parent object */
- gpencil_apply_parent(depsgraph, obact, gpl, gps);
+ /* Change position relative to parent object. */
+ gpencil_world_to_object_space(depsgraph, obact, gpl, gps);
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
if ((!is_depth) && (((align_flag & GP_PROJECT_VIEWSPACE) && is_lock_axis_view) || is_camera)) {
ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps);
@@ -1387,7 +1384,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
}
gpencil_update_cache(p->gpd);
- BKE_gpencil_tag_full_update(p->gpd, gpl, p->gpf, NULL);
+ BKE_gpencil_tag_full_update(
+ p->gpd, gpl, GPENCIL_MULTIEDIT_SESSIONS_ON(p->gpd) ? NULL : p->gpf, NULL);
}
/* --- 'Eraser' for 'Paint' Tool ------ */
@@ -1551,10 +1549,10 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
/* only process if it hasn't been masked out... */
if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
bGPDspoint pt_temp;
- gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp);
+ gpencil_point_to_world_space(gps->points, p->diff_mat, &pt_temp);
gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* free stroke */
@@ -1575,11 +1573,11 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
/* get points to work with */
pt1 = gps->points + i;
bGPDspoint npt;
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_world_space(pt1, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* free stroke */
@@ -1633,14 +1631,14 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
bGPDspoint npt;
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_world_space(pt1, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
- gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
+ gpencil_point_to_world_space(pt2, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
if (pt0) {
- gpencil_point_to_parent_space(pt0, p->diff_mat, &npt);
+ gpencil_point_to_world_space(pt0, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
}
else {
@@ -1649,9 +1647,9 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
/* Check that point segment of the bound-box of the eraser stroke. */
- if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1]) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1]) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that line-width is irrelevant.
@@ -1743,14 +1741,14 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
/* 2) Tag any point with overly low influence for removal in the next pass */
if ((inf1 > 0.0f) &&
- (((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
- (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)))) {
+ ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))) {
pt1->flag |= GP_SPOINT_TAG;
do_cull = true;
}
if ((inf1 > 2.0f) &&
- (((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
- (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)))) {
+ ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) ||
+ (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD))) {
pt2->flag |= GP_SPOINT_TAG;
do_cull = true;
}
@@ -3331,7 +3329,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
return OPERATOR_RUNNING_MODAL;
}
-/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+/* gpencil modal operator stores area, which can be removed while using it (like full-screen). */
static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
bScreen *screen = CTX_wm_screen(C);
@@ -3716,7 +3714,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view.
*/
}
- else if ((!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP))) {
+ else if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP)) {
gpencil_guide_event_handling(C, op, event, p);
estate = OPERATOR_RUNNING_MODAL;
}
@@ -3738,7 +3736,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* (Disabling RIGHTMOUSE case here results in bugs like T32647)
* also making sure we have a valid event value, to not exit too early
*/
- if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
+ if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && ELEM(event->val, KM_PRESS, KM_RELEASE)) {
/* if painting, end stroke */
if (p->status == GP_STATUS_PAINTING) {
p->status = GP_STATUS_DONE;
@@ -3888,7 +3886,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
+ /* gpencil modal operator stores area, which can be removed while using it (like full-screen). */
if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 4a4fffc9638..b693d4ae185 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -677,8 +677,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
center[0] = tgpi->start[0] + ((tgpi->end[0] - tgpi->start[0]) / 2.0f);
center[1] = tgpi->start[1] + ((tgpi->end[1] - tgpi->start[1]) / 2.0f);
- radius[0] = fabsf(((tgpi->end[0] - tgpi->start[0]) / 2.0f));
- radius[1] = fabsf(((tgpi->end[1] - tgpi->start[1]) / 2.0f));
+ radius[0] = fabsf((tgpi->end[0] - tgpi->start[0]) / 2.0f);
+ radius[1] = fabsf((tgpi->end[1] - tgpi->start[1]) / 2.0f);
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
@@ -1073,7 +1073,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* if parented change position relative to parent object */
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
- gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt);
+ gpencil_world_to_object_space_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt);
}
/* If camera view or view projection, reproject flat to view to avoid perspective effect. */
@@ -1515,7 +1515,7 @@ static void gpencil_primitive_edit_event_handling(
break;
}
case EVT_MKEY: {
- if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) {
+ if ((event->val == KM_PRESS) && (tgpi->curve) && ELEM(tgpi->orign_type, GP_STROKE_ARC)) {
tgpi->flip ^= 1;
gpencil_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
@@ -1703,7 +1703,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_PADPLUSKEY:
case WHEELUPMOUSE: {
- if ((event->val != KM_RELEASE)) {
+ if (event->val != KM_RELEASE) {
tgpi->tot_edges = tgpi->tot_edges + 1;
CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -1713,7 +1713,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_PADMINUS:
case WHEELDOWNMOUSE: {
- if ((event->val != KM_RELEASE)) {
+ if (event->val != KM_RELEASE) {
tgpi->tot_edges = tgpi->tot_edges - 1;
CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -1723,7 +1723,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_FKEY: /* brush thickness/ brush strength */
{
- if ((event->val == KM_PRESS)) {
+ if (event->val == KM_PRESS) {
if (event->modifier & KM_SHIFT) {
tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_STRENGTH;
@@ -1808,14 +1808,14 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
}
else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
- (!ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
/* set control points and enter edit mode */
tgpi->flag = IN_CURVE_EDIT;
gpencil_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
- (!ELEM(tgpi->type, GP_STROKE_CURVE, GP_STROKE_POLYLINE))) {
+ !ELEM(tgpi->type, GP_STROKE_CURVE, GP_STROKE_POLYLINE)) {
/* stop drawing primitive */
tgpi->flag = IDLE;
gpencil_primitive_interaction_end(C, op, win, tgpi);
@@ -1823,7 +1823,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_FINISHED;
}
else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
- (ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
/* set control points and enter edit mode */
tgpi->flag = IN_POLYLINE;
gpencil_primitive_update(C, op, tgpi);
@@ -1869,7 +1869,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_PADPLUSKEY:
case WHEELUPMOUSE: {
- if ((event->val != KM_RELEASE)) {
+ if (event->val != KM_RELEASE) {
tgpi->tot_edges = tgpi->tot_edges + 1;
CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -1881,7 +1881,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_PADMINUS:
case WHEELDOWNMOUSE: {
- if ((event->val != KM_RELEASE)) {
+ if (event->val != KM_RELEASE) {
tgpi->tot_edges = tgpi->tot_edges - 1;
CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
@@ -1893,7 +1893,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_GKEY: /* grab mode */
{
- if ((event->val == KM_PRESS)) {
+ if (event->val == KM_PRESS) {
tgpi->flag = IN_MOVE;
WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
@@ -1901,7 +1901,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case EVT_FKEY: /* brush thickness/ brush strength */
{
- if ((event->val == KM_PRESS)) {
+ if (event->val == KM_PRESS) {
if (event->modifier & KM_SHIFT) {
tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_STRENGTH;
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index e27cd255217..ab3edfdd4fa 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -68,6 +68,8 @@
#include "gpencil_intern.h"
+#define SEARCH_RADIUS_PIXEL 20
+
/* ************************************************ */
/* General Brush Editing Context */
@@ -78,6 +80,7 @@ typedef struct tGP_BrushEditData {
Main *bmain;
Scene *scene;
Object *object;
+ Object *ob_eval;
ScrArea *area;
ARegion *region;
@@ -516,7 +519,7 @@ static void gpencil_brush_grab_calc_dvec(tGP_BrushEditData *gso)
float mval_f[2];
- /* convert from 2D screenspace to 3D... */
+ /* Convert from 2D screen-space to 3D. */
mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
@@ -544,8 +547,10 @@ static void gpencil_brush_grab_apply_cached(tGP_BrushEditData *gso,
return;
}
- float inverse_diff_mat[4][4];
- invert_m4_m4(inverse_diff_mat, diff_mat);
+ float matrix[4][4], inverse_diff_mat[4][4];
+ copy_m4_m4(matrix, diff_mat);
+ zero_axis_bias_m4(matrix);
+ invert_m4_m4(inverse_diff_mat, matrix);
/* Apply dvec to all of the stored points */
for (int i = 0; i < data->size; i++) {
@@ -669,7 +674,7 @@ static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso,
/* 1) Make this point relative to the cursor/midpoint (dvec) */
float fpt[3];
- mul_v3_m4v3(fpt, gso->object->obmat, &pt->x);
+ mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x);
sub_v3_v3v3(vec, fpt, gso->dvec);
/* 2) Shrink the distance by pulling the point towards the midpoint
@@ -689,7 +694,7 @@ static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso,
/* 3) Translate back to original space, with the shrinkage applied */
add_v3_v3v3(fpt, gso->dvec, vec);
- mul_v3_m4v3(&pt->x, gso->object->imat, fpt);
+ mul_v3_m4v3(&pt->x, gso->object->world_to_object, fpt);
/* compute lock axis */
gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
@@ -700,8 +705,8 @@ static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso,
/* ----------------------------------------------- */
/* Twist Brush - Rotate Around midpoint */
-/* Take the screenspace coordinates of the point, rotate this around the brush midpoint,
- * convert the rotated point and convert it into "data" space
+/* Take the screen-space coordinates of the point, rotate this around the brush midpoint,
+ * convert the rotated point and convert it into "data" space.
*/
static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso,
@@ -741,12 +746,12 @@ static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso,
/* Rotate point */
float fpt[3];
- mul_v3_m4v3(fpt, gso->object->obmat, &pt->x);
+ mul_v3_m4v3(fpt, gso->object->object_to_world, &pt->x);
sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center
* (center is stored in dvec) */
mul_m3_v3(rmat, vec);
add_v3_v3v3(fpt, vec, gso->dvec); /* restore */
- mul_v3_m4v3(&pt->x, gso->object->imat, fpt);
+ mul_v3_m4v3(&pt->x, gso->object->world_to_object, fpt);
/* compute lock axis */
gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
@@ -807,7 +812,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso,
/* apply random to position */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
/* Jitter is applied perpendicular to the mouse movement vector
- * - We compute all effects in screenspace (since it's easier)
+ * - We compute all effects in screen-space (since it's easier)
* and then project these to get the points/distances in
* view-space as needed.
*/
@@ -989,8 +994,8 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
float delta[3];
size_t strokes_added = 0;
- /* Compute amount to offset the points by */
- /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
+ /* Compute amount to offset the points by. */
+ /* NOTE: This assumes that screen-space strokes are NOT used in the 3D view. */
gpencil_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
@@ -1035,11 +1040,11 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
*/
for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
/* Rotate around center new position */
- mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */
+ mul_mat3_m4_v3(gso->object->object_to_world, &pt->x); /* only rotation component */
/* assume that the delta can just be applied, and then everything works */
add_v3_v3(&pt->x, delta);
- mul_m4_v3(gso->object->imat, &pt->x);
+ mul_m4_v3(gso->object->world_to_object, &pt->x);
}
/* Store ref for later */
@@ -1063,7 +1068,7 @@ static void gpencil_brush_clone_adjust(tGP_BrushEditData *gso)
/* For each of the stored strokes, apply the offset to each point */
/* NOTE: Again this assumes that in the 3D view,
- * we only have 3d space and not screenspace strokes... */
+ * we only have 3d space and not screen-space strokes. */
for (snum = 0; snum < data->totitems; snum++) {
bGPDstroke *gps = data->new_strokes[snum];
bGPDspoint *pt;
@@ -1169,13 +1174,18 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->scene = scene;
gso->object = ob;
if (ob) {
- invert_m4_m4(gso->inv_mat, ob->obmat);
+ float matrix[4][4];
+ copy_m4_m4(matrix, ob->object_to_world);
+ zero_axis_bias_m4(matrix);
+ invert_m4_m4(gso->inv_mat, matrix);
gso->vrgroup = gso->gpd->vertex_group_active_index - 1;
if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) {
gso->vrgroup = -1;
}
/* Check if some modifier can transform the stroke. */
gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob);
+
+ gso->ob_eval = (Object *)DEG_get_evaluated_id(gso->depsgraph, &ob->id);
}
else {
unit_m4(gso->inv_mat);
@@ -1191,12 +1201,19 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->brush = brush;
BKE_curvemapping_init(gso->brush->curve);
- if (brush->gpencil_settings->sculpt_mode_flag &
- (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
- GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) {
+ const bool is_automasking = (ts->gp_sculpt.flag &
+ (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE)) != 0;
+ if (is_automasking) {
gso->automasking_strokes = BLI_ghash_ptr_new(__func__);
}
else {
+ if (gso->automasking_strokes != NULL) {
+ BLI_ghash_free(gso->automasking_strokes, NULL, NULL);
+ }
gso->automasking_strokes = NULL;
}
/* save mask */
@@ -1287,6 +1304,10 @@ static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op)
}
default:
+ if (gso->stroke_customdata != NULL) {
+ BLI_ghash_free(gso->stroke_customdata, NULL, NULL);
+ gso->stroke_customdata = NULL;
+ }
break;
}
@@ -1462,12 +1483,12 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
bGPDspoint pt_temp;
pt = &gps->points[0];
if ((is_masking && (pt->flag & GP_SPOINT_SELECT) != 0) || (!is_masking)) {
- gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
round_v2i_v2fl(mval_i, gso->mval);
@@ -1499,15 +1520,15 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
}
}
bGPDspoint npt;
- gpencil_point_to_parent_space(pt1, diff_mat, &npt);
+ gpencil_point_to_world_space(pt1, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
- gpencil_point_to_parent_space(pt2, diff_mat, &npt);
+ gpencil_point_to_world_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
/* Check that point segment of the bound-box of the selection stroke. */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1]) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* brush region (either within stroke painted, or on its lines)
* - this assumes that line-width is irrelevant.
@@ -1592,13 +1613,16 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
bGPdata *gpd = ob->data;
const char tool = gso->brush->gpencil_sculpt_tool;
GP_SpaceConversion *gsc = &gso->gsc;
+ ToolSettings *ts = gso->scene->toolsettings;
Brush *brush = gso->brush;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
- const bool is_automasking = (brush->gpencil_settings->sculpt_mode_flag &
- (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE |
- GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
- GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) != 0;
+ const bool is_automasking = (ts->gp_sculpt.flag &
+ (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE)) != 0;
/* Calc bound box matrix. */
float bound_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
@@ -1615,14 +1639,14 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
{
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
- if ((is_automasking) && (!BLI_ghash_haskey(gso->automasking_strokes, gps_active))) {
+ if ((is_automasking) && !BLI_ghash_haskey(gso->automasking_strokes, gps_active)) {
continue;
}
}
/* Check if the stroke collide with brush. */
if ((gps->totpoints > 1) &&
- (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat))) {
+ !ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
continue;
}
@@ -1731,27 +1755,111 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
return changed;
}
+/* Find the stroke nearer to the brush. */
+static void get_nearest_stroke_to_brush(tGP_BrushEditData *gso,
+ int mval_i[2],
+ bGPDlayer **r_gpl,
+ bGPDstroke **r_gps)
+{
+ const int radius = SEARCH_RADIUS_PIXEL;
+
+ Object *ob_eval = gso->ob_eval;
+ bGPdata *gpd = (bGPdata *)ob_eval->data;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ float dist = FLT_MAX;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* Calculate bound box matrix. */
+ float bound_mat[4][4];
+ BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
+
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ if (gps->totpoints == 0) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_material_editable(gso->object, 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;
+ }
+
+ bGPDspoint *pt;
+ int pc2D[2] = {0};
+ bGPDspoint npt;
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = gps->points + i;
+ gpencil_point_to_world_space(pt, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc2D[0], &pc2D[1]);
+ float d = len_v2v2_int(mval_i, pc2D);
+ if (d < dist) {
+ dist = d;
+ *r_gpl = gpl;
+ *r_gps = gps_active;
+ }
+ }
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+}
+
/* Get list of Auto-Masking strokes. */
static bool get_automasking_strokes_list(tGP_BrushEditData *gso)
{
- bGPdata *gpd = gso->gpd;
+ Object *ob_eval = gso->ob_eval;
+ bGPdata *gpd = (bGPdata *)ob_eval->data;
GP_SpaceConversion *gsc = &gso->gsc;
- Brush *brush = gso->brush;
+ ToolSettings *ts = gso->scene->toolsettings;
Object *ob = gso->object;
- Material *mat_active = BKE_gpencil_material(ob, ob->actcol);
+ const eGP_Sculpt_SettingsFlag flag = ts->gp_sculpt.flag;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const bool is_masking_stroke = (brush->gpencil_settings->sculpt_mode_flag &
- GP_SCULPT_FLAGMODE_AUTOMASK_STROKE) != 0;
- const bool is_masking_layer = (brush->gpencil_settings->sculpt_mode_flag &
- GP_SCULPT_FLAGMODE_AUTOMASK_LAYER) != 0;
- const bool is_masking_material = (brush->gpencil_settings->sculpt_mode_flag &
- GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL) != 0;
+ const bool is_masking_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE) != 0;
+ const bool is_masking_layer_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE) != 0;
+ const bool is_masking_material_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE) !=
+ 0;
+ const bool is_masking_layer_active = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE) != 0;
+ const bool is_masking_material_active = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE) !=
+ 0;
int mval_i[2];
round_v2i_v2fl(mval_i, gso->mval);
/* Define a fix number of pixel as cursor radius. */
- const int radius = 10;
+ const int radius = SEARCH_RADIUS_PIXEL;
bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd);
+ Material *mat_active = BKE_gpencil_material(ob, ob->actcol);
+
+ /* By default use active values. */
+ bGPDlayer *gpl_active_stroke = gpl_active;
+ Material *mat_active_stroke = mat_active;
+ /* Find nearest stroke to find the layer and material. */
+ if (is_masking_layer_stroke || is_masking_material_stroke) {
+ bGPDlayer *gpl_near = NULL;
+ bGPDstroke *gps_near = NULL;
+ get_nearest_stroke_to_brush(gso, mval_i, &gpl_near, &gps_near);
+ if (gps_near != NULL) {
+ if (is_masking_layer_stroke) {
+ gpl_active_stroke = gpl_near;
+ }
+ if (is_masking_material_stroke) {
+ mat_active_stroke = BKE_object_material_get(ob, gps_near->mat_nr + 1);
+ }
+ }
+ }
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Only editable and visible layers are considered. */
@@ -1765,87 +1873,113 @@ static bool get_automasking_strokes_list(tGP_BrushEditData *gso)
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ bool pick_stroke = false;
+ bool pick_layer_stroke = false;
+ bool pick_material_stroke = false;
+ bool pick_layer_active = false;
+ bool pick_material_active = false;
+
if (gps->totpoints == 0) {
continue;
}
- /* Check if the color is editable. */
+ /* Check if the material is editable. */
if (ED_gpencil_stroke_material_editable(gso->object, gpl, gps) == false) {
continue;
}
- /* Layer Auto-Masking. */
- if ((is_masking_layer) && (gpl == gpl_active)) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- continue;
+ /* Stroke Layer Auto-Masking. */
+ if (is_masking_layer_stroke && (gpl == gpl_active_stroke)) {
+ pick_layer_stroke = true;
}
- /* Material Auto-Masking. */
- if (is_masking_material) {
+ /* Active Layer Auto-Masking. */
+ if (is_masking_layer_active && (gpl == gpl_active)) {
+ pick_layer_active = true;
+ }
+ /* Stroke Material Auto-Masking. */
+ if (is_masking_material_stroke) {
Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1);
- if (mat == mat_active) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- continue;
+ if (mat == mat_active_stroke) {
+ pick_material_stroke = true;
}
}
-
- /* If Stroke Auto-Masking is not enabled, nothing else to do. */
- if (!is_masking_stroke) {
- continue;
+ /* Active Material Auto-Masking. */
+ if (is_masking_material_active) {
+ Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1);
+ if (mat == mat_active) {
+ pick_material_active = true;
+ }
}
/* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
- continue;
- }
-
- bGPDspoint *pt1, *pt2;
- int pc1[2] = {0};
- int pc2[2] = {0};
- bGPDspoint npt;
+ if ((is_masking_stroke) &&
+ ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
- if (gps->totpoints == 1) {
- gpencil_point_to_parent_space(gps->points, bound_mat, &npt);
- gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ bGPDspoint npt;
- /* Only check if point is inside. */
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- }
- }
- else {
- /* Loop over the points in the stroke, checking for intersections
- * - an intersection means that we touched the stroke.
- */
- for (int i = 0; (i + 1) < gps->totpoints; i++) {
- /* Get points to work with. */
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
-
- /* Check first point. */
- gpencil_point_to_parent_space(pt1, bound_mat, &npt);
+ if (gps->totpoints == 1) {
+ gpencil_point_to_world_space(gps->points, bound_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- i = gps->totpoints;
- continue;
- }
- /* Check second point. */
- gpencil_point_to_parent_space(pt2, bound_mat, &npt);
- gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
- if (len_v2v2_int(mval_i, pc2) <= radius) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- i = gps->totpoints;
- continue;
+ /* Only check if point is inside. */
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ pick_stroke = true;
}
-
- /* Check segment. */
- if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
- BLI_ghash_insert(gso->automasking_strokes, gps, gps);
- i = gps->totpoints;
- continue;
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke.
+ */
+ for (int i = 0; (i + 1) < gps->totpoints && !pick_stroke; i++) {
+ /* Get points to work with. */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Check first point. */
+ gpencil_point_to_world_space(pt1, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ pick_stroke = true;
+ i = gps->totpoints;
+ }
+
+ /* Check second point. */
+ gpencil_point_to_world_space(pt2, bound_mat, &npt);
+ gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+ if (len_v2v2_int(mval_i, pc2) <= radius) {
+ pick_stroke = true;
+ i = gps->totpoints;
+ }
+
+ /* Check segment. */
+ if (!pick_stroke && gpencil_stroke_inside_circle(
+ gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ pick_stroke = true;
+ i = gps->totpoints;
+ }
}
}
}
+ /* if the stroke meets all the masking conditions, add to the hash table. */
+ if (is_masking_stroke && !pick_stroke) {
+ continue;
+ }
+ if (is_masking_layer_stroke && !pick_layer_stroke) {
+ continue;
+ }
+ if (is_masking_material_stroke && !pick_material_stroke) {
+ continue;
+ }
+ if (is_masking_layer_active && !pick_layer_active) {
+ continue;
+ }
+ if (is_masking_material_active && !pick_material_active) {
+ continue;
+ }
+ BLI_ghash_insert(gso->automasking_strokes, gps_active, gps_active);
}
/* If not multi-edit, exit loop. */
if (!is_multiedit) {
@@ -1865,7 +1999,7 @@ static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *
Object *obact = gso->object;
bool changed = false;
- Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
+ Object *ob_eval = gso->ob_eval;
bGPdata *gpd = (bGPdata *)ob_eval->data;
/* Calculate brush-specific data which applies equally to all points */
@@ -1903,7 +2037,7 @@ static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *
/* Find visible strokes, and perform operations on those if hit */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* If no active frame, don't do anything... */
- if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}
@@ -1959,6 +2093,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
{
tGP_BrushEditData *gso = op->customdata;
Brush *brush = gso->brush;
+ ToolSettings *ts = gso->scene->toolsettings;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
float mousef[2];
@@ -2000,9 +2135,10 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
/* Get list of Auto-Masking strokes. */
if ((!gso->automasking_ready) &&
- (brush->gpencil_settings->sculpt_mode_flag &
- (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER |
- GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL))) {
+ (ts->gp_sculpt.flag &
+ (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE | GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE | GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE |
+ GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE))) {
gso->automasking_ready = get_automasking_strokes_list(gso);
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index a19265720e8..13455861924 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -94,13 +94,13 @@ static bool gpencil_select_poll(bContext *C)
ToolSettings *ts = CTX_data_tool_settings(C);
if (GPENCIL_SCULPT_MODE(gpd)) {
- if (!(GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt))) {
+ if (!GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)) {
return false;
}
}
if (GPENCIL_VERTEX_MODE(gpd)) {
- if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
+ if (!GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)) {
return false;
}
}
@@ -267,7 +267,7 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
/* For sculpt mode, if mask is disable, only allows deselect */
if (GPENCIL_SCULPT_MODE(gpd)) {
ToolSettings *ts = CTX_data_tool_settings(C);
- if ((!(GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt))) && (action != SEL_DESELECT)) {
+ if (!GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt) && (action != SEL_DESELECT)) {
return OPERATOR_CANCELLED;
}
}
@@ -529,7 +529,7 @@ static int gpencil_select_random_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
- if ((gpd == NULL) || (GPENCIL_NONE_EDIT_MODE(gpd))) {
+ if ((gpd == NULL) || GPENCIL_NONE_EDIT_MODE(gpd)) {
return OPERATOR_CANCELLED;
}
@@ -576,7 +576,7 @@ static int gpencil_select_random_exec(bContext *C, wmOperator *op)
if (selectmode == GP_SELECTMODE_STROKE) {
RNG *rng = BLI_rng_new(seed_iter);
- const unsigned int j = BLI_rng_get_uint(rng) % gps->totpoints;
+ const uint j = BLI_rng_get_uint(rng) % gps->totpoints;
bool select_stroke = ((gps->totpoints * randfac) <= j) ? true : false;
select_stroke ^= select;
/* Curve function has select parameter inverted. */
@@ -647,7 +647,7 @@ static int gpencil_select_random_exec(bContext *C, wmOperator *op)
if (selectmode == GP_SELECTMODE_STROKE) {
RNG *rng = BLI_rng_new(seed_iter);
- const unsigned int j = BLI_rng_get_uint(rng) % gps->totpoints;
+ const uint j = BLI_rng_get_uint(rng) % gps->totpoints;
bool select_stroke = ((gps->totpoints * randfac) <= j) ? true : false;
select_stroke ^= select;
select_all_stroke_points(gpd, gps, select_stroke);
@@ -1497,11 +1497,11 @@ static bool gpencil_stroke_do_circle_sel(bGPdata *gpd,
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
bGPDspoint pt_temp;
- gpencil_point_to_parent_space(pt, diff_mat, &pt_temp);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &x0, &y0);
/* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
+ if (!ELEM(V2D_IS_CLIPPED, x0, y0) && BLI_rcti_isect_pt(rect, x0, y0)) {
/* only check if point is inside */
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
hit = true;
@@ -2040,7 +2040,7 @@ static bool gpencil_generic_stroke_select(bContext *C,
gpencil_point_conversion_init(C, &gsc);
/* deselect all strokes first? */
- if (SEL_OP_USE_PRE_DESELECT(sel_op) || (GPENCIL_PAINT_MODE(gpd))) {
+ if (SEL_OP_USE_PRE_DESELECT(sel_op) || GPENCIL_PAINT_MODE(gpd)) {
/* Set selection index to 0. */
gpd->select_last_index = 0;
@@ -2071,8 +2071,9 @@ static bool gpencil_generic_stroke_select(bContext *C,
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
- /* convert point coords to screenspace */
- const bool is_inside = is_inside_fn(gsc.region, gpstroke_iter.diff_mat, &pt->x, user_data);
+ /* Convert point coords to screen-space. */
+ const bool is_inside = is_inside_fn(
+ gsc.region, gpstroke_iter.diff_mat, &pt_active->x, user_data);
if (strokemode == false) {
const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
@@ -2477,7 +2478,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
int xy[2];
bGPDspoint pt2;
- gpencil_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
+ gpencil_point_to_world_space(pt, gpstroke_iter.diff_mat, &pt2);
gpencil_point_to_xy(&gsc, gps_active, &pt2, &xy[0], &xy[1]);
/* do boundbox check first */
@@ -2766,7 +2767,7 @@ static bool gpencil_select_vertex_color_poll(bContext *C)
bGPdata *gpd = (bGPdata *)ob->data;
if (GPENCIL_VERTEX_MODE(gpd)) {
- if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
+ if (!GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)) {
return false;
}
diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c
index f6e88e05d46..1a18e10412e 100644
--- a/source/blender/editors/gpencil/gpencil_trace_ops.c
+++ b/source/blender/editors/gpencil/gpencil_trace_ops.c
@@ -45,7 +45,7 @@
typedef struct TraceJob {
/* from wmJob */
struct Object *owner;
- short *stop, *do_update;
+ bool *stop, *do_update;
float *progress;
bContext *C;
@@ -71,6 +71,9 @@ typedef struct TraceJob {
int32_t thickness;
int32_t turnpolicy;
int32_t mode;
+ /** Frame to render to be used by python API. Not exposed in UI.
+ * This feature is only used in Studios to run custom video trace for selected frames. */
+ int32_t frame_num;
bool success;
bool was_canceled;
@@ -195,7 +198,7 @@ static void trace_initialize_job_data(TraceJob *trace_job)
}
}
-static void trace_start_job(void *customdata, short *stop, short *do_update, float *progress)
+static void trace_start_job(void *customdata, bool *stop, bool *do_update, float *progress)
{
TraceJob *trace_job = customdata;
@@ -212,7 +215,10 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo
(trace_job->mode == GPENCIL_TRACE_MODE_SINGLE)) {
void *lock;
ImageUser *iuser = trace_job->ob_active->iuser;
- iuser->framenr = init_frame;
+
+ iuser->framenr = ((trace_job->frame_num == 0) || (trace_job->frame_num > iuser->frames)) ?
+ init_frame :
+ trace_job->frame_num;
ImBuf *ibuf = BKE_image_acquire_ibuf(trace_job->image, iuser, &lock);
if (ibuf) {
/* Create frame. */
@@ -251,7 +257,7 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo
trace_job->success = !trace_job->was_canceled;
*do_update = true;
- *stop = 0;
+ *stop = false;
}
static void trace_end_job(void *customdata)
@@ -300,9 +306,10 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op)
/* Create a new grease pencil object or reuse selected. */
eGP_TargetObjectMode target = RNA_enum_get(op->ptr, "target");
- job->ob_gpencil = (target == GP_TARGET_OB_SELECTED) ? BKE_view_layer_non_active_selected_object(
- CTX_data_view_layer(C), job->v3d) :
- NULL;
+ job->ob_gpencil = (target == GP_TARGET_OB_SELECTED) ?
+ BKE_view_layer_non_active_selected_object(
+ scene, CTX_data_view_layer(C), job->v3d) :
+ NULL;
if (job->ob_gpencil != NULL) {
if (job->ob_gpencil->type != OB_GPENCIL) {
@@ -324,14 +331,15 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op)
job->thickness = RNA_int_get(op->ptr, "thickness");
job->turnpolicy = RNA_enum_get(op->ptr, "turnpolicy");
job->mode = RNA_enum_get(op->ptr, "mode");
+ job->frame_num = RNA_int_get(op->ptr, "frame_number");
trace_initialize_job_data(job);
/* Back to active base. */
ED_object_base_activate(job->C, job->base_active);
- if (job->image->source == IMA_SRC_FILE) {
- short stop = 0, do_update = true;
+ if ((job->image->source == IMA_SRC_FILE) || (job->frame_num > 0)) {
+ bool stop = false, do_update = true;
float progress;
trace_start_job(job, &stop, &do_update, &progress);
trace_end_job(job);
@@ -364,6 +372,8 @@ static int gpencil_trace_image_invoke(bContext *C, wmOperator *op, const wmEvent
void GPENCIL_OT_trace_image(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem turnpolicy_type[] = {
{POTRACE_TURNPOLICY_BLACK,
"BLACK",
@@ -475,4 +485,15 @@ void GPENCIL_OT_trace_image(wmOperatorType *ot)
true,
"Start At Current Frame",
"Trace Image starting in current image frame");
+ prop = RNA_def_int(
+ ot->srna,
+ "frame_number",
+ 0,
+ 0,
+ 9999,
+ "Trace Frame",
+ "Used to trace only one frame of the image sequence, set to zero to trace all",
+ 0,
+ 9999);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c
index 735759d40ec..aa9a2a653bb 100644
--- a/source/blender/editors/gpencil/gpencil_trace_utils.c
+++ b/source/blender/editors/gpencil/gpencil_trace_utils.c
@@ -119,7 +119,7 @@ static void pixel_at_index(const ImBuf *ibuf, const int32_t idx, float r_col[4])
copy_v4_v4(r_col, frgba);
}
else {
- unsigned char *cp = (unsigned char *)(ibuf->rect + idx);
+ uchar *cp = (uchar *)(ibuf->rect + idx);
r_col[0] = (float)cp[0] / 255.0f;
r_col[1] = (float)cp[1] / 255.0f;
r_col[2] = (float)cp[2] / 255.0f;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index e47f16ac466..7d814b43196 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -518,7 +518,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
/* filter stroke types by flags + spacetype */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D strokes - only in 3D view */
- return (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_PROPERTIES));
+ return ELEM(area->spacetype, SPACE_VIEW3D, SPACE_PROPERTIES);
}
if (gps->flag & GP_STROKE_2DIMAGE) {
/* Special "image" strokes - only in Image Editor */
@@ -612,17 +612,17 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
}
-void gpencil_point_to_parent_space(const bGPDspoint *pt,
- const float diff_mat[4][4],
- bGPDspoint *r_pt)
+void gpencil_point_to_world_space(const bGPDspoint *pt,
+ const float diff_mat[4][4],
+ bGPDspoint *r_pt)
{
- float fpt[3];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- copy_v3_v3(&r_pt->x, fpt);
+ mul_v3_m4v3(&r_pt->x, diff_mat, &pt->x);
}
-void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps)
+void gpencil_world_to_object_space(Depsgraph *depsgraph,
+ Object *obact,
+ bGPDlayer *gpl,
+ bGPDstroke *gps)
{
bGPDspoint *pt;
int i;
@@ -630,34 +630,31 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
- float fpt[3];
BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ zero_axis_bias_m4(diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
for (i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
- mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x);
- copy_v3_v3(&pt->x, fpt);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
}
}
-void gpencil_apply_parent_point(Depsgraph *depsgraph,
- Object *obact,
- bGPDlayer *gpl,
- bGPDspoint *pt)
+void gpencil_world_to_object_space_point(Depsgraph *depsgraph,
+ Object *obact,
+ bGPDlayer *gpl,
+ bGPDspoint *pt)
{
/* undo matrix */
float diff_mat[4][4];
float inverse_diff_mat[4][4];
- float fpt[3];
BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
+ zero_axis_bias_m4(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);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
}
void gpencil_point_to_xy(
@@ -770,7 +767,7 @@ void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc,
float xyval[2];
/* sanity checks */
- BLI_assert((gsc->area->spacetype == SPACE_VIEW3D));
+ BLI_assert(gsc->area->spacetype == SPACE_VIEW3D);
if (flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_float_global(region, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
@@ -857,7 +854,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
int mval_i[2];
round_v2i_v2fl(mval_i, point2D->m_xy);
- if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
+ if ((depth != NULL) && ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth)) {
/* projecting onto 3D-Geometry
* - nothing more needs to be done here, since view_autodist_simple() has already done it
*/
@@ -903,7 +900,7 @@ void ED_gpencil_drawing_reference_get(const Scene *scene,
}
else {
/* use object location */
- copy_v3_v3(r_vec, ob->obmat[3]);
+ copy_v3_v3(r_vec, ob->object_to_world[3]);
/* Apply layer offset. */
bGPdata *gpd = ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -935,6 +932,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
gpencil_point_conversion_init(C, &gsc);
BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
+ zero_axis_bias_m4(diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
/* Adjust each point */
@@ -942,7 +940,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke *
float xy[2];
bGPDspoint pt2;
- gpencil_point_to_parent_space(pt, diff_mat, &pt2);
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
gpencil_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
/* Planar - All on same plane parallel to the viewplane */
@@ -986,7 +984,7 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene,
/* if object, apply object rotation */
if (ob && (ob->type == OB_GPENCIL)) {
float mat[4][4];
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
/* move origin to cursor */
if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
@@ -1038,7 +1036,8 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
bGPDframe *gpf,
bGPDstroke *gps,
const eGP_ReprojectModes mode,
- const bool keep_original)
+ const bool keep_original,
+ const float offset)
{
ToolSettings *ts = gsc->scene->toolsettings;
ARegion *region = gsc->region;
@@ -1050,6 +1049,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
float diff_mat[4][4], inverse_diff_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(depsgraph, gsc->ob, gpl, diff_mat);
+ zero_axis_bias_m4(diff_mat);
invert_m4_m4(inverse_diff_mat, diff_mat);
float origin[3];
@@ -1087,7 +1087,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
* artifacts in the final points. */
bGPDspoint pt2;
- gpencil_point_to_parent_space(pt, diff_mat, &pt2);
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
gpencil_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]);
/* Project stroke in one axis */
@@ -1121,7 +1121,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
copy_v3_v3(&pt->x, &pt2.x);
/* apply parent again */
- gpencil_apply_parent_point(depsgraph, gsc->ob, gpl, pt);
+ gpencil_world_to_object_space_point(depsgraph, gsc->ob, gpl, pt);
}
/* Project screen-space back to 3D space (from current perspective)
* so that all points have been treated the same way. */
@@ -1156,7 +1156,13 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
&depth,
&location[0],
&normal[0])) {
- copy_v3_v3(&pt->x, location);
+ /* Apply offset over surface. */
+ float normal_vector[3];
+ sub_v3_v3v3(normal_vector, ray_start, location);
+ normalize_v3(normal_vector);
+ mul_v3_fl(normal_vector, offset);
+
+ add_v3_v3v3(&pt->x, location, normal_vector);
}
else {
/* Default to planar */
@@ -1200,7 +1206,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
/* if object, apply object rotation */
if (ob && (ob->type == OB_GPENCIL)) {
float mat[4][4];
- copy_m4_m4(mat, ob->obmat);
+ copy_m4_m4(mat, ob->object_to_world);
if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
if (gpl != NULL) {
add_v3_v3(mat[3], gpl->location);
@@ -1227,7 +1233,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene,
/* move origin to object */
if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) {
- copy_v3_v3(mat[3], ob->obmat[3]);
+ copy_v3_v3(mat[3], ob->object_to_world[3]);
}
mul_mat3_m4_v3(mat, plane_normal);
@@ -1359,16 +1365,16 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata
if (gpl->parent != NULL) {
/* calculate new matrix */
if (ELEM(gpl->partype, PAROBJECT, PARSKEL)) {
- invert_m4_m4(cur_mat, gpl->parent->obmat);
- copy_v3_v3(gpl_loc, obact->obmat[3]);
+ invert_m4_m4(cur_mat, gpl->parent->object_to_world);
+ copy_v3_v3(gpl_loc, obact->object_to_world[3]);
}
else if (gpl->partype == PARBONE) {
bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr);
if (pchan) {
float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat);
+ mul_m4_m4m4(tmp_mat, gpl->parent->object_to_world, pchan->pose_mat);
invert_m4_m4(cur_mat, tmp_mat);
- copy_v3_v3(gpl_loc, obact->obmat[3]);
+ copy_v3_v3(gpl_loc, obact->object_to_world[3]);
}
}
@@ -1656,11 +1662,11 @@ static bool gpencil_check_cursor_region(bContext *C, const int mval_i[2])
ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- if ((ob == NULL) || (!ELEM(ob->mode,
- OB_MODE_PAINT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL,
- OB_MODE_VERTEX_GPENCIL))) {
+ if ((ob == NULL) || !ELEM(ob->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL)) {
return false;
}
@@ -1749,7 +1755,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
const int mval_i[2] = {x, y};
/* Check if cursor is in drawing region and has valid data-block. */
- if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
+ if (!gpencil_check_cursor_region(C, mval_i) || (gpd == NULL)) {
return;
}
@@ -1787,7 +1793,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
* is too disruptive and the size of cursor does not change with zoom factor.
* The decision was to use a fix size, instead of brush->thickness value.
*/
- if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ if ((gp_style) && GPENCIL_PAINT_MODE(gpd) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
(brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
@@ -1872,7 +1878,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
/* Inner Ring: Color from UI panel */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
- if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) &&
+ if ((gp_style) && GPENCIL_PAINT_MODE(gpd) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
(brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
@@ -2745,7 +2751,7 @@ void ED_gpencil_init_random_settings(Brush *brush,
const int mval[2],
GpRandomSettings *random_settings)
{
- int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+ int seed = ((uint)ceil(PIL_check_seconds_timer()) + 1) % 128;
/* Use mouse position to get randomness. */
int ix = mval[0] * seed;
int iy = mval[1] * seed;
@@ -2791,7 +2797,7 @@ static void gpencil_sbuffer_vertex_color_random(
{
BrushGpencilSettings *brush_settings = brush->gpencil_settings;
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
- int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+ int seed = ((uint)ceil(PIL_check_seconds_timer()) + 1) % 128;
int ix = (int)(tpt->m_xy[0] * seed);
int iy = (int)(tpt->m_xy[1] * seed);
@@ -2941,7 +2947,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
for (int i = 0; i < 8; i++) {
bGPDspoint pt_dummy, pt_dummy_ps;
copy_v3_v3(&pt_dummy.x, bb.vec[i]);
- gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(&pt_dummy, diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &bounds[i][0], &bounds[i][1]);
}
@@ -3005,7 +3011,7 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
int i;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
bGPDspoint pt2;
- gpencil_point_to_parent_space(pt, diff_mat, &pt2);
+ gpencil_point_to_world_space(pt, diff_mat, &pt2);
gpencil_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]);
}
@@ -3014,7 +3020,7 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
BLI_lasso_boundbox(&rect, mcoords, len);
/* Test if point inside stroke. */
- hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
+ hit = (!ELEM(V2D_IS_CLIPPED, mval[0], mval[1]) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX));
/* Free memory. */
@@ -3031,9 +3037,9 @@ void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
{
bGPDspoint pt_dummy_ps;
- gpencil_point_to_parent_space(&gps->points[0], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(&gps->points[0], diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl1[0], &r_ctrl1[1]);
- gpencil_point_to_parent_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_world_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps);
gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl2[0], &r_ctrl2[1]);
}
@@ -3061,11 +3067,11 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
float pt2d_start[2], pt2d_end[2];
bGPDspoint *pt = &gps->points[0];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_start[0], &pt2d_start[1]);
pt = &gps->points[gps->totpoints - 1];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_end[0], &pt2d_end[1]);
/* Loop all strokes of the active frame. */
@@ -3082,8 +3088,8 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
}
/* Check if one of the ends is inside target stroke bounding box. */
- 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))) {
+ 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.
@@ -3091,11 +3097,11 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
float pt2d_target_start[2], pt2d_target_end[2];
pt = &gps_target->points[0];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_start[0], &pt2d_target_start[1]);
pt = &gps_target->points[gps_target->totpoints - 1];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
/* If the distance to the original stroke extremes is too big, the stroke must not be joined.
@@ -3119,7 +3125,7 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
for (i = 0, pt = gps_target->points; i < gps_target->totpoints; i++, pt++) {
/* Convert point to 2D. */
float pt2d[2];
- gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
+ gpencil_point_to_world_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d[0], &pt2d[1]);
/* Check with Start point. */
diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c
index 51cb08cf592..0144ffa07c7 100644
--- a/source/blender/editors/gpencil/gpencil_uv.c
+++ b/source/blender/editors/gpencil/gpencil_uv.c
@@ -138,7 +138,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op)
opdata->array_loc = NULL;
opdata->array_rot = NULL;
opdata->array_scale = NULL;
- opdata->ob_scale = mat4_to_scale(opdata->ob->obmat);
+ opdata->ob_scale = mat4_to_scale(opdata->ob->object_to_world);
opdata->vinit_rotation[0] = 1.0f;
opdata->vinit_rotation[1] = 0.0f;
@@ -158,7 +158,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op)
float r_center[3];
gpencil_stroke_center(gps, r_center);
/* Add object location. */
- add_v3_v3(r_center, opdata->ob->obmat[3]);
+ add_v3_v3(r_center, opdata->ob->object_to_world[3]);
add_v3_v3(center, r_center);
i++;
}
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 865c4e360b5..41f939813e4 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -131,7 +131,7 @@ static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator
/*
* The algorithm is by Werner D. Streidt
* (http://visca.com/ffactory/archives/5-99/msg00021.html)
- * Extracted of OpenCV demhist.c
+ * Extracted of OpenCV `demhist.c`.
*/
if (contrast > 0) {
gain = 1.0f - delta * 2.0f;
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index c221d8e25e4..ca0729ecb94 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -846,12 +846,12 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
- gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
round_v2i_v2fl(mval_i, gso->mval);
@@ -884,15 +884,15 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
}
bGPDspoint npt;
- gpencil_point_to_parent_space(pt1, diff_mat, &npt);
+ gpencil_point_to_world_space(pt1, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
- gpencil_point_to_parent_space(pt2, diff_mat, &npt);
+ gpencil_point_to_world_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
/* Check that point segment of the bound-box of the selection stroke. */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1]) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* brush region (either within stroke painted, or on its lines)
* - this assumes that line-width is irrelevant.
@@ -957,7 +957,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
}
/* If nothing hit, check if the mouse is inside any filled stroke. */
- if ((!hit) && (ELEM(tool, GPAINT_TOOL_TINT, GPVERTEX_TOOL_DRAW))) {
+ if ((!hit) && ELEM(tool, GPAINT_TOOL_TINT, GPVERTEX_TOOL_DRAW)) {
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(gso->object,
gps_active->mat_nr + 1);
if (gp_style->flag & GP_MATERIAL_FILL_SHOW) {
@@ -1113,7 +1113,7 @@ static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVert
/* Find visible strokes, and perform operations on those if hit */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* If locked or no active frame, don't do anything. */
- if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 22fbf0021fc..f73c6f8c658 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -235,7 +235,7 @@ static bool brush_draw_apply(tGP_BrushWeightpaintData *gso,
if (gso->vrgroup == -1) {
if (gso->object) {
Object *ob_armature = BKE_modifiers_is_deformed_by_armature(gso->object);
- if ((ob_armature != NULL)) {
+ if (ob_armature != NULL) {
Bone *actbone = ((bArmature *)ob_armature->data)->act_bone;
if (actbone != NULL) {
bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name);
@@ -413,12 +413,12 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
- gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* Do bound-box check first. */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ if (!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
int mval_i[2];
round_v2i_v2fl(mval_i, gso->mval);
@@ -440,15 +440,15 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
pt2 = gps->points + i + 1;
bGPDspoint npt;
- gpencil_point_to_parent_space(pt1, diff_mat, &npt);
+ gpencil_point_to_world_space(pt1, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
- gpencil_point_to_parent_space(pt2, diff_mat, &npt);
+ gpencil_point_to_world_space(pt2, diff_mat, &npt);
gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
/* Check that point segment of the bound-box of the selection stroke */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1]) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ (!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1]) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
/* Check if point segment of stroke had anything to do with
* brush region (either within stroke painted, or on its lines)
* - this assumes that line-width is irrelevant.
@@ -579,7 +579,7 @@ static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeig
/* Find visible strokes, and perform operations on those if hit */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* If locked or no active frame, don't do anything. */
- if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
continue;
}