diff options
author | Aleš Jelovčan <frogstomp> | 2022-09-27 18:47:01 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2022-09-27 18:55:43 +0300 |
commit | b0d70a9c80402e8b7af173a76e9a8b6050598825 (patch) | |
tree | cc2d98fe527473e16052ab09adf6ed5615a07f61 /source/blender/editors/object | |
parent | 12fdf9069abe3cd2250a9efec6e059eb85ec59d8 (diff) |
Gpencil: Time Offset modifier new Chain mode
This patch adds 5th mode to Time offset modifier, which should allow
to create time segments list.
This will allow users to chain together multiple time ranges in 4 modes:
- Forward
- Backwards
- Pingpong
- Reverse Pingpong
It also comes with additional Repeat parameter which specifies number
of times particular segment should run.
The mechanic of it is transforming initial parameters into array of frames which
are mapped to existing cfra (current frame) value.
Prototype : https://jsfiddle.net/ha2sjw8p/3/
This is also closely aligned to community request:
https://blender.community/c/rightclickselect/Txhbbc/
This should allow creation of complex animations like dancing,
which consists of repeating loops and transitions to the next.
One important side effect of this is dramatically reduced
file sizes, as user no longer needs to copy paste keyframes.
Reviewed By: antoniov, mendio, pepeland
Differential Revision: https://developer.blender.org/D15052
Diffstat (limited to 'source/blender/editors/object')
-rw-r--r-- | source/blender/editors/object/object_gpencil_modifier.c | 236 | ||||
-rw-r--r-- | source/blender/editors/object/object_intern.h | 4 | ||||
-rw-r--r-- | source/blender/editors/object/object_ops.c | 4 |
3 files changed, 244 insertions, 0 deletions
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index 42ac6d166b4..e85947534cd 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -934,6 +934,242 @@ void OBJECT_OT_gpencil_modifier_copy_to_selected(wmOperatorType *ot) gpencil_edit_modifier_properties(ot); } +/************************* Time Offset Advanced Modifier *******************************/ + +static bool time_segment_poll(bContext *C) +{ + return gpencil_edit_modifier_poll_generic(C, &RNA_TimeGpencilModifier, 0, false); +} + +static bool time_segment_name_exists_fn(void *arg, const char *name) +{ + const TimeGpencilModifierData *gpmd = (const TimeGpencilModifierData *)arg; + for (int i = 0; i < gpmd->segments_len; i++) { + if (STREQ(gpmd->segments[i].name, name) && gpmd->segments[i].name != name) { + return true; + } + } + return false; +} + +static int time_segment_add_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get( + op, ob, eGpencilModifierType_Time); + if (gpmd == NULL) { + return OPERATOR_CANCELLED; + } + const int new_active_index = gpmd->segment_active_index + 1; + TimeGpencilModifierSegment *new_segments = MEM_malloc_arrayN( + gpmd->segments_len + 1, sizeof(TimeGpencilModifierSegment), __func__); + + if (gpmd->segments_len != 0) { + /* Copy the segments before the new segment. */ + memcpy(new_segments, gpmd->segments, sizeof(TimeGpencilModifierSegment) * new_active_index); + /* Copy the segments after the new segment. */ + memcpy(new_segments + new_active_index + 1, + gpmd->segments + new_active_index, + sizeof(TimeGpencilModifierSegment) * (gpmd->segments_len - new_active_index)); + } + + /* Create the new segment. */ + TimeGpencilModifierSegment *ds = &new_segments[new_active_index]; + memcpy( + ds, DNA_struct_default_get(TimeGpencilModifierSegment), sizeof(TimeGpencilModifierSegment)); + BLI_uniquename_cb( + time_segment_name_exists_fn, gpmd, DATA_("Segment"), '.', ds->name, sizeof(ds->name)); + ds->gpmd = gpmd; + + MEM_SAFE_FREE(gpmd->segments); + gpmd->segments = new_segments; + gpmd->segments_len++; + gpmd->segment_active_index++; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int time_segment_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) { + return time_segment_add_exec(C, op); + } + return OPERATOR_CANCELLED; +} + +void GPENCIL_OT_time_segment_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Segment"; + ot->description = "Add a segment to the time modifier"; + ot->idname = "GPENCIL_OT_time_segment_add"; + + /* api callbacks */ + ot->poll = time_segment_poll; + ot->invoke = time_segment_add_invoke; + ot->exec = time_segment_add_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +static int time_segment_remove_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + + TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get( + op, ob, eGpencilModifierType_Time); + + if (gpmd->segment_active_index < 0 || gpmd->segment_active_index >= gpmd->segments_len) { + return OPERATOR_CANCELLED; + } + + if (gpmd->segments_len == 1) { + MEM_SAFE_FREE(gpmd->segments); + gpmd->segment_active_index = -1; + } + else { + TimeGpencilModifierSegment *new_segments = MEM_malloc_arrayN( + gpmd->segments_len, sizeof(TimeGpencilModifierSegment), __func__); + + /* Copy the segments before the deleted segment. */ + memcpy(new_segments, + gpmd->segments, + sizeof(TimeGpencilModifierSegment) * gpmd->segment_active_index); + + /* Copy the segments after the deleted segment. */ + memcpy(new_segments + gpmd->segment_active_index, + gpmd->segments + gpmd->segment_active_index + 1, + sizeof(TimeGpencilModifierSegment) * + (gpmd->segments_len - gpmd->segment_active_index - 1)); + + MEM_freeN(gpmd->segments); + gpmd->segments = new_segments; + gpmd->segment_active_index = MAX2(gpmd->segment_active_index - 1, 0); + } + + gpmd->segments_len--; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int time_segment_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) { + return time_segment_remove_exec(C, op); + } + return OPERATOR_CANCELLED; +} + +void GPENCIL_OT_time_segment_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Time Segment"; + ot->description = "Remove the active segment from the time modifier"; + ot->idname = "GPENCIL_OT_time_segment_remove"; + + /* api callbacks */ + ot->poll = time_segment_poll; + ot->invoke = time_segment_remove_invoke; + ot->exec = time_segment_remove_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); + + RNA_def_int( + ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of the segment to remove", 0, INT_MAX); +} + +enum { + GP_TIME_SEGEMENT_MOVE_UP = -1, + GP_TIME_SEGEMENT_MOVE_DOWN = 1, +}; + +static int time_segment_move_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + + TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)gpencil_edit_modifier_property_get( + op, ob, eGpencilModifierType_Time); + + if (gpmd->segments_len < 2) { + return OPERATOR_CANCELLED; + } + + const int direction = RNA_enum_get(op->ptr, "type"); + if (direction == GP_TIME_SEGEMENT_MOVE_UP) { + if (gpmd->segment_active_index == 0) { + return OPERATOR_CANCELLED; + } + + SWAP(TimeGpencilModifierSegment, + gpmd->segments[gpmd->segment_active_index], + gpmd->segments[gpmd->segment_active_index - 1]); + + gpmd->segment_active_index--; + } + else if (direction == GP_TIME_SEGEMENT_MOVE_DOWN) { + if (gpmd->segment_active_index == gpmd->segments_len - 1) { + return OPERATOR_CANCELLED; + } + + SWAP(TimeGpencilModifierSegment, + gpmd->segments[gpmd->segment_active_index], + gpmd->segments[gpmd->segment_active_index + 1]); + + gpmd->segment_active_index++; + } + else { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int time_segment_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) { + return time_segment_move_exec(C, op); + } + return OPERATOR_CANCELLED; +} + +void GPENCIL_OT_time_segment_move(wmOperatorType *ot) +{ + static const EnumPropertyItem segment_move[] = { + {GP_TIME_SEGEMENT_MOVE_UP, "UP", 0, "Up", ""}, + {GP_TIME_SEGEMENT_MOVE_DOWN, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Move Time Segment"; + ot->description = "Move the active time segment up or down"; + ot->idname = "GPENCIL_OT_time_segment_move"; + + /* api callbacks */ + ot->poll = time_segment_poll; + ot->invoke = time_segment_move_invoke; + ot->exec = time_segment_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); + + ot->prop = RNA_def_enum(ot->srna, "type", segment_move, 0, "Type", ""); +} + /************************* Dash Modifier *******************************/ static bool dash_segment_poll(bContext *C) diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 63f010cd526..b136f311557 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -221,6 +221,10 @@ void GPENCIL_OT_segment_add(struct wmOperatorType *ot); void GPENCIL_OT_segment_remove(struct wmOperatorType *ot); void GPENCIL_OT_segment_move(struct wmOperatorType *ot); +void GPENCIL_OT_time_segment_add(struct wmOperatorType *ot); +void GPENCIL_OT_time_segment_remove(struct wmOperatorType *ot); +void GPENCIL_OT_time_segment_move(struct wmOperatorType *ot); + /* object_shader_fx.c */ void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 24a4556b075..a73cc98c78e 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -151,6 +151,10 @@ void ED_operatortypes_object(void) WM_operatortype_append(GPENCIL_OT_segment_remove); WM_operatortype_append(GPENCIL_OT_segment_move); + WM_operatortype_append(GPENCIL_OT_time_segment_add); + WM_operatortype_append(GPENCIL_OT_time_segment_remove); + WM_operatortype_append(GPENCIL_OT_time_segment_move); + /* grease pencil line art */ WM_operatortypes_lineart(); |