Blender V4.5
MOD_grease_pencil_util.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
8
10
11#include "BLI_set.hh"
12#include "BLI_vector_set.hh"
13
15#include "DNA_material_types.h"
16#include "DNA_modifier_types.h"
17#include "DNA_screen_types.h"
18
19#include "BKE_colortools.hh"
20#include "BKE_curves.hh"
21#include "BKE_grease_pencil.hh"
22#include "BKE_lib_query.hh"
23#include "BKE_material.hh"
24
25#include "BLT_translation.hh"
26
27#include "BLO_read_write.hh"
28
29#include "RNA_access.hh"
30#include "RNA_prototypes.hh"
31
32#include "UI_interface.hh"
33
35
37
42
44 const bool has_custom_curve)
45{
46 if (has_custom_curve) {
47 influence_data->custom_curve = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
48 BKE_curvemapping_init(influence_data->custom_curve);
49 }
50}
51
53 GreasePencilModifierInfluenceData *influence_data_dst,
54 const int /*flag*/)
55{
56 memcpy(influence_data_dst, influence_data_src, sizeof(GreasePencilModifierInfluenceData));
57 influence_data_dst->custom_curve = BKE_curvemapping_copy(influence_data_src->custom_curve);
58}
59
61{
62 if (influence_data->custom_curve) {
63 BKE_curvemapping_free(influence_data->custom_curve);
64 influence_data->custom_curve = nullptr;
65 }
66}
67
69 Object *ob,
70 IDWalkFunc walk,
71 void *user_data)
72{
73 walk(user_data, ob, (ID **)&influence_data->material, IDWALK_CB_USER);
74}
75
77 const GreasePencilModifierInfluenceData *influence_data)
78{
79 if (influence_data->custom_curve) {
80 BKE_curvemapping_blend_write(writer, influence_data->custom_curve);
81 }
82}
83
86{
87 BLO_read_struct(reader, CurveMapping, &influence_data->custom_curve);
88 if (influence_data->custom_curve) {
89 BKE_curvemapping_blend_read(reader, influence_data->custom_curve);
90 /* Make sure the internal table exists. */
91 BKE_curvemapping_init(influence_data->custom_curve);
92 }
93}
94
96{
97 PointerRNA ob_ptr = RNA_pointer_create_discrete(ptr->owner_id, &RNA_Object, ptr->owner_id);
98 PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
99 const bool use_layer_pass = RNA_boolean_get(ptr, "use_layer_pass_filter");
100 const bool use_layer_group_filter = RNA_boolean_get(ptr, "use_layer_group_filter");
101 uiLayout *row, *col, *sub, *subsub;
102
103 uiLayoutSetPropSep(layout, true);
104
105 col = &layout->column(true);
106 row = &col->row(true);
107 uiLayoutSetPropDecorate(row, false);
108 if (use_layer_group_filter) {
109 uiItemPointerR(row,
110 ptr,
111 "tree_node_filter",
112 &obj_data_ptr,
113 "layer_groups",
114 "Group",
115 ICON_GREASEPENCIL_LAYER_GROUP);
116 }
117 else {
118 uiItemPointerR(row,
119 ptr,
120 "tree_node_filter",
121 &obj_data_ptr,
122 "layers",
123 std::nullopt,
124 ICON_OUTLINER_DATA_GP_LAYER);
125 }
126 sub = &row->row(true);
127 sub->prop(ptr, "use_layer_group_filter", UI_ITEM_NONE, "", ICON_GREASEPENCIL_LAYER_GROUP);
128 sub->prop(ptr, "invert_layer_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
129
130 row = &col->row(true, IFACE_("Layer Pass"));
131 uiLayoutSetPropDecorate(row, false);
132 sub = &row->row(true);
133 sub->prop(ptr, "use_layer_pass_filter", UI_ITEM_NONE, "", ICON_NONE);
134 subsub = &sub->row(true);
135 uiLayoutSetActive(subsub, use_layer_pass);
136 subsub->prop(ptr, "layer_pass_filter", UI_ITEM_NONE, "", ICON_NONE);
137 subsub->prop(ptr, "invert_layer_pass_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
138}
139
141{
142 PointerRNA ob_ptr = RNA_pointer_create_discrete(ptr->owner_id, &RNA_Object, ptr->owner_id);
143 PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
144 const bool use_material_pass = RNA_boolean_get(ptr, "use_material_pass_filter");
145 uiLayout *row, *col, *sub, *subsub;
146
147 uiLayoutSetPropSep(layout, true);
148
149 col = &layout->column(true);
150 row = &col->row(true);
151 uiLayoutSetPropDecorate(row, false);
153 row, ptr, "material_filter", &obj_data_ptr, "materials", std::nullopt, ICON_SHADING_TEXTURE);
154 sub = &row->row(true);
155 sub->prop(ptr, "invert_material_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
156
157 row = &col->row(true, IFACE_("Material Pass"));
158 uiLayoutSetPropDecorate(row, false);
159 sub = &row->row(true);
160 sub->prop(ptr, "use_material_pass_filter", UI_ITEM_NONE, "", ICON_NONE);
161 subsub = &sub->row(true);
162 uiLayoutSetActive(subsub, use_material_pass);
163 subsub->prop(ptr, "material_pass_filter", UI_ITEM_NONE, "", ICON_NONE);
164 subsub->prop(ptr, "invert_material_pass_filter", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
165}
166
168{
169 PointerRNA ob_ptr = RNA_pointer_create_discrete(ptr->owner_id, &RNA_Object, ptr->owner_id);
170 bool has_vertex_group = RNA_string_length(ptr, "vertex_group_name") != 0;
171 uiLayout *row, *col, *sub;
172
173 uiLayoutSetPropSep(layout, true);
174
175 col = &layout->column(true);
176 row = &col->row(true);
177 uiLayoutSetPropDecorate(row, false);
178 uiItemPointerR(row, ptr, "vertex_group_name", &ob_ptr, "vertex_groups", std::nullopt, ICON_NONE);
179 sub = &row->row(true);
180 uiLayoutSetActive(sub, has_vertex_group);
181 uiLayoutSetPropDecorate(sub, false);
182 sub->prop(ptr, "invert_vertex_group", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
183}
184
186{
187 bool use_custom_curve = RNA_boolean_get(ptr, "use_custom_curve");
188 uiLayout *row;
189
190 uiLayoutSetPropSep(layout, true);
191 row = &layout->row(true);
192 uiLayoutSetPropDecorate(row, false);
193 row->prop(ptr, "use_custom_curve", UI_ITEM_NONE, IFACE_("Custom Curve"), ICON_NONE);
194 if (use_custom_curve) {
195 uiTemplateCurveMapping(layout, ptr, "custom_curve", 0, false, false, false, false);
196 }
197}
198
205{
206 short *totcol = BKE_object_material_len_p(const_cast<Object *>(ob));
207 Vector<int> result(*totcol, 0);
208 for (short i = 0; i < *totcol; i++) {
209 const Material *ma = BKE_object_material_get(const_cast<Object *>(ob), i + 1);
210 if (ma) {
211 /* Pass index of the grease pencil material. */
212 result[i] = ma->gp_style->index;
213 }
214 }
215 return result;
216}
217
219 const std::optional<StringRef> tree_node_name_filter,
220 const std::optional<int> layer_pass_filter,
221 const bool layer_filter_invert,
222 const bool layer_pass_filter_invert,
223 IndexMaskMemory &memory)
224{
225 const IndexMask full_mask = grease_pencil.layers().index_range();
226 if (!tree_node_name_filter && !layer_pass_filter) {
227 return full_mask;
228 }
229
230 bke::AttributeAccessor layer_attributes = grease_pencil.attributes();
231 const Span<const Layer *> layers = grease_pencil.layers();
232 const VArray<int> layer_passes =
233 layer_attributes.lookup_or_default<int>("pass_index", bke::AttrDomain::Layer, 0).varray;
234
235 const LayerGroup *filter_layer_group = nullptr;
236 if (tree_node_name_filter) {
237 for (const LayerGroup *group : grease_pencil.layer_groups()) {
238 if (group->name() == tree_node_name_filter.value()) {
239 filter_layer_group = group;
240 break;
241 }
242 }
243 }
244
246 full_mask, GrainSize(4096), memory, [&](const int64_t layer_i) {
247 if (tree_node_name_filter) {
248 const Layer *layer = layers[layer_i];
249 if (filter_layer_group) {
250 const bool match = layer->is_child_of(*filter_layer_group);
251 if (match == layer_filter_invert) {
252 return false;
253 }
254 }
255 else {
256 const bool match = (layer->name() == tree_node_name_filter.value());
257 if (match == layer_filter_invert) {
258 return false;
259 }
260 }
261 }
262 if (layer_pass_filter) {
263 const int layer_pass = layer_passes.get(layer_i);
264 const bool match = (layer_pass == layer_pass_filter.value());
265 if (match == layer_pass_filter_invert) {
266 return false;
267 }
268 }
269 return true;
270 });
271 return result;
272}
273
275 const GreasePencilModifierInfluenceData &influence_data,
276 IndexMaskMemory &memory)
277{
279 grease_pencil,
280 influence_data.layer_name[0] != '\0' ?
281 std::make_optional<StringRef>(influence_data.layer_name) :
282 std::nullopt,
284 std::make_optional<int>(influence_data.layer_pass) :
285 std::nullopt,
288 memory);
289}
290
292 const bke::CurvesGeometry &curves,
293 const Material *material_filter,
294 const std::optional<int> material_pass_filter,
295 const bool material_filter_invert,
296 const bool material_pass_filter_invert,
297 IndexMaskMemory &memory)
298{
299 const IndexMask full_mask = curves.curves_range();
300 if (!material_filter && !material_pass_filter) {
301 return full_mask;
302 }
303
304 const int material_filter_index = BKE_object_material_index_get(
305 const_cast<Object *>(ob), const_cast<Material *>(material_filter));
306 const Vector<int> material_pass_by_index = get_grease_pencil_material_passes(ob);
307
308 bke::AttributeAccessor attributes = curves.attributes();
309 VArray<int> stroke_materials =
310 attributes.lookup_or_default<int>("material_index", bke::AttrDomain::Curve, 0).varray;
311
313 full_mask, GrainSize(4096), memory, [&](const int64_t stroke_i) {
314 const int material_index = stroke_materials.get(stroke_i);
315 if (material_filter != nullptr) {
316 const bool match = (material_index == material_filter_index);
317 if (match == material_filter_invert) {
318 return false;
319 }
320 }
321 if (material_pass_filter) {
322 const int material_pass = material_pass_by_index[material_index];
323 const bool match = (material_pass == material_pass_filter.value());
324 if (match == material_pass_filter_invert) {
325 return false;
326 }
327 }
328 return true;
329 });
330 return result;
331}
332
334 const bke::CurvesGeometry &curves,
335 const GreasePencilModifierInfluenceData &influence_data,
336 IndexMaskMemory &memory)
337{
339 ob,
340 curves,
341 influence_data.material,
343 std::make_optional<int>(influence_data.material_pass) :
344 std::nullopt,
347 memory);
348}
349
351 const GreasePencilModifierInfluenceData &influence_data)
352{
353 if (influence_data.vertex_group_name[0] == '\0') {
354 /* If vertex group is not set, use full weight for all vertices. */
355 return VArray<float>::ForSingle(1.0f, curves.point_num);
356 }
357 /* Vertex group weights, with zero weight as a fallback. */
358 VArray<float> influence_weights = *curves.attributes().lookup_or_default<float>(
359 influence_data.vertex_group_name, bke::AttrDomain::Point, 0.0f);
360
362 Array<float> influence_weights_inverted(influence_weights.size());
364 influence_weights_inverted.index_range(), 8192, [&](const IndexRange range) {
365 for (const int i : range) {
366 influence_weights_inverted[i] = 1.0f - influence_weights[i];
367 }
368 });
369 return VArray<float>::ForContainer(influence_weights_inverted);
370 }
371
372 return influence_weights;
373}
374
376 const IndexMask &layer_mask,
377 const int frame)
378{
379 using namespace blender::bke::greasepencil;
380 VectorSet<Drawing *> drawings;
381 layer_mask.foreach_index([&](const int64_t layer_i) {
382 const Layer &layer = grease_pencil.layer(layer_i);
383 /* Set of owned drawings, ignore drawing references to other data blocks. */
384 if (Drawing *drawing = grease_pencil.get_drawing_at(layer, frame)) {
385 drawings.add(drawing);
386 }
387 });
388 return Vector<Drawing *>(drawings.as_span());
389}
390
392 const IndexMask &layer_mask,
393 const int frame)
394{
395 using namespace blender::bke::greasepencil;
396 Set<Drawing *> drawings;
397 Vector<LayerDrawingInfo> drawing_infos;
398 layer_mask.foreach_index([&](const int64_t layer_i) {
399 const Layer &layer = grease_pencil.layer(layer_i);
400 Drawing *drawing = grease_pencil.get_drawing_at(layer, frame);
401 if (drawing == nullptr) {
402 return;
403 }
404
405 if (!drawings.contains(drawing)) {
406 drawings.add_new(drawing);
407 drawing_infos.append({drawing, int(layer_i)});
408 }
409 });
410 return drawing_infos;
411}
412
414 const IndexMask &layer_mask,
415 const int frame)
416{
417 using namespace blender::bke::greasepencil;
418 Set<Drawing *> drawings;
419 Vector<FrameDrawingInfo> drawing_infos;
420 layer_mask.foreach_index([&](const int64_t layer_i) {
421 const Layer &layer = grease_pencil.layer(layer_i);
422 const std::optional<int> start_frame = layer.start_frame_at(frame);
423 if (!start_frame) {
424 return;
425 }
426 Drawing *drawing = grease_pencil.get_drawing_at(layer, *start_frame);
427 if (drawing == nullptr) {
428 return;
429 }
430
431 if (!drawings.contains(drawing)) {
432 drawings.add_new(drawing);
433 drawing_infos.append({drawing, *start_frame});
434 }
435 });
436 return drawing_infos;
437}
438
440{
441 const bke::CurvesGeometry &curves = drawing.strokes();
442 IndexMaskMemory memory;
443 const IndexMask bezier_selection = curves.indices_for_curve_type(CURVE_TYPE_BEZIER, memory);
444 if (bezier_selection.is_empty()) {
445 return;
446 }
447 drawing.strokes_for_write() = geometry::resample_to_evaluated(curves, bezier_selection);
448 drawing.tag_topology_changed();
449}
450
451} // namespace blender::modifier::greasepencil
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
CurveMapping * BKE_curvemapping_copy(const CurveMapping *cumap)
void BKE_curvemapping_init(CurveMapping *cumap)
CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition colortools.cc:89
void BKE_curvemapping_free(CurveMapping *cumap)
void BKE_curvemapping_blend_write(BlendWriter *writer, const CurveMapping *cumap)
Low-level operations for curves.
Low-level operations for grease pencil.
@ IDWALK_CB_USER
General operations, lookup, etc. for materials.
short * BKE_object_material_len_p(Object *ob)
Material * BKE_object_material_get(Object *ob, short act)
int BKE_object_material_index_get(Object *ob, const Material *ma)
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
#define BLO_read_struct(reader, struct_name, ptr_p)
#define IFACE_(msgid)
float[3] Vector
@ CURVE_TYPE_BEZIER
@ GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP
@ GREASE_PENCIL_INFLUENCE_USE_MATERIAL_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_USE_LAYER_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_LAYER_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_PASS_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_MATERIAL_FILTER
@ GREASE_PENCIL_INFLUENCE_INVERT_LAYER_PASS_FILTER
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, PointerRNA *searchptr, blender::StringRefNull searchpropname, std::optional< blender::StringRefNull > name, int icon)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
long long int int64_t
IndexRange index_range() const
Definition BLI_array.hh:349
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
bool contains(const Key &key) const
Definition BLI_set.hh:310
void add_new(const Key &key)
Definition BLI_set.hh:233
T get(const int64_t index) const
static VArray ForContainer(ContainerT container)
static VArray ForSingle(T value, const int64_t size)
bool add(const Key &key)
Span< Key > as_span() const
void append(const T &value)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
IndexRange curves_range() const
AttributeAccessor attributes() const
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
std::optional< int > start_frame_at(int frame_number) const
void foreach_index(Fn &&fn) const
uint col
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves, const IndexMask &selection, const ResampleCurvesOutputAttributeIDs &output_ids={})
void read_influence_data(BlendDataReader *reader, GreasePencilModifierInfluenceData *influence_data)
void init_influence_data(GreasePencilModifierInfluenceData *influence_data, const bool has_custom_curve)
Vector< LayerDrawingInfo > get_drawing_infos_by_layer(GreasePencil &grease_pencil, const IndexMask &layer_mask, const int frame)
Vector< FrameDrawingInfo > get_drawing_infos_by_frame(GreasePencil &grease_pencil, const IndexMask &layer_mask, const int frame)
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)
void draw_vertex_group_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
VArray< float > get_influence_vertex_weights(const bke::CurvesGeometry &curves, const GreasePencilModifierInfluenceData &influence_data)
static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > tree_node_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
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)
static Vector< int > get_grease_pencil_material_passes(const Object *ob)
void draw_custom_curve_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 ensure_no_bezier_curves(Drawing &drawing)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
int RNA_string_length(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
Definition DNA_ID.h:404
struct MaterialGPencilStyle * gp_style
uiLayout & column(bool align)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4227