diff options
Diffstat (limited to 'source/blender/editors/gpencil')
-rw-r--r-- | source/blender/editors/gpencil/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_add_blank.c | 101 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_data.c | 48 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_edit.c | 156 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_intern.h | 1 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_interpolate.c | 26 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_ops.c | 1 |
7 files changed, 253 insertions, 81 deletions
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 47ae90acb74..f7ab72a8a43 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -36,6 +36,7 @@ set(SRC annotate_paint.c drawgpencil.c editaction_gpencil.c + gpencil_add_blank.c gpencil_add_lineart.c gpencil_add_monkey.c gpencil_add_stroke.c diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c new file mode 100644 index 00000000000..3bd61d5c88a --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_add_blank.c @@ -0,0 +1,101 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup edgpencil + */ + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "DEG_depsgraph.h" + +#include "ED_gpencil.h" + +/* Definition of the most important info from a color */ +typedef struct ColorTemplate { + const char *name; + float line[4]; + float fill[4]; +} ColorTemplate; + +/* Add color an ensure duplications (matched by name) */ +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); + + copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); + srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); + + copy_v4_v4(ma->gp_style->fill_rgba, pct->fill); + srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba); + + return index; +} + +/* ***************************************************************** */ +/* Stroke Geometry */ + +/* ***************************************************************** */ +/* Color Data */ + +static const ColorTemplate gp_stroke_material_black = { + "Black", + {0.0f, 0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, +}; + +/* ***************************************************************** */ +/* Blank API */ + +/* Add a Simple empty object with one layer and one color. */ +void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4])) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + bGPdata *gpd = (bGPdata *)ob->data; + + /* create colors */ + int color_black = gpencil_stroke_material(bmain, ob, &gp_stroke_material_black); + + /* set first color as active and in brushes */ + ob->actcol = color_black + 1; + + /* layers */ + bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true); + + /* frames */ + BKE_gpencil_frame_addnew(layer, CFRA); + + /* update depsgraph */ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; +} diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index b269fd84d5f..c93fcb9eb8c 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -3745,3 +3745,51 @@ void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot) ot->exec = gpencil_layer_mask_remove_exec; ot->poll = gpencil_active_layer_poll; } + +static int gpencil_layer_mask_move_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); + const int direction = RNA_enum_get(op->ptr, "type"); + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl)) { + return OPERATOR_CANCELLED; + } + if (gpl->act_mask > 0) { + bGPDlayer_Mask *mask = BLI_findlink(&gpl->mask_layers, gpl->act_mask - 1); + if (mask != NULL) { + BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */ + if (BLI_listbase_link_move(&gpl->mask_layers, mask, direction)) { + gpl->act_mask += direction; + 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_layer_mask_move(wmOperatorType *ot) +{ + static const EnumPropertyItem slot_move[] = { + {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""}, + {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Move Grease Pencil Layer Mask"; + ot->idname = "GPENCIL_OT_layer_mask_move"; + ot->description = "Move the active Grease Pencil mask layer up/down in the list"; + + /* api callbacks */ + ot->exec = gpencil_layer_mask_move_exec; + ot->poll = gpencil_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", ""); +} diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index d388e11dc8c..d90f74fbf4f 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1818,18 +1818,13 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - Scene *scene = CTX_data_scene(C); bGPDlayer *target_layer = NULL; ListBase strokes = {NULL, NULL}; int layer_num = RNA_int_get(op->ptr, "layer"); const bool use_autolock = (bool)(gpd->flag & GP_DATA_AUTOLOCK_LAYERS); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) { - BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); - return OPERATOR_CANCELLED; - } - - /* if autolock enabled, disabled now */ + /* If autolock enabled, disabled now. */ if (use_autolock) { gpd->flag &= ~GP_DATA_AUTOLOCK_LAYERS; } @@ -1852,53 +1847,59 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* Extract all strokes to move to this layer - * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes - * getting repeatedly moved - */ - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - - /* skip if no frame with strokes, or if this is the layer we're moving strokes to */ - if ((gpl == target_layer) || (gpf == NULL)) { + /* Extract all strokes to move to this layer. */ + CTX_DATA_BEGIN (C, bGPDlayer *, gpl_src, editable_gpencil_layers) { + /* Skip if this is the layer we're moving strokes to. */ + if (gpl_src == target_layer) { continue; } + bGPDframe *init_gpf = (is_multiedit) ? gpl_src->frames.first : gpl_src->actframe; + for (bGPDframe *gpf_src = init_gpf; gpf_src; gpf_src = gpf_src->next) { + if ((gpf_src == gpl_src->actframe) || + ((gpf_src->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf_src == NULL) { + continue; + } - /* make copies of selected strokes, and deselect these once we're done */ - LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { + bGPDstroke *gpsn = NULL; + BLI_listbase_clear(&strokes); + for (bGPDstroke *gps = gpf_src->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + /* Skip strokes that are invalid for current view. */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* Check if the color is editable. */ + if (ED_gpencil_stroke_material_editable(ob, gpl_src, gps) == false) { + continue; + } - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } + if (gps->flag & GP_STROKE_SELECT) { + BLI_remlink(&gpf_src->strokes, gps); + BLI_addtail(&strokes, gps); + } + } + /* Paste them all in one go. */ + if (strokes.first) { + bGPDframe *gpf_dst = BKE_gpencil_layer_frame_get( + target_layer, gpf_src->framenum, GP_GETFRAME_ADD_NEW); - /* Check if the color is editable. */ - if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) { - continue; + BLI_movelisttolist(&gpf_dst->strokes, &strokes); + BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL)); + } } - - /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */ - if (gps->flag & GP_STROKE_SELECT) { - BLI_remlink(&gpf->strokes, gps); - BLI_addtail(&strokes, gps); + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; } } - - /* if new layer and autolock, lock old layer */ + /* If new layer and autolock, lock old layer. */ if ((layer_num == -1) && (use_autolock)) { - gpl->flag |= GP_LAYER_LOCKED; + gpl_src->flag |= GP_LAYER_LOCKED; } } CTX_DATA_END; - /* Paste them all in one go */ - if (strokes.first) { - bGPDframe *gpf = BKE_gpencil_layer_frame_get(target_layer, CFRA, GP_GETFRAME_ADD_NEW); - - BLI_movelisttolist(&gpf->strokes, &strokes); - BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL)); - } - /* back autolock status */ if (use_autolock) { gpd->flag |= GP_DATA_AUTOLOCK_LAYERS; @@ -3762,6 +3763,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) const eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type"); 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); /* Init snap context for geometry projection. */ SnapObjectContext *sctx = NULL; @@ -3774,36 +3776,55 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op) int cfra_prv = INT_MIN; /* Go through each editable + selected stroke, adjusting each of its points one by one... */ - GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { - bool curve_select = false; - if (is_curve_edit && gps->editcurve != NULL) { - curve_select = gps->editcurve->flag & GP_CURVE_SELECT; - } + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; - if (gps->flag & GP_STROKE_SELECT || curve_select) { + 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) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + bool curve_select = false; + if (is_curve_edit && gps->editcurve != NULL) { + curve_select = gps->editcurve->flag & GP_CURVE_SELECT; + } - /* 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; - BKE_scene_graph_update_for_newframe(depsgraph); - } + if (gps->flag & GP_STROKE_SELECT || curve_select) { - ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf_, gps, mode, keep_original); + /* 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; + BKE_scene_graph_update_for_newframe(depsgraph); + } - if (is_curve_edit && gps->editcurve != NULL) { - BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps); - /* Update the selection from the stroke to the curve. */ - BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve); + ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf, gps, mode, keep_original); - gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; - BKE_gpencil_stroke_geometry_update(gpd, gps); - } + if (is_curve_edit && gps->editcurve != NULL) { + BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps); + /* Update the selection from the stroke to the curve. */ + BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve); - changed = true; + gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; + BKE_gpencil_stroke_geometry_update(gpd, gps); + } + + changed = true; + } + } + } + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; + } } } - GP_EDITABLE_STROKES_END(gpstroke_iter); + CTX_DATA_END; /* return frame state and DB to original state */ CFRA = oldframe; @@ -3832,7 +3853,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) "VIEW", 0, "View", - "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " + "Reproject the strokes to end up on the same plane, as if drawn from the current " + "viewpoint " "using 'Cursor' Stroke Placement"}, {GP_REPROJECT_SURFACE, "SURFACE", @@ -3851,7 +3873,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) ot->name = "Reproject Strokes"; ot->idname = "GPENCIL_OT_reproject"; ot->description = - "Reproject the selected strokes from the current viewpoint as if they had been newly drawn " + "Reproject the selected strokes from the current viewpoint as if they had been newly " + "drawn " "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, " "or for matching deforming geometry)"; @@ -4208,7 +4231,8 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) ot->name = "Subdivide Stroke"; ot->idname = "GPENCIL_OT_stroke_subdivide"; ot->description = - "Subdivide between continuous selected points of the stroke adding a point half way between " + "Subdivide between continuous selected points of the stroke adding a point half way " + "between " "them"; /* api callbacks */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index c6f74c39beb..09200125cb7 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -421,6 +421,7 @@ void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot); void GPENCIL_OT_layer_mask_add(struct wmOperatorType *ot); void GPENCIL_OT_layer_mask_remove(struct wmOperatorType *ot); +void GPENCIL_OT_layer_mask_move(struct wmOperatorType *ot); void GPENCIL_OT_hide(struct wmOperatorType *ot); void GPENCIL_OT_reveal(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 7ca53779522..0062e363cdf 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -1434,36 +1434,32 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op) { uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); uiLayout *col, *row; - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type"); uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "step", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "step", 0, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "layers", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "layers", 0, NULL, ICON_NONE); if (CTX_data_mode_enum(C) == CTX_MODE_EDIT_GPENCIL) { row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "interpolate_selected_only", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "interpolate_selected_only", 0, NULL, ICON_NONE); } row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "flip", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "flip", 0, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, &ptr, "smooth_factor", 0, NULL, ICON_NONE); - uiItemR(col, &ptr, "smooth_steps", 0, NULL, ICON_NONE); + uiItemR(col, op->ptr, "smooth_factor", 0, NULL, ICON_NONE); + uiItemR(col, op->ptr, "smooth_steps", 0, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, &ptr, "type", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "type", 0, NULL, ICON_NONE); if (type == GP_IPO_CURVEMAP) { /* Get an RNA pointer to ToolSettings to give to the custom curve. */ @@ -1477,16 +1473,16 @@ static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op) } else if (type != GP_IPO_LINEAR) { row = uiLayoutRow(layout, false); - uiItemR(row, &ptr, "easing", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "easing", 0, NULL, ICON_NONE); if (type == GP_IPO_BACK) { row = uiLayoutRow(layout, false); - uiItemR(row, &ptr, "back", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "back", 0, NULL, ICON_NONE); } else if (type == GP_IPO_ELASTIC) { row = uiLayoutRow(layout, false); - uiItemR(row, &ptr, "amplitude", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "amplitude", 0, NULL, ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, &ptr, "period", 0, NULL, ICON_NONE); + uiItemR(row, op->ptr, "period", 0, NULL, ICON_NONE); } } } diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 1a6cb5670c4..7d454eb3be1 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -601,6 +601,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_mask_add); WM_operatortype_append(GPENCIL_OT_layer_mask_remove); + WM_operatortype_append(GPENCIL_OT_layer_mask_move); WM_operatortype_append(GPENCIL_OT_hide); WM_operatortype_append(GPENCIL_OT_reveal); |