diff --git a/scripts/startup/bl_ui/properties_data_modifier.py b/scripts/startup/bl_ui/properties_data_modifier.py index 36f164f4f01..7d046148de7 100644 --- a/scripts/startup/bl_ui/properties_data_modifier.py +++ b/scripts/startup/bl_ui/properties_data_modifier.py @@ -71,7 +71,7 @@ class OBJECT_MT_modifier_add(ModifierAddMenu, Menu): if geometry_nodes_supported: self.operator_modifier_add(layout, 'NODES') layout.separator() - if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE'}: + if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'LATTICE', 'GREASEPENCIL'}: layout.menu("OBJECT_MT_modifier_add_edit") if ob_type in {'MESH', 'CURVE', 'FONT', 'SURFACE', 'VOLUME'}: layout.menu("OBJECT_MT_modifier_add_generate") @@ -105,6 +105,8 @@ class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu): self.operator_modifier_add(layout, 'VERTEX_WEIGHT_EDIT') self.operator_modifier_add(layout, 'VERTEX_WEIGHT_MIX') self.operator_modifier_add(layout, 'VERTEX_WEIGHT_PROXIMITY') + if ob_type == 'GREASEPENCIL': + self.operator_modifier_add(layout, 'GREASE_PENCIL_OPACITY') layout.template_modifier_asset_menu_items(catalog_path=self.bl_label) diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index 4fc4a9341b1..288fa3b4473 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -801,4 +801,11 @@ .mat_ofs = 0, \ } +#define _DNA_DEFAULT_GreasePencilOpacityModifierData \ + { \ + .color_mode = MOD_GREASE_PENCIL_COLOR_BOTH, \ + .color_factor = 1.0f, \ + .hardness_factor = 1.0f, \ + } + /* clang-format off */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 0e31f383266..7bc475c24f1 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -93,6 +93,7 @@ typedef enum ModifierType { eModifierType_MeshToVolume = 58, eModifierType_VolumeDisplace = 59, eModifierType_VolumeToMesh = 60, + eModifierType_GreasePencilOpacity = 61, NUM_MODIFIER_TYPES, } ModifierType; @@ -2484,3 +2485,65 @@ typedef enum VolumeToMeshResolutionMode { typedef enum VolumeToMeshFlag { VOLUME_TO_MESH_USE_SMOOTH_SHADE = 1 << 0, } VolumeToMeshFlag; + +/** + * Common influence data for grease pencil modifiers. + * Not all parts may be used by all modifier types. + */ +typedef struct GreasePencilModifierInfluenceData { + /** GreasePencilModifierInfluenceFlag */ + int flag; + char _pad1[4]; + /** Filter by layer name. */ + char layer_name[64]; + /** Filter by stroke material. */ + struct Material *material; + /** Filter by layer pass. */ + int layer_pass; + /** Filter by material pass. */ + int material_pass; + /** #MAX_VGROUP_NAME. */ + char vertex_group_name[64]; + struct CurveMapping *custom_curve; + void *_pad2; +} GreasePencilModifierInfluenceData; + +typedef enum GreasePencilModifierInfluenceFlag { + GREASE_PENCIL_INFLUENCE_INVERT_LAYER_FILTER = (1 << 0), + GREASE_PENCIL_INFLUENCE_USE_LAYER_PASS_FILTER = (1 << 1), + GREASE_PENCIL_INFLUENCE_INVERT_LAYER_PASS_FILTER = (1 << 2), + GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_FILTER = (1 << 3), + GREASE_PENCIL_INFLUENCE_USE_MATERIAL_PASS_FILTER = (1 << 4), + GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_PASS_FILTER = (1 << 5), + GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP = (1 << 6), + GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE = (1 << 7), +} GreasePencilModifierInfluenceFlag; + +typedef struct GreasePencilOpacityModifierData { + ModifierData modifier; + GreasePencilModifierInfluenceData influence; + /** GreasePencilOpacityModifierFlag */ + int flag; + /** GreasePencilModifierColorMode */ + char color_mode; + char _pad1[3]; + float color_factor; + float hardness_factor; + void *_pad2; +} GreasePencilOpacityModifierData; + +/** Which attributes are affected by color modifiers. */ +typedef enum GreasePencilModifierColorMode { + MOD_GREASE_PENCIL_COLOR_STROKE = 0, + MOD_GREASE_PENCIL_COLOR_FILL = 1, + MOD_GREASE_PENCIL_COLOR_BOTH = 2, + MOD_GREASE_PENCIL_COLOR_HARDNESS = 3, +} GreasePencilModifierColorMode; + +typedef enum GreasePencilOpacityModifierFlag { + MOD_GREASE_PENCIL_OPACITY_OPEN_INFLUENCE_PANEL = (1 << 0), + /* Use vertex group as opacity factors instead of influence. */ + MOD_GREASE_PENCIL_OPACITY_USE_WEIGHT_AS_FACTOR = (1 << 1), + /* Set the opacity for every point in a stroke, otherwise multiply existing opacity. */ + MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY = (1 << 2), +} GreasePencilOpacityModifierFlag; diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 82dfa47d76d..5249d684906 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -322,6 +322,7 @@ SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierData); SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment); SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData); SDNA_DEFAULT_DECL_STRUCT(EnvelopeGpencilModifierData); +SDNA_DEFAULT_DECL_STRUCT(GreasePencilOpacityModifierData); #undef SDNA_DEFAULT_DECL_STRUCT @@ -566,6 +567,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = { SDNA_DEFAULT_DECL(DashGpencilModifierSegment), SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData), SDNA_DEFAULT_DECL(EnvelopeGpencilModifierData), + SDNA_DEFAULT_DECL(GreasePencilOpacityModifierData), }; #undef SDNA_DEFAULT_DECL #undef SDNA_DEFAULT_DECL_EX diff --git a/source/blender/makesrna/intern/rna_modifier.cc b/source/blender/makesrna/intern/rna_modifier.cc index 3dbc5db42bc..3b6306e3852 100644 --- a/source/blender/makesrna/intern/rna_modifier.cc +++ b/source/blender/makesrna/intern/rna_modifier.cc @@ -100,6 +100,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Proximity", "Set the vertex group weights based on the distance to another target object"}, + {eModifierType_GreasePencilOpacity, + "GREASE_PENCIL_OPACITY", + ICON_MOD_OPACITY, + "Opacity", + "Change the opacity of the strokes"}, RNA_ENUM_ITEM_HEADING(N_("Generate"), nullptr), {eModifierType_Array, @@ -668,11 +673,13 @@ const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[] = { #ifdef RNA_RUNTIME # include "DNA_curve_types.h" # include "DNA_fluid_types.h" +# include "DNA_material_types.h" # include "DNA_particle_types.h" # include "BKE_cachefile.h" # include "BKE_context.hh" # include "BKE_deform.h" +# include "BKE_material.h" # include "BKE_mesh_runtime.hh" # include "BKE_modifier.hh" # include "BKE_object.hh" @@ -1705,6 +1712,78 @@ static IDProperty **rna_NodesModifier_properties(PointerRNA *ptr) NodesModifierSettings *settings = &nmd->settings; return &settings->properties; } + +bool rna_GreasePencilModifier_material_poll(PointerRNA *ptr, PointerRNA value) +{ + Object *ob = reinterpret_cast(ptr->owner_id); + Material *ma = reinterpret_cast(value.owner_id); + + return BKE_object_material_index_get(ob, ma) != -1; +} + +/* Write material to a generic target pointer without the final modifier struct. */ +static void rna_GreasePencilModifier_material_set(PointerRNA *ptr, + PointerRNA value, + ReportList *reports, + Material **ma_target) +{ + Object *ob = reinterpret_cast(ptr->owner_id); + Material *ma = reinterpret_cast(value.owner_id); + + if (ma == nullptr || BKE_object_material_index_get(ob, ma) != -1) { + id_lib_extern(reinterpret_cast(ob)); + *ma_target = ma; + } + else { + BKE_reportf( + reports, + RPT_ERROR, + "Cannot assign material '%s', it has to be used by the grease pencil object already", + ma->id.name); + } +} + +# define RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(_type) \ + static void rna_##_type##Modifier_material_filter_set( \ + PointerRNA *ptr, PointerRNA value, ReportList *reports) \ + { \ + _type##ModifierData *tmd = static_cast<_type##ModifierData *>(ptr->data); \ + rna_GreasePencilModifier_material_set(ptr, value, reports, &tmd->influence.material); \ + } + +# define RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(_type) \ + static void rna_##_type##Modifier_vertex_group_name_set(PointerRNA *ptr, const char *value) \ + { \ + _type##ModifierData *tmd = static_cast<_type##ModifierData *>(ptr->data); \ + rna_object_vgroup_name_set(ptr, \ + value, \ + tmd->influence.vertex_group_name, \ + sizeof(tmd->influence.vertex_group_name)); \ + } + +RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOpacity); +RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity); + +static void rna_GreasePencilOpacityModifier_opacity_factor_range( + PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) +{ + GreasePencilOpacityModifierData *omd = static_cast(ptr->data); + + *min = 0.0f; + *softmin = 0.0f; + *softmax = (omd->flag & MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY) ? 1.0f : 2.0f; + *max = *softmax; +} + +static void rna_GreasePencilOpacityModifier_opacity_factor_max_set(PointerRNA *ptr, float value) +{ + GreasePencilOpacityModifierData *omd = static_cast(ptr->data); + + omd->color_factor = (omd->flag & MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY) ? + std::min(value, 1.0f) : + value; +} + #else static void rna_def_modifier_panel_open_prop(StructRNA *srna, const char *identifier, const int id) @@ -7423,6 +7502,186 @@ static void rna_def_modifier_volume_to_mesh(BlenderRNA *brna) RNA_define_lib_overridable(false); } +static void rna_def_modifier_grease_pencil_layer_filter(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "layer_filter", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, nullptr, "influence.layer_name"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_layer_pass_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_USE_LAYER_PASS_FILTER); + RNA_def_property_ui_text(prop, "Use Layer Pass", "Use layer pass filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "layer_pass_filter", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, nullptr, "influence.layer_pass"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Layer Pass", "Layer pass filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_layer_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_INVERT_LAYER_FILTER); + RNA_def_property_ui_text(prop, "Invert Layer", "Invert layer filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_layer_pass_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_INVERT_LAYER_PASS_FILTER); + RNA_def_property_ui_text(prop, "Invert Layer Pass", "Invert layer pass filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + +static void rna_def_modifier_grease_pencil_material_filter(StructRNA *srna, + const char *material_set_fn) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "material_filter", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, nullptr, "influence.material"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs( + prop, nullptr, material_set_fn, nullptr, "rna_GreasePencilModifier_material_poll"); + RNA_def_property_ui_text(prop, "Material", "Material used for filtering"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_material_pass_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_USE_MATERIAL_PASS_FILTER); + RNA_def_property_ui_text(prop, "Use Material Pass", "Use material pass filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "material_pass_filter", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, nullptr, "influence.material_pass"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Material Pass", "Material pass"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_material_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_FILTER); + RNA_def_property_ui_text(prop, "Invert Material", "Invert material filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_material_pass_filter", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_PASS_FILTER); + RNA_def_property_ui_text(prop, "Invert Material Pass", "Invert material pass filter"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + +static void rna_def_modifier_grease_pencil_vertex_group(StructRNA *srna, + const char *vertex_group_name_set_fn) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "vertex_group_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, nullptr, "influence.vertex_group_name"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, nullptr, nullptr, vertex_group_name_set_fn); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP); + RNA_def_property_ui_text(prop, "Invert Vertex Group", "Invert vertex group weights"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + +static void rna_def_modifier_grease_pencil_custom_curve(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "influence.flag", GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE); + RNA_def_property_ui_text( + prop, "Use Custom Curve", "Use a custom curve to define a factor along the strokes"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "custom_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, nullptr, "influence.custom_curve"); + RNA_def_property_ui_text(prop, "Curve", "Custom curve to apply effect"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + +static void rna_def_modifier_grease_pencil_opacity(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem color_mode_items[] = { + {MOD_GREASE_PENCIL_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, + {MOD_GREASE_PENCIL_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, + {MOD_GREASE_PENCIL_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, + {MOD_GREASE_PENCIL_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + srna = RNA_def_struct(brna, "GreasePencilOpacityModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Grease Pencil Opacity Modifier", ""); + RNA_def_struct_sdna(srna, "GreasePencilOpacityModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_OPACITY); + + rna_def_modifier_grease_pencil_layer_filter(srna); + rna_def_modifier_grease_pencil_material_filter( + srna, "rna_GreasePencilOpacityModifier_material_filter_set"); + rna_def_modifier_grease_pencil_vertex_group( + srna, "rna_GreasePencilOpacityModifier_vertex_group_name_set"); + rna_def_modifier_grease_pencil_custom_curve(srna); + + prop = RNA_def_property(srna, "open_influence_panel", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "flag", MOD_GREASE_PENCIL_OPACITY_OPEN_INFLUENCE_PANEL); + RNA_def_property_ui_text(prop, "Open Influence Panel", "Open the influence panel"); + RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, nullptr); + + RNA_define_lib_overridable(true); + + prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, color_mode_items); + RNA_def_property_ui_text(prop, "Mode", "Attributes to modify"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "color_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, nullptr, "color_factor"); + RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2); + RNA_def_property_float_funcs(prop, + nullptr, + "rna_GreasePencilOpacityModifier_opacity_factor_max_set", + "rna_GreasePencilOpacityModifier_opacity_factor_range"); + RNA_def_property_ui_text(prop, "Opacity Factor", "Factor of opacity"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "hardness_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, nullptr, "hardness_factor"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 0.1, 2); + RNA_def_property_ui_text(prop, "Hardness Factor", "Factor of stroke hardness"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_weight_as_factor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "flag", MOD_GREASE_PENCIL_OPACITY_USE_WEIGHT_AS_FACTOR); + RNA_def_property_ui_text( + prop, "Use Weight as Factor", "Use vertex group weight as factor instead of influence"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_uniform_opacity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "flag", MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY); + RNA_def_property_ui_text( + prop, "Uniform Opacity", "Replace the stroke opacity instead of modulating each point"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); +} + void RNA_def_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -7583,6 +7842,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_mesh_to_volume(brna); rna_def_modifier_volume_displace(brna); rna_def_modifier_volume_to_mesh(brna); + rna_def_modifier_grease_pencil_opacity(brna); } #endif diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index ef9ff57b606..f3920f2560f 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -44,6 +44,8 @@ set(SRC intern/MOD_edgesplit.cc intern/MOD_explode.cc intern/MOD_fluid.cc + intern/MOD_grease_pencil_opacity.cc + intern/MOD_grease_pencil_util.cc intern/MOD_hook.cc intern/MOD_laplaciandeform.cc intern/MOD_laplaciansmooth.cc @@ -97,6 +99,7 @@ set(SRC MOD_modifiertypes.hh MOD_nodes.hh + intern/MOD_grease_pencil_util.hh intern/MOD_meshcache_util.hh intern/MOD_solidify_util.hh intern/MOD_ui_common.hh diff --git a/source/blender/modifiers/MOD_modifiertypes.hh b/source/blender/modifiers/MOD_modifiertypes.hh index 64f95d4479f..909e6b3ce18 100644 --- a/source/blender/modifiers/MOD_modifiertypes.hh +++ b/source/blender/modifiers/MOD_modifiertypes.hh @@ -73,6 +73,7 @@ extern ModifierTypeInfo modifierType_Nodes; extern ModifierTypeInfo modifierType_MeshToVolume; extern ModifierTypeInfo modifierType_VolumeDisplace; extern ModifierTypeInfo modifierType_VolumeToMesh; +extern ModifierTypeInfo modifierType_GreasePencilOpacity; /* MOD_util.cc */ diff --git a/source/blender/modifiers/intern/MOD_grease_pencil_opacity.cc b/source/blender/modifiers/intern/MOD_grease_pencil_opacity.cc new file mode 100644 index 00000000000..52d31d7bc06 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_grease_pencil_opacity.cc @@ -0,0 +1,340 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup modifiers + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_defaults.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_colortools.hh" +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" +#include "BKE_grease_pencil.hh" +#include "BKE_modifier.hh" + +#include "BLO_read_write.hh" + +#include "DEG_depsgraph_query.hh" + +#include "UI_interface.hh" +#include "UI_resources.hh" + +#include "BLT_translation.h" + +#include "WM_types.hh" + +#include "RNA_access.hh" +#include "RNA_enum_types.hh" +#include "RNA_prototypes.h" + +#include "MOD_grease_pencil_util.hh" +#include "MOD_modifiertypes.hh" +#include "MOD_ui_common.hh" + +#include + +namespace blender { + +using bke::greasepencil::Drawing; +using bke::greasepencil::FramesMapKey; +using bke::greasepencil::Layer; + +static void init_data(ModifierData *md) +{ + auto *omd = reinterpret_cast(md); + + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(omd, modifier)); + + MEMCPY_STRUCT_AFTER(omd, DNA_struct_default_get(GreasePencilOpacityModifierData), modifier); + modifier::greasepencil::init_influence_data(&omd->influence, true); +} + +static void copy_data(const ModifierData *md, ModifierData *target, const int flag) +{ + const auto *omd = reinterpret_cast(md); + auto *tomd = reinterpret_cast(target); + + modifier::greasepencil::free_influence_data(&tomd->influence); + + BKE_modifier_copydata_generic(md, target, flag); + modifier::greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flag); +} + +static void free_data(ModifierData *md) +{ + auto *omd = reinterpret_cast(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(md); + modifier::greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data); +} + +static void modify_stroke_color(const GreasePencilOpacityModifierData &omd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + const bool use_uniform_opacity = (omd.flag & MOD_GREASE_PENCIL_OPACITY_USE_UNIFORM_OPACITY); + const bool use_weight_as_factor = (omd.flag & MOD_GREASE_PENCIL_OPACITY_USE_WEIGHT_AS_FACTOR); + const bool invert_vertex_group = (omd.influence.flag & + GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP); + const bool use_curve = (omd.influence.flag & GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE); + const OffsetIndices points_by_curve = curves.points_by_curve(); + + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + bke::SpanAttributeWriter opacities = attributes.lookup_or_add_for_write_span( + "opacity", bke::AttrDomain::Point); + const VArray vgroup_weights = + attributes + .lookup_or_default(omd.influence.vertex_group_name, bke::AttrDomain::Point, 1.0f) + .varray; + + curves_mask.foreach_index(GrainSize(512), [&](const int64_t curve_i) { + const IndexRange points = points_by_curve[curve_i]; + for (const int64_t point_i : points) { + const float curve_input = points.size() >= 2 ? + (float(point_i - points.first()) / float(points.size() - 1)) : + 0.0f; + const float curve_factor = use_curve ? BKE_curvemapping_evaluateF( + omd.influence.custom_curve, 0, curve_input) : + 1.0f; + + if (use_uniform_opacity) { + opacities.span[point_i] = std::clamp(omd.color_factor * curve_factor, 0.0f, 1.0f); + } + else if (use_weight_as_factor) { + /* Use vertex group weights as opacity factors. */ + opacities.span[point_i] = std::clamp( + omd.color_factor * curve_factor * vgroup_weights[point_i], 0.0f, 1.0f); + } + else { + /* Use vertex group weights as influence factors. */ + const float vgroup_weight = vgroup_weights[point_i]; + const float vgroup_influence = invert_vertex_group ? 1.0f - vgroup_weight : vgroup_weight; + opacities.span[point_i] = std::clamp( + opacities.span[point_i] + omd.color_factor * curve_factor * vgroup_influence - 1.0f, + 0.0f, + 1.0f); + } + } + }); + + opacities.finish(); +} + +static void modify_fill_color(const GreasePencilOpacityModifierData &omd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + const bool use_vgroup_opacity = (omd.flag & MOD_GREASE_PENCIL_OPACITY_USE_WEIGHT_AS_FACTOR); + const bool invert_vertex_group = (omd.influence.flag & + GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP); + const OffsetIndices points_by_curve = curves.points_by_curve(); + + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + /* Fill color opacity per stroke. */ + bke::SpanAttributeWriter fill_opacities = attributes.lookup_or_add_for_write_span( + "fill_opacity", bke::AttrDomain::Curve); + VArray vgroup_weights = attributes + .lookup_or_default(omd.influence.vertex_group_name, + bke::AttrDomain::Point, + 1.0f) + .varray; + + curves_mask.foreach_index(GrainSize(512), [&](int64_t curve_i) { + if (use_vgroup_opacity) { + /* Use the first stroke point as vertex weight. */ + const IndexRange points = points_by_curve[curve_i]; + const float stroke_weight = points.is_empty() ? 1.0f : vgroup_weights[points.first()]; + const float stroke_influence = invert_vertex_group ? 1.0f - stroke_weight : stroke_weight; + + fill_opacities.span[curve_i] = std::clamp(stroke_influence, 0.0f, 1.0f); + } + else { + fill_opacities.span[curve_i] = std::clamp(omd.color_factor, 0.0f, 1.0f); + } + }); + + fill_opacities.finish(); +} + +static void modify_hardness(const GreasePencilOpacityModifierData &omd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + bke::SpanAttributeWriter hardnesses = attributes.lookup_for_write_span("hardness"); + if (!hardnesses) { + return; + } + + curves_mask.foreach_index(GrainSize(512), [&](int64_t curve_i) { + hardnesses.span[curve_i] = std::clamp( + hardnesses.span[curve_i] * omd.hardness_factor, 0.0f, 1.0f); + }); + + hardnesses.finish(); +} + +static void modify_curves(ModifierData *md, + const ModifierEvalContext *ctx, + bke::CurvesGeometry &curves) +{ + auto *omd = reinterpret_cast(md); + + IndexMaskMemory mask_memory; + IndexMask curves_mask = modifier::greasepencil::get_filtered_stroke_mask( + ctx->object, curves, omd->influence, mask_memory); + + switch (omd->color_mode) { + case MOD_GREASE_PENCIL_COLOR_STROKE: + modify_stroke_color(*omd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_FILL: + modify_fill_color(*omd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_BOTH: + modify_stroke_color(*omd, curves, curves_mask); + modify_fill_color(*omd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_HARDNESS: + modify_hardness(*omd, curves, curves_mask); + break; + } +} + +static void modify_geometry_set(ModifierData *md, + const ModifierEvalContext *ctx, + bke::GeometrySet *geometry_set) +{ + auto *omd = reinterpret_cast(md); + const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + const int frame = scene->r.cfra; + + GreasePencil *grease_pencil = geometry_set->get_grease_pencil_for_write(); + if (grease_pencil == nullptr) { + return; + } + + IndexMaskMemory mask_memory; + IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask( + *grease_pencil, omd->influence, mask_memory); + Vector drawings = modifier::greasepencil::get_drawings_for_write( + *grease_pencil, layer_mask, frame); + threading::parallel_for_each(drawings.index_range(), [&](int64_t i) { + modify_curves(md, ctx, drawings[i]->strokes_for_write()); + }); +} + +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); + + uiLayoutSetPropSep(layout, true); + + const GreasePencilModifierColorMode color_mode = GreasePencilModifierColorMode( + RNA_enum_get(ptr, "color_mode")); + + uiItemR(layout, ptr, "color_mode", UI_ITEM_NONE, nullptr, ICON_NONE); + + if (color_mode == MOD_GREASE_PENCIL_COLOR_HARDNESS) { + uiItemR(layout, ptr, "hardness_factor", UI_ITEM_NONE, nullptr, ICON_NONE); + } + else { + const bool use_uniform_opacity = RNA_boolean_get(ptr, "use_uniform_opacity"); + const bool use_weight_as_factor = RNA_boolean_get(ptr, "use_weight_as_factor"); + + uiItemR(layout, ptr, "use_uniform_opacity", UI_ITEM_NONE, nullptr, ICON_NONE); + const char *text = (use_uniform_opacity) ? IFACE_("Opacity") : IFACE_("Opacity Factor"); + + uiLayout *row = uiLayoutRow(layout, true); + uiLayoutSetActive(row, !use_weight_as_factor || use_uniform_opacity); + uiItemR(row, ptr, "color_factor", UI_ITEM_NONE, text, ICON_NONE); + if (!use_uniform_opacity) { + uiLayout *sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, true); + uiItemR(row, ptr, "use_weight_as_factor", UI_ITEM_NONE, "", ICON_MOD_VERTEX_WEIGHT); + } + } + + if (uiLayout *influence_panel = uiLayoutPanel( + C, layout, "Influence", ptr, "open_influence_panel")) + { + modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr); + modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr); + modifier::greasepencil::draw_vertex_group_settings(C, influence_panel, ptr); + modifier::greasepencil::draw_custom_curve_settings(C, influence_panel, ptr); + } + + modifier_panel_end(layout, ptr); +} + +static void panel_register(ARegionType *region_type) +{ + modifier_panel_register(region_type, eModifierType_GreasePencilOpacity, panel_draw); +} + +static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md) +{ + const auto *omd = reinterpret_cast(md); + + BLO_write_struct(writer, GreasePencilOpacityModifierData, omd); + modifier::greasepencil::write_influence_data(writer, &omd->influence); +} + +static void blend_read(BlendDataReader *reader, ModifierData *md) +{ + auto *omd = reinterpret_cast(md); + + modifier::greasepencil::read_influence_data(reader, &omd->influence); +} + +} // namespace blender + +ModifierTypeInfo modifierType_GreasePencilOpacity = { + /*idname*/ "GreasePencilOpacity", + /*name*/ N_("GreasePencilOpacity"), + /*struct_name*/ "GreasePencilOpacityModifierData", + /*struct_size*/ sizeof(GreasePencilOpacityModifierData), + /*srna*/ &RNA_GreasePencilOpacityModifier, + /*type*/ ModifierTypeType::Nonconstructive, + /*flags*/ + static_cast( + eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping), + /*icon*/ ICON_MOD_OPACITY, + + /*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*/ nullptr, + /*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, +}; diff --git a/source/blender/modifiers/intern/MOD_grease_pencil_util.cc b/source/blender/modifiers/intern/MOD_grease_pencil_util.cc new file mode 100644 index 00000000000..fdb2e4c496b --- /dev/null +++ b/source/blender/modifiers/intern/MOD_grease_pencil_util.cc @@ -0,0 +1,333 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup modifiers + */ + +#include "MOD_grease_pencil_util.hh" + +#include "BLI_set.hh" + +#include "DNA_grease_pencil_types.h" +#include "DNA_material_types.h" +#include "DNA_modifier_types.h" +#include "DNA_screen_types.h" + +#include "BKE_colortools.hh" +#include "BKE_curves.hh" +#include "BKE_grease_pencil.hh" +#include "BKE_lib_query.h" +#include "BKE_material.h" + +#include "BLO_read_write.hh" + +#include "DNA_defaults.h" + +#include "DEG_depsgraph_query.hh" + +#include "MOD_ui_common.hh" + +#include "RNA_access.hh" +#include "RNA_prototypes.h" + +#include "UI_interface.hh" + +namespace blender::modifier::greasepencil { + +using bke::greasepencil::Drawing; +using bke::greasepencil::Layer; + +void init_influence_data(GreasePencilModifierInfluenceData *influence_data, + const bool has_custom_curve) +{ + if (has_custom_curve) { + influence_data->custom_curve = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_init(influence_data->custom_curve); + } +} + +void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src, + GreasePencilModifierInfluenceData *influence_data_dst, + const int /*flag*/) +{ + memcpy(influence_data_dst, influence_data_src, sizeof(GreasePencilModifierInfluenceData)); + influence_data_dst->custom_curve = BKE_curvemapping_copy(influence_data_src->custom_curve); +} + +void free_influence_data(GreasePencilModifierInfluenceData *influence_data) +{ + if (influence_data->custom_curve) { + BKE_curvemapping_free(influence_data->custom_curve); + influence_data->custom_curve = nullptr; + } +} + +void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data, + Object *ob, + IDWalkFunc walk, + void *user_data) +{ + walk(user_data, ob, (ID **)&influence_data->material, IDWALK_CB_USER); +} + +void write_influence_data(BlendWriter *writer, + const GreasePencilModifierInfluenceData *influence_data) +{ + if (influence_data->custom_curve) { + BKE_curvemapping_blend_write(writer, influence_data->custom_curve); + } +} + +void read_influence_data(BlendDataReader *reader, + GreasePencilModifierInfluenceData *influence_data) +{ + BLO_read_data_address(reader, &influence_data->custom_curve); + if (influence_data->custom_curve) { + BKE_curvemapping_blend_read(reader, influence_data->custom_curve); + /* Make sure the internal table exists. */ + BKE_curvemapping_init(influence_data->custom_curve); + } +} + +void draw_layer_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr) +{ + PointerRNA ob_ptr = RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id); + PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); + const bool use_layer_pass = RNA_boolean_get(ptr, "use_layer_pass_filter"); + uiLayout *row, *col, *sub, *subsub; + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, true); + row = uiLayoutRow(col, true); + uiLayoutSetPropDecorate(row, false); + uiItemPointerR(row, ptr, "layer_filter", &obj_data_ptr, "layers", nullptr, ICON_GREASEPENCIL); + sub = uiLayoutRow(row, true); + uiItemR(sub, ptr, "invert_layer_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT); + + row = uiLayoutRowWithHeading(col, true, "Layer Pass"); + uiLayoutSetPropDecorate(row, false); + sub = uiLayoutRow(row, true); + uiItemR(sub, ptr, "use_layer_pass_filter", UI_ITEM_NONE, "", ICON_NONE); + subsub = uiLayoutRow(sub, true); + uiLayoutSetActive(subsub, use_layer_pass); + uiItemR(subsub, ptr, "layer_pass_filter", UI_ITEM_NONE, "", ICON_NONE); + uiItemR(subsub, ptr, "invert_layer_pass_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT); +} + +void draw_material_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr) +{ + PointerRNA ob_ptr = RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id); + PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); + const bool use_material_pass = RNA_boolean_get(ptr, "use_material_pass_filter"); + uiLayout *row, *col, *sub, *subsub; + + uiLayoutSetPropSep(layout, true); + + col = uiLayoutColumn(layout, true); + row = uiLayoutRow(col, true); + uiLayoutSetPropDecorate(row, false); + uiItemPointerR( + row, ptr, "material_filter", &obj_data_ptr, "materials", nullptr, ICON_SHADING_TEXTURE); + sub = uiLayoutRow(row, true); + uiItemR(sub, ptr, "invert_material_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT); + + row = uiLayoutRowWithHeading(col, true, "Material Pass"); + uiLayoutSetPropDecorate(row, false); + sub = uiLayoutRow(row, true); + uiItemR(sub, ptr, "use_material_pass_filter", UI_ITEM_NONE, "", ICON_NONE); + subsub = uiLayoutRow(sub, true); + uiLayoutSetActive(subsub, use_material_pass); + uiItemR(subsub, ptr, "material_pass_filter", UI_ITEM_NONE, "", ICON_NONE); + uiItemR(subsub, ptr, "invert_material_pass_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT); +} + +void draw_vertex_group_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr) +{ + PointerRNA ob_ptr = RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id); + bool has_vertex_group = RNA_string_length(ptr, "vertex_group_name") != 0; + uiLayout *row, *sub; + + uiLayoutSetPropSep(layout, true); + + row = uiLayoutRow(layout, true); + uiItemPointerR(row, ptr, "vertex_group_name", &ob_ptr, "vertex_groups", nullptr, ICON_NONE); + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, has_vertex_group); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, ptr, "invert_vertex_group", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT); +} + +void draw_custom_curve_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr) +{ + bool use_custom_curve = RNA_boolean_get(ptr, "use_custom_curve"); + + uiLayoutSetPropSep(layout, true); + + uiItemR(layout, ptr, "use_custom_curve", UI_ITEM_NONE, nullptr, ICON_NONE); + if (use_custom_curve) { + uiTemplateCurveMapping(layout, ptr, "custom_curve", 0, false, false, false, false); + } +} + +/** + * Get a list of pass IDs used by grease pencil materials. + * This way the material pass can be looked up by index instead of having to get the material for + * each curve. + */ +static Vector get_grease_pencil_material_passes(const Object *ob) +{ + short *totcol = BKE_object_material_len_p(const_cast(ob)); + Vector result(*totcol); + Material *ma = nullptr; + for (short i = 0; i < *totcol; i++) { + ma = BKE_object_material_get(const_cast(ob), i + 1); + /* Pass index of the grease pencil material. */ + result[i] = ma->gp_style->index; + } + return result; +} + +static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, + const std::optional layer_name_filter, + const std::optional layer_pass_filter, + const bool layer_filter_invert, + const bool layer_pass_filter_invert, + IndexMaskMemory &memory) +{ + const IndexMask full_mask = grease_pencil.layers().index_range(); + if (!layer_name_filter && !layer_pass_filter) { + return full_mask; + } + + bke::AttributeAccessor layer_attributes = grease_pencil.attributes(); + const Span layers = grease_pencil.layers(); + const VArray layer_passes = + layer_attributes.lookup_or_default("pass", bke::AttrDomain::Layer, 0).varray; + + IndexMask result = IndexMask::from_predicate( + full_mask, GrainSize(4096), memory, [&](const int64_t layer_i) { + if (layer_name_filter) { + const Layer &layer = *layers[layer_i]; + const bool match = (layer.name() == layer_name_filter.value()); + if (match == layer_filter_invert) { + return false; + } + } + if (layer_pass_filter) { + const int layer_pass = layer_passes.get(layer_i); + const bool match = (layer_pass == layer_pass_filter.value()); + if (match == layer_pass_filter_invert) { + return false; + } + } + return true; + }); + return result; +} + +IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, + const GreasePencilModifierInfluenceData &influence_data, + IndexMaskMemory &memory) +{ + return get_filtered_layer_mask( + grease_pencil, + influence_data.layer_name[0] != '\0' ? + std::make_optional(influence_data.layer_name) : + std::nullopt, + (influence_data.flag & GREASE_PENCIL_INFLUENCE_USE_LAYER_PASS_FILTER) ? + std::make_optional(influence_data.layer_pass) : + std::nullopt, + influence_data.flag & GREASE_PENCIL_INFLUENCE_INVERT_LAYER_FILTER, + influence_data.flag & GREASE_PENCIL_INFLUENCE_INVERT_LAYER_PASS_FILTER, + memory); +} + +static IndexMask get_filtered_stroke_mask(const Object *ob, + const bke::CurvesGeometry &curves, + const Material *material_filter, + const std::optional material_pass_filter, + const bool material_filter_invert, + const bool material_pass_filter_invert, + IndexMaskMemory &memory) +{ + const IndexMask full_mask = curves.curves_range(); + if (!material_filter && !material_pass_filter) { + return full_mask; + } + + const int material_filter_index = BKE_object_material_index_get( + const_cast(ob), const_cast(material_filter)); + const Vector material_pass_by_index = get_grease_pencil_material_passes(ob); + + bke::AttributeAccessor attributes = curves.attributes(); + VArray stroke_materials = + attributes.lookup_or_default("material_index", bke::AttrDomain::Curve, 0).varray; + + IndexMask result = IndexMask::from_predicate( + full_mask, GrainSize(4096), memory, [&](const int64_t stroke_i) { + const int material_index = stroke_materials.get(stroke_i); + if (material_filter != nullptr) { + const bool match = (material_index == material_filter_index); + if (match == material_filter_invert) { + return false; + } + } + if (material_pass_filter) { + const int material_pass = material_pass_by_index[material_index]; + const bool match = (material_pass == material_pass_filter.value()); + if (match == material_pass_filter_invert) { + return false; + } + } + return true; + }); + return result; +} + +IndexMask get_filtered_stroke_mask(const Object *ob, + const bke::CurvesGeometry &curves, + const GreasePencilModifierInfluenceData &influence_data, + IndexMaskMemory &memory) +{ + return get_filtered_stroke_mask( + ob, + curves, + influence_data.material, + (influence_data.flag & GREASE_PENCIL_INFLUENCE_USE_MATERIAL_PASS_FILTER) ? + std::make_optional(influence_data.material_pass) : + std::nullopt, + influence_data.flag & GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_FILTER, + influence_data.flag & GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_PASS_FILTER, + memory); +} + +Vector get_drawings_for_write(GreasePencil &grease_pencil, + const IndexMask &layer_mask, + int frame) +{ + /* Set of unique drawing indices. */ + Set drawing_indices; + for (const int64_t i : layer_mask.index_range()) { + Layer *layer = grease_pencil.layers_for_write()[layer_mask[i]]; + const int drawing_index = layer->drawing_index_at(frame); + if (drawing_index >= 0) { + drawing_indices.add(drawing_index); + } + } + + /* List of owned drawings, ignore drawing references to other data blocks. */ + Vector drawings; + for (const int drawing_index : drawing_indices) { + GreasePencilDrawingBase *drawing_base = grease_pencil.drawing(drawing_index); + if (drawing_base->type == GP_DRAWING) { + GreasePencilDrawing *drawing = reinterpret_cast(drawing_base); + drawings.append(&drawing->wrap()); + } + } + return drawings; +} + +} // namespace blender::modifier::greasepencil diff --git a/source/blender/modifiers/intern/MOD_grease_pencil_util.hh b/source/blender/modifiers/intern/MOD_grease_pencil_util.hh new file mode 100644 index 00000000000..9652ff47e0d --- /dev/null +++ b/source/blender/modifiers/intern/MOD_grease_pencil_util.hh @@ -0,0 +1,66 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup modifiers + */ + +#pragma once + +#include "BLI_index_mask.hh" +#include "BLI_vector.hh" + +#include "BKE_modifier.hh" + +struct ARegionType; +struct bContext; +struct GreasePencil; +struct GreasePencilModifierInfluenceData; +struct GreasePencilModifierLayerFilter; +struct GreasePencilModifierMaterialFilter; +struct PanelType; +struct PointerRNA; +struct uiLayout; +namespace blender::bke { +class CurvesGeometry; +namespace greasepencil { +class Drawing; +} +} // namespace blender::bke + +namespace blender::modifier::greasepencil { + +void init_influence_data(GreasePencilModifierInfluenceData *influence_data, bool has_custom_curve); +void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src, + GreasePencilModifierInfluenceData *influence_data_dst, + int flag); +void free_influence_data(GreasePencilModifierInfluenceData *influence_data); +void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data, + Object *ob, + IDWalkFunc walk, + void *user_data); +void write_influence_data(BlendWriter *writer, + const GreasePencilModifierInfluenceData *influence_data); +void read_influence_data(BlendDataReader *reader, + GreasePencilModifierInfluenceData *influence_data); + +void draw_layer_filter_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr); +void draw_material_filter_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr); +void draw_vertex_group_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr); +void draw_custom_curve_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr); + +IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, + const GreasePencilModifierInfluenceData &influence_data, + IndexMaskMemory &memory); + +IndexMask get_filtered_stroke_mask(const Object *ob, + const bke::CurvesGeometry &curves, + const GreasePencilModifierInfluenceData &influence_data, + IndexMaskMemory &memory); + +Vector get_drawings_for_write(GreasePencil &grease_pencil, + const IndexMask &layer_mask, + int frame); + +} // namespace blender::modifier::greasepencil diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 2e1913ff938..7db69740186 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -270,5 +270,6 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(VolumeDisplace); INIT_TYPE(VolumeToMesh); INIT_TYPE(Nodes); + INIT_TYPE(GreasePencilOpacity); #undef INIT_TYPE }