Blender V4.3
MOD_grease_pencil_mirror.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "DNA_defaults.h"
10#include "DNA_modifier_types.h"
11
12#include "BKE_curves.hh"
13#include "BKE_geometry_set.hh"
14#include "BKE_grease_pencil.hh"
15#include "BKE_instances.hh"
16#include "BKE_lib_query.hh"
17#include "BKE_modifier.hh"
18
19#include "BLO_read_write.hh"
20
22
23#include "UI_interface.hh"
24#include "UI_resources.hh"
25
26#include "BLT_translation.hh"
27
28#include "WM_types.hh"
29
30#include "RNA_prototypes.hh"
31
33#include "MOD_ui_common.hh"
34
35namespace blender {
36
37static void init_data(ModifierData *md)
38{
39 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
40
42
44 modifier::greasepencil::init_influence_data(&mmd->influence, false);
45}
46
47static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
48{
49 const auto *mmd = reinterpret_cast<const GreasePencilMirrorModifierData *>(md);
50 auto *tmmd = reinterpret_cast<GreasePencilMirrorModifierData *>(target);
51
53
55 modifier::greasepencil::copy_influence_data(&mmd->influence, &tmmd->influence, flag);
56}
57
58static void free_data(ModifierData *md)
59{
60 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
62}
63
64static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
65{
66 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
67 walk(user_data, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
68 modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
69}
70
72{
73 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
74 if (mmd->object != nullptr) {
76 ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Grease Pencil Mirror Modifier");
77 DEG_add_depends_on_transform_relation(ctx->node, "Grease Pencil Mirror Modifier");
78 }
79}
80
83 const bool mirror_x,
84 const bool mirror_y,
85 const bool mirror_z)
86{
88 float3(mirror_x ? -1.0f : 1.0f, mirror_y ? -1.0f : 1.0f, mirror_z ? -1.0f : 1.0f));
89
90 if (mmd.object) {
91 /* Transforms from parent object space to target object space. */
92 const float4x4 to_target = math::invert(mmd.object->object_to_world()) * ob.object_to_world();
93 /* Mirror points in the target object space. */
94 matrix = math::invert(to_target) * matrix * to_target;
95 }
96 return matrix;
97}
98
101 const bke::CurvesGeometry &base_curves,
102 const bke::CurvesGeometry &mirror_curves)
103{
104 const bool use_mirror_x = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_X);
105 const bool use_mirror_y = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_Y);
106 const bool use_mirror_z = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_Z);
107
108 Curves *base_curves_id = bke::curves_new_nomain(base_curves);
109 Curves *mirror_curves_id = bke::curves_new_nomain(mirror_curves);
110 bke::GeometrySet base_geo = bke::GeometrySet::from_curves(base_curves_id);
111 bke::GeometrySet mirror_geo = bke::GeometrySet::from_curves(mirror_curves_id);
112
113 std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
114 const int base_handle = instances->add_reference(bke::InstanceReference{base_geo});
115 const int mirror_handle = instances->add_reference(bke::InstanceReference{mirror_geo});
116 for (const int mirror_x : IndexRange(use_mirror_x ? 2 : 1)) {
117 for (const int mirror_y : IndexRange(use_mirror_y ? 2 : 1)) {
118 for (const int mirror_z : IndexRange(use_mirror_z ? 2 : 1)) {
119 if (mirror_x == 0 && mirror_y == 0 && mirror_z == 0) {
120 instances->add_instance(base_handle, float4x4::identity());
121 }
122 else {
123 const float4x4 matrix = get_mirror_matrix(
124 ob, mmd, bool(mirror_x), bool(mirror_y), bool(mirror_z));
125 instances->add_instance(mirror_handle, matrix);
126 }
127 }
128 }
129 }
130
132 options.keep_original_ids = true;
133 options.realize_instance_attributes = false;
135 bke::GeometrySet::from_instances(instances.release()), options);
136 return std::move(result_geo.get_curves_for_write()->geometry.wrap());
137}
138
140 const ModifierEvalContext &ctx,
142{
143 const bool use_mirror_x = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_X);
144 const bool use_mirror_y = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_Y);
145 const bool use_mirror_z = (mmd.flag & MOD_GREASE_PENCIL_MIRROR_AXIS_Z);
146 if (!use_mirror_x && !use_mirror_y && !use_mirror_z) {
147 return;
148 }
149
150 const bke::CurvesGeometry &src_curves = drawing.strokes();
151 if (src_curves.curve_num == 0) {
152 return;
153 }
154 /* Selected source curves. */
155 IndexMaskMemory curve_mask_memory;
157 ctx.object, src_curves, mmd.influence, curve_mask_memory);
158
159 if (curves_mask.size() == src_curves.curve_num) {
160 /* All geometry gets mirrored. */
161 drawing.strokes_for_write() = create_mirror_copies(*ctx.object, mmd, src_curves, src_curves);
162 }
163 else {
164 /* Create masked geometry, then mirror it. */
166 src_curves, curves_mask, {});
167
169 *ctx.object, mmd, src_curves, masked_curves);
170 }
171
172 drawing.tag_topology_changed();
173}
174
176 const ModifierEvalContext *ctx,
177 bke::GeometrySet *geometry_set)
178{
180
181 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
182
183 if (!geometry_set->has_grease_pencil()) {
184 return;
185 }
186 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
187 const int frame = grease_pencil.runtime->eval_frame;
188
189 IndexMaskMemory mask_memory;
191 grease_pencil, mmd->influence, mask_memory);
192
194 grease_pencil, layer_mask, frame);
196 [&](Drawing *drawing) { modify_drawing(*mmd, *ctx, *drawing); });
197}
198
199static void panel_draw(const bContext *C, Panel *panel)
200{
201 uiLayout *layout = panel->layout;
202
203 PointerRNA ob_ptr;
206
207 uiLayoutSetPropSep(layout, true);
208
209 uiLayout *row = uiLayoutRowWithHeading(layout, true, IFACE_("Axis"));
210 uiItemR(row, ptr, "use_axis_x", toggles_flag, nullptr, ICON_NONE);
211 uiItemR(row, ptr, "use_axis_y", toggles_flag, nullptr, ICON_NONE);
212 uiItemR(row, ptr, "use_axis_z", toggles_flag, nullptr, ICON_NONE);
213
214 uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
215
216 if (uiLayout *influence_panel = uiLayoutPanelProp(
217 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
218 {
221 }
222
223 modifier_panel_end(layout, ptr);
224}
225
230
231static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
232{
233 const auto *mmd = reinterpret_cast<const GreasePencilMirrorModifierData *>(md);
234
236 modifier::greasepencil::write_influence_data(writer, &mmd->influence);
237}
238
239static void blend_read(BlendDataReader *reader, ModifierData *md)
240{
241 auto *mmd = reinterpret_cast<GreasePencilMirrorModifierData *>(md);
242
243 modifier::greasepencil::read_influence_data(reader, &mmd->influence);
244}
245
246} // namespace blender
247
249 /*idname*/ "GreasePencilMirror",
250 /*name*/ N_("Mirror"),
251 /*struct_name*/ "GreasePencilMirrorModifierData",
252 /*struct_size*/ sizeof(GreasePencilMirrorModifierData),
253 /*srna*/ &RNA_GreasePencilMirrorModifier,
257 /*icon*/ ICON_MOD_MIRROR,
258
259 /*copy_data*/ blender::copy_data,
260
261 /*deform_verts*/ nullptr,
262 /*deform_matrices*/ nullptr,
263 /*deform_verts_EM*/ nullptr,
264 /*deform_matrices_EM*/ nullptr,
265 /*modify_mesh*/ nullptr,
266 /*modify_geometry_set*/ blender::modify_geometry_set,
267
268 /*init_data*/ blender::init_data,
269 /*required_data_mask*/ nullptr,
270 /*free_data*/ blender::free_data,
271 /*is_disabled*/ nullptr,
272 /*update_depsgraph*/ blender::update_depsgraph,
273 /*depends_on_time*/ nullptr,
274 /*depends_on_normals*/ nullptr,
275 /*foreach_ID_link*/ blender::foreach_ID_link,
276 /*foreach_tex_link*/ nullptr,
277 /*free_runtime_data*/ nullptr,
278 /*panel_register*/ blender::panel_register,
279 /*blend_write*/ blender::blend_write,
280 /*blend_read*/ blender::blend_read,
281};
Low-level operations for curves.
Low-level operations for grease pencil.
@ IDWALK_CB_NOP
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
#define BLI_assert(a)
Definition BLI_assert.h:50
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define IFACE_(msgid)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
#define DNA_struct_default_get(struct_name)
@ MOD_GREASE_PENCIL_MIRROR_AXIS_Z
@ MOD_GREASE_PENCIL_MIRROR_AXIS_X
@ MOD_GREASE_PENCIL_MIRROR_AXIS_Y
@ eModifierType_GreasePencilMirror
struct GreasePencilMirrorModifierData GreasePencilMirrorModifierData
ModifierTypeInfo modifierType_GreasePencilMirror
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
#define UI_ITEM_NONE
PanelLayout uiLayoutPanelProp(const bContext *C, uiLayout *layout, PointerRNA *open_prop_owner, const char *open_prop_name)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
eUI_Item_Flag
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
CCL_NAMESPACE_BEGIN struct Options options
CurvesGeometry curves_copy_curve_selection(const CurvesGeometry &curves, const IndexMask &curves_to_copy, const AttributeFilter &attribute_filter)
Curves * curves_new_nomain(int points_num, int curves_num)
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
CartesianBasis invert(const CartesianBasis &basis)
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
void read_influence_data(BlendDataReader *reader, GreasePencilModifierInfluenceData *influence_data)
void init_influence_data(GreasePencilModifierInfluenceData *influence_data, const bool has_custom_curve)
static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > layer_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
static IndexMask get_filtered_stroke_mask(const Object *ob, const bke::CurvesGeometry &curves, const Material *material_filter, const std::optional< int > material_pass_filter, const bool material_filter_invert, const bool material_pass_filter_invert, IndexMaskMemory &memory)
void write_influence_data(BlendWriter *writer, const GreasePencilModifierInfluenceData *influence_data)
Vector< bke::greasepencil::Drawing * > get_drawings_for_write(GreasePencil &grease_pencil, const IndexMask &layer_mask, const int frame)
void draw_material_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void draw_layer_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void free_influence_data(GreasePencilModifierInfluenceData *influence_data)
void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data, Object *ob, IDWalkFunc walk, void *user_data)
void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src, GreasePencilModifierInfluenceData *influence_data_dst, const int)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:58
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static bke::CurvesGeometry create_mirror_copies(const Object &ob, const GreasePencilMirrorModifierData &mmd, const bke::CurvesGeometry &base_curves, const bke::CurvesGeometry &mirror_curves)
static void init_data(ModifierData *md)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void panel_draw(const bContext *C, Panel *panel)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
static float4x4 get_mirror_matrix(const Object &ob, const GreasePencilMirrorModifierData &mmd, const bool mirror_x, const bool mirror_y, const bool mirror_z)
static void free_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void modify_drawing(const GreasePencilArrayModifierData &mmd, const ModifierEvalContext &ctx, bke::greasepencil::Drawing &drawing)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
VecBase< float, 3 > float3
static void blend_read(BlendDataReader *reader, ModifierData *md)
CurvesGeometry geometry
GreasePencilModifierInfluenceData influence
GreasePencilRuntimeHandle * runtime
Definition DNA_ID.h:413
struct uiLayout * layout
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GreasePencil * get_grease_pencil_for_write()
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138