diff options
Diffstat (limited to 'source/blender/editors/gpencil')
26 files changed, 765 insertions, 207 deletions
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 09a3cac0d48..866df16f3d6 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -12,8 +12,8 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager - ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../bmesh # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index f720f261ad5..ae09aea28d3 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -841,7 +841,8 @@ void ED_annotation_draw_2dimage(const bContext *C) } /* draw it! */ - annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype); + annotation_draw_data_all( + scene, gpd, offsx, offsy, sizex, sizey, scene->r.cfra, dflag, area->spacetype); } void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d) @@ -877,7 +878,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d) } annotation_draw_data_all( - scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype); + scene, gpd, 0, 0, region->winx, region->winy, scene->r.cfra, dflag, area->spacetype); } void ED_annotation_draw_view3d( @@ -928,7 +929,8 @@ void ED_annotation_draw_view3d( } /* draw it! */ - annotation_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); + annotation_draw_data_all( + scene, gpd, offsx, offsy, winx, winy, scene->r.cfra, dflag, v3d->spacetype); } void ED_annotation_draw_ex( diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 8c393cc4f3f..287dce1a509 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -1568,7 +1568,7 @@ static void annotation_paint_initstroke(tGPsdata *p, add_frame_mode = GP_GETFRAME_ADD_NEW; } - p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode); + p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode); if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; @@ -1715,7 +1715,7 @@ static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_pt if (p->paintmode == GP_PAINTMODE_ERASER) { GPUVertFormat *format = immVertexFormat(); const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); @@ -1725,7 +1725,7 @@ static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_pt immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -1782,7 +1782,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); GPU_line_width(1.25f); @@ -2062,11 +2062,18 @@ static void annotation_draw_apply_event( PointerRNA itemptr; float mousef[2]; - /* convert from window-space to area-space mouse coordinates - * add any x,y override position for fake events - */ - p->mval[0] = (float)event->mval[0] - x; - p->mval[1] = (float)event->mval[1] - y; + /* Convert from window-space to area-space mouse coordinates + * add any x,y override position for fake events. */ + if (p->flags & GP_PAINTFLAG_FIRSTRUN) { + /* The first run may be a drag event, see: T99368. */ + WM_event_drag_start_mval_fl(event, p->region, p->mval); + p->mval[0] -= x; + p->mval[1] -= y; + } + else { + p->mval[0] = (float)event->mval[0] - x; + p->mval[1] = (float)event->mval[1] - y; + } /* Key to toggle stabilization. */ if ((event->modifier & KM_SHIFT) && (p->paintmode == GP_PAINTMODE_DRAW)) { @@ -2634,7 +2641,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve /* handle mode-specific events */ if (p->status == GP_STATUS_PAINTING) { /* handle painting mouse-movements? */ - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { + if (ISMOUSE_MOTION(event->type) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { annotation_add_missing_events(C, op, event, p); diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 949043e4be1..8a98dcb57fc 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -214,6 +214,18 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked, } } +void ED_gpencil_set_active_channel(bGPdata *gpd, bGPDlayer *gpl) +{ + gpl->flag |= GP_LAYER_SELECT; + + /* Update other layer status. */ + if (BKE_gpencil_layer_active_get(gpd) != gpl) { + BKE_gpencil_layer_active_set(gpd, gpl); + BKE_gpencil_layer_autolock_set(gpd, false); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } +} + /* ***************************************** */ /* Frame Editing Tools */ @@ -316,8 +328,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - /* assume that each of these is a GP layer */ for (ale = anim_data.first; ale; ale = ale->next) { + /* This function only deals with grease pencil layer frames. + * This check is needed in the case of a call from the main dopesheet. */ + if (ale->type != ANIMTYPE_GPLAYER) { + continue; + } + ListBase copied_frames = {NULL, NULL}; bGPDlayer *gpl = (bGPDlayer *)ale->data; @@ -354,19 +371,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) } /* in case 'relative' paste method is used */ - gpencil_anim_copy_cfra = CFRA; + gpencil_anim_copy_cfra = scene->r.cfra; /* clean up */ ANIM_animdata_freelist(&anim_data); - /* check if anything ended up in the buffer */ - if (ELEM(NULL, gpencil_anim_copybuf.first, gpencil_anim_copybuf.last)) { - BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); - return false; - } - /* report success */ - return true; + return !BLI_listbase_is_empty(&gpencil_anim_copybuf); } bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) @@ -381,7 +392,6 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* check if buffer is empty */ if (BLI_listbase_is_empty(&gpencil_anim_copybuf)) { - BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste"); return false; } @@ -393,13 +403,13 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* methods of offset (eKeyPasteOffset) */ switch (offset_mode) { case KEYFRAME_PASTE_OFFSET_CFRA_START: - offset = (CFRA - gpencil_anim_copy_firstframe); + offset = (scene->r.cfra - gpencil_anim_copy_firstframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_END: - offset = (CFRA - gpencil_anim_copy_lastframe); + offset = (scene->r.cfra - gpencil_anim_copy_lastframe); break; case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: - offset = (CFRA - gpencil_anim_copy_cfra); + offset = (scene->r.cfra - gpencil_anim_copy_cfra); break; case KEYFRAME_PASTE_OFFSET_NONE: offset = 0; @@ -414,6 +424,11 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* from selected channels */ for (ale = anim_data.first; ale; ale = ale->next) { + /* only deal with GPlayers (case of calls from general dopesheet) */ + if (ale->type != ANIMTYPE_GPLAYER) { + continue; + } + bGPDlayer *gpld = (bGPDlayer *)ale->data; bGPDlayer *gpls = NULL; bGPDframe *gpfs, *gpf; @@ -503,7 +518,7 @@ static bool gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene) static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene) { if (gpf->flag & GP_FRAME_SELECT) { - gpf->framenum = (int)CFRA; + gpf->framenum = (int)scene->r.cfra; } return false; } @@ -545,8 +560,8 @@ static bool gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene) int diff; if (gpf->flag & GP_FRAME_SELECT) { - diff = CFRA - gpf->framenum; - gpf->framenum = CFRA + diff; + diff = scene->r.cfra - gpf->framenum; + gpf->framenum = scene->r.cfra + diff; } return false; diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c index 2f22fad53e7..b88b33913ac 100644 --- a/source/blender/editors/gpencil/gpencil_add_blank.c +++ b/source/blender/editors/gpencil/gpencil_add_blank.c @@ -19,6 +19,8 @@ #include "BKE_main.h" #include "BKE_material.h" +#include "BLT_translation.h" + #include "DEG_depsgraph.h" #include "ED_gpencil.h" @@ -34,7 +36,7 @@ typedef struct ColorTemplate { static int gpencil_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct) { int index; - Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index); + Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); @@ -52,7 +54,7 @@ static int gpencil_stroke_material(Main *bmain, Object *ob, const ColorTemplate /* Color Data */ static const ColorTemplate gp_stroke_material_black = { - "Black", + N_("Black"), {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; @@ -76,7 +78,7 @@ void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4])) bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false); /* frames */ - BKE_gpencil_frame_addnew(layer, CFRA); + BKE_gpencil_frame_addnew(layer, scene->r.cfra); /* update depsgraph */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c index 964a57a8ced..2ac26c927f4 100644 --- a/source/blender/editors/gpencil/gpencil_add_lineart.c +++ b/source/blender/editors/gpencil/gpencil_add_lineart.c @@ -21,6 +21,8 @@ #include "BKE_main.h" #include "BKE_material.h" +#include "BLT_translation.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -40,7 +42,7 @@ static int gpencil_lineart_material(Main *bmain, const bool fill) { int index; - Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index); + Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); @@ -59,7 +61,7 @@ static int gpencil_lineart_material(Main *bmain, /* Color Data */ static const ColorTemplate gp_stroke_material_black = { - "Black", + N_("Black"), {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 65ee732f6a9..00066d5f2b8 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -19,6 +19,8 @@ #include "BKE_main.h" #include "BKE_material.h" +#include "BLT_translation.h" + #include "DEG_depsgraph.h" #include "ED_gpencil.h" @@ -54,7 +56,7 @@ static int gpencil_monkey_color( Main *bmain, Object *ob, const ColorTemplate *pct, bool stroke, bool fill) { int index; - Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index); + Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); @@ -781,37 +783,37 @@ static const float data27[33 * GP_PRIM_DATABUF_SIZE] = { /* Monkey Color Data */ static const ColorTemplate gp_monkey_pct_black = { - "Black", + N_("Black"), {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_monkey_pct_skin = { - "Skin", + N_("Skin"), {0.733f, 0.569f, 0.361f, 1.0f}, {0.745f, 0.502f, 0.278f, 1.0f}, }; static const ColorTemplate gp_monkey_pct_skin_light = { - "Skin_Light", + N_("Skin_Light"), {0.914f, 0.827f, 0.635f, 1.0f}, {0.913f, 0.828f, 0.637f, 0.0f}, }; static const ColorTemplate gp_monkey_pct_skin_shadow = { - "Skin_Shadow", + N_("Skin_Shadow"), {0.322f, 0.29f, 0.224f, 0.5f}, {0.32f, 0.29f, 0.223f, 0.3f}, }; static const ColorTemplate gp_monkey_pct_eyes = { - "Eyes", + N_("Eyes"), {0.553f, 0.39f, 0.266f, 0.0f}, {0.847f, 0.723f, 0.599f, 1.0f}, }; static const ColorTemplate gp_monkey_pct_pupils = { - "Pupils", + N_("Pupils"), {0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}, }; @@ -821,6 +823,8 @@ static const ColorTemplate gp_monkey_pct_pupils = { void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) { + /* Original model created by Matias Mendiola. */ + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -844,8 +848,8 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) /* frames */ /* NOTE: No need to check for existing, as this will take care of it for us */ - bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, CFRA); - bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, CFRA); + bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, scene->r.cfra); + bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, scene->r.cfra); /* generate strokes */ gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false); diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index bc5fe9b5cfb..8522c81cb39 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -19,6 +19,8 @@ #include "BKE_main.h" #include "BKE_material.h" +#include "BLT_translation.h" + #include "DEG_depsgraph.h" #include "ED_gpencil.h" @@ -37,7 +39,7 @@ static int gpencil_stroke_material(Main *bmain, const bool fill) { int index; - Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, pct->name, &index); + Material *ma = BKE_gpencil_object_material_ensure_by_name(bmain, ob, DATA_(pct->name), &index); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); @@ -150,37 +152,37 @@ static const float data0[175 * GP_PRIM_DATABUF_SIZE] = { /* Color Data */ static const ColorTemplate gp_stroke_material_black = { - "Black", + N_("Black"), {0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_stroke_material_white = { - "White", + N_("White"), {1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_stroke_material_red = { - "Red", + N_("Red"), {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_stroke_material_green = { - "Green", + N_("Green"), {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_stroke_material_blue = { - "Blue", + N_("Blue"), {0.0f, 0.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}, }; static const ColorTemplate gp_stroke_material_grey = { - "Grey", + N_("Grey"), {0.358f, 0.358f, 0.358f, 1.0f}, {0.5f, 0.5f, 0.5f, 1.0f}, }; @@ -190,6 +192,8 @@ static const ColorTemplate gp_stroke_material_grey = { void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) { + /* Original design created by Daniel M. Lara and Matias Mendiola. */ + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); bGPdata *gpd = (bGPdata *)ob->data; @@ -211,8 +215,8 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false); /* frames */ - bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, CFRA); - bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, CFRA); + bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, scene->r.cfra); + bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, scene->r.cfra); UNUSED_VARS(frame_color); /* generate stroke */ diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index d389f7eb5dd..5f5a4b41b27 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" @@ -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 66f53bea326..e480852a9bb 100644 --- a/source/blender/editors/gpencil/gpencil_bake_animation.cc +++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc @@ -265,7 +265,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op } /* Move scene to new frame. */ - CFRA = i; + scene->r.cfra = i; BKE_scene_graph_update_for_newframe(depsgraph); /* Loop all objects in the list. */ @@ -285,7 +285,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op /* Apply time modifier. */ int remap_cfra = BKE_gpencil_time_modifier_cfra( - depsgraph, scene, elem->ob, gpl_src, CFRA, false); + depsgraph, scene, elem->ob, gpl_src, scene->r.cfra, false); /* Duplicate frame. */ bGPDframe *gpf_src = BKE_gpencil_layer_frame_get( gpl_src, remap_cfra, GP_GETFRAME_USE_PREV); @@ -293,7 +293,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op continue; } bGPDframe *gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, true); - gpf_dst->framenum = CFRA + frame_offset; + gpf_dst->framenum = scene->r.cfra + frame_offset; gpf_dst->flag &= ~GP_FRAME_SELECT; BLI_addtail(&gpl_dst->frames, gpf_dst); @@ -337,7 +337,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op } } /* Return scene frame state and DB to original state. */ - CFRA = oldframe; + scene->r.cfra = oldframe; BKE_scene_graph_update_for_newframe(depsgraph); /* Free memory. */ diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 0601d009bf7..bf78111a636 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -588,7 +588,7 @@ static void gpencil_stroke_path_animation(bContext *C, } /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ - calchandles_fcurve(fcu); + BKE_fcurve_handles_recalc(fcu); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); @@ -1271,7 +1271,7 @@ static void gpencil_layer_to_curve(bContext *C, Collection *collection = CTX_data_collection(C); Scene *scene = CTX_data_scene(C); - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); bGPDstroke *prev_gps = NULL; Object *ob; Curve *cu; @@ -1303,6 +1303,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 */ @@ -1414,7 +1415,7 @@ static bool gpencil_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, int i; bool valid = true; - if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) || + if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) || !(gps = gpf->strokes.first)) { return false; } @@ -1481,7 +1482,7 @@ static bool gpencil_convert_poll(bContext *C) * and if we are not in edit mode! */ return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) && - (gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) && + (gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) && (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd))); } @@ -1811,7 +1812,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Add layer and frame. */ bGPdata *gpd = (bGPdata *)ob->data; bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true, false); - bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA); + bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, scene->r.cfra); done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask); if (done) { diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 6843c42d2d0..340288b2d74 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -226,7 +226,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op) bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false); /* Add a new frame to make it visible in Dopesheet. */ if (gpl != NULL) { - gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW); } } } @@ -646,12 +646,12 @@ static int gpencil_frame_duplicate_exec(bContext *C, wmOperator *op) } if (mode == 0) { - BKE_gpencil_frame_addcopy(gpl_active, CFRA); + BKE_gpencil_frame_addcopy(gpl_active, scene->r.cfra); } else { LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if ((gpl->flag & GP_LAYER_LOCKED) == 0) { - BKE_gpencil_frame_addcopy(gpl, CFRA); + BKE_gpencil_frame_addcopy(gpl, scene->r.cfra); } } } @@ -2076,6 +2076,9 @@ static void gpencil_brush_delete_mode_brushes(Main *bmain, } BKE_brush_delete(bmain, brush); + if (brush == brush_active) { + brush_active = NULL; + } } } @@ -2109,8 +2112,8 @@ static int gpencil_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) char tool = '0'; if (paint) { - Brush *brush_active = paint->brush; - if (brush_active) { + if (paint->brush) { + Brush *brush_active = paint->brush; switch (mode) { case CTX_MODE_PAINT_GPENCIL: { tool = brush_active->gpencil_tool; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 5028baf1589..ecb281f9c44 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -67,6 +67,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -1713,12 +1714,17 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op) } } - /* Ensure we have a frame to draw into + /* Ensure we have a frame to draw into. * NOTE: Since this is an op which creates strokes, - * we are obliged to add a new frame if one - * doesn't exist already + * we reuse active frame or add a new frame if one + * doesn't exist already depending on REC button status. */ - gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); + if (IS_AUTOKEY_ON(scene) || (gpl->actframe == NULL)) { + gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW); + } + else { + gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); + } if (gpf) { /* Create new stroke */ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true); @@ -1971,7 +1977,7 @@ static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); - int cfra = CFRA; + int cfra = scene->r.cfra; bGPDlayer *active_gpl = BKE_gpencil_layer_active_get(gpd); @@ -2075,7 +2081,7 @@ static int gpencil_actframe_delete_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); /* if there's no existing Grease-Pencil data there, add some */ if (gpd == NULL) { @@ -2150,7 +2156,7 @@ static int gpencil_actframe_delete_all_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { /* try to get the "active" frame - but only if it actually occurs on this frame */ - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; @@ -3395,6 +3401,7 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); const int type = RNA_enum_get(op->ptr, "type"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); /* sanity checks */ if (ELEM(NULL, gpd)) { @@ -3404,46 +3411,57 @@ static int gpencil_stroke_caps_set_exec(bContext *C, wmOperator *op) bool changed = false; /* loop all selected strokes */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - if (gpl->actframe == NULL) { - continue; - } + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } - /* skip strokes that are not selected or invalid for current view */ - if (((gps->flag & GP_STROKE_SELECT) == 0) || (ED_gpencil_stroke_can_use(C, gps) == false)) { - continue; - } - /* skip hidden or locked colors */ - if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) || - (gp_style->flag & GP_MATERIAL_LOCKED)) { - continue; - } + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - short prev_first = gps->caps[0]; - short prev_last = gps->caps[1]; + /* skip strokes that are not selected or invalid for current view */ + if (((gps->flag & GP_STROKE_SELECT) == 0) || + (ED_gpencil_stroke_can_use(C, gps) == false)) { + continue; + } + /* skip hidden or locked colors */ + if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) || + (gp_style->flag & GP_MATERIAL_LOCKED)) { + continue; + } + + short prev_first = gps->caps[0]; + short prev_last = gps->caps[1]; - if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_START)) { - ++gps->caps[0]; - if (gps->caps[0] >= GP_STROKE_CAP_MAX) { - gps->caps[0] = GP_STROKE_CAP_ROUND; + if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_START)) { + ++gps->caps[0]; + if (gps->caps[0] >= GP_STROKE_CAP_MAX) { + gps->caps[0] = GP_STROKE_CAP_ROUND; + } + } + if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_END)) { + ++gps->caps[1]; + if (gps->caps[1] >= GP_STROKE_CAP_MAX) { + gps->caps[1] = GP_STROKE_CAP_ROUND; + } + } + if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) { + gps->caps[0] = GP_STROKE_CAP_ROUND; + gps->caps[1] = GP_STROKE_CAP_ROUND; + } + + if (prev_first != gps->caps[0] || prev_last != gps->caps[1]) { + changed = true; + } } - } - if (ELEM(type, GP_STROKE_CAPS_TOGGLE_BOTH, GP_STROKE_CAPS_TOGGLE_END)) { - ++gps->caps[1]; - if (gps->caps[1] >= GP_STROKE_CAP_MAX) { - gps->caps[1] = GP_STROKE_CAP_ROUND; + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; } } - if (type == GP_STROKE_CAPS_TOGGLE_DEFAULT) { - gps->caps[0] = GP_STROKE_CAP_ROUND; - gps->caps[1] = GP_STROKE_CAP_ROUND; - } - - if (prev_first != gps->caps[0] || prev_last != gps->caps[1]) { - changed = true; - } } } CTX_DATA_END; @@ -3550,9 +3568,9 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *activegpl = BKE_gpencil_layer_active_get(gpd); Object *ob = CTX_data_active_object(C); - /* Limit the number of strokes to join. It makes no sense to allow an very high number of strokes - * for CPU time and because to have a stroke with thousands of points is unpractical, so limit - * this number avoid to joining a full frame scene in one single stroke. */ + /* Limit the number of strokes to join. It makes no sense to allow an very high number of + * strokes for CPU time and because to have a stroke with thousands of points is unpractical, + * so limit this number avoid to joining a full frame scene in one single stroke. */ const int max_join_strokes = 128; const int type = RNA_enum_get(op->ptr, "type"); @@ -3638,7 +3656,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op) } elem = &strokes_list[i]; /* Join new_stroke and stroke B. */ - BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false); + BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false, true); elem->used = true; } @@ -3709,35 +3727,44 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); + bool changed = false; - /* read all selected strokes */ + /* Read all selected strokes. */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - if (gpf == NULL) { - continue; - } + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - if (gps->flag & GP_STROKE_SELECT) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { continue; } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + continue; + } - if (is_curve_edit) { - BKE_report(op->reports, RPT_ERROR, "Not implemented!"); - } - else { - /* Flip stroke. */ - BKE_gpencil_stroke_flip(gps); + if (is_curve_edit) { + BKE_report(op->reports, RPT_ERROR, "Not implemented!"); + } + else { + /* Flip stroke. */ + BKE_gpencil_stroke_flip(gps); + changed = true; + } + } } - - changed = true; + } + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; } } } @@ -3770,6 +3797,101 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Stroke Start Set Operator + * \{ */ + +static int gpencil_stroke_start_set_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ob->data; + + /* sanity checks */ + if (ELEM(NULL, ob, gpd)) { + return OPERATOR_CANCELLED; + } + + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); + if (is_curve_edit) { + BKE_report(op->reports, RPT_ERROR, "Curve Edit mode not supported"); + return OPERATOR_CANCELLED; + } + + bool changed = false; + /* Read all selected strokes. */ + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { + continue; + } + + /* Only cyclic strokes. */ + if ((gps->flag & GP_STROKE_CYCLIC) == 0) { + continue; + } + + /* Find first selected point and set start. */ + bGPDspoint *pt; + 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); + BKE_gpencil_stroke_geometry_update(gpd, gps); + changed = true; + break; + } + } + } + } + } + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; + } + } + } + CTX_DATA_END; + + if (changed) { + /* notifiers */ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_start_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Start Point"; + ot->idname = "GPENCIL_OT_stroke_start_set"; + ot->description = "Set start point for cyclic strokes"; + + /* api callbacks */ + ot->exec = gpencil_stroke_start_set_exec; + ot->poll = gpencil_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Stroke Re-project Operator * \{ */ @@ -3818,7 +3940,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) /* update frame to get the new location of objects */ if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf->framenum)) { cfra_prv = gpf->framenum; - CFRA = gpf->framenum; + scene->r.cfra = gpf->framenum; BKE_scene_graph_update_for_newframe(depsgraph); } @@ -3846,7 +3968,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* return frame state and DB to original state */ - CFRA = oldframe; + scene->r.cfra = oldframe; BKE_scene_graph_update_for_newframe(depsgraph); if (sctx != NULL) { @@ -3864,6 +3986,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) 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"}, @@ -3909,12 +4032,13 @@ 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); } static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3939,6 +4063,284 @@ static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +/* -------------------------------------------------------------------- */ +/** \name Stroke Perimeter from View Operator + * \{ */ + +enum { + GP_PERIMETER_VIEW = 0, + GP_PERIMETER_FRONT = 1, + GP_PERIMETER_SIDE = 2, + GP_PERIMETER_TOP = 3, + GP_PERIMETER_CAMERA = 4, +}; + +enum { + GP_STROKE_USE_ACTIVE_MATERIAL = 0, + GP_STROKE_USE_CURRENT_MATERIAL = 1, + GP_STROKE_USE_NEW_MATERIAL = 2, +}; + +static int gpencil_stroke_outline_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = (bGPdata *)ob->data; + const int subdivisions = RNA_int_get(op->ptr, "subdivisions"); + const float length = RNA_float_get(op->ptr, "length"); + const bool keep = RNA_boolean_get(op->ptr, "keep"); + const int thickness = RNA_int_get(op->ptr, "thickness"); + + const int view_mode = RNA_enum_get(op->ptr, "view_mode"); + const int material_mode = RNA_enum_get(op->ptr, "material_mode"); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + + /* sanity checks */ + if (ELEM(NULL, gpd)) { + return OPERATOR_CANCELLED; + } + + bool changed = false; + + float viewmat[4][4]; + copy_m4_m4(viewmat, rv3d->viewmat); + + switch (view_mode) { + case GP_PERIMETER_FRONT: + unit_m4(rv3d->viewmat); + viewmat[1][1] = 0.0f; + viewmat[1][2] = -1.0f; + + viewmat[2][1] = 1.0f; + viewmat[2][2] = 0.0f; + + viewmat[3][2] = -10.0f; + break; + case GP_PERIMETER_SIDE: + zero_m4(viewmat); + viewmat[0][2] = 1.0f; + viewmat[1][0] = 1.0f; + viewmat[2][1] = 1.0f; + viewmat[3][3] = 1.0f; + break; + case GP_PERIMETER_TOP: + unit_m4(viewmat); + break; + case GP_PERIMETER_CAMERA: { + Scene *scene = CTX_data_scene(C); + Object *cam_ob = scene->camera; + if (cam_ob != NULL) { + invert_m4_m4(viewmat, cam_ob->obmat); + } + break; + } + default: + break; + } + + /* Untag strokes to be sure nothing is pending. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->flag &= ~GP_STROKE_TAG; + } + } + } + /* Create a new material. */ + int mat_idx = 0; + if (material_mode == GP_STROKE_USE_NEW_MATERIAL) { + Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Material", NULL); + MaterialGPencilStyle *gp_style = ma->gp_style; + + gp_style->flag |= GP_MATERIAL_FILL_SHOW; + mat_idx = ob->totcol - 1; + } + + /* loop all selected strokes */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + /* Prepare transform matrix. */ + float diff_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat); + + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) { + continue; + } + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if ((gps->flag & GP_STROKE_SELECT) == 0) { + continue; + } + if (gps->totpoints == 0) { + continue; + } + if (!ED_gpencil_stroke_material_visible(ob, gps)) { + continue; + } + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); + + if (!is_stroke) { + continue; + } + + /* Duplicate the stroke to apply any layer thickness change. */ + bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false); + + /* Apply layer thickness change. */ + gps_duplicate->thickness += gpl->line_change; + /* Apply object scale to thickness. */ + gps_duplicate->thickness *= mat4_to_scale(ob->obmat); + CLAMP_MIN(gps_duplicate->thickness, 1.0f); + + /* Stroke. */ + const float ovr_thickness = keep ? thickness : 0.0f; + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + viewmat, gpd, gpl, gps_duplicate, subdivisions, diff_mat, ovr_thickness); + gps_perimeter->flag &= ~GP_STROKE_SELECT; + /* Assign material. */ + switch (material_mode) { + case GP_STROKE_USE_ACTIVE_MATERIAL: { + if (ob->actcol - 1 < 0) { + gps_perimeter->mat_nr = 0; + } + else { + gps_perimeter->mat_nr = ob->actcol - 1; + } + break; + } + case GP_STROKE_USE_CURRENT_MATERIAL: + gps_perimeter->mat_nr = gps->mat_nr; + break; + case GP_STROKE_USE_NEW_MATERIAL: + gps_perimeter->mat_nr = mat_idx; + break; + default: + break; + } + + /* Sample stroke. */ + if (length > 0.0f) { + BKE_gpencil_stroke_sample(gpd, gps_perimeter, length, false, 0); + } + /* Set stroke thickness. */ + gps_perimeter->thickness = thickness; + + /* Set pressure constant. */ + bGPDspoint *pt; + for (int i = 0; i < gps_perimeter->totpoints; i++) { + pt = &gps_perimeter->points[i]; + pt->pressure = 1.0f; + } + + /* Add perimeter stroke to frame. */ + BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter); + + /* Tag original stroke to be removed. */ + gps->flag |= GP_STROKE_TAG; + + /* Free Temp stroke. */ + BKE_gpencil_free_stroke(gps_duplicate); + changed = true; + } + + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; + } + } + } + } + /* Free old strokes. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_TAG) { + BLI_remlink(&gpf->strokes, gps); + BKE_gpencil_free_stroke(gps); + } + } + } + } + + if (changed) { + /* notifiers */ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_outline(wmOperatorType *ot) +{ + static const EnumPropertyItem view_mode[] = { + {GP_PERIMETER_VIEW, "VIEW", 0, "View", ""}, + {GP_PERIMETER_FRONT, "FRONT", 0, "Front", ""}, + {GP_PERIMETER_SIDE, "SIDE", 0, "Side", ""}, + {GP_PERIMETER_TOP, "TOP", 0, "Top", ""}, + {GP_PERIMETER_CAMERA, "CAMERA", 0, "Camera", ""}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem material_mode[] = { + {GP_STROKE_USE_ACTIVE_MATERIAL, "ACTIVE", 0, "Active Material", ""}, + {GP_STROKE_USE_CURRENT_MATERIAL, "KEEP", 0, "Keep Material", "Keep current stroke material"}, + {GP_STROKE_USE_NEW_MATERIAL, "NEW", 0, "New Material", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Convert Stroke to Outline"; + ot->idname = "GPENCIL_OT_stroke_outline"; + ot->description = "Convert stroke to perimeter"; + + /* api callbacks */ + ot->exec = gpencil_stroke_outline_exec; + ot->poll = gpencil_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "view_mode", view_mode, GP_PERIMETER_VIEW, "View", ""); + RNA_def_enum(ot->srna, + "material_mode", + material_mode, + GP_STROKE_USE_ACTIVE_MATERIAL, + "Material Mode", + ""); + + RNA_def_int(ot->srna, + "thickness", + 1, + 1, + 1000, + "Thickness", + "Thickness of the stroke perimeter", + 1, + 1000); + RNA_def_boolean(ot->srna, + "keep", + true, + "Keep Shape", + "Try to keep global shape when the stroke thickness change"); + + RNA_def_int(ot->srna, "subdivisions", 3, 0, 10, "Subdivisions", "", 0, 10); + + RNA_def_float(ot->srna, "length", 0.0f, 0.0f, 100.0f, "Sample Length", "", 0.0f, 100.0f); +} + +/** \} */ + void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) { /* identifiers */ @@ -3980,6 +4382,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) /* TODO use `BKE_gpencil_stroke_smooth` when the weights are better used. */ bGPDstroke gps_old = *gps; gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points); + bool need_update = false; /* Here the iteration needs to be done outside the smooth functions, * as there are points that don't get smoothed. */ for (int n = 0; n < repeat; n++) { @@ -3991,6 +4394,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) /* Perform smoothing. */ if (smooth_position) { BKE_gpencil_stroke_smooth_point(&gps_old, i, factor, 1, false, false, gps); + need_update = true; } if (smooth_strength) { BKE_gpencil_stroke_smooth_strength(&gps_old, i, factor, 1, gps); @@ -4000,6 +4404,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } if (smooth_uv) { BKE_gpencil_stroke_smooth_uv(&gps_old, i, factor, 1, gps); + need_update = true; } } if (n < repeat - 1) { @@ -4007,6 +4412,11 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } } MEM_freeN(gps_old.points); + + if (need_update) { + gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; + BKE_gpencil_stroke_geometry_update(gpd_, gps); + } } } GP_EDITABLE_STROKES_END(gpstroke_iter); @@ -4454,6 +4864,8 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) /* properties */ prop = RNA_def_float(ot->srna, "length", 0.1f, 0.0f, 100.0f, "Length", "", 0.0f, 100.0f); + prop = RNA_def_float( + ot->srna, "sharp_threshold", 0.1f, 0.0f, M_PI, "Sharp Threshold", "", 0.0f, M_PI); /* avoid re-using last var */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 3f06dbfdbb3..5305c764b3a 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1748,7 +1748,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op) tgpf->v3d = tgpf->area->spacedata.first; tgpf->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); tgpf->win = CTX_wm_window(C); - tgpf->active_cfra = CFRA; + tgpf->active_cfra = scene->r.cfra; tgpf->reports = op->reports; /* Setup space conversions. */ @@ -2222,8 +2222,8 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Hash of selected frames. */ GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); - /* If not multi-frame and there is no frame in CFRA for the active layer, create - * a new frame. */ + /* If not multi-frame and there is no frame in scene->r.cfra for the active layer, + * create a new frame. */ if (!is_multiedit) { tgpf->gpf = BKE_gpencil_layer_frame_get( tgpf->gpl, diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index d656241c463..4d62f834d86 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -593,6 +593,7 @@ void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot); */ void GPENCIL_OT_stroke_caps_set(struct wmOperatorType *ot); void GPENCIL_OT_stroke_join(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_start_set(struct wmOperatorType *ot); void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot); void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot); void GPENCIL_OT_stroke_simplify(struct wmOperatorType *ot); @@ -608,6 +609,7 @@ void GPENCIL_OT_stroke_merge_by_distance(struct wmOperatorType *ot); void GPENCIL_OT_stroke_merge_material(struct wmOperatorType *ot); void GPENCIL_OT_stroke_reset_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_stroke_normalize(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_outline(struct wmOperatorType *ot); void GPENCIL_OT_material_to_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_extract_palette_vertex(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 0039dbae674..dc63acf5136 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -483,10 +483,10 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; - bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, CFRA); + bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra); tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true); - gpf = gpencil_get_next_keyframe(gpl, CFRA); + gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra); tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true); BLI_addtail(&tgpi->ilayers, tgpil); @@ -750,7 +750,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent tGPDinterpolate *tgpi = NULL; /* Cannot interpolate if not between 2 frames. */ - int cfra = CFRA; + int cfra = scene->r.cfra; bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra); bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra); if (ELEM(NULL, gpf_prv, gpf_next)) { @@ -1221,7 +1221,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) GP_SpaceConversion gsc; gpencil_point_conversion_init(C, &gsc); - int cfra = CFRA; + int cfra = scene->r.cfra; GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; const int step = RNA_int_get(op->ptr, "step"); @@ -1483,7 +1483,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) */ static const EnumPropertyItem gpencil_interpolation_type_items[] = { /* Interpolation. */ - RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Interpolation"), + N_("Standard transitions between keyframes")), {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, @@ -1496,9 +1497,9 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Custom interpolation defined using a curve map"}, /* Easing. */ - RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"), - "Predefined inertial transitions, useful for motion graphics " - "(from least to most \"dramatic\")"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Easing (by strength)"), + N_("Predefined inertial transitions, useful for motion graphics " + "(from least to most \"dramatic\")")), {GP_IPO_SINE, "SINE", ICON_IPO_SINE, @@ -1515,7 +1516,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) "Circular", "Circular easing (strongest and most dynamic)"}, - RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_GPENCIL, "Dynamic Effects"), + N_("Simple physics-inspired easing effects")), {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"}, {GP_IPO_BOUNCE, "BOUNCE", @@ -1569,6 +1571,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) /* identifiers */ ot->name = "Interpolate Sequence"; ot->idname = "GPENCIL_OT_interpolate_sequence"; + ot->translation_context = BLT_I18NCONTEXT_ID_GPENCIL; ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames"; /* api callbacks */ diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 06343dcad43..8ff3f20cef3 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -113,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo else { add_frame_mode = GP_GETFRAME_ADD_NEW; } - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode); /* stroke */ bGPDstroke *gps = BKE_gpencil_stroke_new(MAX2(ob->actcol - 1, 0), totpoints, brush->size); diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc index aee00d4ede3..bb39ad2dfaa 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.cc +++ b/source/blender/editors/gpencil/gpencil_mesh.cc @@ -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!"); @@ -283,7 +283,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) } /* Move scene to new frame. */ - CFRA = i; + scene->r.cfra = i; BKE_scene_graph_update_for_newframe(depsgraph); /* Loop all objects in the list. */ @@ -325,7 +325,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) } /* Return scene frame state and DB to original state. */ - CFRA = oldframe; + scene->r.cfra = oldframe; BKE_scene_graph_update_for_newframe(depsgraph); /* Remove unused materials. */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 99e28270c3e..85cc281ca90 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -621,6 +621,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_stroke_caps_set); WM_operatortype_append(GPENCIL_OT_stroke_join); WM_operatortype_append(GPENCIL_OT_stroke_flip); + WM_operatortype_append(GPENCIL_OT_stroke_start_set); WM_operatortype_append(GPENCIL_OT_stroke_subdivide); WM_operatortype_append(GPENCIL_OT_stroke_simplify); WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed); @@ -635,6 +636,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_stroke_merge_material); WM_operatortype_append(GPENCIL_OT_stroke_reset_vertex_color); WM_operatortype_append(GPENCIL_OT_stroke_normalize); + WM_operatortype_append(GPENCIL_OT_stroke_outline); WM_operatortype_append(GPENCIL_OT_material_to_vertex_color); WM_operatortype_append(GPENCIL_OT_extract_palette_vertex); diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 8119646137c..50fbafff732 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 */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 7c7f532f087..8e33a029229 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -918,6 +918,67 @@ static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps) } } +static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps) +{ + bGPDlayer *gpl = p->gpl; + RegionView3D *rv3d = p->region->regiondata; + Brush *brush = p->brush; + BrushGpencilSettings *gpencil_settings = brush->gpencil_settings; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(p->ob, gps->mat_nr + 1); + const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0); + + if (!is_stroke) { + return gps; + } + + /* Duplicate the stroke to apply any layer thickness change. */ + bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false); + + /* Apply layer thickness change. */ + gps_duplicate->thickness += gpl->line_change; + /* Apply object scale to thickness. */ + gps_duplicate->thickness *= mat4_to_scale(p->ob->obmat); + CLAMP_MIN(gps_duplicate->thickness, 1.0f); + + /* Stroke. */ + float diff_mat[4][4]; + unit_m4(diff_mat); + const float outline_thickness = (float)brush->size * gpencil_settings->outline_fac * 0.5f; + bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view( + rv3d->viewmat, p->gpd, gpl, gps_duplicate, 3, diff_mat, outline_thickness); + /* Assign material. */ + if (gpencil_settings->material_alt == NULL) { + gps_perimeter->mat_nr = gps->mat_nr; + } + else { + Material *ma = gpencil_settings->material_alt; + int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(p->ob, ma->id.name + 2); + if (mat_idx > -1) { + gps_perimeter->mat_nr = mat_idx; + } + else { + gps_perimeter->mat_nr = gps->mat_nr; + } + } + + /* Set pressure constant. */ + gps_perimeter->thickness = max_ii((int)outline_thickness, 1); + + bGPDspoint *pt; + for (int i = 0; i < gps_perimeter->totpoints; i++) { + pt = &gps_perimeter->points[i]; + pt->pressure = 1.0f; + } + + /* Remove original stroke. */ + BKE_gpencil_free_stroke(gps); + + /* Free Temp stroke. */ + BKE_gpencil_free_stroke(gps_duplicate); + + return gps_perimeter; +} + /* make a new stroke from the buffer data */ static void gpencil_stroke_newfrombuffer(tGPsdata *p) { @@ -1221,6 +1282,23 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) BKE_gpencil_stroke_simplify_adaptive(gpd, gps, brush->gpencil_settings->simplify_f); } + /* Set material index. */ + gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush); + if (gps->mat_nr < 0) { + if (p->ob->actcol - 1 < 0) { + gps->mat_nr = 0; + } + else { + gps->mat_nr = p->ob->actcol - 1; + } + } + + /* Convert to Outline. */ + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && + (brush->gpencil_settings->flag & GP_BRUSH_OUTLINE_STROKE)) { + gps = gpencil_stroke_to_outline(p, gps); + } + /* reproject to plane (only in 3d space) */ gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ @@ -1235,17 +1313,6 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) } } - /* Save material index */ - gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush); - if (gps->mat_nr < 0) { - if (p->ob->actcol - 1 < 0) { - gps->mat_nr = 0; - } - else { - gps->mat_nr = p->ob->actcol - 1; - } - } - /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke * is added on listbase head because the drawing order is inverse and the head stroke is the * first to draw. This is very useful for artist when drawing the background. @@ -2166,7 +2233,7 @@ static void gpencil_paint_initstroke(tGPsdata *p, if (gpl->actframe && gpl->actframe->strokes.first) { if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV; - gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, frame_mode); + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, frame_mode); } has_layer_to_erase = true; break; @@ -2204,7 +2271,7 @@ static void gpencil_paint_initstroke(tGPsdata *p, bool need_tag = p->gpl->actframe == NULL; bGPDframe *actframe = p->gpl->actframe; - p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode); + p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode); /* Only if there wasn't an active frame, need update. */ if (need_tag) { DEG_id_tag_update(&p->gpd->id, ID_RECALC_GEOMETRY); @@ -2343,7 +2410,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) if (p->paintmode == GP_PAINTMODE_ERASER) { GPUVertFormat *format = immVertexFormat(); const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); @@ -2353,7 +2420,7 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -3658,9 +3725,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } } - /* Exit painting mode (and/or end current stroke). - * - */ + /* Exit painting mode (and/or end current stroke). */ if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, EVT_ESCKEY, EVT_SPACEKEY)) { p->status = GP_STATUS_DONE; @@ -3755,7 +3820,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* handle mode-specific events */ if (p->status == GP_STATUS_PAINTING) { /* handle painting mouse-movements? */ - if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { + if (ISMOUSE_MOTION(event->type) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ bool is_speed_guide = ((guide->use_guide) && (p->brush && (p->brush->gpencil_tool == GPAINT_TOOL_DRAW))); diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index b57b8145749..4a4fffc9638 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -292,7 +292,7 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) Scene *scene = CTX_data_scene(C); ToolSettings *ts = scene->toolsettings; Brush *brush = tgpi->brush; - int cfra = CFRA; + int cfra = scene->r.cfra; bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); @@ -1024,8 +1024,10 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false); /* add small offset to keep stroke over the surface */ - if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) { - depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f)); + if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) { + if ((depth_arr) && (gpd->zdepth_offset > 0.0f) && (depth_arr[i] != DEPTH_INVALID)) { + depth_arr[i] *= (1.0f - (gpd->zdepth_offset / 1000.0f)); + } } /* convert screen-coordinates to 3D coordinates */ @@ -1107,7 +1109,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive /* Initialize mouse points. */ static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event) { - copy_v2fl_v2i(tgpi->mval, event->mval); + WM_event_drag_start_mval_fl(event, tgpi->region, tgpi->mval); copy_v2_v2(tgpi->origin, tgpi->mval); copy_v2_v2(tgpi->start, tgpi->mval); copy_v2_v2(tgpi->end, tgpi->mval); @@ -1195,7 +1197,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) tgpi->orign_type = RNA_enum_get(op->ptr, "type"); /* set current frame number */ - tgpi->cframe = CFRA; + tgpi->cframe = scene->r.cfra; /* set GP datablock */ tgpi->gpd = gpd; diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 6d0848de36d..e27cd255217 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1013,7 +1013,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso) gpl = CTX_data_active_gpencil_layer(C); } bGPDframe *gpf = BKE_gpencil_layer_frame_get( - gpl, CFRA, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV); + gpl, scene->r.cfra, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; } @@ -1161,6 +1161,7 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->is_painting = false; gso->first = true; + gso->mval_prev[0] = -1.0f; gso->gpd = ED_gpencil_data_get_active(C); gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */ @@ -1335,7 +1336,7 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso bGPdata *gpd = gso->gpd; Scene *scene = gso->scene; - int cfra = CFRA; + int cfra = scene->r.cfra; /* only try to add a new frame if this is the first stroke, or the frame has changed */ if ((gpd == NULL) || (cfra == gso->cfra)) { @@ -1442,6 +1443,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, char tool = gso->brush->gpencil_sculpt_tool; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; + const bool is_masking = GPENCIL_ANY_SCULPT_MASK(gso->mask); bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; @@ -1459,7 +1461,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - if (GPENCIL_ANY_SCULPT_MASK(gso->mask) && (pt->flag & GP_SPOINT_SELECT) != 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_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); @@ -1516,7 +1518,8 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, /* To each point individually... */ pt = &gps->points[i]; - if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) { + if ((i != gps->totpoints - 2) && (pt->runtime.pt_orig == NULL) && + (tool != GPSCULPT_TOOL_GRAB)) { continue; } pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; @@ -1618,7 +1621,8 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, } /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { + if ((gps->totpoints > 1) && + (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat))) { continue; } @@ -1982,7 +1986,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA * } /* Store coordinates as reference, if operator just started running */ - if (gso->first) { + if (gso->mval_prev[0] == -1.0f) { gso->mval_prev[0] = gso->mval[0]; gso->mval_prev[1] = gso->mval[1]; gso->pressure_prev = gso->pressure; diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index e903d11a1e0..a19265720e8 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -759,7 +759,7 @@ static bool gpencil_select_same_layer(bContext *C) bool changed = false; CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); bGPDstroke *gps; bool found = false; diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c index 24a0dab24c9..36165c6b7c0 100644 --- a/source/blender/editors/gpencil/gpencil_trace_ops.c +++ b/source/blender/editors/gpencil/gpencil_trace_ops.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; @@ -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. */ @@ -295,14 +301,15 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op) job->base_active = CTX_data_active_base(C); job->ob_active = job->base_active->object; job->image = (Image *)job->ob_active->data; - job->frame_target = CFRA; + job->frame_target = scene->r.cfra; job->use_current_frame = RNA_boolean_get(op->ptr, "use_current_frame"); /* Create a new grease pencil object or reuse selected. */ eGP_TargetObjectMode target = RNA_enum_get(op->ptr, "target"); - 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,13 +331,14 @@ 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) { + if ((job->image->source == IMA_SRC_FILE) || (job->frame_num > 0)) { short stop = 0, do_update = true; float progress; trace_start_job(job, &stop, &do_update, &progress); @@ -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_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index fc5b3838900..e47f16ac466 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -388,6 +388,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, /* Create new layer */ /* TODO: have some way of specifying that we don't want this? */ + { + /* "New Layer" entry */ + item_tmp.identifier = "__CREATE__"; + item_tmp.name = "New Layer"; + item_tmp.value = -1; + item_tmp.icon = ICON_ADD; + RNA_enum_item_add(&item, &totitem, &item_tmp); + + /* separator */ + RNA_enum_item_add_separator(&item, &totitem); + } const int tot = BLI_listbase_count(&gpd->layers); /* Existing layers */ @@ -405,17 +416,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, RNA_enum_item_add(&item, &totitem, &item_tmp); } - { - /* separator */ - RNA_enum_item_add_separator(&item, &totitem); - - /* "New Layer" entry */ - item_tmp.identifier = "__CREATE__"; - item_tmp.name = "New Layer"; - item_tmp.value = -1; - item_tmp.icon = ICON_ADD; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1683,7 +1683,7 @@ void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y) GPUVertFormat *format = immVertexFormat(); const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); @@ -1693,7 +1693,7 @@ void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y) immUnbindProgram(); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -1865,7 +1865,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat /* draw icon */ GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); @@ -3189,7 +3189,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim( /* Join both strokes. */ int totpoint = gps_final->totpoints; - BKE_gpencil_stroke_join(gps_final, gps, false, true, true); + BKE_gpencil_stroke_join(gps_final, gps, false, true, true, true); /* Select the join points and merge if the distance is very small. */ pt = &gps_final->points[totpoint - 1]; |