Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleš Jelovčan <frogstomp>2022-09-27 18:47:01 +0300
committerAntonio Vazquez <blendergit@gmail.com>2022-09-27 18:55:43 +0300
commitb0d70a9c80402e8b7af173a76e9a8b6050598825 (patch)
treecc2d98fe527473e16052ab09adf6ed5615a07f61 /source/blender/gpencil_modifiers
parent12fdf9069abe3cd2250a9efec6e059eb85ec59d8 (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.c211
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,
};