Blender V4.3
MOD_weightvgmix.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
9#include "BLI_utildefines.h"
10
11#include "BLI_listbase.h"
12
13#include "BLT_translation.hh"
14
15#include "DNA_defaults.h"
16#include "DNA_mesh_types.h"
17#include "DNA_meshdata_types.h"
18#include "DNA_modifier_types.h"
19#include "DNA_object_types.h"
20#include "DNA_screen_types.h"
21
22#include "BKE_customdata.hh"
23#include "BKE_deform.hh"
24#include "BKE_lib_query.hh"
25#include "BKE_mesh.hh"
26#include "BKE_modifier.hh"
27#include "BKE_texture.h" /* Texture masking. */
28
29#include "UI_interface.hh"
30#include "UI_resources.hh"
31
32#include "RNA_access.hh"
33#include "RNA_prototypes.hh"
34
37
38#include "MEM_guardedalloc.h"
39
40#include "MOD_ui_common.hh"
41#include "MOD_util.hh"
42#include "MOD_weightvg_util.hh"
43
47static float mix_weight(float weight, float weight2, char mix_mode)
48{
49#if 0
50 /*
51 * XXX Don't know why, but the switch version takes many CPU time,
52 * and produces lag in realtime playback...
53 */
54 switch (mix_mode) {
55 case MOD_WVG_MIX_ADD:
56 return (weight + weight2);
57 case MOD_WVG_MIX_SUB:
58 return (weight - weight2);
59 case MOD_WVG_MIX_MUL:
60 return (weight * weight2);
61 case MOD_WVG_MIX_DIV:
62 /* Avoid dividing by zero (or really small values). */
63 if (0.0 <= weight2 < MOD_WVG_ZEROFLOOR) {
64 weight2 = MOD_WVG_ZEROFLOOR;
65 }
66 else if (-MOD_WVG_ZEROFLOOR < weight2) {
67 weight2 = -MOD_WVG_ZEROFLOOR;
68 }
69 return (weight / weight2);
70 case MOD_WVG_MIX_DIF:
71 return (weight < weight2 ? weight2 - weight : weight - weight2);
72 case MOD_WVG_MIX_AVG:
73 return (weight + weight2) / 2.0;
74 case MOD_WVG_MIX_SET:
75 default:
76 return weight2;
77 }
78#endif
79 if (mix_mode == MOD_WVG_MIX_SET) {
80 return weight2;
81 }
82 if (mix_mode == MOD_WVG_MIX_ADD) {
83 return (weight + weight2);
84 }
85 if (mix_mode == MOD_WVG_MIX_SUB) {
86 return (weight - weight2);
87 }
88 if (mix_mode == MOD_WVG_MIX_MUL) {
89 return (weight * weight2);
90 }
91 if (mix_mode == MOD_WVG_MIX_DIV) {
92 /* Avoid dividing by zero (or really small values). */
93 if (weight2 < 0.0f && weight2 > -MOD_WVG_ZEROFLOOR) {
94 weight2 = -MOD_WVG_ZEROFLOOR;
95 }
96 else if (weight2 >= 0.0f && weight2 < MOD_WVG_ZEROFLOOR) {
97 weight2 = MOD_WVG_ZEROFLOOR;
98 }
99 return (weight / weight2);
100 }
101 if (mix_mode == MOD_WVG_MIX_DIF) {
102 return (weight < weight2 ? weight2 - weight : weight - weight2);
103 }
104 if (mix_mode == MOD_WVG_MIX_AVG) {
105 return (weight + weight2) * 0.5f;
106 }
107 if (mix_mode == MOD_WVG_MIX_MIN) {
108 return (weight < weight2 ? weight : weight2);
109 }
110 if (mix_mode == MOD_WVG_MIX_MAX) {
111 return (weight > weight2 ? weight : weight2);
112 }
113
114 return weight2;
115}
116
117/**************************************
118 * Modifiers functions. *
119 **************************************/
128
129static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
130{
132
133 /* We need vertex groups! */
134 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
135
136 /* Ask for UV coordinates if we need them. */
137 if (wmd->mask_tex_mapping == MOD_DISP_MAP_UV) {
138 r_cddata_masks->fmask |= CD_MASK_MTFACE;
139 }
140}
141
142static bool depends_on_time(Scene * /*scene*/, ModifierData *md)
143{
145
146 if (wmd->mask_texture) {
148 }
149 return false;
150}
151
152static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
153{
155
156 walk(user_data, ob, (ID **)&wmd->mask_texture, IDWALK_CB_USER);
157 walk(user_data, ob, (ID **)&wmd->mask_tex_map_obj, IDWALK_CB_NOP);
158}
159
160static void foreach_tex_link(ModifierData *md, Object *ob, TexWalkFunc walk, void *user_data)
161{
162 PointerRNA ptr = RNA_pointer_create(&ob->id, &RNA_Modifier, md);
163 PropertyRNA *prop = RNA_struct_find_property(&ptr, "mask_texture");
164 walk(user_data, ob, md, &ptr, prop);
165}
166
168{
170 bool need_transform_relation = false;
171
172 if (wmd->mask_texture != nullptr) {
173 DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier");
174
175 if (wmd->mask_tex_map_obj != nullptr && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
177 ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGMix Modifier");
178 need_transform_relation = true;
179 }
180 else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
181 need_transform_relation = true;
182 }
183 }
184
185 if (need_transform_relation) {
186 DEG_add_depends_on_transform_relation(ctx->node, "WeightVGMix Modifier");
187 }
188}
189
190static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
191{
193 /* If no vertex group, bypass. */
194 return (wmd->defgrp_name_a[0] == '\0');
195}
196
197static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
198{
199 BLI_assert(mesh != nullptr);
200
202
203 MDeformWeight **dw1, **tdw1, **dw2, **tdw2;
204 float *org_w;
205 float *new_w;
206 int *tidx, *indices = nullptr;
207 int index_num = 0;
208 int i;
209 const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0;
210 const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0;
211
212 /*
213 * Note that we only invert the weight values within provided vgroups, the selection based on
214 * which vertex is affected because it belongs or not to a group remains unchanged.
215 * In other words, vertices not belonging to a group won't be affected, even though their
216 * inverted 'virtual' weight would be 1.0f.
217 */
218 const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0;
219 const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0;
220
221 /* Flags. */
222#if 0
223 const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
224#endif
225
226 /* Get number of verts. */
227 const int verts_num = mesh->verts_num;
228
229 /* Check if we can just return the original mesh.
230 * Must have verts and therefore verts assigned to vgroups to do anything useful!
231 */
232 if ((verts_num == 0) || BLI_listbase_is_empty(&mesh->vertex_group_names)) {
233 return mesh;
234 }
235
236 /* Get vgroup idx from its name. */
237 const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_a);
238 if (defgrp_index == -1) {
239 return mesh;
240 }
241 /* Get second vgroup idx from its name, if given. */
242 int defgrp_index_other = -1;
243 if (wmd->defgrp_name_b[0] != '\0') {
244 defgrp_index_other = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name_b);
245 if (defgrp_index_other == -1) {
246 return mesh;
247 }
248 }
249
250 const bool has_mdef = CustomData_has_layer(&mesh->vert_data, CD_MDEFORMVERT);
251 /* If no vertices were ever added to an object's vgroup, dvert might be nullptr. */
252 if (!has_mdef) {
253 /* If not affecting all vertices, just return. */
254 if (wmd->mix_set != MOD_WVG_SET_ALL) {
255 return mesh;
256 }
257 }
258
259 MDeformVert *dvert = mesh->deform_verts_for_write().data();
260
261 /* Ultimate security check. */
262 if (!dvert) {
263 return mesh;
264 }
265
266 /* Find out which vertices to work on. */
267 tidx = static_cast<int *>(MEM_malloc_arrayN(verts_num, sizeof(int), __func__));
268 tdw1 = static_cast<MDeformWeight **>(
269 MEM_malloc_arrayN(verts_num, sizeof(MDeformWeight *), __func__));
270 tdw2 = static_cast<MDeformWeight **>(
271 MEM_malloc_arrayN(verts_num, sizeof(MDeformWeight *), __func__));
272 switch (wmd->mix_set) {
273 case MOD_WVG_SET_A:
274 /* All vertices in first vgroup. */
275 for (i = 0; i < verts_num; i++) {
276 MDeformWeight *dw = BKE_defvert_find_index(&dvert[i], defgrp_index);
277 if (dw) {
278 tdw1[index_num] = dw;
279 tdw2[index_num] = (defgrp_index_other >= 0) ?
280 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
281 nullptr;
282 tidx[index_num++] = i;
283 }
284 }
285 break;
286 case MOD_WVG_SET_B:
287 /* All vertices in second vgroup. */
288 for (i = 0; i < verts_num; i++) {
289 MDeformWeight *dw = (defgrp_index_other >= 0) ?
290 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
291 nullptr;
292 if (dw) {
293 tdw1[index_num] = BKE_defvert_find_index(&dvert[i], defgrp_index);
294 tdw2[index_num] = dw;
295 tidx[index_num++] = i;
296 }
297 }
298 break;
299 case MOD_WVG_SET_OR:
300 /* All vertices in one vgroup or the other. */
301 for (i = 0; i < verts_num; i++) {
302 MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index);
303 MDeformWeight *bdw = (defgrp_index_other >= 0) ?
304 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
305 nullptr;
306 if (adw || bdw) {
307 tdw1[index_num] = adw;
308 tdw2[index_num] = bdw;
309 tidx[index_num++] = i;
310 }
311 }
312 break;
313 case MOD_WVG_SET_AND:
314 /* All vertices in both vgroups. */
315 for (i = 0; i < verts_num; i++) {
316 MDeformWeight *adw = BKE_defvert_find_index(&dvert[i], defgrp_index);
317 MDeformWeight *bdw = (defgrp_index_other >= 0) ?
318 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
319 nullptr;
320 if (adw && bdw) {
321 tdw1[index_num] = adw;
322 tdw2[index_num] = bdw;
323 tidx[index_num++] = i;
324 }
325 }
326 break;
327 case MOD_WVG_SET_ALL:
328 default:
329 /* Use all vertices. */
330 for (i = 0; i < verts_num; i++) {
331 tdw1[i] = BKE_defvert_find_index(&dvert[i], defgrp_index);
332 tdw2[i] = (defgrp_index_other >= 0) ?
333 BKE_defvert_find_index(&dvert[i], defgrp_index_other) :
334 nullptr;
335 }
336 index_num = -1;
337 break;
338 }
339 if (index_num == 0) {
340 /* Use no vertices! Hence, return org data. */
341 MEM_freeN(tdw1);
342 MEM_freeN(tdw2);
343 MEM_freeN(tidx);
344 return mesh;
345 }
346 if (index_num != -1) {
347 indices = static_cast<int *>(MEM_malloc_arrayN(index_num, sizeof(int), __func__));
348 memcpy(indices, tidx, sizeof(int) * index_num);
349 dw1 = static_cast<MDeformWeight **>(
350 MEM_malloc_arrayN(index_num, sizeof(MDeformWeight *), __func__));
351 memcpy(dw1, tdw1, sizeof(MDeformWeight *) * index_num);
352 MEM_freeN(tdw1);
353 dw2 = static_cast<MDeformWeight **>(
354 MEM_malloc_arrayN(index_num, sizeof(MDeformWeight *), __func__));
355 memcpy(dw2, tdw2, sizeof(MDeformWeight *) * index_num);
356 MEM_freeN(tdw2);
357 }
358 else {
359 /* Use all vertices. */
360 index_num = verts_num;
361 /* Just copy MDeformWeight pointers arrays, they will be freed at the end. */
362 dw1 = tdw1;
363 dw2 = tdw2;
364 }
365 MEM_freeN(tidx);
366
367 org_w = static_cast<float *>(MEM_malloc_arrayN(index_num, sizeof(float), __func__));
368 new_w = static_cast<float *>(MEM_malloc_arrayN(index_num, sizeof(float), __func__));
369
370 /* Mix weights. */
371 for (i = 0; i < index_num; i++) {
372 float weight2;
373 if (invert_vgroup_a) {
374 org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a);
375 }
376 else {
377 org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
378 }
379 if (invert_vgroup_b) {
380 weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b);
381 }
382 else {
383 weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
384 }
385
386 new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
387 }
388
389 /* Do masking. */
392 index_num,
393 indices,
394 org_w,
395 new_w,
396 ctx->object,
397 mesh,
398 wmd->mask_constant,
399 wmd->mask_defgrp_name,
400 scene,
401 wmd->mask_texture,
403 wmd->mask_tex_mapping,
404 wmd->mask_tex_map_obj,
407 invert_vgroup_mask);
408
409 /* Update (add to) vgroup.
410 * XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
411 */
412 weightvg_update_vg(dvert,
413 defgrp_index,
414 dw1,
415 index_num,
416 indices,
417 org_w,
418 true,
419 -FLT_MAX,
420 false,
421 0.0f,
422 do_normalize);
423
424 /* If weight preview enabled... */
425#if 0 /* XXX Currently done in mod stack :/ */
426 if (do_prev) {
427 DM_update_weight_mcol(ob, dm, 0, org_w, index_num, indices);
428 }
429#endif
430
431 /* Freeing stuff. */
432 MEM_freeN(org_w);
433 MEM_freeN(new_w);
434 MEM_freeN(dw1);
435 MEM_freeN(dw2);
436 MEM_SAFE_FREE(indices);
437
438 mesh->runtime->is_original_bmesh = false;
439
440 /* Return the vgroup-modified mesh. */
441 return mesh;
442}
443
444static void panel_draw(const bContext * /*C*/, Panel *panel)
445{
446 uiLayout *layout = panel->layout;
447
448 PointerRNA ob_ptr;
450
451 uiLayoutSetPropSep(layout, true);
452
453 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_a", "invert_vertex_group_a", nullptr);
454 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group_b", "invert_vertex_group_b", IFACE_("B"));
455
456 uiItemS(layout);
457
458 uiItemR(layout, ptr, "default_weight_a", UI_ITEM_NONE, nullptr, ICON_NONE);
459 uiItemR(layout, ptr, "default_weight_b", UI_ITEM_NONE, IFACE_("B"), ICON_NONE);
460
461 uiItemS(layout);
462
463 uiItemR(layout, ptr, "mix_set", UI_ITEM_NONE, nullptr, ICON_NONE);
464 uiItemR(layout, ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
465
466 uiItemR(layout, ptr, "normalize", UI_ITEM_NONE, nullptr, ICON_NONE);
467
468 modifier_panel_end(layout, ptr);
469}
470
471static void influence_panel_draw(const bContext *C, Panel *panel)
472{
473 uiLayout *layout = panel->layout;
474
475 PointerRNA ob_ptr;
477
478 weightvg_ui_common(C, &ob_ptr, ptr, layout);
479}
480
481static void panel_register(ARegionType *region_type)
482{
486 region_type, "influence", "Influence", nullptr, influence_panel_draw, panel_type);
487}
488
490 /*idname*/ "VertexWeightMix",
491 /*name*/ N_("VertexWeightMix"),
492 /*struct_name*/ "WeightVGMixModifierData",
493 /*struct_size*/ sizeof(WeightVGMixModifierData),
494 /*srna*/ &RNA_VertexWeightMixModifier,
498 /*icon*/ ICON_MOD_VERTEX_WEIGHT,
499
500 /*copy_data*/ BKE_modifier_copydata_generic,
501
502 /*deform_verts*/ nullptr,
503 /*deform_matrices*/ nullptr,
504 /*deform_verts_EM*/ nullptr,
505 /*deform_matrices_EM*/ nullptr,
506 /*modify_mesh*/ modify_mesh,
507 /*modify_geometry_set*/ nullptr,
508
509 /*init_data*/ init_data,
510 /*required_data_mask*/ required_data_mask,
511 /*free_data*/ nullptr,
512 /*is_disabled*/ is_disabled,
513 /*update_depsgraph*/ update_depsgraph,
514 /*depends_on_time*/ depends_on_time,
515 /*depends_on_normals*/ nullptr,
516 /*foreach_ID_link*/ foreach_ID_link,
517 /*foreach_tex_link*/ foreach_tex_link,
518 /*free_runtime_data*/ nullptr,
519 /*panel_register*/ panel_register,
520 /*blend_write*/ nullptr,
521 /*blend_read*/ nullptr,
522 /*foreach_cache*/ nullptr,
523};
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:543
@ IDWALK_CB_USER
@ IDWALK_CB_NOP
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
void(*)(void *user_data, Object *ob, ModifierData *md, const PointerRNA *ptr, PropertyRNA *texture_prop) TexWalkFunc
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
bool BKE_texture_dependsOnTime(const struct Tex *texture)
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#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
@ CD_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
@ MOD_WVG_SET_AND
@ MOD_WVG_SET_B
@ MOD_WVG_SET_ALL
@ MOD_WVG_SET_OR
@ MOD_WVG_SET_A
@ MOD_WVG_MIX_INVERT_VGROUP_MASK
@ MOD_WVG_MIX_INVERT_VGROUP_B
@ MOD_WVG_MIX_WEIGHTS_NORMALIZE
@ MOD_WVG_MIX_INVERT_VGROUP_A
@ MOD_DISP_MAP_OBJECT
@ MOD_DISP_MAP_GLOBAL
@ MOD_DISP_MAP_UV
@ eModifierType_WeightVGMix
struct WeightVGMixModifierData WeightVGMixModifierData
@ MOD_WVG_MIX_ADD
@ MOD_WVG_MIX_SUB
@ MOD_WVG_MIX_MIN
@ MOD_WVG_MIX_DIF
@ MOD_WVG_MIX_SET
@ MOD_WVG_MIX_MAX
@ MOD_WVG_MIX_DIV
@ MOD_WVG_MIX_AVG
@ MOD_WVG_MIX_MUL
Object is a sort of wrapper for general info.
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
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 modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_depsgraph_update_object_bone_relation(DepsNodeHandle *node, Object *object, const char *bonename, const char *description)
Definition MOD_util.cc:189
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)
#define MOD_WVG_ZEROFLOOR
static void influence_panel_draw(const bContext *C, Panel *panel)
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static float mix_weight(float weight, float weight2, char mix_mode)
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)
ModifierTypeInfo modifierType_WeightVGMix
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
#define UI_ITEM_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:413
struct uiLayout * layout
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126