Blender V4.3
grease_pencil_vertex_groups.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BLI_listbase.h"
12#include "BLI_set.hh"
13#include "BLI_string.h"
14
15#include "BKE_curves.hh"
16#include "BKE_deform.hh"
17#include "BKE_grease_pencil.hh"
19
21
22/* ------------------------------------------------------------------- */
27{
28 Set<std::string> valid_names;
29 LISTBASE_FOREACH (const bDeformGroup *, defgroup, &grease_pencil.vertex_group_names) {
30 valid_names.add_new(defgroup->name);
31 }
32
33 for (GreasePencilDrawingBase *base : grease_pencil.drawings()) {
34 if (base->type != GP_DRAWING) {
35 continue;
36 }
37 Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
38
39 /* Remove unknown vertex groups. */
40 CurvesGeometry &curves = drawing.strokes_for_write();
41 int defgroup_index = 0;
42 LISTBASE_FOREACH_MUTABLE (bDeformGroup *, defgroup, &curves.vertex_group_names) {
43 if (!valid_names.contains(defgroup->name)) {
44 remove_defgroup_index(curves.deform_verts_for_write(), defgroup_index);
45
46 BLI_remlink(&curves.vertex_group_names, defgroup);
47 MEM_SAFE_FREE(defgroup);
48 }
49
50 ++defgroup_index;
51 }
52 }
53}
54
55int ensure_vertex_group(const StringRef name, ListBase &vertex_group_names)
56{
57 int def_nr = BKE_defgroup_name_index(&vertex_group_names, name);
58 if (def_nr < 0) {
59 bDeformGroup *defgroup = MEM_cnew<bDeformGroup>(__func__);
60 name.copy(defgroup->name);
61 BLI_addtail(&vertex_group_names, defgroup);
62 def_nr = BLI_listbase_count(&vertex_group_names) - 1;
63 BLI_assert(def_nr >= 0);
64 }
65 return def_nr;
66}
67
69 const IndexMask &mask,
70 const StringRef name,
71 const float weight)
72{
73 if (mask.is_empty()) {
74 return;
75 }
76
77 ListBase &vertex_group_names = curves.vertex_group_names;
78 /* Look for existing group, otherwise lazy-initialize if any vertex is selected. */
79 int def_nr = BKE_defgroup_name_index(&vertex_group_names, name);
80
81 /* Lazily add the vertex group if any vertex is selected. */
82 if (def_nr < 0) {
83 bDeformGroup *defgroup = MEM_cnew<bDeformGroup>(__func__);
84 name.copy(defgroup->name);
85 BLI_addtail(&vertex_group_names, defgroup);
86 def_nr = BLI_listbase_count(&vertex_group_names) - 1;
87 BLI_assert(def_nr >= 0);
88 }
89
90 const MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
91 mask.foreach_index([&](const int point_i) {
92 if (MDeformWeight *dw = BKE_defvert_ensure_index(&dverts[point_i], def_nr)) {
93 dw->weight = weight;
94 }
95 });
96}
97
98void assign_to_vertex_group(Drawing &drawing, const StringRef name, const float weight)
99{
100
101 bke::CurvesGeometry &curves = drawing.strokes_for_write();
102 ListBase &vertex_group_names = curves.vertex_group_names;
103
104 const bke::AttributeAccessor attributes = curves.attributes();
105 const VArray<bool> selection = *attributes.lookup_or_default<bool>(
106 ".selection", bke::AttrDomain::Point, true);
107
108 /* Look for existing group, otherwise lazy-initialize if any vertex is selected. */
109 int def_nr = BKE_defgroup_name_index(&vertex_group_names, name);
110
111 const MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
112 for (const int i : dverts.index_range()) {
113 if (selection[i]) {
114 /* Lazily add the vertex group if any vertex is selected. */
115 if (def_nr < 0) {
116 bDeformGroup *defgroup = MEM_cnew<bDeformGroup>(__func__);
117 name.copy(defgroup->name);
118
119 BLI_addtail(&vertex_group_names, defgroup);
120 def_nr = BLI_listbase_count(&vertex_group_names) - 1;
121 BLI_assert(def_nr >= 0);
122 }
123
124 MDeformWeight *dw = BKE_defvert_ensure_index(&dverts[i], def_nr);
125 if (dw) {
126 dw->weight = weight;
127 }
128 }
129 }
130}
131
132bool remove_from_vertex_group(Drawing &drawing, const StringRef name, const bool use_selection)
133{
134 bool changed = false;
135 bke::CurvesGeometry &curves = drawing.strokes_for_write();
136 ListBase &vertex_group_names = curves.vertex_group_names;
137
138 const int def_nr = BKE_defgroup_name_index(&vertex_group_names, name);
139 if (def_nr < 0) {
140 /* No vertices assigned to the group in this drawing. */
141 return false;
142 }
143
144 const MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
145 const bke::AttributeAccessor attributes = curves.attributes();
146 const VArray<bool> selection = *attributes.lookup_or_default<bool>(
147 ".selection", bke::AttrDomain::Point, true);
148 for (const int i : dverts.index_range()) {
149 if (!use_selection || selection[i]) {
150 MDeformVert *dv = &dverts[i];
151 MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
153
154 /* Adjust remaining vertex group indices. */
155 for (const int j : IndexRange(dv->totweight)) {
156 if (dv->dw[j].def_nr > def_nr) {
157 dv->dw[j].def_nr--;
158 }
159 }
160
161 changed = true;
162 }
163 }
164 return changed;
165}
166
168{
169 for (GreasePencilDrawingBase *base : grease_pencil.drawings()) {
170 if (base->type != GP_DRAWING) {
171 continue;
172 }
173 Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
174 bke::CurvesGeometry &curves = drawing.strokes_for_write();
175
176 for (MDeformVert &dvert : curves.deform_verts_for_write()) {
177 BKE_defvert_clear(&dvert);
178 }
179 }
180}
181
183 const AttrDomain selection_domain,
184 const StringRef name,
185 const bool select)
186{
187
188 bke::CurvesGeometry &curves = drawing.strokes_for_write();
189 ListBase &vertex_group_names = curves.vertex_group_names;
190
191 const int def_nr = BKE_defgroup_name_index(&vertex_group_names, name);
192 if (def_nr < 0) {
193 /* No vertices assigned to the group in this drawing. */
194 return;
195 }
196
197 const Span<MDeformVert> dverts = curves.deform_verts_for_write();
198 if (dverts.is_empty()) {
199 return;
200 }
201
202 MutableAttributeAccessor attributes = curves.attributes_for_write();
203 const int num_elements = attributes.domain_size(selection_domain);
204 SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
205 ".selection",
206 selection_domain,
208
209 switch (selection_domain) {
211 threading::parallel_for(curves.points_range(), 4096, [&](const IndexRange range) {
212 for (const int point_i : range) {
213 if (BKE_defvert_find_index(&dverts[point_i], def_nr)) {
214 selection.span[point_i] = select;
215 }
216 }
217 });
218 break;
219 case AttrDomain::Curve: {
220 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
221 threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange range) {
222 for (const int curve_i : range) {
223 const IndexRange points = points_by_curve[curve_i];
224 bool any_point_in_group = false;
225 for (const int point_i : points) {
226 if (BKE_defvert_find_index(&dverts[point_i], def_nr)) {
227 any_point_in_group = true;
228 break;
229 }
230 }
231 if (any_point_in_group) {
232 selection.span[curve_i] = select;
233 }
234 }
235 });
236 break;
237 }
238
239 default:
241 break;
242 }
243
244 selection.finish();
245}
246
249} // namespace blender::bke::greasepencil
Low-level operations for curves.
support for deformation groups and hooks.
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:534
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
void BKE_defvert_clear(MDeformVert *dvert)
Definition deform.cc:904
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:871
Low-level operations for grease pencil.
Utility functions for vertex groups in grease pencil objects.
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define MEM_SAFE_FREE(v)
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
bool contains(const Key &key) const
Definition BLI_set.hh:291
void add_new(const Key &key)
Definition BLI_set.hh:233
constexpr bool is_empty() const
Definition BLI_span.hh:261
int domain_size(const AttrDomain domain) const
bke::CurvesGeometry & strokes_for_write()
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
void clear_vertex_groups(GreasePencil &grease_pencil)
bool remove_from_vertex_group(Drawing &drawing, StringRef name, bool use_selection)
int ensure_vertex_group(const StringRef name, ListBase &vertex_group_names)
void select_from_group(Drawing &drawing, const AttrDomain selection_domain, StringRef name, bool select)
void assign_to_vertex_group(Drawing &drawing, StringRef name, float weight)
void assign_to_vertex_group_from_mask(CurvesGeometry &curves, const IndexMask &mask, StringRef name, float weight)
void validate_drawing_vertex_groups(GreasePencil &grease_pencil)
void remove_defgroup_index(MutableSpan< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1796
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:95
float wrap(float value, float max, float min)
Definition node_math.h:71
struct MDeformWeight * dw
unsigned int def_nr