Fix: GPv3: Duplicate previous key using auto key
When erasing, sculpting or tinting, the previous key was not being duplicated. The `ed::greasepencil::ensure_active_keyframe` didn't have a good mechanism to make this work. This adds a parameter to the `ensure_active_keyframe` function so that the caller can decide what should be done. For the sculpting tools, eraser, and tint tool, this will now duplicate the previous key, when auto-key is on. Resolves #124082. Pull Request: https://projects.blender.org/blender/blender/pulls/125224
This commit is contained in:
@@ -2251,7 +2251,7 @@ static int grease_pencil_paste_strokes_exec(bContext *C, wmOperator *op)
|
||||
|
||||
/* Ensure active keyframe. */
|
||||
bool inserted_keyframe = false;
|
||||
if (!ensure_active_keyframe(C, grease_pencil, inserted_keyframe)) {
|
||||
if (!ensure_active_keyframe(C, grease_pencil, false, inserted_keyframe)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
@@ -337,7 +337,10 @@ void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
|
||||
}
|
||||
}
|
||||
|
||||
bool ensure_active_keyframe(bContext *C, GreasePencil &grease_pencil, bool &r_inserted_keyframe)
|
||||
bool ensure_active_keyframe(bContext *C,
|
||||
GreasePencil &grease_pencil,
|
||||
const bool duplicate_previous_key,
|
||||
bool &r_inserted_keyframe)
|
||||
{
|
||||
Scene &scene = *CTX_data_scene(C);
|
||||
const int current_frame = scene.r.cfra;
|
||||
@@ -351,24 +354,17 @@ bool ensure_active_keyframe(bContext *C, GreasePencil &grease_pencil, bool &r_in
|
||||
* keyframe needs to be inserted. */
|
||||
const bool is_first = active_layer.is_empty() ||
|
||||
(active_layer.sorted_keys().first() > current_frame);
|
||||
const std::optional<int> current_start_frame = active_layer.start_frame_at(current_frame);
|
||||
const bool needs_new_drawing = is_first || !current_start_frame ||
|
||||
(current_start_frame < current_frame);
|
||||
const std::optional<int> previous_key_frame_start = active_layer.start_frame_at(current_frame);
|
||||
const bool has_previous_key = previous_key_frame_start.has_value();
|
||||
const bool needs_new_drawing = is_first || !has_previous_key ||
|
||||
(previous_key_frame_start < current_frame);
|
||||
if (blender::animrig::is_autokey_on(&scene) && needs_new_drawing) {
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
const Brush *brush = BKE_paint_brush_for_read(BKE_paint_get_active(&scene, view_layer));
|
||||
const bool use_additive_drawing = (scene.toolsettings->gpencil_flags &
|
||||
GP_TOOL_FLAG_RETAIN_LAST) != 0;
|
||||
/* Eraser tool makes no sense on empty drawings, don't insert new frames. */
|
||||
const bool allow_empty_frame = (brush->gpencil_tool != GPAINT_TOOL_ERASE);
|
||||
if (current_start_frame && (use_additive_drawing || !allow_empty_frame)) {
|
||||
/* For additive drawing, we duplicate the frame that's currently visible and insert it at the
|
||||
* current frame.
|
||||
* NOTE: Also duplicate the frame when erasing, Otherwise empty drawing is added, see
|
||||
* !119051.
|
||||
*/
|
||||
if (has_previous_key && (use_additive_drawing || duplicate_previous_key)) {
|
||||
/* We duplicate the frame that's currently visible and insert it at the current frame. */
|
||||
grease_pencil.insert_duplicate_frame(
|
||||
active_layer, *current_start_frame, current_frame, false);
|
||||
active_layer, *previous_key_frame_start, current_frame, false);
|
||||
}
|
||||
else {
|
||||
/* Otherwise we just insert a blank keyframe at the current frame. */
|
||||
|
||||
@@ -656,7 +656,7 @@ static void grease_pencil_primitive_update_view(bContext *C, PrimitiveToolOperat
|
||||
/* Invoke handler: Initialize the operator. */
|
||||
static int grease_pencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int return_value = ed::greasepencil::grease_pencil_draw_operator_invoke(C, op);
|
||||
int return_value = ed::greasepencil::grease_pencil_draw_operator_invoke(C, op, false);
|
||||
if (return_value != OPERATOR_RUNNING_MODAL) {
|
||||
return return_value;
|
||||
}
|
||||
|
||||
@@ -1237,7 +1237,9 @@ float opacity_from_input_sample(const float pressure,
|
||||
return opacity;
|
||||
}
|
||||
|
||||
int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op)
|
||||
int grease_pencil_draw_operator_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const bool use_duplicate_previous_key)
|
||||
{
|
||||
const Object *object = CTX_data_active_object(C);
|
||||
if (!object || object->type != OB_GREASE_PENCIL) {
|
||||
@@ -1265,7 +1267,9 @@ int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op)
|
||||
|
||||
/* Ensure a drawing at the current keyframe. */
|
||||
bool inserted_keyframe = false;
|
||||
if (!ed::greasepencil::ensure_active_keyframe(C, grease_pencil, inserted_keyframe)) {
|
||||
if (!ed::greasepencil::ensure_active_keyframe(
|
||||
C, grease_pencil, use_duplicate_previous_key, inserted_keyframe))
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,10 @@ bool has_any_frame_selected(const bke::greasepencil::Layer &layer);
|
||||
* create one when auto-key is on (taking additive drawing setting into account).
|
||||
* \return false when no keyframe could be found or created.
|
||||
*/
|
||||
bool ensure_active_keyframe(bContext *C, GreasePencil &grease_pencil, bool &r_inserted_keyframe);
|
||||
bool ensure_active_keyframe(bContext *C,
|
||||
GreasePencil &grease_pencil,
|
||||
bool duplicate_previous_key,
|
||||
bool &r_inserted_keyframe);
|
||||
|
||||
void create_keyframe_edit_data_selected_frames_list(KeyframeEditData *ked,
|
||||
const bke::greasepencil::Layer &layer);
|
||||
@@ -250,7 +253,9 @@ float radius_from_input_sample(const RegionView3D *rv3d,
|
||||
float3 location,
|
||||
float4x4 to_world,
|
||||
const BrushGpencilSettings *settings);
|
||||
int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op);
|
||||
int grease_pencil_draw_operator_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
bool use_duplicate_previous_key);
|
||||
float4x2 calculate_texture_space(const Scene *scene,
|
||||
const ARegion *region,
|
||||
const float2 &mouse,
|
||||
|
||||
@@ -210,7 +210,28 @@ static bool grease_pencil_brush_stroke_poll(bContext *C)
|
||||
|
||||
static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
int return_value = ed::greasepencil::grease_pencil_draw_operator_invoke(C, op);
|
||||
const bool use_duplicate_previous_key = [&]() -> bool {
|
||||
const Paint *paint = BKE_paint_get_active_from_context(C);
|
||||
const Brush &brush = *BKE_paint_brush_for_read(paint);
|
||||
const PaintMode mode = BKE_paintmode_get_active_from_context(C);
|
||||
const BrushStrokeMode stroke_mode = BrushStrokeMode(RNA_enum_get(op->ptr, "mode"));
|
||||
if (mode == PaintMode::GPencil) {
|
||||
/* For the eraser and tint tool, we don't want auto-key to create an empty keyframe, so we
|
||||
* duplicate the previous frame. */
|
||||
if (ELEM(eBrushGPaintTool(brush.gpencil_tool), GPAINT_TOOL_ERASE, GPAINT_TOOL_TINT)) {
|
||||
return true;
|
||||
}
|
||||
/* Same for the temporary eraser when using the draw tool. */
|
||||
if (eBrushGPaintTool(brush.gpencil_tool) == GPAINT_TOOL_DRAW &&
|
||||
stroke_mode == BRUSH_STROKE_ERASE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
int return_value = ed::greasepencil::grease_pencil_draw_operator_invoke(
|
||||
C, op, use_duplicate_previous_key);
|
||||
if (return_value != OPERATOR_RUNNING_MODAL) {
|
||||
return return_value;
|
||||
}
|
||||
@@ -304,7 +325,12 @@ static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const
|
||||
|
||||
/* Ensure a drawing at the current keyframe. */
|
||||
bool inserted_keyframe = false;
|
||||
if (!ed::greasepencil::ensure_active_keyframe(C, grease_pencil, inserted_keyframe)) {
|
||||
/* For the sculpt tools, we don't want the auto-key to create an empty keyframe, so we duplicate
|
||||
* the previous key. */
|
||||
const bool use_duplicate_previous_key = true;
|
||||
if (!ed::greasepencil::ensure_active_keyframe(
|
||||
C, grease_pencil, use_duplicate_previous_key, inserted_keyframe))
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user