Blender V5.0
MOD_weightvgedit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 by Bastien Montagne. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include "BLI_utildefines.h"
12
13#include "BLI_ghash.h"
14#include "BLI_listbase.h"
15#include "BLI_rand.h"
16
17#include "BLT_translation.hh"
18
19#include "DNA_color_types.h" /* CurveMapping. */
20#include "DNA_defaults.h"
21#include "DNA_mesh_types.h"
22#include "DNA_meshdata_types.h"
23#include "DNA_modifier_types.h"
24#include "DNA_object_types.h"
25#include "DNA_screen_types.h"
26#include "DNA_texture_types.h"
27
28#include "BKE_colortools.hh" /* CurveMapping. */
29#include "BKE_customdata.hh"
30#include "BKE_deform.hh"
31#include "BKE_lib_query.hh"
32#include "BKE_mesh.hh"
33#include "BKE_modifier.hh"
34#include "BKE_texture.h" /* Texture masking. */
35
36#include "UI_interface.hh"
38#include "UI_resources.hh"
39
40#include "BLO_read_write.hh"
41
42#include "RNA_access.hh"
43#include "RNA_prototypes.hh"
44
47
48#include "MEM_guardedalloc.h"
49
50#include "MOD_ui_common.hh"
51#include "MOD_util.hh"
52#include "MOD_weightvg_util.hh"
53
54/**************************************
55 * Modifiers functions. *
56 **************************************/
68
74
75static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
76{
79
81
83}
84
85static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
86{
88
89 /* We need vertex groups! */
90 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
91
92 /* Ask for UV coordinates if we need them. */
94 r_cddata_masks->fmask |= CD_MASK_MTFACE;
95 }
96}
97
98static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
99{
101
102 if (wmd->mask_texture) {
104 }
105 return false;
106}
107
108static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
109{
111
112 walk(user_data, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
113 walk(user_data, ob, (ID **)&wmd->mask_tex_map_obj, IDWALK_CB_NOP);
114}
115
116static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
117{
118 PointerRNA ptr = RNA_pointer_create_discrete(&ob->id, &RNA_Modifier, md);
119 PropertyRNA *prop = RNA_struct_find_property(&ptr, "mask_texture");
120 walk(user_data, ob, md, &ptr, prop);
121}
122
124{
126 bool need_transform_relation = false;
127
128 if (wmd->mask_texture != nullptr) {
129 DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGEdit Modifier");
130
131 if (wmd->mask_tex_map_obj != nullptr && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
133 ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGEdit Modifier");
134 need_transform_relation = true;
135 }
136 else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
137 need_transform_relation = true;
138 }
139 }
140
141 if (need_transform_relation) {
142 DEG_add_depends_on_transform_relation(ctx->node, "WeightVGEdit Modifier");
143 }
144}
145
146static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
147{
149 /* If no vertex group, bypass. */
150 return (wmd->defgrp_name[0] == '\0');
151}
152
153static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
154{
155 BLI_assert(mesh != nullptr);
156
158
159 MDeformWeight **dw = nullptr;
160 float *org_w; /* Array original weights. */
161 float *new_w; /* Array new weights. */
162 int i;
163 const bool invert_vgroup_mask = (wmd->edit_flags & MOD_WVG_EDIT_INVERT_VGROUP_MASK) != 0;
164
165 /* Flags. */
166 const bool do_add = (wmd->edit_flags & MOD_WVG_EDIT_ADD2VG) != 0;
167 const bool do_rem = (wmd->edit_flags & MOD_WVG_EDIT_REMFVG) != 0;
168 /* Only do weight-preview in Object, Sculpt and Pose modes! */
169#if 0
170 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview);
171#endif
172
173 /* Get number of verts. */
174 const int verts_num = mesh->verts_num;
175
176 /* Check if we can just return the original mesh.
177 * Must have verts and therefore verts assigned to vgroups to do anything useful!
178 */
179 if ((verts_num == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) {
180 return mesh;
181 }
182
183 /* Get vgroup idx from its name. */
184 const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
185 if (defgrp_index == -1) {
186 return mesh;
187 }
188
189 const bool has_mdef = !mesh->deform_verts().is_empty();
190 /* If no vertices were ever added to an object's vgroup, dvert might be nullptr. */
191 if (!has_mdef) {
192 /* If this modifier is not allowed to add vertices, just return. */
193 if (!do_add) {
194 return mesh;
195 }
196 }
197
198 MDeformVert *dvert = mesh->deform_verts_for_write().data();
199
200 /* Ultimate security check. */
201 if (!dvert) {
202 return mesh;
203 }
204
205 /* Get org weights, assuming 0.0 for vertices not in given vgroup. */
206 org_w = MEM_malloc_arrayN<float>(size_t(verts_num), __func__);
207 new_w = MEM_malloc_arrayN<float>(size_t(verts_num), __func__);
208 dw = MEM_malloc_arrayN<MDeformWeight *>(size_t(verts_num), __func__);
209 for (i = 0; i < verts_num; i++) {
210 dw[i] = BKE_defvert_find_index(&dvert[i], defgrp_index);
211 if (dw[i]) {
212 org_w[i] = new_w[i] = dw[i]->weight;
213 }
214 else {
215 org_w[i] = new_w[i] = wmd->default_weight;
216 }
217 }
218
219 /* Do mapping. */
220 const bool do_invert_mapping = (wmd->edit_flags & MOD_WVG_INVERT_FALLOFF) != 0;
221 const bool do_normalize = (wmd->edit_flags & MOD_WVG_EDIT_WEIGHTS_NORMALIZE) != 0;
222 if (do_invert_mapping || wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
223 RNG *rng = nullptr;
224
227 }
228
229 weightvg_do_map(verts_num, new_w, wmd->falloff_type, do_invert_mapping, wmd->cmap_curve, rng);
230
231 if (rng) {
232 BLI_rng_free(rng);
233 }
234 }
235
236 /* Do masking. */
239 verts_num,
240 nullptr,
241 org_w,
242 new_w,
243 ctx->object,
244 mesh,
245 wmd->mask_constant,
246 wmd->mask_defgrp_name,
247 scene,
248 wmd->mask_texture,
250 wmd->mask_tex_mapping,
251 wmd->mask_tex_map_obj,
254 invert_vgroup_mask);
255
256 /* Update/add/remove from vgroup. */
257 weightvg_update_vg(dvert,
258 defgrp_index,
259 dw,
260 verts_num,
261 nullptr,
262 org_w,
263 do_add,
264 wmd->add_threshold,
265 do_rem,
266 wmd->rem_threshold,
267 do_normalize);
268
269 /* If weight preview enabled... */
270#if 0 /* XXX Currently done in mod stack :/ */
271 if (do_prev) {
272 DM_update_weight_mcol(ob, dm, 0, org_w, 0, nullptr);
273 }
274#endif
275
276 /* Freeing stuff. */
277 MEM_freeN(org_w);
278 MEM_freeN(new_w);
279 MEM_freeN(dw);
280
281 mesh->runtime->is_original_bmesh = false;
282
283 /* Return the vgroup-modified mesh. */
284 return mesh;
285}
286
287static void panel_draw(const bContext * /*C*/, Panel *panel)
288{
289 uiLayout *sub, *col, *row;
290 uiLayout *layout = panel->layout;
291
292 PointerRNA ob_ptr;
294
295 layout->use_property_split_set(true);
296
297 col = &layout->column(true);
298 col->prop_search(ptr, "vertex_group", &ob_ptr, "vertex_groups", std::nullopt, ICON_GROUP_VERTEX);
299
300 layout->prop(ptr, "default_weight", UI_ITEM_R_SLIDER, std::nullopt, ICON_NONE);
301
302 col = &layout->column(false, IFACE_("Group Add"));
303 row = &col->row(true);
304 row->use_property_decorate_set(false);
305 sub = &row->row(true);
306 sub->prop(ptr, "use_add", UI_ITEM_NONE, "", ICON_NONE);
307 sub = &sub->row(true);
308 sub->active_set(RNA_boolean_get(ptr, "use_add"));
309 sub->use_property_split_set(false);
310 sub->prop(ptr, "add_threshold", UI_ITEM_R_SLIDER, IFACE_("Threshold"), ICON_NONE);
311 row->decorator(ptr, "add_threshold", 0);
312
313 col = &layout->column(false, IFACE_("Group Remove"));
314 row = &col->row(true);
315 row->use_property_decorate_set(false);
316 sub = &row->row(true);
317 sub->prop(ptr, "use_remove", UI_ITEM_NONE, "", ICON_NONE);
318 sub = &sub->row(true);
319 sub->active_set(RNA_boolean_get(ptr, "use_remove"));
320 sub->use_property_split_set(false);
321 sub->prop(ptr, "remove_threshold", UI_ITEM_R_SLIDER, IFACE_("Threshold"), ICON_NONE);
322 row->decorator(ptr, "remove_threshold", 0);
323
324 layout->prop(ptr, "normalize", UI_ITEM_NONE, std::nullopt, ICON_NONE);
325
327}
328
329static void falloff_panel_draw(const bContext * /*C*/, Panel *panel)
330{
331 uiLayout *row, *sub;
332 uiLayout *layout = panel->layout;
333
334 PointerRNA ob_ptr;
336
337 layout->use_property_split_set(true);
338
339 row = &layout->row(true);
340 row->prop(ptr, "falloff_type", UI_ITEM_NONE, IFACE_("Type"), ICON_NONE);
341 sub = &row->row(true);
342 sub->use_property_split_set(false);
343 row->prop(ptr, "invert_falloff", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
344 if (RNA_enum_get(ptr, "falloff_type") == MOD_WVG_MAPPING_CURVE) {
345 uiTemplateCurveMapping(layout, ptr, "map_curve", 0, false, false, false, false, false);
346 }
347}
348
349static void influence_panel_draw(const bContext *C, Panel *panel)
350{
351 uiLayout *layout = panel->layout;
352
353 PointerRNA ob_ptr;
355
356 weightvg_ui_common(C, &ob_ptr, ptr, layout);
357}
358
359static void panel_register(ARegionType *region_type)
360{
364 region_type, "falloff", "Falloff", nullptr, falloff_panel_draw, panel_type);
366 region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type);
367}
368
369static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
370{
371 const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md;
372
374
375 if (wmd->cmap_curve) {
377 }
378}
379
380static void blend_read(BlendDataReader *reader, ModifierData *md)
381{
383
385 if (wmd->cmap_curve) {
387 }
388}
389
391 /*idname*/ "VertexWeightEdit",
392 /*name*/ N_("VertexWeightEdit"),
393 /*struct_name*/ "WeightVGEditModifierData",
394 /*struct_size*/ sizeof(WeightVGEditModifierData),
395 /*srna*/ &RNA_VertexWeightEditModifier,
399 /*icon*/ ICON_MOD_VERTEX_WEIGHT,
400
401 /*copy_data*/ copy_data,
402
403 /*deform_verts*/ nullptr,
404 /*deform_matrices*/ nullptr,
405 /*deform_verts_EM*/ nullptr,
406 /*deform_matrices_EM*/ nullptr,
407 /*modify_mesh*/ modify_mesh,
408 /*modify_geometry_set*/ nullptr,
409
410 /*init_data*/ init_data,
411 /*required_data_mask*/ required_data_mask,
412 /*free_data*/ free_data,
413 /*is_disabled*/ is_disabled,
414 /*update_depsgraph*/ update_depsgraph,
415 /*depends_on_time*/ depends_on_time,
416 /*depends_on_normals*/ nullptr,
417 /*foreach_ID_link*/ foreach_ID_link,
418 /*foreach_tex_link*/ foreach_tex_link,
419 /*free_runtime_data*/ nullptr,
420 /*panel_register*/ panel_register,
421 /*blend_write*/ blend_write,
422 /*blend_read*/ blend_read,
423 /*foreach_cache*/ nullptr,
424 /*foreach_working_space_color*/ nullptr,
425};
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)
CustomData interface, see also DNA_customdata_types.h.
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:806
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:549
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ModifierData *md, const PointerRNA *ptr, PropertyRNA *texture_prop) TexWalkFunc
bool BKE_texture_dependsOnTime(const struct Tex *texture)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_ghashutil_strhash(key)
Definition BLI_ghash.h:570
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:53
struct RNG * BLI_rng_new_srandom(unsigned int seed)
Definition rand.cc:46
#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 BLO_read_struct(reader, struct_name, ptr_p)
#define IFACE_(msgid)
void DEG_add_generic_id_relation(DepsNodeHandle *node_handle, ID *id, const char *description)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
#define CD_MASK_MDEFORMVERT
#define CD_MASK_MTFACE
#define DNA_struct_default_get(struct_name)
@ MOD_WVG_EDIT_INVERT_VGROUP_MASK
@ MOD_WVG_EDIT_WEIGHTS_NORMALIZE
@ MOD_WVG_INVERT_FALLOFF
@ MOD_WVG_EDIT_REMFVG
@ MOD_WVG_EDIT_ADD2VG
@ eModifierType_WeightVGEdit
@ MOD_DISP_MAP_OBJECT
@ MOD_DISP_MAP_GLOBAL
@ MOD_DISP_MAP_UV
@ MOD_WVG_MAPPING_NONE
@ MOD_WVG_MAPPING_CURVE
@ MOD_WVG_MAPPING_RANDOM
Object is a sort of wrapper for general info.
static bool is_disabled
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void free_data(ModifierData *md)
Definition MOD_bevel.cc:272
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:433
static bool depends_on_time(Scene *, ModifierData *)
Definition MOD_build.cc:47
static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
static void falloff_panel_draw(const bContext *, Panel *panel)
Definition MOD_hook.cc:484
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
void MOD_depsgraph_update_object_bone_relation(DepsNodeHandle *node, Object *object, const char *bonename, const char *description)
Definition MOD_util.cc:186
void weightvg_do_map(int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num, const int *indices, const float *weights, const bool do_add, const float add_thresh, const bool do_rem, const float rem_thresh, const bool do_normalize)
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
void weightvg_do_mask(const ModifierEvalContext *ctx, const int num, const int *indices, float *org_w, const float *new_w, Object *ob, Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME], Scene *, Tex *texture, const int tex_use_channel, const int tex_mapping, Object *tex_map_object, const char *text_map_bone, const char *tex_uvlayer_name, const bool invert_vgroup_mask)
static void influence_panel_draw(const bContext *C, Panel *panel)
static void init_data(ModifierData *md)
ModifierTypeInfo modifierType_WeightVGEdit
static void falloff_panel_draw(const bContext *, Panel *panel)
static void panel_register(ARegionType *region_type)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void free_data(ModifierData *md)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static bool depends_on_time(Scene *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
#define C
Definition RandGen.cpp:29
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, blender::StringRefNull propname, int type, bool levels, bool brush, bool neg_slope, bool tone, bool presets)
@ UI_ITEM_R_SLIDER
#define UI_ITEM_NONE
uint col
static void update_depsgraph(tGraphSliderOp *gso)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
MeshRuntimeHandle * runtime
ListBase vertex_group_names
int verts_num
struct uiLayout * layout
Definition rand.cc:33
struct CurveMapping * cmap_curve
void use_property_decorate_set(bool is_sep)
void decorator(PointerRNA *ptr, PropertyRNA *prop, int index)
uiLayout & column(bool align)
void active_set(bool active)
uiLayout & row(bool align)
void use_property_split_set(bool value)
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
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145