From baeb4d775393e96fbcc497d602fa06d0ed60287b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Fri, 19 Jan 2024 16:59:39 +0100 Subject: [PATCH] GPv3: Tint and Color modifiers Implements the Tint and Color (aka. "Hue/Saturation") modifiers. Pull Request: https://projects.blender.org/blender/blender/pulls/117297 --- .../startup/bl_ui/properties_data_modifier.py | 2 + .../blender/makesdna/DNA_modifier_defaults.h | 16 + source/blender/makesdna/DNA_modifier_types.h | 44 ++ source/blender/makesdna/intern/dna_defaults.c | 4 + .../blender/makesrna/intern/rna_modifier.cc | 165 +++++- source/blender/modifiers/CMakeLists.txt | 2 + source/blender/modifiers/MOD_modifiertypes.hh | 2 + .../intern/MOD_grease_pencil_color.cc | 316 +++++++++++ .../intern/MOD_grease_pencil_tint.cc | 509 ++++++++++++++++++ source/blender/modifiers/intern/MOD_util.cc | 2 + 10 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 source/blender/modifiers/intern/MOD_grease_pencil_color.cc create mode 100644 source/blender/modifiers/intern/MOD_grease_pencil_tint.cc diff --git a/scripts/startup/bl_ui/properties_data_modifier.py b/scripts/startup/bl_ui/properties_data_modifier.py index 76fe29aa9cd..7857678032a 100644 --- a/scripts/startup/bl_ui/properties_data_modifier.py +++ b/scripts/startup/bl_ui/properties_data_modifier.py @@ -219,6 +219,8 @@ class OBJECT_MT_modifier_add_color(ModifierAddMenu, Menu): layout = self.layout ob_type = context.object.type if ob_type == 'GREASEPENCIL': + self.operator_modifier_add(layout, 'GREASE_PENCIL_COLOR') + self.operator_modifier_add(layout, 'GREASE_PENCIL_TINT') 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 0488d563232..c7a37586de3 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -813,4 +813,20 @@ .level = 1, \ } +#define _DNA_DEFAULT_GreasePencilColorModifierData \ + { \ + .color_mode = MOD_GREASE_PENCIL_COLOR_BOTH, \ + .hsv = {0.5f, 1.0f, 1.0f}, \ + } + + +#define _DNA_DEFAULT_GreasePencilTintModifierData \ + { \ + .color_mode = MOD_GREASE_PENCIL_COLOR_BOTH, \ + .tint_mode = MOD_GREASE_PENCIL_TINT_UNIFORM, \ + .factor = 0.5f, \ + .radius = 1.0f, \ + .color = {1.0f, 1.0f, 1.0f}, \ + } + /* clang-format off */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 7fdbe522c79..a22aa241220 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -95,6 +95,8 @@ typedef enum ModifierType { eModifierType_VolumeToMesh = 60, eModifierType_GreasePencilOpacity = 61, eModifierType_GreasePencilSubdiv = 62, + eModifierType_GreasePencilColor = 63, + eModifierType_GreasePencilTint = 64, NUM_MODIFIER_TYPES, } ModifierType; @@ -2563,3 +2565,45 @@ typedef struct GreasePencilSubdivModifierData { typedef enum GreasePencilSubdivModifierFlag { MOD_GREASE_PENCIL_SUBDIV_OPEN_INFLUENCE_PANEL = (1 << 0), } GreasePencilSubdivModifierFlag; + +typedef struct GreasePencilColorModifierData { + ModifierData modifier; + GreasePencilModifierInfluenceData influence; + /** GreasePencilModifierColorMode */ + char color_mode; + char _pad1[3]; + /** HSV factors. */ + float hsv[3]; + void *_pad2; +} GreasePencilColorModifierData; + +typedef struct GreasePencilTintModifierData { + ModifierData modifier; + GreasePencilModifierInfluenceData influence; + /** GreasePencilTintModifierFlag */ + short flag; + /** GreasePencilModifierColorMode */ + char color_mode; + /** GreasePencilTintModifierMode */ + char tint_mode; + float factor; + /** Influence distance from the gradient object. */ + float radius; + /** Simple tint color. */ + float color[3]; + /** Object for gradient direction. */ + struct Object *object; + /** Color ramp for the gradient. */ + struct ColorBand *color_ramp; + void *_pad; +} GreasePencilTintModifierData; + +typedef enum GreasePencilTintModifierMode { + MOD_GREASE_PENCIL_TINT_UNIFORM = 0, + MOD_GREASE_PENCIL_TINT_GRADIENT = 1, +} GreasePencilTintModifierMode; + +typedef enum GreasePencilTintModifierFlag { + /* Use vertex group as factors instead of influence. */ + MOD_GREASE_PENCIL_TINT_USE_WEIGHT_AS_FACTOR = (1 << 0), +} GreasePencilTintModifierFlag; diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 06620e0236e..600eb618268 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -324,6 +324,8 @@ SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment); SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData); SDNA_DEFAULT_DECL_STRUCT(EnvelopeGpencilModifierData); SDNA_DEFAULT_DECL_STRUCT(GreasePencilOpacityModifierData); +SDNA_DEFAULT_DECL_STRUCT(GreasePencilColorModifierData); +SDNA_DEFAULT_DECL_STRUCT(GreasePencilTintModifierData); #undef SDNA_DEFAULT_DECL_STRUCT @@ -570,6 +572,8 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = { SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData), SDNA_DEFAULT_DECL(EnvelopeGpencilModifierData), SDNA_DEFAULT_DECL(GreasePencilOpacityModifierData), + SDNA_DEFAULT_DECL(GreasePencilColorModifierData), + SDNA_DEFAULT_DECL(GreasePencilTintModifierData), }; #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 af36d23cf38..d746a42c321 100644 --- a/source/blender/makesrna/intern/rna_modifier.cc +++ b/source/blender/makesrna/intern/rna_modifier.cc @@ -101,6 +101,16 @@ 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_GreasePencilColor, + "GREASE_PENCIL_COLOR", + ICON_MOD_HUE_SATURATION, + "Hue/Saturation", + "Change hue/saturation/value of the strokes"}, + {eModifierType_GreasePencilTint, + "GREASE_PENCIL_TINT", + ICON_MOD_TINT, + "Tint", + "Tint the color of the strokes"}, {eModifierType_GreasePencilOpacity, "GREASE_PENCIL_OPACITY", ICON_MOD_OPACITY, @@ -1800,11 +1810,14 @@ static void rna_GreasePencilModifier_material_set(PointerRNA *ptr, sizeof(tmd->influence.vertex_group_name)); \ } +RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilColor); RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOpacity); RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilSubdiv); +RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilTint); RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity); RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilSubdiv); +RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilTint); static void rna_GreasePencilOpacityModifier_opacity_factor_range( PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax) @@ -1826,6 +1839,17 @@ static void rna_GreasePencilOpacityModifier_opacity_factor_max_set(PointerRNA *p value; } +static void rna_GreasePencilTintModifier_object_set(PointerRNA *ptr, + PointerRNA value, + ReportList * /*reports*/) +{ + GreasePencilTintModifierData *tmd = static_cast(ptr->data); + Object *ob = static_cast(value.data); + + tmd->object = ob; + id_lib_extern(&ob->id); +} + #else static void rna_def_modifier_panel_open_prop(StructRNA *srna, const char *identifier, const int id) @@ -7695,7 +7719,6 @@ static void rna_def_modifier_grease_pencil_opacity(BlenderRNA *brna) rna_def_modifier_grease_pencil_vertex_group( srna, "rna_GreasePencilOpacityModifier_vertex_group_name_set"); rna_def_modifier_grease_pencil_custom_curve(srna); - RNA_define_lib_overridable(true); prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE); @@ -7771,6 +7794,144 @@ static void rna_def_modifier_grease_pencil_subdiv(BlenderRNA *brna) RNA_define_lib_overridable(false); } +static void rna_def_modifier_grease_pencil_color(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"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + srna = RNA_def_struct(brna, "GreasePencilColorModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Grease Pencil Color Modifier", ""); + RNA_def_struct_sdna(srna, "GreasePencilColorModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_HUE_SATURATION); + + rna_def_modifier_grease_pencil_layer_filter(srna); + rna_def_modifier_grease_pencil_material_filter( + srna, "rna_GreasePencilColorModifier_material_filter_set"); + rna_def_modifier_grease_pencil_custom_curve(srna); + + 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, "hue", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); + RNA_def_property_float_sdna(prop, nullptr, "hsv[0]"); + RNA_def_property_ui_text(prop, "Hue", "Color hue offset"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3); + RNA_def_property_float_sdna(prop, nullptr, "hsv[1]"); + RNA_def_property_ui_text(prop, "Saturation", "Color saturation factor"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3); + RNA_def_property_float_sdna(prop, nullptr, "hsv[2]"); + RNA_def_property_ui_text(prop, "Value", "Color value factor"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); +} + +static void rna_def_modifier_grease_pencil_tint(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"}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + static const EnumPropertyItem tint_mode_items[] = { + {MOD_GREASE_PENCIL_TINT_UNIFORM, "UNIFORM", 0, "Uniform", ""}, + {MOD_GREASE_PENCIL_TINT_GRADIENT, "GRADIENT", 0, "Gradient", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + srna = RNA_def_struct(brna, "GreasePencilTintModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Grease Pencil Tint Modifier", ""); + RNA_def_struct_sdna(srna, "GreasePencilTintModifierData"); + 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_GreasePencilTintModifier_material_filter_set"); + rna_def_modifier_grease_pencil_vertex_group( + srna, "rna_GreasePencilTintModifier_vertex_group_name_set"); + rna_def_modifier_grease_pencil_custom_curve(srna); + + 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, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0, 2.0); + RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 2); + RNA_def_property_ui_text(prop, "Factor", "Factor for tinting"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Type of Tint. */ + prop = RNA_def_property(srna, "tint_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, tint_mode_items); + RNA_def_property_ui_text(prop, "Tint Mode", ""); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Simple Color. */ + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Color", "Color used for tinting"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* Color band. */ + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", "Gradient tinting colors"); + 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 for the gradient direction"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_pointer_funcs( + prop, nullptr, "rna_GreasePencilTintModifier_object_set", nullptr, nullptr); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + + prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 1, 3); + RNA_def_property_ui_text(prop, "Radius", "Influence distance from the object"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + RNA_define_lib_overridable(false); + + prop = RNA_def_property(srna, "use_weight_as_factor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, nullptr, "flag", MOD_GREASE_PENCIL_TINT_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"); +} + void RNA_def_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -7933,6 +8094,8 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_volume_to_mesh(brna); rna_def_modifier_grease_pencil_opacity(brna); rna_def_modifier_grease_pencil_subdiv(brna); + rna_def_modifier_grease_pencil_color(brna); + rna_def_modifier_grease_pencil_tint(brna); } #endif diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index dafd5ecbcf9..d64184d3ee5 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -44,8 +44,10 @@ set(SRC intern/MOD_edgesplit.cc intern/MOD_explode.cc intern/MOD_fluid.cc + intern/MOD_grease_pencil_color.cc intern/MOD_grease_pencil_opacity.cc intern/MOD_grease_pencil_subdiv.cc + intern/MOD_grease_pencil_tint.cc intern/MOD_grease_pencil_util.cc intern/MOD_hook.cc intern/MOD_laplaciandeform.cc diff --git a/source/blender/modifiers/MOD_modifiertypes.hh b/source/blender/modifiers/MOD_modifiertypes.hh index 3dd36537c8a..088366c44ba 100644 --- a/source/blender/modifiers/MOD_modifiertypes.hh +++ b/source/blender/modifiers/MOD_modifiertypes.hh @@ -75,6 +75,8 @@ extern ModifierTypeInfo modifierType_VolumeDisplace; extern ModifierTypeInfo modifierType_VolumeToMesh; extern ModifierTypeInfo modifierType_GreasePencilOpacity; extern ModifierTypeInfo modifierType_GreasePencilSubdiv; +extern ModifierTypeInfo modifierType_GreasePencilColor; +extern ModifierTypeInfo modifierType_GreasePencilTint; /* MOD_util.cc */ diff --git a/source/blender/modifiers/intern/MOD_grease_pencil_color.cc b/source/blender/modifiers/intern/MOD_grease_pencil_color.cc new file mode 100644 index 00000000000..b04e8907f06 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_grease_pencil_color.cc @@ -0,0 +1,316 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup modifiers + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math_color.hh" + +#include "DNA_defaults.h" +#include "DNA_material_types.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_material.h" +#include "BKE_modifier.hh" +#include "BKE_screen.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" + +namespace blender { + +using bke::greasepencil::Drawing; + +static void init_data(ModifierData *md) +{ + auto *cmd = reinterpret_cast(md); + + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(cmd, modifier)); + + MEMCPY_STRUCT_AFTER(cmd, DNA_struct_default_get(GreasePencilColorModifierData), modifier); + modifier::greasepencil::init_influence_data(&cmd->influence, true); +} + +static void copy_data(const ModifierData *md, ModifierData *target, const int flag) +{ + const auto *cmd = reinterpret_cast(md); + auto *tcmd = reinterpret_cast(target); + + modifier::greasepencil::free_influence_data(&tcmd->influence); + + BKE_modifier_copydata_generic(md, target, flag); + modifier::greasepencil::copy_influence_data(&cmd->influence, &tcmd->influence, flag); +} + +static void free_data(ModifierData *md) +{ + auto *cmd = reinterpret_cast(md); + modifier::greasepencil::free_influence_data(&cmd->influence); +} + +static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data) +{ + auto *cmd = reinterpret_cast(md); + modifier::greasepencil::foreach_influence_ID_link(&cmd->influence, ob, walk, user_data); +} + +static void apply_color_factor(ColorGeometry4f &color, + const ColorGeometry4f &material_color, + const float3 factor) +{ + float3 hsv; + /* When input alpha is zero, replace with material color. */ + if (color.a == 0.0f && material_color.a > 0.0f) { + color.a = 1.0f; + rgb_to_hsv_v(material_color, hsv); + } + else { + rgb_to_hsv_v(color, hsv); + } + hsv[0] = fractf(hsv[0] + factor[0] + 0.5f); + hsv[1] = clamp_f(hsv[1] * factor[1], 0.0f, 1.0f); + hsv[2] = hsv[2] * factor[2]; + hsv_to_rgb_v(hsv, color); +} + +static void modify_stroke_color(Object &ob, + const GreasePencilColorModifierData &cmd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask, + const MutableSpan vertex_colors) +{ + const bool use_curve = (cmd.influence.flag & GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE); + const OffsetIndices points_by_curve = curves.points_by_curve(); + + bke::AttributeAccessor attributes = curves.attributes(); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + + curves_mask.foreach_index(GrainSize(512), [&](const int64_t curve_i) { + const Material *ma = BKE_object_material_get(&ob, stroke_materials[curve_i]); + const MaterialGPencilStyle *gp_style = ma ? ma->gp_style : nullptr; + const ColorGeometry4f material_color = (gp_style ? gp_style->fill_rgba : + ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + + const IndexRange points = points_by_curve[curve_i]; + for (const int64_t i : points.index_range()) { + const int64_t point_i = points[i]; + float3 factor = cmd.hsv; + if (use_curve) { + const float curve_input = points.size() >= 2 ? (float(i) / float(points.size() - 1)) : + 0.0f; + const float curve_factor = BKE_curvemapping_evaluateF( + cmd.influence.custom_curve, 0, curve_input); + factor *= curve_factor; + } + + apply_color_factor(vertex_colors[point_i], material_color, factor); + } + }); +} + +static void modify_fill_color(Object &ob, + const GreasePencilColorModifierData &cmd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + /* Fill color per stroke. */ + bke::SpanAttributeWriter fill_colors = + attributes.lookup_or_add_for_write_span("fill_color", + bke::AttrDomain::Curve); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + + curves_mask.foreach_index(GrainSize(512), [&](int64_t curve_i) { + const Material *ma = BKE_object_material_get(&ob, stroke_materials[curve_i]); + const MaterialGPencilStyle *gp_style = ma ? ma->gp_style : nullptr; + const ColorGeometry4f material_color = (gp_style ? gp_style->fill_rgba : + ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + + apply_color_factor(fill_colors.span[curve_i], material_color, cmd.hsv); + }); + + fill_colors.finish(); +} + +static void modify_drawing(ModifierData &md, const ModifierEvalContext &ctx, Drawing &drawing) +{ + auto &cmd = reinterpret_cast(md); + + bke::CurvesGeometry &curves = drawing.strokes_for_write(); + IndexMaskMemory mask_memory; + const IndexMask curves_mask = modifier::greasepencil::get_filtered_stroke_mask( + ctx.object, curves, cmd.influence, mask_memory); + + switch (cmd.color_mode) { + case MOD_GREASE_PENCIL_COLOR_STROKE: + modify_stroke_color( + *ctx.object, cmd, curves, curves_mask, drawing.vertex_colors_for_write()); + break; + case MOD_GREASE_PENCIL_COLOR_FILL: + modify_fill_color(*ctx.object, cmd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_BOTH: + modify_stroke_color( + *ctx.object, cmd, curves, curves_mask, drawing.vertex_colors_for_write()); + modify_fill_color(*ctx.object, cmd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_HARDNESS: + BLI_assert_unreachable(); + break; + } +} + +static void modify_geometry_set(ModifierData *md, + const ModifierEvalContext *ctx, + bke::GeometrySet *geometry_set) +{ + auto *cmd = reinterpret_cast(md); + + if (!geometry_set->has_grease_pencil()) { + return; + } + GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write(); + const int frame = grease_pencil.runtime->eval_frame; + + IndexMaskMemory mask_memory; + const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask( + grease_pencil, cmd->influence, mask_memory); + const Vector drawings = modifier::greasepencil::get_drawings_for_write( + grease_pencil, layer_mask, frame); + threading::parallel_for_each(drawings, + [&](Drawing *drawing) { modify_drawing(*md, *ctx, *drawing); }); +} + +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); + } + } + + LayoutPanelState *influence_panel_state = BKE_panel_layout_panel_state_ensure( + panel, "influence", true); + PointerRNA influence_state_ptr = RNA_pointer_create( + nullptr, &RNA_LayoutPanelState, influence_panel_state); + if (uiLayout *influence_panel = uiLayoutPanel( + C, layout, "Influence", &influence_state_ptr, "is_open")) + { + 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_GreasePencilColor, panel_draw); +} + +static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md) +{ + const auto *cmd = reinterpret_cast(md); + + BLO_write_struct(writer, GreasePencilColorModifierData, cmd); + modifier::greasepencil::write_influence_data(writer, &cmd->influence); +} + +static void blend_read(BlendDataReader *reader, ModifierData *md) +{ + auto *cmd = reinterpret_cast(md); + + modifier::greasepencil::read_influence_data(reader, &cmd->influence); +} + +} // namespace blender + +ModifierTypeInfo modifierType_GreasePencilColor = { + /*idname*/ "GreasePencilColor", + /*name*/ N_("Color"), + /*struct_name*/ "GreasePencilColorModifierData", + /*struct_size*/ sizeof(GreasePencilColorModifierData), + /*srna*/ &RNA_GreasePencilColorModifier, + /*type*/ ModifierTypeType::NonGeometrical, + /*flags*/ eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping, + /*icon*/ ICON_MOD_HUE_SATURATION, + + /*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_tint.cc b/source/blender/modifiers/intern/MOD_grease_pencil_tint.cc new file mode 100644 index 00000000000..e84081bcb65 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_grease_pencil_tint.cc @@ -0,0 +1,509 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup modifiers + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math_matrix.hh" + +#include "DNA_defaults.h" +#include "DNA_material_types.h" +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_colorband.hh" +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" +#include "BKE_grease_pencil.hh" +#include "BKE_lib_query.hh" +#include "BKE_material.h" +#include "BKE_modifier.hh" +#include "BKE_screen.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" + +namespace blender { + +using bke::greasepencil::Drawing; + +static void init_data(ModifierData *md) +{ + auto *tmd = reinterpret_cast(md); + + BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(tmd, modifier)); + + MEMCPY_STRUCT_AFTER(tmd, DNA_struct_default_get(GreasePencilTintModifierData), modifier); + modifier::greasepencil::init_influence_data(&tmd->influence, true); + + /* Add default color ramp. */ + tmd->color_ramp = BKE_colorband_add(false); + if (tmd->color_ramp) { + BKE_colorband_init(tmd->color_ramp, true); + CBData *data = tmd->color_ramp->data; + data[0].r = data[0].g = data[0].b = data[0].a = 1.0f; + data[0].pos = 0.0f; + data[1].r = data[1].g = data[1].b = 0.0f; + data[1].a = 1.0f; + data[1].pos = 1.0f; + + tmd->color_ramp->tot = 2; + } +} + +static void copy_data(const ModifierData *md, ModifierData *target, const int flag) +{ + const auto *tmd = reinterpret_cast(md); + auto *ttmd = reinterpret_cast(target); + + modifier::greasepencil::free_influence_data(&ttmd->influence); + MEM_SAFE_FREE(ttmd->color_ramp); + + BKE_modifier_copydata_generic(md, target, flag); + modifier::greasepencil::copy_influence_data(&tmd->influence, &ttmd->influence, flag); + + if (tmd->color_ramp) { + ttmd->color_ramp = static_cast(MEM_dupallocN(tmd->color_ramp)); + } +} + +static void free_data(ModifierData *md) +{ + auto *tmd = reinterpret_cast(md); + modifier::greasepencil::free_influence_data(&tmd->influence); + + MEM_SAFE_FREE(tmd->color_ramp); +} + +static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data) +{ + auto *tmd = reinterpret_cast(md); + modifier::greasepencil::foreach_influence_ID_link(&tmd->influence, ob, walk, user_data); + walk(user_data, ob, (ID **)&tmd->object, IDWALK_CB_NOP); +} + +static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/) +{ + auto *tmd = reinterpret_cast(md); + if (tmd->tint_mode == MOD_GREASE_PENCIL_TINT_GRADIENT) { + return tmd->object == nullptr; + } + return false; +} + +static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + auto *tmd = reinterpret_cast(md); + if (tmd->object != nullptr) { + DEG_add_object_relation( + ctx->node, tmd->object, DEG_OB_COMP_TRANSFORM, "Grease Pencil Tint Modifier"); + } + DEG_add_object_relation( + ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Grease Pencil Tint Modifier"); +} + +static ColorGeometry4f get_base_color(const ColorGeometry4f &input_color, + const ColorGeometry4f &material_color) +{ + /* When input alpha is zero, replace with material color. */ + return (input_color.a == 0.0f && material_color.a > 0.0f) ? material_color : input_color; +} + +static ColorGeometry4f apply_uniform_tint(const GreasePencilTintModifierData &tmd, + const ColorGeometry4f &input_color, + const float factor) +{ + const float3 rgb = math::interpolate( + float3(input_color.r, input_color.g, input_color.b), float3(tmd.color), factor); + /* Alpha is unchanged. */ + return ColorGeometry4f(rgb[0], rgb[1], rgb[2], input_color.a); +} + +static ColorGeometry4f apply_gradient_tint(const GreasePencilTintModifierData &tmd, + const float4x4 &matrix, + const float3 &position, + const ColorGeometry4f &input_color, + const float factor) +{ + const float3 gradient_pos = math::transform_point(matrix, position); + const float gradient_factor = std::clamp( + math::safe_divide(math::length(gradient_pos), tmd.radius), 0.0f, 1.0f); + + float4 gradient_color; + BKE_colorband_evaluate(tmd.color_ramp, gradient_factor, gradient_color); + + const float3 input_rgb = {input_color.r, input_color.g, input_color.b}; + /* GP2 compatibility: ignore vertex group factor and use the plain modifier setting for + * RGB mixing. */ + const float3 rgb = math::interpolate(input_rgb, gradient_color.xyz(), tmd.factor); + /* GP2 compatibility: use vertex group factor for alpha. */ + return ColorGeometry4f(rgb[0], rgb[1], rgb[2], factor); +} + +static void modify_stroke_color(Object &ob, + const GreasePencilTintModifierData &tmd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask, + const MutableSpan vertex_colors) +{ + const bool use_weight_as_factor = (tmd.flag & MOD_GREASE_PENCIL_TINT_USE_WEIGHT_AS_FACTOR); + const bool invert_vertex_group = (tmd.influence.flag & + GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP); + const OffsetIndices points_by_curve = curves.points_by_curve(); + + bke::AttributeAccessor attributes = curves.attributes(); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + const VArray vgroup_weights = *attributes.lookup_or_default( + tmd.influence.vertex_group_name, bke::AttrDomain::Point, 1.0f); + + /* Common input color and base factor calculation. */ + auto get_material_color = [&](const int64_t curve_i) { + const Material *ma = BKE_object_material_get(&ob, stroke_materials[curve_i]); + const MaterialGPencilStyle *gp_style = ma ? ma->gp_style : nullptr; + return (gp_style ? gp_style->stroke_rgba : ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + }; + + auto get_point_factor = [&](const int64_t point_i) { + if (use_weight_as_factor) { + const float weight = vgroup_weights[point_i]; + return invert_vertex_group ? 1.0f - weight : weight; + } + return tmd.factor; + }; + + const GreasePencilTintModifierMode tint_mode = GreasePencilTintModifierMode(tmd.tint_mode); + switch (tint_mode) { + case MOD_GREASE_PENCIL_TINT_UNIFORM: { + curves_mask.foreach_index(GrainSize(512), [&](const int64_t curve_i) { + const ColorGeometry4f material_color = get_material_color(curve_i); + + const IndexRange points = points_by_curve[curve_i]; + for (const int64_t point_i : points) { + vertex_colors[point_i] = apply_uniform_tint( + tmd, + get_base_color(vertex_colors[point_i], material_color), + get_point_factor(point_i)); + } + }); + break; + } + case MOD_GREASE_PENCIL_TINT_GRADIENT: { + if (tmd.object == nullptr) { + return; + } + + const OffsetIndices points_by_curve = curves.points_by_curve(); + const Span positions = curves.positions(); + /* Transforms points to the gradient object space. */ + const float4x4 matrix = float4x4_view(tmd.object->world_to_object) * + float4x4_view(ob.object_to_world); + + curves_mask.foreach_index(GrainSize(512), [&](const int64_t curve_i) { + const ColorGeometry4f material_color = get_material_color(curve_i); + + const IndexRange points = points_by_curve[curve_i]; + for (const int64_t point_i : points) { + vertex_colors[point_i] = apply_gradient_tint( + tmd, + matrix, + positions[point_i], + get_base_color(vertex_colors[point_i], material_color), + get_point_factor(point_i)); + } + }); + break; + } + } +} + +static void modify_fill_color(Object &ob, + const GreasePencilTintModifierData &tmd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + const bool use_weight_as_factor = (tmd.flag & MOD_GREASE_PENCIL_TINT_USE_WEIGHT_AS_FACTOR); + const bool invert_vertex_group = (tmd.influence.flag & + GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP); + const OffsetIndices points_by_curve = curves.points_by_curve(); + const GreasePencilTintModifierMode tint_mode = GreasePencilTintModifierMode(tmd.tint_mode); + + /* Check early before getting attribute writers. */ + if (tint_mode == MOD_GREASE_PENCIL_TINT_GRADIENT && tmd.object == nullptr) { + return; + } + + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + /* Fill color per stroke. */ + bke::SpanAttributeWriter fill_colors = + attributes.lookup_or_add_for_write_span("fill_color", + bke::AttrDomain::Curve); + const VArray stroke_materials = *attributes.lookup_or_default( + "material_index", bke::AttrDomain::Curve, 0); + const VArray vgroup_weights = *attributes.lookup_or_default( + tmd.influence.vertex_group_name, bke::AttrDomain::Point, 1.0f); + + /* Common input color and base factor calculation. */ + auto get_material_color = [&](const int64_t curve_i) { + const Material *ma = BKE_object_material_get(&ob, stroke_materials[curve_i]); + const MaterialGPencilStyle *gp_style = ma ? ma->gp_style : nullptr; + return (gp_style ? gp_style->fill_rgba : ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + }; + + auto get_curve_factor = [&](const int64_t curve_i) { + if (use_weight_as_factor) { + /* Use the first stroke point as vertex weight. */ + const IndexRange points = points_by_curve[curve_i]; + const float weight = points.is_empty() ? 1.0f : vgroup_weights[points.first()]; + return invert_vertex_group ? 1.0f - weight : weight; + } + return tmd.factor; + }; + + switch (tint_mode) { + case MOD_GREASE_PENCIL_TINT_UNIFORM: { + curves_mask.foreach_index(GrainSize(512), [&](int64_t curve_i) { + const ColorGeometry4f material_color = get_material_color(curve_i); + fill_colors.span[curve_i] = apply_uniform_tint( + tmd, + get_base_color(fill_colors.span[curve_i], material_color), + get_curve_factor(curve_i)); + }); + break; + } + case MOD_GREASE_PENCIL_TINT_GRADIENT: { + const OffsetIndices points_by_curve = curves.points_by_curve(); + const Span positions = curves.positions(); + /* Transforms points to the gradient object space. */ + const float4x4 matrix = float4x4_view(tmd.object->world_to_object) * + float4x4_view(ob.object_to_world); + + curves_mask.foreach_index(GrainSize(512), [&](int64_t curve_i) { + const ColorGeometry4f material_color = get_material_color(curve_i); + /* Use the first stroke point for gradient position. */ + const IndexRange points = points_by_curve[curve_i]; + const float3 pos = points.is_empty() ? float3(0.0f, 0.0f, 0.0f) : + positions[points.first()]; + + fill_colors.span[curve_i] = apply_gradient_tint( + tmd, + matrix, + pos, + get_base_color(fill_colors.span[curve_i], material_color), + get_curve_factor(curve_i)); + }); + break; + } + } + + fill_colors.finish(); +} + +static void modify_opacity(const GreasePencilTintModifierData &tmd, + bke::CurvesGeometry &curves, + const IndexMask &curves_mask) +{ + /* Only when factor is greater than 1. */ + if (tmd.factor <= 1.0f) { + return; + } + + 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); + + 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) { + opacities.span[point_i] = std::clamp( + opacities.span[point_i] + tmd.factor - 1.0f, 0.0f, 1.0f); + } + }); + + opacities.finish(); +} + +static void modify_curves(ModifierData &md, const ModifierEvalContext &ctx, Drawing &drawing) +{ + auto &tmd = reinterpret_cast(md); + bke::CurvesGeometry &curves = drawing.strokes_for_write(); + + IndexMaskMemory mask_memory; + const IndexMask curves_mask = modifier::greasepencil::get_filtered_stroke_mask( + ctx.object, curves, tmd.influence, mask_memory); + + /* Factor > 1.0 also affects the opacity of the stroke. */ + modify_opacity(tmd, curves, curves_mask); + + switch (tmd.color_mode) { + case MOD_GREASE_PENCIL_COLOR_STROKE: + modify_stroke_color( + *ctx.object, tmd, curves, curves_mask, drawing.vertex_colors_for_write()); + break; + case MOD_GREASE_PENCIL_COLOR_FILL: + modify_fill_color(*ctx.object, tmd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_BOTH: + modify_stroke_color( + *ctx.object, tmd, curves, curves_mask, drawing.vertex_colors_for_write()); + modify_fill_color(*ctx.object, tmd, curves, curves_mask); + break; + case MOD_GREASE_PENCIL_COLOR_HARDNESS: + BLI_assert_unreachable(); + break; + } +} + +static void modify_geometry_set(ModifierData *md, + const ModifierEvalContext *ctx, + bke::GeometrySet *geometry_set) +{ + auto *tmd = reinterpret_cast(md); + + if (!geometry_set->has_grease_pencil()) { + return; + } + GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write(); + const int frame = grease_pencil.runtime->eval_frame; + + IndexMaskMemory mask_memory; + const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask( + grease_pencil, tmd->influence, mask_memory); + const Vector drawings = modifier::greasepencil::get_drawings_for_write( + grease_pencil, layer_mask, frame); + threading::parallel_for_each(drawings, + [&](Drawing *drawing) { modify_curves(*md, *ctx, *drawing); }); +} + +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 GreasePencilTintModifierMode tint_mode = GreasePencilTintModifierMode( + RNA_enum_get(ptr, "tint_mode")); + const bool use_weight_as_factor = RNA_boolean_get(ptr, "use_weight_as_factor"); + + uiItemR(layout, ptr, "color_mode", UI_ITEM_NONE, nullptr, ICON_NONE); + + uiLayout *row = uiLayoutRow(layout, true); + uiLayoutSetActive(row, !use_weight_as_factor); + uiItemR(row, ptr, "factor", UI_ITEM_NONE, nullptr, ICON_NONE); + uiItemR(row, ptr, "use_weight_as_factor", UI_ITEM_NONE, "", ICON_MOD_VERTEX_WEIGHT); + + uiItemR(layout, ptr, "tint_mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + switch (tint_mode) { + case MOD_GREASE_PENCIL_TINT_UNIFORM: + uiItemR(layout, ptr, "color", UI_ITEM_NONE, nullptr, ICON_NONE); + break; + case MOD_GREASE_PENCIL_TINT_GRADIENT: + uiLayout *col = uiLayoutColumn(layout, false); + uiLayoutSetPropSep(col, false); + uiTemplateColorRamp(col, ptr, "color_ramp", true); + uiItemS(layout); + uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE); + uiItemR(layout, ptr, "radius", UI_ITEM_NONE, nullptr, ICON_NONE); + break; + } + + LayoutPanelState *influence_panel_state = BKE_panel_layout_panel_state_ensure( + panel, "influence", true); + PointerRNA influence_state_ptr = RNA_pointer_create( + nullptr, &RNA_LayoutPanelState, influence_panel_state); + if (uiLayout *influence_panel = uiLayoutPanel( + C, layout, "Influence", &influence_state_ptr, "is_open")) + { + 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_GreasePencilTint, panel_draw); +} + +static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md) +{ + const auto *tmd = reinterpret_cast(md); + + BLO_write_struct(writer, GreasePencilTintModifierData, tmd); + modifier::greasepencil::write_influence_data(writer, &tmd->influence); + if (tmd->color_ramp) { + BLO_write_struct(writer, ColorBand, tmd->color_ramp); + } +} + +static void blend_read(BlendDataReader *reader, ModifierData *md) +{ + auto *tmd = reinterpret_cast(md); + + modifier::greasepencil::read_influence_data(reader, &tmd->influence); + BLO_read_data_address(reader, &tmd->color_ramp); +} + +} // namespace blender + +ModifierTypeInfo modifierType_GreasePencilTint = { + /*idname*/ "GreasePencilTint", + /*name*/ N_("Tint"), + /*struct_name*/ "GreasePencilTintModifierData", + /*struct_size*/ sizeof(GreasePencilTintModifierData), + /*srna*/ &RNA_GreasePencilTintModifier, + /*type*/ ModifierTypeType::NonGeometrical, + /*flags*/ eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping, + /*icon*/ ICON_MOD_TINT, + + /*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*/ blender::is_disabled, + /*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, +}; diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 4a2964a983b..505db9e77bb 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -272,5 +272,7 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(Nodes); INIT_TYPE(GreasePencilOpacity); INIT_TYPE(GreasePencilSubdiv); + INIT_TYPE(GreasePencilColor); + INIT_TYPE(GreasePencilTint); #undef INIT_TYPE }