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/gpencil_modifiers | |
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/gpencil_modifiers')
-rw-r--r-- | source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c | 211 |
1 files changed, 201 insertions, 10 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index 1d45030b68b..e3d49ba37d5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -9,6 +9,11 @@ #include <stdlib.h> #include <string.h> +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -16,20 +21,33 @@ #include "DNA_defaults.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_geom.h" #include "BKE_gpencil_modifier.h" +#include "BKE_lib_query.h" +#include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_screen.h" -#include "UI_interface.h" -#include "UI_resources.h" - #include "RNA_access.h" +#include "RNA_prototypes.h" #include "MOD_gpencil_modifiertypes.h" #include "MOD_gpencil_ui_common.h" +#include "MOD_gpencil_util.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" + +#include "DEG_depsgraph.h" static void initData(GpencilModifierData *md) { @@ -38,11 +56,26 @@ static void initData(GpencilModifierData *md) BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier)); MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(TimeGpencilModifierData), modifier); + TimeGpencilModifierSegment *ds = DNA_struct_default_alloc(TimeGpencilModifierSegment); + ds->gpmd = gpmd; + BLI_strncpy(ds->name, DATA_("Segment"), sizeof(ds->name)); + + gpmd->segments = ds; } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)target; + const TimeGpencilModifierData *gpmd_src = (const TimeGpencilModifierData *)md; BKE_gpencil_modifier_copydata_generic(md, target); + gpmd->segments = MEM_dupallocN(gpmd_src->segments); +} + +static void freeData(GpencilModifierData *md) +{ + TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)md; + + MEM_SAFE_FREE(gpmd->segments); } static int remapTime(struct GpencilModifierData *md, @@ -60,6 +93,7 @@ static int remapTime(struct GpencilModifierData *md, int efra = custom ? mmd->efra : scene->r.efra; int offset = mmd->offset; int nfra = 0; + CLAMP_MIN(sfra, 0); CLAMP_MIN(efra, 0); @@ -100,6 +134,7 @@ static int remapTime(struct GpencilModifierData *md, /* apply frame scale */ cfra *= mmd->frame_scale; + CLAMP_MIN(cfra, 1); /* if fix mode, return predefined frame number */ if (mmd->mode == GP_TIME_MODE_FIX) { @@ -146,10 +181,111 @@ static int remapTime(struct GpencilModifierData *md, } } + if (mmd->mode == GP_TIME_MODE_CHAIN) { + int sequence_length = 0; + int frame_key = 0; + int *segment_arr; + int start, end; + if (mmd->segments_len > 0) { + for (int i = 0; i < mmd->segments_len; i++) { + start = mmd->segments[i].seg_start; + end = mmd->segments[i].seg_end; + if (mmd->segments[i].seg_end < mmd->segments[i].seg_start) { + start = mmd->segments[i].seg_end; + end = mmd->segments[i].seg_start; + } + + if (ELEM(mmd->segments[i].seg_mode, GP_TIME_SEG_MODE_PINGPONG)) { + sequence_length += ((end - start) * mmd->segments[i].seg_repeat) * 2 + 1; + } + else { + sequence_length += (((end - start + 1)) * mmd->segments[i].seg_repeat); + } + } + segment_arr = MEM_malloc_arrayN(sequence_length, sizeof(int *), __func__); + + for (int i = 0; i < mmd->segments_len; i++) { + + if (mmd->segments[i].seg_end < mmd->segments[i].seg_start) { + start = mmd->segments[i].seg_end; + end = mmd->segments[i].seg_start; + } + else { + start = mmd->segments[i].seg_start; + end = mmd->segments[i].seg_end; + } + for (int a = 0; a < mmd->segments[i].seg_repeat; a++) { + switch (mmd->segments[i].seg_mode) { + case GP_TIME_SEG_MODE_NORMAL: + for (int b = 0; b < end - start + 1; b++) { + segment_arr[frame_key] = start + b; + frame_key++; + } + break; + case GP_TIME_SEG_MODE_REVERSE: + for (int b = 0; b < end - start + 1; b++) { + segment_arr[frame_key] = end - b; + frame_key++; + } + break; + case GP_TIME_SEG_MODE_PINGPONG: + for (int b = 0; b < end - start; b++) { + segment_arr[frame_key] = start + b; + frame_key++; + } + for (int b = 0; b < end - start; b++) { + segment_arr[frame_key] = end - b; + frame_key++; + if (a == mmd->segments[i].seg_repeat - 1 && b == end - start - 1) { + segment_arr[frame_key] = start; + frame_key++; + } + } + break; + } + } + } + + if ((mmd->flag & GP_TIME_KEEP_LOOP) == 0) { + if ((cfra + offset - 1) < sequence_length) { + nfra = segment_arr[(cfra - 1 + offset)]; + } + else { + nfra = segment_arr[frame_key - 1]; + } + } + else { + nfra = segment_arr[(cfra - 1 + offset) % sequence_length]; + } + + MEM_freeN(segment_arr); + } + } + return nfra; } -static void panel_draw(const bContext *UNUSED(C), Panel *panel) +static void segment_list_item(struct uiList *UNUSED(ui_list), + struct bContext *UNUSED(C), + struct uiLayout *layout, + struct PointerRNA *UNUSED(idataptr), + struct PointerRNA *itemptr, + int UNUSED(icon), + struct PointerRNA *UNUSED(active_dataptr), + const char *UNUSED(active_propname), + int UNUSED(index), + int UNUSED(flt_flag)) +{ + uiLayout *row = uiLayoutRow(layout, true); + uiItemR(row, itemptr, "name", UI_ITEM_R_NO_BG, "", ICON_NONE); +} +static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData) +{ + TimeGpencilModifierData *mmd = (TimeGpencilModifierData *)md; + + walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER); +} +static void panel_draw(const bContext *C, Panel *panel) { uiLayout *row, *col; uiLayout *layout = panel->layout; @@ -175,6 +311,56 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetActive(row, mode != GP_TIME_MODE_FIX); uiItemR(row, ptr, "use_keep_loop", 0, NULL, ICON_NONE); + if (mode == GP_TIME_MODE_CHAIN) { + + uiLayout *row = uiLayoutRow(layout, false); + uiLayoutSetPropSep(row, false); + + uiTemplateList(row, + (bContext *)C, + "MOD_UL_time_segment", + "", + ptr, + "segments", + ptr, + "segment_active_index", + NULL, + 3, + 10, + 0, + 1, + UI_TEMPLATE_LIST_FLAG_NONE); + + uiLayout *col = uiLayoutColumn(row, false); + uiLayoutSetContextPointer(col, "modifier", ptr); + + uiLayout *sub = uiLayoutColumn(col, true); + uiItemO(sub, "", ICON_ADD, "GPENCIL_OT_time_segment_add"); + uiItemO(sub, "", ICON_REMOVE, "GPENCIL_OT_time_segment_remove"); + uiItemS(col); + sub = uiLayoutColumn(col, true); + uiItemEnumO_string(sub, "", ICON_TRIA_UP, "GPENCIL_OT_time_segment_move", "type", "UP"); + uiItemEnumO_string(sub, "", ICON_TRIA_DOWN, "GPENCIL_OT_time_segment_move", "type", "DOWN"); + + TimeGpencilModifierData *gpmd = ptr->data; + if (gpmd->segment_active_index >= 0 && gpmd->segment_active_index < gpmd->segments_len) { + PointerRNA ds_ptr; + RNA_pointer_create(ptr->owner_id, + &RNA_TimeGpencilModifierSegment, + &gpmd->segments[gpmd->segment_active_index], + &ds_ptr); + + sub = uiLayoutColumn(layout, true); + uiItemR(sub, &ds_ptr, "seg_mode", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(layout, true); + uiItemR(sub, &ds_ptr, "seg_start", 0, NULL, ICON_NONE); + uiItemR(sub, &ds_ptr, "seg_end", 0, NULL, ICON_NONE); + uiItemR(sub, &ds_ptr, "seg_repeat", 0, NULL, ICON_NONE); + } + + gpencil_modifier_panel_end(layout, ptr); + } + gpencil_modifier_panel_end(layout, ptr); } @@ -186,7 +372,7 @@ static void custom_range_header_draw(const bContext *UNUSED(C), Panel *panel) int mode = RNA_enum_get(ptr, "mode"); - uiLayoutSetActive(layout, mode != GP_TIME_MODE_FIX); + uiLayoutSetActive(layout, (mode != GP_TIME_MODE_FIX && mode != GP_TIME_MODE_CHAIN)); uiItemR(layout, ptr, "use_custom_frame_range", 0, NULL, ICON_NONE); } @@ -201,9 +387,9 @@ static void custom_range_panel_draw(const bContext *UNUSED(C), Panel *panel) int mode = RNA_enum_get(ptr, "mode"); uiLayoutSetPropSep(layout, true); - - uiLayoutSetActive( - layout, (mode != GP_TIME_MODE_FIX) && (RNA_boolean_get(ptr, "use_custom_frame_range"))); + uiLayoutSetActive(layout, + (mode != GP_TIME_MODE_FIX && mode != GP_TIME_MODE_CHAIN) && + (RNA_boolean_get(ptr, "use_custom_frame_range"))); col = uiLayoutColumn(layout, true); uiItemR(col, ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE); @@ -227,6 +413,11 @@ static void panelRegister(ARegionType *region_type) panel_type); gpencil_modifier_subpanel_register( region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type); + + uiListType *list_type = MEM_callocN(sizeof(uiListType), "time modifier segment uilist"); + strcpy(list_type->idname, "MOD_UL_time_segment"); + list_type->draw_item = segment_list_item; + WM_uilisttype_add(list_type); } GpencilModifierTypeInfo modifierType_Gpencil_Time = { @@ -244,11 +435,11 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = { /* remapTime */ remapTime, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, - /* foreachIDLink */ NULL, + /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ NULL, /* panelRegister */ panelRegister, }; |