GPv3: Build Modifer migration
Reimplemented build modifier using the new `CurvesGeometry` logic. Pull Request: https://projects.blender.org/blender/blender/pulls/118739
This commit is contained in:
parent
c250b4bd51
commit
3689dfca4f
|
@ -155,6 +155,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
||||||
self.operator_modifier_add(layout, 'WIREFRAME')
|
self.operator_modifier_add(layout, 'WIREFRAME')
|
||||||
if ob_type == 'GREASEPENCIL':
|
if ob_type == 'GREASEPENCIL':
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARRAY')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARRAY')
|
||||||
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_BUILD')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_DASH')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_DASH')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_ENVELOPE')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_ENVELOPE')
|
||||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_LENGTH')
|
self.operator_modifier_add(layout, 'GREASE_PENCIL_LENGTH')
|
||||||
|
|
|
@ -1737,6 +1737,97 @@ static void legacy_object_modifier_weight_lineart(Object &object, GpencilModifie
|
||||||
greasepencil::convert::lineart_wrap_v3(&legacy_md_lineart, &md_lineart);
|
greasepencil::convert::lineart_wrap_v3(&legacy_md_lineart, &md_lineart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void legacy_object_modifier_build(Object &object, GpencilModifierData &legacy_md)
|
||||||
|
{
|
||||||
|
ModifierData &md = legacy_object_modifier_common(
|
||||||
|
object, eModifierType_GreasePencilBuild, legacy_md);
|
||||||
|
auto &md_build = reinterpret_cast<GreasePencilBuildModifierData &>(md);
|
||||||
|
auto &legacy_md_build = reinterpret_cast<BuildGpencilModifierData &>(legacy_md);
|
||||||
|
|
||||||
|
md_build.flag = 0;
|
||||||
|
if (legacy_md_build.flag & GP_BUILD_RESTRICT_TIME) {
|
||||||
|
md_build.flag |= MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME;
|
||||||
|
}
|
||||||
|
if (legacy_md_build.flag & GP_BUILD_USE_FADING) {
|
||||||
|
md_build.flag |= MOD_GREASE_PENCIL_BUILD_USE_FADING;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (legacy_md_build.mode) {
|
||||||
|
case GP_BUILD_MODE_ADDITIVE:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_MODE_CONCURRENT:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_MODE_SEQUENTIAL:
|
||||||
|
default:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (legacy_md_build.time_alignment) {
|
||||||
|
default:
|
||||||
|
case GP_BUILD_TIMEALIGN_START:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_TIMEALIGN_END:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (legacy_md_build.time_mode) {
|
||||||
|
default:
|
||||||
|
case GP_BUILD_TIMEMODE_FRAMES:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_TIMEMODE_PERCENTAGE:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_TIMEMODE_DRAWSPEED:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (legacy_md_build.transition) {
|
||||||
|
default:
|
||||||
|
case GP_BUILD_TRANSITION_GROW:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_TRANSITION_SHRINK:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK;
|
||||||
|
break;
|
||||||
|
case GP_BUILD_TRANSITION_VANISH:
|
||||||
|
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
md_build.start_frame = legacy_md_build.start_frame;
|
||||||
|
md_build.end_frame = legacy_md_build.end_frame;
|
||||||
|
md_build.start_delay = legacy_md_build.start_delay;
|
||||||
|
md_build.length = legacy_md_build.length;
|
||||||
|
md_build.fade_fac = legacy_md_build.fade_fac;
|
||||||
|
md_build.fade_opacity_strength = legacy_md_build.fade_opacity_strength;
|
||||||
|
md_build.fade_thickness_strength = legacy_md_build.fade_thickness_strength;
|
||||||
|
md_build.percentage_fac = legacy_md_build.percentage_fac;
|
||||||
|
md_build.speed_fac = legacy_md_build.speed_fac;
|
||||||
|
md_build.speed_maxgap = legacy_md_build.speed_maxgap;
|
||||||
|
STRNCPY(md_build.target_vgname, legacy_md_build.target_vgname);
|
||||||
|
|
||||||
|
legacy_object_modifier_influence(md_build.influence,
|
||||||
|
legacy_md_build.layername,
|
||||||
|
legacy_md_build.layer_pass,
|
||||||
|
legacy_md_build.flag & GP_WEIGHT_INVERT_LAYER,
|
||||||
|
legacy_md_build.flag & GP_WEIGHT_INVERT_LAYERPASS,
|
||||||
|
&legacy_md_build.material,
|
||||||
|
legacy_md_build.pass_index,
|
||||||
|
legacy_md_build.flag & GP_WEIGHT_INVERT_MATERIAL,
|
||||||
|
legacy_md_build.flag & GP_WEIGHT_INVERT_PASS,
|
||||||
|
legacy_md_build.target_vgname,
|
||||||
|
legacy_md_build.flag & GP_WEIGHT_INVERT_VGROUP,
|
||||||
|
nullptr,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
||||||
{
|
{
|
||||||
BLI_assert(BLI_listbase_is_empty(&object.modifiers));
|
BLI_assert(BLI_listbase_is_empty(&object.modifiers));
|
||||||
|
@ -1818,6 +1909,8 @@ static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
||||||
legacy_object_modifier_weight_lineart(object, *gpd_md);
|
legacy_object_modifier_weight_lineart(object, *gpd_md);
|
||||||
break;
|
break;
|
||||||
case eGpencilModifierType_Build:
|
case eGpencilModifierType_Build:
|
||||||
|
legacy_object_modifier_build(object, *gpd_md);
|
||||||
|
break;
|
||||||
case eGpencilModifierType_Simplify:
|
case eGpencilModifierType_Simplify:
|
||||||
case eGpencilModifierType_Texture:
|
case eGpencilModifierType_Texture:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1044,4 +1044,22 @@
|
||||||
.smooth_step = 1, \
|
.smooth_step = 1, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Here we deliberately set effective range to the half the default
|
||||||
|
* frame-range to have an immediate effect to suggest use-cases. */
|
||||||
|
#define _DNA_DEFAULT_GreasePencilBuildModifierData \
|
||||||
|
{ \
|
||||||
|
.start_frame = 1, \
|
||||||
|
.end_frame = 125, \
|
||||||
|
.start_delay = 0.0f, \
|
||||||
|
.length = 100.0f, \
|
||||||
|
.flag = 0, \
|
||||||
|
.mode = 0, \
|
||||||
|
.transition = 0, \
|
||||||
|
.time_alignment = 0, \
|
||||||
|
.time_mode = 0, \
|
||||||
|
.speed_fac = 1.2f, \
|
||||||
|
.speed_maxgap = 0.5f, \
|
||||||
|
.percentage_fac = 0.0f, \
|
||||||
|
}
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
|
|
|
@ -118,6 +118,7 @@ typedef enum ModifierType {
|
||||||
eModifierType_GreasePencilEnvelope = 81,
|
eModifierType_GreasePencilEnvelope = 81,
|
||||||
eModifierType_GreasePencilOutline = 82,
|
eModifierType_GreasePencilOutline = 82,
|
||||||
eModifierType_GreasePencilShrinkwrap = 83,
|
eModifierType_GreasePencilShrinkwrap = 83,
|
||||||
|
eModifierType_GreasePencilBuild = 84,
|
||||||
NUM_MODIFIER_TYPES,
|
NUM_MODIFIER_TYPES,
|
||||||
} ModifierType;
|
} ModifierType;
|
||||||
|
|
||||||
|
@ -3310,3 +3311,96 @@ typedef struct GreasePencilShrinkwrapModifierData {
|
||||||
/** Runtime only. */
|
/** Runtime only. */
|
||||||
struct ShrinkwrapTreeData *cache_data;
|
struct ShrinkwrapTreeData *cache_data;
|
||||||
} GreasePencilShrinkwrapModifierData;
|
} GreasePencilShrinkwrapModifierData;
|
||||||
|
|
||||||
|
typedef struct GreasePencilBuildModifierData {
|
||||||
|
ModifierData modifier;
|
||||||
|
GreasePencilModifierInfluenceData influence;
|
||||||
|
/**
|
||||||
|
* If GP_BUILD_RESTRICT_TIME is set,
|
||||||
|
* the defines the frame range where GP frames are considered.
|
||||||
|
*/
|
||||||
|
float start_frame;
|
||||||
|
float end_frame;
|
||||||
|
|
||||||
|
/** Start time added on top of the drawing frame number */
|
||||||
|
float start_delay;
|
||||||
|
float length;
|
||||||
|
|
||||||
|
/** #GreasePencilBuildFlag. */
|
||||||
|
short flag;
|
||||||
|
|
||||||
|
/** #GreasePencilBuildMode. */
|
||||||
|
short mode;
|
||||||
|
/** #GreasePencilBuildTransition. */
|
||||||
|
short transition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* #GreasePencilBuildTimeAlignment.
|
||||||
|
* For the "Concurrent" mode, when should "shorter" strips start/end.
|
||||||
|
*/
|
||||||
|
short time_alignment;
|
||||||
|
|
||||||
|
/** Speed factor for #GP_BUILD_TIMEMODE_DRAWSPEED. */
|
||||||
|
float speed_fac;
|
||||||
|
/** Maximum time gap between strokes for #GP_BUILD_TIMEMODE_DRAWSPEED. */
|
||||||
|
float speed_maxgap;
|
||||||
|
/** GreasePencilBuildTimeMode. */
|
||||||
|
short time_mode;
|
||||||
|
char _pad[6];
|
||||||
|
|
||||||
|
/** Build origin control object. */
|
||||||
|
struct Object *object;
|
||||||
|
|
||||||
|
/** Factor of the stroke (used instead of frame evaluation). */
|
||||||
|
float percentage_fac;
|
||||||
|
|
||||||
|
/** Weight fading at the end of the stroke. */
|
||||||
|
float fade_fac;
|
||||||
|
/** Target vertex-group name, #MAX_VGROUP_NAME. */
|
||||||
|
char target_vgname[64];
|
||||||
|
/** Fading strength of opacity and thickness */
|
||||||
|
float fade_opacity_strength;
|
||||||
|
float fade_thickness_strength;
|
||||||
|
} GreasePencilBuildModifierData;
|
||||||
|
|
||||||
|
typedef enum GreasePencilBuildMode {
|
||||||
|
/* Strokes are shown one by one until all have appeared */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL = 0,
|
||||||
|
/* All strokes start at the same time */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT = 1,
|
||||||
|
/* Only the new strokes are built */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE = 2,
|
||||||
|
} GreasePencilBuildMode;
|
||||||
|
|
||||||
|
typedef enum GreasePencilBuildTransition {
|
||||||
|
/* Show in forward order */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW = 0,
|
||||||
|
/* Hide in reverse order */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK = 1,
|
||||||
|
/* Hide in forward order */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH = 2,
|
||||||
|
} GreasePencilBuildTransition;
|
||||||
|
|
||||||
|
typedef enum GreasePencilBuildTimeAlignment {
|
||||||
|
/* All strokes start at same time */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START = 0,
|
||||||
|
/* All strokes end at same time */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END = 1,
|
||||||
|
|
||||||
|
/* TODO: Random Offsets, Stretch-to-Fill */
|
||||||
|
} GreasePencilBuildTimeAlignment;
|
||||||
|
|
||||||
|
typedef enum GreasePencilBuildTimeMode {
|
||||||
|
/** Use a number of frames build. */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES = 0,
|
||||||
|
/** Use manual percentage to build. */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE = 1,
|
||||||
|
/** Use factor of recorded speed to build. */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED = 2,
|
||||||
|
} GreasePencilBuildTimeMode;
|
||||||
|
|
||||||
|
typedef enum GreasePencilBuildFlag {
|
||||||
|
/* Restrict modifier to only operating between the nominated frames */
|
||||||
|
MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME = (1 << 0),
|
||||||
|
MOD_GREASE_PENCIL_BUILD_USE_FADING = (1 << 14),
|
||||||
|
} GreasePencilBuildFlag;
|
||||||
|
|
|
@ -305,6 +305,7 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilSubdivModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilNoiseModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilNoiseModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLengthModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLengthModifierData);
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLineartModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLineartModifierData);
|
||||||
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilBuildModifierData);
|
||||||
|
|
||||||
/* Grease Pencil 3.0 modifiers. */
|
/* Grease Pencil 3.0 modifiers. */
|
||||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSmoothModifierData);
|
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSmoothModifierData);
|
||||||
|
@ -581,6 +582,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||||
SDNA_DEFAULT_DECL(GreasePencilLengthModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilLengthModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilHookModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilHookModifierData),
|
||||||
SDNA_DEFAULT_DECL(GreasePencilLineartModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilLineartModifierData),
|
||||||
|
SDNA_DEFAULT_DECL(GreasePencilBuildModifierData),
|
||||||
|
|
||||||
/* Grease Pencil 3.0 defaults. */
|
/* Grease Pencil 3.0 defaults. */
|
||||||
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),
|
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),
|
||||||
|
|
|
@ -234,6 +234,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
||||||
ICON_MOD_ARRAY,
|
ICON_MOD_ARRAY,
|
||||||
"Array strokes",
|
"Array strokes",
|
||||||
"Duplicate strokes into an array"},
|
"Duplicate strokes into an array"},
|
||||||
|
{eModifierType_GreasePencilBuild,
|
||||||
|
"GREASE_PENCIL_BUILD",
|
||||||
|
ICON_MOD_BUILD,
|
||||||
|
"Build",
|
||||||
|
"Grease Pencil build modifier"},
|
||||||
{eModifierType_GreasePencilLength,
|
{eModifierType_GreasePencilLength,
|
||||||
"GREASE_PENCIL_LENGTH",
|
"GREASE_PENCIL_LENGTH",
|
||||||
ICON_MOD_LENGTH,
|
ICON_MOD_LENGTH,
|
||||||
|
@ -784,6 +789,25 @@ const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[] = {
|
||||||
{0, nullptr, 0, nullptr, nullptr},
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const EnumPropertyItem grease_pencil_build_time_mode_items[] = {
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED,
|
||||||
|
"DRAWSPEED",
|
||||||
|
0,
|
||||||
|
"Natural Drawing Speed",
|
||||||
|
"Use recorded speed multiplied by a factor"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES,
|
||||||
|
"FRAMES",
|
||||||
|
0,
|
||||||
|
"Number of Frames",
|
||||||
|
"Set a fixed number of frames for all build animations"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE,
|
||||||
|
"PERCENTAGE",
|
||||||
|
0,
|
||||||
|
"Percentage Factor",
|
||||||
|
"Set a manual percentage to build"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef RNA_RUNTIME
|
#ifdef RNA_RUNTIME
|
||||||
|
|
||||||
# include <algorithm>
|
# include <algorithm>
|
||||||
|
@ -944,6 +968,7 @@ RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
|
||||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightAngle, target_vgname);
|
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightAngle, target_vgname);
|
||||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightProximity, target_vgname);
|
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightProximity, target_vgname);
|
||||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilLineart, vgname);
|
RNA_MOD_VGROUP_NAME_SET(GreasePencilLineart, vgname);
|
||||||
|
RNA_MOD_VGROUP_NAME_SET(GreasePencilBuild, target_vgname);
|
||||||
|
|
||||||
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
||||||
{
|
{
|
||||||
|
@ -1029,6 +1054,7 @@ RNA_MOD_OBJECT_SET(GreasePencilArmature, object, OB_ARMATURE);
|
||||||
RNA_MOD_OBJECT_SET(GreasePencilOutline, object, OB_EMPTY);
|
RNA_MOD_OBJECT_SET(GreasePencilOutline, object, OB_EMPTY);
|
||||||
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, target, OB_MESH);
|
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, target, OB_MESH);
|
||||||
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, aux_target, OB_MESH);
|
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, aux_target, OB_MESH);
|
||||||
|
RNA_MOD_OBJECT_SET(GreasePencilBuild, object, OB_EMPTY);
|
||||||
|
|
||||||
static void rna_HookModifier_object_set(PointerRNA *ptr,
|
static void rna_HookModifier_object_set(PointerRNA *ptr,
|
||||||
PointerRNA value,
|
PointerRNA value,
|
||||||
|
@ -1969,6 +1995,7 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilHook);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilEnvelope);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilEnvelope);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOutline);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOutline);
|
||||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilShrinkwrap);
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilShrinkwrap);
|
||||||
|
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilBuild);
|
||||||
|
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
|
||||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
|
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
|
||||||
|
@ -2089,6 +2116,35 @@ static void rna_GreasePencilDashModifier_segments_begin(CollectionPropertyIterat
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EnumPropertyItem *grease_pencil_build_time_mode_filter(bContext * /*C*/,
|
||||||
|
PointerRNA *ptr,
|
||||||
|
PropertyRNA * /*prop*/,
|
||||||
|
bool *r_free)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto *md = static_cast<ModifierData *>(ptr->data);
|
||||||
|
auto *mmd = reinterpret_cast<BuildGpencilModifierData *>(md);
|
||||||
|
const bool is_concurrent = (mmd->mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT);
|
||||||
|
|
||||||
|
EnumPropertyItem *item_list = nullptr;
|
||||||
|
int totitem = 0;
|
||||||
|
|
||||||
|
for (const EnumPropertyItem *item = grease_pencil_build_time_mode_items;
|
||||||
|
item->identifier != nullptr;
|
||||||
|
item++)
|
||||||
|
{
|
||||||
|
if (is_concurrent && (item->value == MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RNA_enum_item_add(&item_list, &totitem, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
RNA_enum_item_end(&item_list, &totitem);
|
||||||
|
*r_free = true;
|
||||||
|
|
||||||
|
return item_list;
|
||||||
|
}
|
||||||
|
|
||||||
static const GreasePencilTimeModifierData *find_grease_pencil_time_modifier_of_segment(
|
static const GreasePencilTimeModifierData *find_grease_pencil_time_modifier_of_segment(
|
||||||
const Object &ob, const GreasePencilTimeModifierSegment &time_segment)
|
const Object &ob, const GreasePencilTimeModifierSegment &time_segment)
|
||||||
{
|
{
|
||||||
|
@ -10444,6 +10500,217 @@ static void rna_def_modifier_grease_pencil_shrinkwrap(BlenderRNA *brna)
|
||||||
RNA_define_lib_overridable(false);
|
RNA_define_lib_overridable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_def_modifier_grease_pencil_build(BlenderRNA *brna)
|
||||||
|
{
|
||||||
|
static EnumPropertyItem prop_gpencil_build_mode_items[] = {
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL,
|
||||||
|
"SEQUENTIAL",
|
||||||
|
0,
|
||||||
|
"Sequential",
|
||||||
|
"Strokes appear/disappear one after the other, but only a single one changes at a time"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT,
|
||||||
|
"CONCURRENT",
|
||||||
|
0,
|
||||||
|
"Concurrent",
|
||||||
|
"Multiple strokes appear/disappear at once"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE,
|
||||||
|
"ADDITIVE",
|
||||||
|
0,
|
||||||
|
"Additive",
|
||||||
|
"Builds only new strokes (assuming 'additive' drawing)"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
static EnumPropertyItem prop_gpencil_build_transition_items[] = {
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW,
|
||||||
|
"GROW",
|
||||||
|
0,
|
||||||
|
"Grow",
|
||||||
|
"Show points in the order they occur in each stroke "
|
||||||
|
"(e.g. for animating lines being drawn)"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK,
|
||||||
|
"SHRINK",
|
||||||
|
0,
|
||||||
|
"Shrink",
|
||||||
|
"Hide points from the end of each stroke to the start "
|
||||||
|
"(e.g. for animating lines being erased)"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH,
|
||||||
|
"FADE", /* "Fade" is the original id string kept for compatibility purpose. */
|
||||||
|
0,
|
||||||
|
"Vanish",
|
||||||
|
"Hide points in the order they occur in each stroke "
|
||||||
|
"(e.g. for animating ink fading or vanishing after getting drawn)"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
static EnumPropertyItem prop_gpencil_build_time_align_items[] = {
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START,
|
||||||
|
"START",
|
||||||
|
0,
|
||||||
|
"Align Start",
|
||||||
|
"All strokes start at same time (i.e. short strokes finish earlier)"},
|
||||||
|
{MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END,
|
||||||
|
"END",
|
||||||
|
0,
|
||||||
|
"Align End",
|
||||||
|
"All strokes end at same time (i.e. short strokes start later)"},
|
||||||
|
{0, nullptr, 0, nullptr, nullptr},
|
||||||
|
};
|
||||||
|
|
||||||
|
StructRNA *srna;
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
srna = RNA_def_struct(brna, "GreasePencilBuildModifier", "Modifier");
|
||||||
|
RNA_def_struct_ui_text(srna, "Build Modifier", "Animate strokes appearing and disappearing");
|
||||||
|
RNA_def_struct_sdna(srna, "GreasePencilBuildModifierData");
|
||||||
|
RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
|
||||||
|
|
||||||
|
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||||
|
rna_def_modifier_grease_pencil_material_filter(
|
||||||
|
srna, "rna_GreasePencilBuildModifier_material_filter_set");
|
||||||
|
|
||||||
|
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
|
||||||
|
rna_def_modifier_panel_open_prop(srna, "open_frame_range_panel", 1);
|
||||||
|
rna_def_modifier_panel_open_prop(srna, "open_fading_panel", 2);
|
||||||
|
|
||||||
|
RNA_define_lib_overridable(true);
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, prop_gpencil_build_mode_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Mode", "How strokes are being built");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "transition", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_items(prop, prop_gpencil_build_transition_items);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Transition", "How are strokes animated (i.e. are they appearing or disappearing)");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "start_delay", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "start_delay");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Delay", "Number of frames after each GP keyframe before the modifier has any effect");
|
||||||
|
RNA_def_property_range(prop, 0, MAXFRAMEF);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 200, 1, -1);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "length");
|
||||||
|
RNA_def_property_ui_text(prop,
|
||||||
|
"Length",
|
||||||
|
"Maximum number of frames that the build effect can run for "
|
||||||
|
"(unless another GP keyframe occurs before this time has elapsed)");
|
||||||
|
RNA_def_property_range(prop, 1, MAXFRAMEF);
|
||||||
|
RNA_def_property_ui_range(prop, 1, 1000, 1, -1);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "concurrent_time_alignment", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_sdna(prop, nullptr, "time_alignment");
|
||||||
|
RNA_def_property_enum_items(prop, prop_gpencil_build_time_align_items);
|
||||||
|
RNA_def_property_ui_text(prop, "Time Alignment", "How should strokes start to appear/disappear");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "time_mode", PROP_ENUM, PROP_NONE);
|
||||||
|
RNA_def_property_enum_sdna(prop, nullptr, "time_mode");
|
||||||
|
RNA_def_property_enum_items(prop, grease_pencil_build_time_mode_items);
|
||||||
|
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "grease_pencil_build_time_mode_filter");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop,
|
||||||
|
"Timing",
|
||||||
|
"Use drawing speed, a number of frames, or a manual factor to build strokes");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* Speed factor for MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED. */
|
||||||
|
/* Todo: Does it work? */
|
||||||
|
prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "speed_fac");
|
||||||
|
RNA_def_property_ui_text(prop, "Speed Factor", "Multiply recorded drawing speed by a factor");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 5, 0.001, -1);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* Max gap in seconds between strokes for MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED. */
|
||||||
|
prop = RNA_def_property(srna, "speed_maxgap", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "speed_maxgap");
|
||||||
|
RNA_def_property_ui_text(prop, "Maximum Gap", "The maximum gap between strokes in seconds");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||||
|
RNA_def_property_ui_range(prop, 0, 4, 0.01, -1);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_restrict_frame_range", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Restrict Frame Range", "Only modify strokes during the specified frame range");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
/* Use percentage bool (used by sequential & concurrent modes) */
|
||||||
|
prop = RNA_def_property(srna, "use_percentage", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(
|
||||||
|
prop, nullptr, "time_mode", MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Restrict Visible Points", "Use a percentage factor to determine the visible points");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
prop = RNA_def_property(srna, "percentage_factor", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "percentage_fac");
|
||||||
|
RNA_def_property_ui_text(prop, "Factor", "Defines how much of the stroke is visible");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "start_frame");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Start Frame", "Start Frame (when Restrict Frame Range is enabled)");
|
||||||
|
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "end_frame");
|
||||||
|
RNA_def_property_ui_text(prop, "End Frame", "End Frame (when Restrict Frame Range is enabled)");
|
||||||
|
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_fading", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_BUILD_USE_FADING);
|
||||||
|
RNA_def_property_ui_text(prop, "Use Fading", "Fade out strokes instead of directly cutting off");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "fade_factor", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "fade_fac");
|
||||||
|
RNA_def_property_ui_text(prop, "Fade Factor", "Defines how much of the stroke is fading in/out");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "target_vertex_group", PROP_STRING, PROP_NONE);
|
||||||
|
RNA_def_property_string_sdna(prop, nullptr, "target_vgname");
|
||||||
|
RNA_def_property_ui_text(prop, "Vertex Group", "Output Vertex group");
|
||||||
|
RNA_def_property_string_funcs(
|
||||||
|
prop, nullptr, nullptr, "rna_GreasePencilBuildModifier_target_vgname_set");
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "fade_opacity_strength", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "fade_opacity_strength");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Opacity Strength", "How much strength fading applies on top of stroke opacity");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "fade_thickness_strength", PROP_FLOAT, PROP_FACTOR);
|
||||||
|
RNA_def_property_float_sdna(prop, nullptr, "fade_thickness_strength");
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Thickness Strength", "How much strength fading applies on top of stroke thickness");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||||
|
RNA_def_property_ui_text(prop, "Object", "Object used as build starting position");
|
||||||
|
RNA_def_property_pointer_funcs(
|
||||||
|
prop, nullptr, "rna_GreasePencilBuildModifier_object_set", nullptr, nullptr);
|
||||||
|
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||||
|
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
|
||||||
|
|
||||||
|
RNA_define_lib_overridable(false);
|
||||||
|
}
|
||||||
|
|
||||||
void RNA_def_modifier(BlenderRNA *brna)
|
void RNA_def_modifier(BlenderRNA *brna)
|
||||||
{
|
{
|
||||||
StructRNA *srna;
|
StructRNA *srna;
|
||||||
|
@ -10636,6 +10903,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
||||||
rna_def_modifier_grease_pencil_envelope(brna);
|
rna_def_modifier_grease_pencil_envelope(brna);
|
||||||
rna_def_modifier_grease_pencil_outline(brna);
|
rna_def_modifier_grease_pencil_outline(brna);
|
||||||
rna_def_modifier_grease_pencil_shrinkwrap(brna);
|
rna_def_modifier_grease_pencil_shrinkwrap(brna);
|
||||||
|
rna_def_modifier_grease_pencil_build(brna);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,6 +51,7 @@ set(SRC
|
||||||
intern/MOD_fluid.cc
|
intern/MOD_fluid.cc
|
||||||
intern/MOD_grease_pencil_armature.cc
|
intern/MOD_grease_pencil_armature.cc
|
||||||
intern/MOD_grease_pencil_array.cc
|
intern/MOD_grease_pencil_array.cc
|
||||||
|
intern/MOD_grease_pencil_build.cc
|
||||||
intern/MOD_grease_pencil_color.cc
|
intern/MOD_grease_pencil_color.cc
|
||||||
intern/MOD_grease_pencil_dash.cc
|
intern/MOD_grease_pencil_dash.cc
|
||||||
intern/MOD_grease_pencil_envelope.cc
|
intern/MOD_grease_pencil_envelope.cc
|
||||||
|
|
|
@ -96,6 +96,7 @@ extern ModifierTypeInfo modifierType_GreasePencilTime;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilEnvelope;
|
extern ModifierTypeInfo modifierType_GreasePencilEnvelope;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilOutline;
|
extern ModifierTypeInfo modifierType_GreasePencilOutline;
|
||||||
extern ModifierTypeInfo modifierType_GreasePencilShrinkwrap;
|
extern ModifierTypeInfo modifierType_GreasePencilShrinkwrap;
|
||||||
|
extern ModifierTypeInfo modifierType_GreasePencilBuild;
|
||||||
|
|
||||||
/* MOD_util.cc */
|
/* MOD_util.cc */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,801 @@
|
||||||
|
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup modifiers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BLI_array.hh"
|
||||||
|
#include "BLI_hash.h"
|
||||||
|
#include "BLI_rand.h"
|
||||||
|
#include "BLI_sort.hh"
|
||||||
|
#include "BLI_task.h"
|
||||||
|
|
||||||
|
#include "BLT_translation.hh"
|
||||||
|
|
||||||
|
#include "BLO_read_write.hh"
|
||||||
|
|
||||||
|
#include "DNA_defaults.h"
|
||||||
|
#include "DNA_gpencil_modifier_types.h"
|
||||||
|
#include "DNA_object_types.h"
|
||||||
|
#include "DNA_scene_types.h"
|
||||||
|
|
||||||
|
#include "DEG_depsgraph_query.hh"
|
||||||
|
|
||||||
|
#include "BKE_curves.hh"
|
||||||
|
#include "BKE_geometry_set.hh"
|
||||||
|
#include "BKE_grease_pencil.hh"
|
||||||
|
#include "BKE_lib_query.hh"
|
||||||
|
#include "BKE_modifier.hh"
|
||||||
|
|
||||||
|
#include "UI_interface.hh"
|
||||||
|
#include "UI_resources.hh"
|
||||||
|
|
||||||
|
#include "MOD_grease_pencil_util.hh"
|
||||||
|
#include "MOD_modifiertypes.hh"
|
||||||
|
#include "MOD_ui_common.hh"
|
||||||
|
|
||||||
|
#include "RNA_access.hh"
|
||||||
|
#include "RNA_prototypes.h"
|
||||||
|
|
||||||
|
#include "GEO_reorder.hh"
|
||||||
|
|
||||||
|
namespace blender {
|
||||||
|
|
||||||
|
static void init_data(ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *gpmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
|
||||||
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
|
||||||
|
|
||||||
|
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(GreasePencilBuildModifierData), modifier);
|
||||||
|
modifier::greasepencil::init_influence_data(&gpmd->influence, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void copy_data(const ModifierData *md, ModifierData *target, int flags)
|
||||||
|
{
|
||||||
|
const auto *omd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
|
||||||
|
auto *tomd = reinterpret_cast<GreasePencilBuildModifierData *>(target);
|
||||||
|
|
||||||
|
modifier::greasepencil::free_influence_data(&tomd->influence);
|
||||||
|
|
||||||
|
BKE_modifier_copydata_generic(md, target, flags);
|
||||||
|
modifier::greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_data(ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
modifier::greasepencil::free_influence_data(&omd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||||
|
{
|
||||||
|
auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
modifier::greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
|
||||||
|
{
|
||||||
|
auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
if (mmd->object != nullptr) {
|
||||||
|
DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
|
||||||
|
}
|
||||||
|
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
||||||
|
{
|
||||||
|
const auto *mmd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
|
||||||
|
|
||||||
|
BLO_write_struct(writer, GreasePencilBuildModifierData, mmd);
|
||||||
|
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||||
|
{
|
||||||
|
auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
|
||||||
|
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Array<int> point_counts_to_keep_concurrent(const bke::CurvesGeometry &curves,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const int time_alignment,
|
||||||
|
const int transition,
|
||||||
|
const float factor,
|
||||||
|
const bool clamp_points,
|
||||||
|
int &r_curves_num,
|
||||||
|
int &r_points_num)
|
||||||
|
{
|
||||||
|
const int stroke_count = curves.curves_num();
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
|
||||||
|
curves.ensure_evaluated_lengths();
|
||||||
|
float max_length = 0;
|
||||||
|
for (const int stroke : curves.curves_range()) {
|
||||||
|
const float len = curves.evaluated_length_total_for_curve(stroke, false);
|
||||||
|
max_length = math::max(max_length, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
|
||||||
|
1.0f - factor;
|
||||||
|
if (clamp_points) {
|
||||||
|
r_curves_num = r_points_num = 0;
|
||||||
|
factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get_stroke_factor = [&](const float factor, const int index) {
|
||||||
|
const float max_factor = max_length / curves.evaluated_length_total_for_curve(index, false);
|
||||||
|
if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START) {
|
||||||
|
if (clamp_points) {
|
||||||
|
return std::clamp(factor * max_factor, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
return factor * max_factor;
|
||||||
|
}
|
||||||
|
if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END) {
|
||||||
|
const float min_factor = max_factor - 1.0f;
|
||||||
|
const float use_factor = factor * max_factor;
|
||||||
|
if (clamp_points) {
|
||||||
|
return std::clamp(use_factor - min_factor, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
return use_factor - min_factor;
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array<bool> select(stroke_count);
|
||||||
|
selection.to_bools(select.as_mutable_span());
|
||||||
|
Array<int> result(stroke_count);
|
||||||
|
for (const int curve : curves.curves_range()) {
|
||||||
|
const float local_factor = select[curve] ? get_stroke_factor(factor_to_keep, curve) : 1.0f;
|
||||||
|
const int num_points = points_by_curve[curve].size() * local_factor;
|
||||||
|
result[curve] = num_points;
|
||||||
|
if (clamp_points) {
|
||||||
|
r_points_num += num_points;
|
||||||
|
if (num_points > 0) {
|
||||||
|
r_curves_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bke::CurvesGeometry build_concurrent(bke::greasepencil::Drawing &drawing,
|
||||||
|
bke::CurvesGeometry &curves,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const int time_alignment,
|
||||||
|
const int transition,
|
||||||
|
const float factor,
|
||||||
|
const float factor_start,
|
||||||
|
const float factor_opacity,
|
||||||
|
const float factor_radii,
|
||||||
|
StringRefNull target_vgname)
|
||||||
|
{
|
||||||
|
int dst_curves_num, dst_points_num;
|
||||||
|
const bool has_fade = factor_start != factor;
|
||||||
|
const Array<int> point_counts_to_keep = point_counts_to_keep_concurrent(
|
||||||
|
curves, selection, time_alignment, transition, factor, true, dst_curves_num, dst_points_num);
|
||||||
|
if (dst_curves_num == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const Array<int> starts_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
|
||||||
|
selection,
|
||||||
|
time_alignment,
|
||||||
|
transition,
|
||||||
|
factor_start,
|
||||||
|
false,
|
||||||
|
dst_curves_num,
|
||||||
|
dst_points_num) :
|
||||||
|
Array<int>(0);
|
||||||
|
const Array<int> ends_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
|
||||||
|
selection,
|
||||||
|
time_alignment,
|
||||||
|
transition,
|
||||||
|
factor,
|
||||||
|
false,
|
||||||
|
dst_curves_num,
|
||||||
|
dst_points_num) :
|
||||||
|
Array<int>(0);
|
||||||
|
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
MutableSpan<float> opacities = drawing.opacities_for_write();
|
||||||
|
MutableSpan<float> radii = drawing.radii_for_write();
|
||||||
|
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||||
|
bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
|
||||||
|
|
||||||
|
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||||
|
|
||||||
|
bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
|
||||||
|
Array<int> dst_to_src_point(dst_points_num);
|
||||||
|
Array<int> dst_to_src_curve(dst_curves_num);
|
||||||
|
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||||
|
dst_offsets[0] = 0;
|
||||||
|
|
||||||
|
int next_curve = 0;
|
||||||
|
int next_point = 0;
|
||||||
|
for (const int curve : curves.curves_range()) {
|
||||||
|
if (!point_counts_to_keep[curve]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const IndexRange points = points_by_curve[curve];
|
||||||
|
dst_offsets[next_curve] = point_counts_to_keep[curve];
|
||||||
|
const int curve_size = points.size();
|
||||||
|
|
||||||
|
auto get_fade_weight = [&](const int local_index) {
|
||||||
|
const float fade_range = std::abs(ends_per_curve[curve] - starts_per_curve[curve]);
|
||||||
|
if (is_vanishing) {
|
||||||
|
const float factor_from_start = local_index - curve_size + ends_per_curve[curve];
|
||||||
|
return 1.0f - std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
const float factor_from_start = local_index - starts_per_curve[curve];
|
||||||
|
return std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
const int extra_offset = is_vanishing ? points.size() - point_counts_to_keep[curve] : 0;
|
||||||
|
for (const int stroke_point : IndexRange(point_counts_to_keep[curve])) {
|
||||||
|
const int src_point_index = points.first() + extra_offset + stroke_point;
|
||||||
|
if (has_fade) {
|
||||||
|
const float fade_weight = get_fade_weight(extra_offset + stroke_point);
|
||||||
|
opacities[src_point_index] = opacities[src_point_index] *
|
||||||
|
(1.0f - fade_weight * factor_opacity);
|
||||||
|
radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
|
||||||
|
if (!weights.span.is_empty()) {
|
||||||
|
weights.span[src_point_index] = fade_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_to_src_point[next_point] = src_point_index;
|
||||||
|
next_point++;
|
||||||
|
}
|
||||||
|
dst_to_src_curve[next_curve] = curve;
|
||||||
|
next_curve++;
|
||||||
|
}
|
||||||
|
weights.finish();
|
||||||
|
|
||||||
|
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||||
|
|
||||||
|
const bke::AttributeAccessor src_attributes = curves.attributes();
|
||||||
|
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||||
|
|
||||||
|
gather_attributes(
|
||||||
|
src_attributes, bke::AttrDomain::Point, {}, {}, dst_to_src_point, dst_attributes);
|
||||||
|
gather_attributes(
|
||||||
|
src_attributes, bke::AttrDomain::Curve, {}, {}, dst_to_src_curve, dst_attributes);
|
||||||
|
|
||||||
|
dst_curves.update_curve_types();
|
||||||
|
|
||||||
|
return dst_curves;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void points_info_sequential(const bke::CurvesGeometry &curves,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const int transition,
|
||||||
|
const float factor,
|
||||||
|
const bool clamp_points,
|
||||||
|
int &r_curves_num,
|
||||||
|
int &r_points_num)
|
||||||
|
{
|
||||||
|
const int stroke_count = curves.curves_num();
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
|
||||||
|
float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
|
||||||
|
(1.0f - factor);
|
||||||
|
if (clamp_points) {
|
||||||
|
factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||||
|
|
||||||
|
int effective_points_num = 0;
|
||||||
|
selection.foreach_index(
|
||||||
|
[&](const int index) { effective_points_num += points_by_curve[index].size(); });
|
||||||
|
|
||||||
|
const int untouched_points_num = points_by_curve.total_size() - effective_points_num;
|
||||||
|
effective_points_num *= factor_to_keep;
|
||||||
|
effective_points_num += untouched_points_num;
|
||||||
|
|
||||||
|
r_points_num = effective_points_num;
|
||||||
|
r_curves_num = 0;
|
||||||
|
|
||||||
|
Array<bool> select(stroke_count);
|
||||||
|
selection.to_bools(select.as_mutable_span());
|
||||||
|
|
||||||
|
int counted_points_num = 0;
|
||||||
|
for (const int i : curves.curves_range()) {
|
||||||
|
const int stroke = is_vanishing ? stroke_count - i - 1 : i;
|
||||||
|
if (select[stroke] && counted_points_num >= effective_points_num) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
counted_points_num += points_by_curve[stroke].size();
|
||||||
|
r_curves_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bke::CurvesGeometry build_sequential(bke::greasepencil::Drawing &drawing,
|
||||||
|
bke::CurvesGeometry &curves,
|
||||||
|
const IndexMask &selection,
|
||||||
|
const int transition,
|
||||||
|
const float factor,
|
||||||
|
const float factor_start,
|
||||||
|
const float factor_opacity,
|
||||||
|
const float factor_radii,
|
||||||
|
StringRefNull target_vgname)
|
||||||
|
{
|
||||||
|
const bool has_fade = factor_start != factor;
|
||||||
|
int dst_curves_num, dst_points_num;
|
||||||
|
int start_points_num, end_points_num, dummy_curves_num;
|
||||||
|
points_info_sequential(
|
||||||
|
curves, selection, transition, factor, true, dst_curves_num, dst_points_num);
|
||||||
|
|
||||||
|
if (dst_curves_num == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
points_info_sequential(
|
||||||
|
curves, selection, transition, factor_start, false, dummy_curves_num, start_points_num);
|
||||||
|
points_info_sequential(
|
||||||
|
curves, selection, transition, factor, false, dummy_curves_num, end_points_num);
|
||||||
|
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
MutableSpan<float> opacities = drawing.opacities_for_write();
|
||||||
|
MutableSpan<float> radii = drawing.radii_for_write();
|
||||||
|
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||||
|
bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
|
||||||
|
|
||||||
|
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||||
|
|
||||||
|
bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
|
||||||
|
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||||
|
Array<int> dst_to_src_point(dst_points_num);
|
||||||
|
Array<int> dst_to_src_curve(dst_curves_num);
|
||||||
|
|
||||||
|
dst_offsets[0] = 0;
|
||||||
|
|
||||||
|
int next_curve = 1, next_point = 0;
|
||||||
|
IndexMaskMemory memory;
|
||||||
|
selection.complement(curves.curves_range(), memory).foreach_index([&](const int stroke) {
|
||||||
|
for (const int point : points_by_curve[stroke]) {
|
||||||
|
dst_to_src_point[next_point] = point;
|
||||||
|
next_point++;
|
||||||
|
}
|
||||||
|
dst_offsets[next_curve] = next_point;
|
||||||
|
next_curve++;
|
||||||
|
});
|
||||||
|
|
||||||
|
const int stroke_count = curves.curves_num();
|
||||||
|
bool done_scanning = false;
|
||||||
|
selection.foreach_index([&](const int i) {
|
||||||
|
const int stroke = is_vanishing ? stroke_count - i - 1 : i;
|
||||||
|
if (done_scanning || next_point >= dst_points_num) {
|
||||||
|
done_scanning = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get_fade_weight = [&](const int next_point_count) {
|
||||||
|
return std::clamp(float(next_point_count - start_points_num) /
|
||||||
|
float(abs(end_points_num - start_points_num)),
|
||||||
|
0.0f,
|
||||||
|
1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
const IndexRange points = points_by_curve[stroke];
|
||||||
|
for (const int point : points) {
|
||||||
|
const int local_index = point - points.first();
|
||||||
|
const int src_point_index = is_vanishing ? points.last() - local_index : point;
|
||||||
|
dst_to_src_point[next_point] = src_point_index;
|
||||||
|
|
||||||
|
if (has_fade) {
|
||||||
|
const float fade_weight = get_fade_weight(next_point);
|
||||||
|
opacities[src_point_index] = opacities[src_point_index] *
|
||||||
|
(1.0f - fade_weight * factor_opacity);
|
||||||
|
radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
|
||||||
|
if (!weights.span.is_empty()) {
|
||||||
|
weights.span[src_point_index] = fade_weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_point++;
|
||||||
|
if (next_point >= dst_points_num) {
|
||||||
|
done_scanning = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dst_offsets[next_curve] = next_point;
|
||||||
|
dst_to_src_curve[next_curve - 1] = i;
|
||||||
|
next_curve++;
|
||||||
|
});
|
||||||
|
weights.finish();
|
||||||
|
|
||||||
|
BLI_assert(next_curve == (dst_curves_num + 1));
|
||||||
|
BLI_assert(next_point == dst_points_num);
|
||||||
|
|
||||||
|
const bke::AttributeAccessor src_attributes = curves.attributes();
|
||||||
|
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||||
|
|
||||||
|
gather_attributes(
|
||||||
|
src_attributes, bke::AttrDomain::Point, {}, {}, dst_to_src_point, dst_attributes);
|
||||||
|
gather_attributes(
|
||||||
|
src_attributes, bke::AttrDomain::Curve, {}, {}, dst_to_src_curve, dst_attributes);
|
||||||
|
|
||||||
|
dst_curves.update_curve_types();
|
||||||
|
|
||||||
|
return dst_curves;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bke::CurvesGeometry reorder_strokes(const bke::CurvesGeometry &curves,
|
||||||
|
const Span<bool> select,
|
||||||
|
const Object &object,
|
||||||
|
MutableSpan<bool> r_selection)
|
||||||
|
{
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
const Span<float3> positions = curves.positions();
|
||||||
|
const float3 center = object.object_to_world().location();
|
||||||
|
|
||||||
|
struct Pair {
|
||||||
|
float value;
|
||||||
|
int index;
|
||||||
|
bool selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array<Pair> distances(curves.curves_num());
|
||||||
|
for (const int stroke : curves.curves_range()) {
|
||||||
|
const IndexRange points = points_by_curve[stroke];
|
||||||
|
const float3 p1 = positions[points.first()];
|
||||||
|
const float3 p2 = positions[points.last()];
|
||||||
|
distances[stroke].value = math::max(math::distance(p1, center), math::distance(p2, center));
|
||||||
|
distances[stroke].index = stroke;
|
||||||
|
distances[stroke].selected = select[stroke];
|
||||||
|
}
|
||||||
|
|
||||||
|
parallel_sort(
|
||||||
|
distances.begin(), distances.end(), [](Pair &a, Pair &b) { return a.value < b.value; });
|
||||||
|
|
||||||
|
Array<int> new_order(curves.curves_num());
|
||||||
|
for (const int i : curves.curves_range()) {
|
||||||
|
new_order[i] = distances[i].index;
|
||||||
|
r_selection[i] = distances[i].selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
return geometry::reorder_curves_geometry(curves, new_order.as_span(), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
static float get_factor_from_draw_speed(const bke::CurvesGeometry &curves,
|
||||||
|
const float time_elapsed,
|
||||||
|
const float speed_fac,
|
||||||
|
const float max_gap)
|
||||||
|
{
|
||||||
|
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||||
|
const bke::AttributeAccessor attributes = curves.attributes();
|
||||||
|
const VArray<float> init_times =
|
||||||
|
attributes.lookup_or_default<float>("init_time", bke::AttrDomain::Curve, 0.0f).varray;
|
||||||
|
const VArray<float> delta_times =
|
||||||
|
attributes.lookup_or_default<float>("delta_time", bke::AttrDomain::Point, 0.0f).varray;
|
||||||
|
|
||||||
|
Array<float> times(curves.points_num());
|
||||||
|
float current_time = 0;
|
||||||
|
float previous_init_time = init_times[0];
|
||||||
|
for (const int curve : curves.curves_range()) {
|
||||||
|
if (curve > 0) {
|
||||||
|
current_time += math::max(init_times[curve] - previous_init_time, max_gap);
|
||||||
|
previous_init_time = init_times[curve];
|
||||||
|
}
|
||||||
|
for (const int point : points_by_curve[curve]) {
|
||||||
|
current_time += delta_times[point];
|
||||||
|
times[point] = current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const int point : curves.points_range()) {
|
||||||
|
const float limit = time_elapsed * speed_fac;
|
||||||
|
if (times[point] >= limit) {
|
||||||
|
return math::clamp(float(point) / float(curves.points_num()), 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float get_build_factor(const GreasePencilBuildTimeMode time_mode,
|
||||||
|
const int current_frame,
|
||||||
|
const int start_frame,
|
||||||
|
const int length,
|
||||||
|
const float percentage,
|
||||||
|
const bke::CurvesGeometry &curves,
|
||||||
|
const float scene_fps,
|
||||||
|
const float speed_fac,
|
||||||
|
const float max_gap,
|
||||||
|
const float fade)
|
||||||
|
{
|
||||||
|
switch (time_mode) {
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES:
|
||||||
|
return math::clamp(float(current_frame - start_frame) / length, 0.0f, 1.0f) * (1.0f + fade);
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE:
|
||||||
|
return percentage * (1.0f + fade);
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED:
|
||||||
|
return get_factor_from_draw_speed(
|
||||||
|
curves, float(current_frame) / scene_fps, speed_fac, max_gap) *
|
||||||
|
(1.0f + fade);
|
||||||
|
}
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build_drawing(const GreasePencilBuildModifierData &mmd,
|
||||||
|
const Object &ob,
|
||||||
|
bke::greasepencil::Drawing &drawing,
|
||||||
|
const bke::greasepencil::Drawing *previous_drawing,
|
||||||
|
const int current_time,
|
||||||
|
const float scene_fps)
|
||||||
|
{
|
||||||
|
bke::CurvesGeometry &curves = drawing.strokes_for_write();
|
||||||
|
|
||||||
|
if (curves.points_num() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexMaskMemory memory;
|
||||||
|
IndexMask selection = modifier::greasepencil::get_filtered_stroke_mask(
|
||||||
|
&ob, curves, mmd.influence, memory);
|
||||||
|
|
||||||
|
/* Remove a count of #prev_strokes. */
|
||||||
|
if (mmd.mode == MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE && previous_drawing != nullptr) {
|
||||||
|
const bke::CurvesGeometry &prev_curves = previous_drawing->strokes();
|
||||||
|
const int prev_strokes = prev_curves.curves_num();
|
||||||
|
const int added_strokes = curves.curves_num() - prev_strokes;
|
||||||
|
if (added_strokes > 0) {
|
||||||
|
Array<bool> work_on_select(curves.curves_num());
|
||||||
|
selection.to_bools(work_on_select.as_mutable_span());
|
||||||
|
work_on_select.as_mutable_span().take_front(prev_strokes).fill(false);
|
||||||
|
selection = IndexMask::from_bools(work_on_select, memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mmd.object) {
|
||||||
|
const int curves_num = curves.curves_num();
|
||||||
|
Array<bool> select(curves_num), reordered_select(curves_num);
|
||||||
|
selection.to_bools(select);
|
||||||
|
curves = reorder_strokes(
|
||||||
|
curves, select.as_span(), *mmd.object, reordered_select.as_mutable_span());
|
||||||
|
selection = IndexMask::from_bools(reordered_select, memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float fade_factor = ((mmd.flag & MOD_GREASE_PENCIL_BUILD_USE_FADING) != 0) ? mmd.fade_fac :
|
||||||
|
0.0f;
|
||||||
|
float factor = get_build_factor(GreasePencilBuildTimeMode(mmd.time_mode),
|
||||||
|
current_time,
|
||||||
|
mmd.start_delay,
|
||||||
|
mmd.length,
|
||||||
|
mmd.percentage_fac,
|
||||||
|
curves,
|
||||||
|
scene_fps,
|
||||||
|
mmd.speed_fac,
|
||||||
|
mmd.speed_maxgap,
|
||||||
|
fade_factor);
|
||||||
|
float factor_start = factor - fade_factor;
|
||||||
|
if (mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW) {
|
||||||
|
std::swap(factor, factor_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float use_time_alignment = mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ?
|
||||||
|
!mmd.time_alignment :
|
||||||
|
mmd.time_alignment;
|
||||||
|
switch (mmd.mode) {
|
||||||
|
default:
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL:
|
||||||
|
curves = build_sequential(drawing,
|
||||||
|
curves,
|
||||||
|
selection,
|
||||||
|
mmd.transition,
|
||||||
|
factor,
|
||||||
|
factor_start,
|
||||||
|
mmd.fade_opacity_strength,
|
||||||
|
mmd.fade_thickness_strength,
|
||||||
|
mmd.target_vgname);
|
||||||
|
break;
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT:
|
||||||
|
curves = build_concurrent(drawing,
|
||||||
|
curves,
|
||||||
|
selection,
|
||||||
|
use_time_alignment,
|
||||||
|
mmd.transition,
|
||||||
|
factor,
|
||||||
|
factor_start,
|
||||||
|
mmd.fade_opacity_strength,
|
||||||
|
mmd.fade_thickness_strength,
|
||||||
|
mmd.target_vgname);
|
||||||
|
break;
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE:
|
||||||
|
curves = build_sequential(drawing,
|
||||||
|
curves,
|
||||||
|
selection,
|
||||||
|
mmd.transition,
|
||||||
|
factor,
|
||||||
|
factor_start,
|
||||||
|
mmd.fade_opacity_strength,
|
||||||
|
mmd.fade_thickness_strength,
|
||||||
|
mmd.target_vgname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawing.tag_topology_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void modify_geometry_set(ModifierData *md,
|
||||||
|
const ModifierEvalContext *ctx,
|
||||||
|
blender::bke::GeometrySet *geometry_set)
|
||||||
|
{
|
||||||
|
const auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||||
|
|
||||||
|
if (!geometry_set->has_grease_pencil()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
|
||||||
|
const int eval_frame = grease_pencil.runtime->eval_frame;
|
||||||
|
|
||||||
|
IndexMaskMemory mask_memory;
|
||||||
|
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
|
||||||
|
grease_pencil, mmd->influence, mask_memory);
|
||||||
|
const Vector<modifier::greasepencil::LayerDrawingInfo> drawing_infos =
|
||||||
|
modifier::greasepencil::get_drawing_infos_by_layer(grease_pencil, layer_mask, eval_frame);
|
||||||
|
|
||||||
|
if (mmd->flag & MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME) {
|
||||||
|
if (eval_frame < mmd->start_frame || eval_frame > mmd->end_frame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Scene &scene = *DEG_get_evaluated_scene(ctx->depsgraph);
|
||||||
|
const float scene_fps = float(scene.r.frs_sec) / scene.r.frs_sec_base;
|
||||||
|
const Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
|
||||||
|
|
||||||
|
threading::parallel_for_each(
|
||||||
|
drawing_infos, [&](modifier::greasepencil::LayerDrawingInfo drawing_info) {
|
||||||
|
const bke::greasepencil::Drawing *prev_drawing = grease_pencil.get_drawing_at(
|
||||||
|
*layers[drawing_info.layer_index], eval_frame - 1);
|
||||||
|
build_drawing(
|
||||||
|
*mmd, *ctx->object, *drawing_info.drawing, prev_drawing, eval_frame, scene_fps);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void panel_draw(const bContext *C, Panel *panel)
|
||||||
|
{
|
||||||
|
uiLayout *layout = panel->layout;
|
||||||
|
|
||||||
|
PointerRNA ob_ptr;
|
||||||
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||||
|
|
||||||
|
const GreasePencilBuildMode mode = GreasePencilBuildMode(RNA_enum_get(ptr, "mode"));
|
||||||
|
GreasePencilBuildTimeMode time_mode = GreasePencilBuildTimeMode(RNA_enum_get(ptr, "time_mode"));
|
||||||
|
|
||||||
|
uiLayoutSetPropSep(layout, true);
|
||||||
|
|
||||||
|
/* First: Build mode and build settings. */
|
||||||
|
uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL) {
|
||||||
|
uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT) {
|
||||||
|
/* Concurrent mode doesn't support MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED, so unset it. */
|
||||||
|
if (time_mode == MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED) {
|
||||||
|
RNA_enum_set(ptr, "time_mode", MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES);
|
||||||
|
time_mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES;
|
||||||
|
}
|
||||||
|
uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
uiItemS(layout);
|
||||||
|
|
||||||
|
/* Second: Time mode and time settings. */
|
||||||
|
|
||||||
|
uiItemR(layout, ptr, "time_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT) {
|
||||||
|
uiItemR(layout, ptr, "concurrent_time_alignment", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
switch (time_mode) {
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED:
|
||||||
|
uiItemR(layout, ptr, "speed_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
uiItemR(layout, ptr, "speed_maxgap", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
break;
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES:
|
||||||
|
uiItemR(layout, ptr, "length", UI_ITEM_NONE, IFACE_("Frames"), ICON_NONE);
|
||||||
|
if (mode != MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE) {
|
||||||
|
uiItemR(layout, ptr, "start_delay", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE:
|
||||||
|
uiItemR(layout, ptr, "percentage_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uiItemS(layout);
|
||||||
|
uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||||
|
|
||||||
|
if (uiLayout *panel = uiLayoutPanelProp(
|
||||||
|
C, layout, ptr, "open_frame_range_panel", "Effective Range"))
|
||||||
|
{
|
||||||
|
uiLayoutSetPropSep(panel, true);
|
||||||
|
uiItemR(
|
||||||
|
panel, ptr, "use_restrict_frame_range", UI_ITEM_NONE, IFACE_("Custom Range"), ICON_NONE);
|
||||||
|
|
||||||
|
const bool active = RNA_boolean_get(ptr, "use_restrict_frame_range");
|
||||||
|
uiLayout *col = uiLayoutColumn(panel, false);
|
||||||
|
uiLayoutSetActive(col, active);
|
||||||
|
uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
|
||||||
|
uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiLayout *panel = uiLayoutPanelProp(C, layout, ptr, "open_fading_panel", "Fading")) {
|
||||||
|
uiLayoutSetPropSep(panel, true);
|
||||||
|
uiItemR(panel, ptr, "use_fading", UI_ITEM_NONE, IFACE_("Fade"), ICON_NONE);
|
||||||
|
|
||||||
|
const bool active = RNA_boolean_get(ptr, "use_fading");
|
||||||
|
uiLayout *col = uiLayoutColumn(panel, false);
|
||||||
|
uiLayoutSetActive(col, active);
|
||||||
|
|
||||||
|
uiItemR(col, ptr, "fade_factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
|
||||||
|
|
||||||
|
uiLayout *subcol = uiLayoutColumn(col, true);
|
||||||
|
uiItemR(subcol, ptr, "fade_thickness_strength", UI_ITEM_NONE, IFACE_("Thickness"), ICON_NONE);
|
||||||
|
uiItemR(subcol, ptr, "fade_opacity_strength", UI_ITEM_NONE, IFACE_("Opacity"), ICON_NONE);
|
||||||
|
|
||||||
|
uiItemPointerR(col,
|
||||||
|
ptr,
|
||||||
|
"target_vertex_group",
|
||||||
|
&ob_ptr,
|
||||||
|
"vertex_groups",
|
||||||
|
IFACE_("Weight Output"),
|
||||||
|
ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiLayout *influence_panel = uiLayoutPanelProp(
|
||||||
|
C, layout, ptr, "open_influence_panel", "Influence"))
|
||||||
|
{
|
||||||
|
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
|
||||||
|
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier_panel_end(layout, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void panel_register(ARegionType *region_type)
|
||||||
|
{
|
||||||
|
modifier_panel_register(region_type, eModifierType_GreasePencilBuild, panel_draw);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender
|
||||||
|
|
||||||
|
ModifierTypeInfo modifierType_GreasePencilBuild = {
|
||||||
|
/*idname*/ "GreasePencilBuildModifier",
|
||||||
|
/*name*/ N_("Build"),
|
||||||
|
/*struct_name*/ "GreasePencilBuildModifierData",
|
||||||
|
/*struct_size*/ sizeof(GreasePencilBuildModifierData),
|
||||||
|
/*srna*/ &RNA_GreasePencilBuildModifier,
|
||||||
|
/*type*/ ModifierTypeType::Nonconstructive,
|
||||||
|
/*flags*/
|
||||||
|
eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_EnableInEditmode |
|
||||||
|
eModifierTypeFlag_SupportsEditmode,
|
||||||
|
/*icon*/ ICON_MOD_LENGTH,
|
||||||
|
|
||||||
|
/*copy_data*/ blender::copy_data,
|
||||||
|
|
||||||
|
/*deform_verts*/ nullptr,
|
||||||
|
/*deform_matrices*/ nullptr,
|
||||||
|
/*deform_verts_EM*/ nullptr,
|
||||||
|
/*deform_matrices_EM*/ nullptr,
|
||||||
|
/*modify_mesh*/ nullptr,
|
||||||
|
/*modify_geometry_set*/ blender::modify_geometry_set,
|
||||||
|
|
||||||
|
/*init_data*/ blender::init_data,
|
||||||
|
/*required_data_mask*/ nullptr,
|
||||||
|
/*free_data*/ blender::free_data,
|
||||||
|
/*is_disabled*/ nullptr,
|
||||||
|
/*update_depsgraph*/ blender::update_depsgraph,
|
||||||
|
/*depends_on_time*/ nullptr,
|
||||||
|
/*depends_on_normals*/ nullptr,
|
||||||
|
/*foreach_ID_link*/ blender::foreach_ID_link,
|
||||||
|
/*foreach_tex_link*/ nullptr,
|
||||||
|
/*free_runtime_data*/ nullptr,
|
||||||
|
/*panel_register*/ blender::panel_register,
|
||||||
|
/*blend_write*/ blender::blend_write,
|
||||||
|
/*blend_read*/ blender::blend_read,
|
||||||
|
};
|
|
@ -287,5 +287,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
||||||
INIT_TYPE(GreasePencilEnvelope);
|
INIT_TYPE(GreasePencilEnvelope);
|
||||||
INIT_TYPE(GreasePencilOutline);
|
INIT_TYPE(GreasePencilOutline);
|
||||||
INIT_TYPE(GreasePencilShrinkwrap);
|
INIT_TYPE(GreasePencilShrinkwrap);
|
||||||
|
INIT_TYPE(GreasePencilBuild);
|
||||||
#undef INIT_TYPE
|
#undef INIT_TYPE
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue