From 08eb7f1c970d4ccc47382ebed210acd92d1336d2 Mon Sep 17 00:00:00 2001 From: Amelie Fondevilla Date: Wed, 13 Sep 2023 12:09:20 +0200 Subject: [PATCH] GPv3: Snap selected grease pencil frames Update of the ACTION_OT_snap to take into account grease pencil frames. Implemented modes are snap to current frame, nearest second, and nearest marker. Pull Request: https://projects.blender.org/blender/blender/pulls/111507 --- .../intern/grease_pencil_frames.cc | 46 +++++++++++++++++++ .../editors/include/ED_grease_pencil.hh | 13 ++++-- .../editors/space_action/action_edit.cc | 10 +++- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_frames.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_frames.cc index 3140e12d004..07cd83265fe 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_frames.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_frames.cc @@ -38,6 +38,52 @@ void set_selected_frames_type(bke::greasepencil::Layer &layer, } } +static float get_snapped_frame_number(const float frame_number, + Scene &scene, + const eEditKeyframes_Snap mode) +{ + switch (mode) { + case SNAP_KEYS_CURFRAME: /* Snap to current frame. */ + return scene.r.cfra; + case SNAP_KEYS_NEARSEC: /* Snap to nearest second. */ + { + float secf = (scene.r.frs_sec / scene.r.frs_sec_base); + return floorf(frame_number / secf + 0.5f) * secf; + } + case SNAP_KEYS_NEARMARKER: /* Snap to nearest marker. */ + return ED_markers_find_nearest_marker_time(&scene.markers, frame_number); + default: + break; + } + return frame_number; +} + +bool snap_selected_frames(GreasePencil &grease_pencil, + bke::greasepencil::Layer &layer, + Scene &scene, + const eEditKeyframes_Snap mode) +{ + bool changed = false; + blender::Map frame_number_destinations; + for (auto [frame_number, frame] : layer.frames().items()) { + if (!frame.is_selected()) { + continue; + } + const int snapped = round_fl_to_int( + get_snapped_frame_number(float(frame_number), scene, mode)); + if (snapped != frame_number) { + frame_number_destinations.add(frame_number, snapped); + changed = true; + } + } + + if (changed) { + grease_pencil.move_frames(layer, frame_number_destinations); + } + + return changed; +} + static int get_mirrored_frame_number(const int frame_number, const Scene &scene, const eEditKeyframes_Mirror mode, diff --git a/source/blender/editors/include/ED_grease_pencil.hh b/source/blender/editors/include/ED_grease_pencil.hh index f903f7f2bee..7162c30eb7b 100644 --- a/source/blender/editors/include/ED_grease_pencil.hh +++ b/source/blender/editors/include/ED_grease_pencil.hh @@ -50,16 +50,21 @@ namespace blender::ed::greasepencil { void set_selected_frames_type(bke::greasepencil::Layer &layer, const eBezTriple_KeyframeType key_type); -/* Creates duplicate frames for each selected frame in the layer. The duplicates are stored in the - * LayerTransformData structure of the layer runtime data. This function also unselects the - * selected frames, while keeping the duplicates selected. */ -bool duplicate_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer); +bool snap_selected_frames(GreasePencil &grease_pencil, + bke::greasepencil::Layer &layer, + Scene &scene, + const eEditKeyframes_Snap mode); bool mirror_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, Scene &scene, const eEditKeyframes_Mirror mode); +/* Creates duplicate frames for each selected frame in the layer. The duplicates are stored in the + * LayerTransformData structure of the layer runtime data. This function also unselects the + * selected frames, while keeping the duplicates selected. */ +bool duplicate_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer); + bool remove_all_selected_frames(GreasePencil &grease_pencil, bke::greasepencil::Layer &layer); void select_layer_channel(GreasePencil &grease_pencil, bke::greasepencil::Layer *layer); diff --git a/source/blender/editors/space_action/action_edit.cc b/source/blender/editors/space_action/action_edit.cc index f103a4734d4..7e2dbed9da6 100644 --- a/source/blender/editors/space_action/action_edit.cc +++ b/source/blender/editors/space_action/action_edit.cc @@ -1929,7 +1929,15 @@ static void snap_action_keys(bAnimContext *ac, short mode) ED_gpencil_layer_snap_frames(static_cast(ale->data), ac->scene, mode); } else if (ale->type == ANIMTYPE_GREASE_PENCIL_LAYER) { - /* GPv3: To be implemented. */ + GreasePencil *grease_pencil = reinterpret_cast(ale->id); + GreasePencilLayer *layer = static_cast(ale->data); + + const bool changed = blender::ed::greasepencil::snap_selected_frames( + *grease_pencil, layer->wrap(), *(ac->scene), static_cast(mode)); + + if (changed) { + DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY); + } } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_snap_frames(static_cast(ale->data), ac->scene, mode);