GPv3: Tint and Color modifiers
Implements the Tint and Color (aka. "Hue/Saturation") modifiers. Pull Request: https://projects.blender.org/blender/blender/pulls/117297
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<GreasePencilTintModifierData *>(ptr->data);
|
||||
Object *ob = static_cast<Object *>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
316
source/blender/modifiers/intern/MOD_grease_pencil_color.cc
Normal file
316
source/blender/modifiers/intern/MOD_grease_pencil_color.cc
Normal file
@@ -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<GreasePencilColorModifierData *>(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<const GreasePencilColorModifierData *>(md);
|
||||
auto *tcmd = reinterpret_cast<GreasePencilColorModifierData *>(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<GreasePencilColorModifierData *>(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<GreasePencilColorModifierData *>(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<ColorGeometry4f> vertex_colors)
|
||||
{
|
||||
const bool use_curve = (cmd.influence.flag & GREASE_PENCIL_INFLUENCE_USE_CUSTOM_CURVE);
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
||||
bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"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<ColorGeometry4f> fill_colors =
|
||||
attributes.lookup_or_add_for_write_span<ColorGeometry4f>("fill_color",
|
||||
bke::AttrDomain::Curve);
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"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<GreasePencilColorModifierData &>(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<GreasePencilColorModifierData *>(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<Drawing *> 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<const GreasePencilColorModifierData *>(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<GreasePencilColorModifierData *>(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,
|
||||
};
|
||||
509
source/blender/modifiers/intern/MOD_grease_pencil_tint.cc
Normal file
509
source/blender/modifiers/intern/MOD_grease_pencil_tint.cc
Normal file
@@ -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<GreasePencilTintModifierData *>(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<const GreasePencilTintModifierData *>(md);
|
||||
auto *ttmd = reinterpret_cast<GreasePencilTintModifierData *>(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<ColorBand *>(MEM_dupallocN(tmd->color_ramp));
|
||||
}
|
||||
}
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
auto *tmd = reinterpret_cast<GreasePencilTintModifierData *>(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<GreasePencilTintModifierData *>(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<GreasePencilTintModifierData *>(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<GreasePencilTintModifierData *>(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<ColorGeometry4f> 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<int> points_by_curve = curves.points_by_curve();
|
||||
|
||||
bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
const VArray<float> vgroup_weights = *attributes.lookup_or_default<float>(
|
||||
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<int> points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> 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<int> 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<ColorGeometry4f> fill_colors =
|
||||
attributes.lookup_or_add_for_write_span<ColorGeometry4f>("fill_color",
|
||||
bke::AttrDomain::Curve);
|
||||
const VArray<int> stroke_materials = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Curve, 0);
|
||||
const VArray<float> vgroup_weights = *attributes.lookup_or_default<float>(
|
||||
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<int> points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> 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<int> points_by_curve = curves.points_by_curve();
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> opacities = attributes.lookup_or_add_for_write_span<float>(
|
||||
"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<GreasePencilTintModifierData &>(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<GreasePencilTintModifierData *>(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<Drawing *> 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<const GreasePencilTintModifierData *>(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<GreasePencilTintModifierData *>(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,
|
||||
};
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user