UI: Add custom attribute edge groups for bevel modifier #117366

Open
Mike93 wants to merge 1 commits from Mike93/blender:bevel-edge-attributes into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
11 changed files with 651 additions and 8 deletions

View File

@ -82,7 +82,9 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
miter_inner,
spread,
custom_profile,
vmesh_method);
vmesh_method,
"bevel_weight_edge",
"bevel_weight_vert");
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);

View File

@ -7719,7 +7719,9 @@ void BM_mesh_bevel(BMesh *bm,
const int miter_inner,
const float spread,
const CurveProfile *custom_profile,
const int vmesh_method)
const int vmesh_method,
const char *edge_weight_name,
const char *vertex_weight_name)
{
BMIter iter, liter;
BMVert *v, *v_next;
@ -7737,9 +7739,9 @@ void BM_mesh_bevel(BMesh *bm,
bp.affect_type = affect_type;
bp.use_weights = use_weights;
bp.bweight_offset_vert = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
&bm->vdata, CD_PROP_FLOAT, vertex_weight_name);
bp.bweight_offset_edge = CustomData_get_offset_named(
&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
&bm->edata, CD_PROP_FLOAT, edge_weight_name);
bp.loop_slide = loop_slide;
bp.limit_offset = limit_offset;
bp.offset_adjust = (bp.affect_type != BEVEL_AFFECT_VERTICES) &&

View File

@ -44,4 +44,6 @@ void BM_mesh_bevel(BMesh *bm,
int miter_inner,
float spread,
const CurveProfile *custom_profile,
int vmesh_method);
int vmesh_method,
const char *edge_weight_name,
const char *vertex_weight_name);

View File

@ -2886,6 +2886,15 @@ void uiItemPointerR_prop(uiLayout *layout,
const char *name,
int icon,
bool results_are_suggestions);
void uiItemPointerR_att_prop(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
const char *name,
int icon,
bool results_are_suggestions,
int domain_filter);
void uiItemPointerR(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@ -2893,6 +2902,14 @@ void uiItemPointerR(uiLayout *layout,
const char *searchpropname,
const char *name,
int icon);
void uiItemPointerR_att(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
PointerRNA *searchptr,
const char *searchpropname,
const char *name,
int icon,
int domain_filter);
/**
* Create a list of enum items.

View File

@ -1309,6 +1309,14 @@ uiBut *ui_but_add_search(uiBut *but,
PointerRNA *searchptr,
PropertyRNA *searchprop,
bool results_are_suggestions);
uiBut *ui_but_add_search_att(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
bool results_are_suggestions,
int domain_filter);
/**
* Check all buttons defined in this layout,
* and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
@ -1518,6 +1526,13 @@ struct uiRNACollectionSearch {
void ui_rna_collection_search_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
void ui_rna_collection_search_att_edge_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
void ui_rna_collection_search_att_point_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first);
/* `interface_ops.cc` */
bool ui_jump_to_target_button_poll(bContext *C);

View File

@ -2890,6 +2890,102 @@ uiBut *ui_but_add_search(uiBut *but,
return but;
}
uiBut *ui_but_add_search_att(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
const bool results_are_suggestions,
int domain_filter)
{
/* for ID's we do automatic lookup */
bool has_search_fn = false;
PointerRNA sptr;
if (!searchprop) {
if (RNA_property_type(prop) == PROP_STRING) {
has_search_fn = (RNA_property_string_search_flag(prop) != 0);
}
if (RNA_property_type(prop) == PROP_POINTER) {
StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
search_id_collection(ptype, &sptr, &searchprop);
searchptr = &sptr;
}
}
/* turn button into search button */
if (has_search_fn || searchprop) {
uiRNACollectionSearch *coll_search = static_cast<uiRNACollectionSearch *>(
MEM_mallocN(sizeof(*coll_search), __func__));
uiButSearch *search_but;
but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU);
search_but = (uiButSearch *)but;
if (searchptr) {
search_but->rnasearchpoin = *searchptr;
search_but->rnasearchprop = searchprop;
}
but->hardmax = std::max(but->hardmax, 256.0f);
but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
if (RNA_property_is_unlink(prop)) {
but->flag |= UI_BUT_VALUE_CLEAR;
}
coll_search->target_ptr = *ptr;
coll_search->target_prop = prop;
if (searchptr) {
coll_search->search_ptr = *searchptr;
coll_search->search_prop = searchprop;
}
else {
/* Rely on `has_search_fn`. */
coll_search->search_ptr = PointerRNA_NULL;
coll_search->search_prop = nullptr;
}
coll_search->search_but = but;
coll_search->butstore_block = but->block;
coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
UI_butstore_register(coll_search->butstore, &coll_search->search_but);
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
* but in this case we just want the text */
but->str.clear();
}
UI_but_func_search_set_results_are_suggestions(but, results_are_suggestions);
uiButSearchUpdateFn update_fn = nullptr;
if (domain_filter == 0) {
update_fn = ui_rna_collection_search_att_point_update_fn;
} else if (domain_filter == 1) {
update_fn = ui_rna_collection_search_att_edge_update_fn;
}
UI_but_func_search_set(but,
ui_searchbox_create_generic,
update_fn,
coll_search,
false,
ui_rna_collection_search_arg_free_fn,
nullptr,
nullptr);
/* If this is called multiple times for the same button, an earlier call may have taken the
* else branch below so the button was disabled. Now we have a searchprop, so it can be enabled
* again. */
but->flag &= ~UI_BUT_DISABLED;
}
else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* In case we fail to find proper searchprop,
* so other code might have already set but->type to search menu... */
but->flag |= UI_BUT_DISABLED;
}
return but;
}
void uiItemPointerR_prop(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@ -2949,6 +3045,66 @@ void uiItemPointerR_prop(uiLayout *layout,
but = ui_but_add_search(but, ptr, prop, searchptr, searchprop, results_are_suggestions);
}
void uiItemPointerR_att_prop(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *searchptr,
PropertyRNA *searchprop,
const char *name,
int icon,
bool results_are_suggestions,
int domain_filter)
{
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
ui_block_new_button_group(uiLayoutGetBlock(layout), uiButtonGroupFlag(0));
const PropertyType type = RNA_property_type(prop);
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
RNA_warning("Property %s.%s must be a pointer, string or enum",
RNA_struct_identifier(ptr->type),
RNA_property_identifier(prop));
return;
}
if (RNA_property_type(searchprop) != PROP_COLLECTION) {
RNA_warning("search collection property is not a collection type: %s.%s",
RNA_struct_identifier(searchptr->type),
RNA_property_identifier(searchprop));
return;
}
/* get icon & name */
if (icon == ICON_NONE) {
StructRNA *icontype;
if (type == PROP_POINTER) {
icontype = RNA_property_pointer_type(ptr, prop);
}
else {
icontype = RNA_property_pointer_type(searchptr, searchprop);
}
icon = RNA_struct_ui_icon(icontype);
}
if (!name) {
name = RNA_property_ui_name(prop);
}
char namestr[UI_MAX_NAME_STR];
if (use_prop_sep == false) {
name = ui_item_name_add_colon(name, namestr);
}
/* create button */
uiBlock *block = uiLayoutGetBlock(layout);
int w, h;
ui_item_rna_size(layout, name, icon, ptr, prop, 0, false, false, &w, &h);
w += UI_UNIT_X; /* X icon needs more space */
uiBut *but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
but = ui_but_add_search_att(but, ptr, prop, searchptr, searchprop, results_are_suggestions, domain_filter);
}
void uiItemPointerR(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@ -2974,6 +3130,32 @@ void uiItemPointerR(uiLayout *layout,
uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false);
}
void uiItemPointerR_att(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
PointerRNA *searchptr,
const char *searchpropname,
const char *name,
int icon,
int domain_filter)
{
/* validate arguments */
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
return;
}
PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname);
if (!searchprop) {
RNA_warning("search collection property not found: %s.%s",
RNA_struct_identifier(searchptr->type),
searchpropname);
return;
}
uiItemPointerR_att_prop(layout, ptr, prop, searchptr, searchprop, name, icon, false, domain_filter);
}
void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
{
MenuType *mt = (MenuType *)arg_mt;

View File

@ -675,6 +675,368 @@ void ui_rna_collection_search_update_fn(
MEM_freeN(items_list);
}
void ui_rna_collection_search_att_edge_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
uiRNACollectionSearch *data = static_cast<uiRNACollectionSearch *>(arg);
const int flag = RNA_property_flag(data->target_prop);
ListBase *items_list = MEM_cnew<ListBase>("items_list");
const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
/* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
* match the RNA name exactly. So only for pointer properties, the name can be modified to add
* further UI hints. */
const bool requires_exact_data_name = !is_ptr_target;
const bool skip_filter = is_first;
char name_buf[UI_MAX_DRAW_STR];
char *name;
bool has_id_icon = false;
blender::ui::string_search::StringSearch<CollItemSearch> search;
if (data->search_prop != nullptr) {
/* build a temporary list of relevant items first */
int item_index = 0;
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
if (flag & PROP_ID_SELF_CHECK) {
if (itemptr.data == data->target_ptr.owner_id) {
continue;
}
}
/* use filter */
if (is_ptr_target) {
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
continue;
}
}
int name_prefix_offset = 0;
int iconid = ICON_NONE;
bool has_sep_char = false;
const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
if (is_id) {
iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
if (!ELEM(iconid, 0, ICON_BLANK1)) {
has_id_icon = true;
}
if (requires_exact_data_name) {
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
else {
const ID *id = static_cast<ID *>(itemptr.data);
BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
"Name string buffer should be big enough to hold full UI ID name");
name = name_buf;
has_sep_char = ID_IS_LINKED(id);
}
}
else {
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
if (name) {
CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
cis->data = itemptr.data;
cis->name = BLI_strdup(name);
cis->index = item_index;
cis->iconid = iconid;
cis->is_id = is_id;
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
PropertyRNA *domain_prop = RNA_struct_find_property(&itemptr, "domain");
int domain = RNA_property_int_get(&itemptr, domain_prop);
int domain_filter = 1;
if (domain == domain_filter && name[0] != '.') {
if (!skip_filter) {
search.add(name, cis);
}
BLI_addtail(items_list, cis);
}
if (name != name_buf) {
MEM_freeN(name);
}
}
item_index++;
}
RNA_PROP_END;
}
else {
BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
data->target_prop);
BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
struct SearchVisitUserData {
blender::string_search::StringSearch<CollItemSearch> *search;
bool skip_filter;
int item_index;
ListBase *items_list;
const char *func_id;
} user_data = {nullptr};
user_data.search = &search;
user_data.skip_filter = skip_filter;
user_data.items_list = items_list;
user_data.func_id = __func__;
RNA_property_string_search(
C,
&data->target_ptr,
data->target_prop,
str,
[](void *user_data, const StringPropertySearchVisitParams *visit_params) {
const bool show_extra_info = (G.debug_value == 102);
SearchVisitUserData *search_data = (SearchVisitUserData *)user_data;
CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
cis->data = nullptr;
if (visit_params->info && show_extra_info) {
cis->name = BLI_sprintfN(
"%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
}
else {
cis->name = BLI_strdup(visit_params->text);
}
cis->index = search_data->item_index;
cis->iconid = ICON_NONE;
cis->is_id = false;
cis->name_prefix_offset = 0;
cis->has_sep_char = visit_params->info != nullptr;
if (!search_data->skip_filter) {
search_data->search->add(visit_params->text, cis);
}
BLI_addtail(search_data->items_list, cis);
search_data->item_index++;
},
(void *)&user_data);
if (search_flag & PROP_STRING_SEARCH_SORT) {
BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
const CollItemSearch *cis_a = (const CollItemSearch *)a_;
const CollItemSearch *cis_b = (const CollItemSearch *)b_;
return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
});
int i = 0;
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
cis->index = i;
i++;
}
}
}
if (skip_filter) {
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
else {
const blender::Vector<CollItemSearch *> filtered_items = search.query(str);
for (CollItemSearch *cis : filtered_items) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
MEM_freeN(cis->name);
}
BLI_freelistN(items_list);
MEM_freeN(items_list);
}
void ui_rna_collection_search_att_point_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
{
uiRNACollectionSearch *data = static_cast<uiRNACollectionSearch *>(arg);
const int flag = RNA_property_flag(data->target_prop);
ListBase *items_list = MEM_cnew<ListBase>("items_list");
const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
/* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
* match the RNA name exactly. So only for pointer properties, the name can be modified to add
* further UI hints. */
const bool requires_exact_data_name = !is_ptr_target;
const bool skip_filter = is_first;
char name_buf[UI_MAX_DRAW_STR];
char *name;
bool has_id_icon = false;
blender::ui::string_search::StringSearch<CollItemSearch> search;
if (data->search_prop != nullptr) {
/* build a temporary list of relevant items first */
int item_index = 0;
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
if (flag & PROP_ID_SELF_CHECK) {
if (itemptr.data == data->target_ptr.owner_id) {
continue;
}
}
/* use filter */
if (is_ptr_target) {
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
continue;
}
}
int name_prefix_offset = 0;
int iconid = ICON_NONE;
bool has_sep_char = false;
const bool is_id = itemptr.type && RNA_struct_is_ID(itemptr.type);
if (is_id) {
iconid = ui_id_icon_get(C, static_cast<ID *>(itemptr.data), false);
if (!ELEM(iconid, 0, ICON_BLANK1)) {
has_id_icon = true;
}
if (requires_exact_data_name) {
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
else {
const ID *id = static_cast<ID *>(itemptr.data);
BKE_id_full_name_ui_prefix_get(name_buf, id, true, UI_SEP_CHAR, &name_prefix_offset);
BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
"Name string buffer should be big enough to hold full UI ID name");
name = name_buf;
has_sep_char = ID_IS_LINKED(id);
}
}
else {
name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), nullptr);
}
if (name) {
CollItemSearch *cis = MEM_cnew<CollItemSearch>(__func__);
cis->data = itemptr.data;
cis->name = BLI_strdup(name);
cis->index = item_index;
cis->iconid = iconid;
cis->is_id = is_id;
cis->name_prefix_offset = name_prefix_offset;
cis->has_sep_char = has_sep_char;
PropertyRNA *domain_prop = RNA_struct_find_property(&itemptr, "domain");
int domain = RNA_property_int_get(&itemptr, domain_prop);
int domain_filter = 0;
if (domain == domain_filter && name[0] != '.') {
if (!skip_filter) {
search.add(name, cis);
}
BLI_addtail(items_list, cis);
}
if (name != name_buf) {
MEM_freeN(name);
}
}
item_index++;
}
RNA_PROP_END;
}
else {
BLI_assert(RNA_property_type(data->target_prop) == PROP_STRING);
const eStringPropertySearchFlag search_flag = RNA_property_string_search_flag(
data->target_prop);
BLI_assert(search_flag & PROP_STRING_SEARCH_SUPPORTED);
struct SearchVisitUserData {
blender::string_search::StringSearch<CollItemSearch> *search;
bool skip_filter;
int item_index;
ListBase *items_list;
const char *func_id;
} user_data = {nullptr};
user_data.search = &search;
user_data.skip_filter = skip_filter;
user_data.items_list = items_list;
user_data.func_id = __func__;
RNA_property_string_search(
C,
&data->target_ptr,
data->target_prop,
str,
[](void *user_data, const StringPropertySearchVisitParams *visit_params) {
const bool show_extra_info = (G.debug_value == 102);
SearchVisitUserData *search_data = (SearchVisitUserData *)user_data;
CollItemSearch *cis = MEM_cnew<CollItemSearch>(search_data->func_id);
cis->data = nullptr;
if (visit_params->info && show_extra_info) {
cis->name = BLI_sprintfN(
"%s" UI_SEP_CHAR_S "%s", visit_params->text, visit_params->info);
}
else {
cis->name = BLI_strdup(visit_params->text);
}
cis->index = search_data->item_index;
cis->iconid = ICON_NONE;
cis->is_id = false;
cis->name_prefix_offset = 0;
cis->has_sep_char = visit_params->info != nullptr;
if (!search_data->skip_filter) {
search_data->search->add(visit_params->text, cis);
}
BLI_addtail(search_data->items_list, cis);
search_data->item_index++;
},
(void *)&user_data);
if (search_flag & PROP_STRING_SEARCH_SORT) {
BLI_listbase_sort(items_list, [](const void *a_, const void *b_) -> int {
const CollItemSearch *cis_a = (const CollItemSearch *)a_;
const CollItemSearch *cis_b = (const CollItemSearch *)b_;
return BLI_strcasecmp_natural(cis_a->name, cis_b->name);
});
int i = 0;
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
cis->index = i;
i++;
}
}
}
if (skip_filter) {
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
else {
const blender::Vector<CollItemSearch *> filtered_items = search.query(str);
for (CollItemSearch *cis : filtered_items) {
if (!add_collection_search_item(cis, requires_exact_data_name, has_id_icon, items)) {
break;
}
}
}
LISTBASE_FOREACH (CollItemSearch *, cis, items_list) {
MEM_freeN(cis->name);
}
BLI_freelistN(items_list);
MEM_freeN(items_list);
}
int UI_icon_from_id(const ID *id)
{
if (id == nullptr) {

View File

@ -53,6 +53,8 @@
.miter_outer = MOD_BEVEL_MITER_SHARP, \
.affect_type = MOD_BEVEL_AFFECT_EDGES, \
.profile = 0.5f, \
.edge_weight_name = "bevel_weight_edge", \
.vertex_weight_name = "bevel_weight_vert", \
.bevel_angle = DEG2RADF(30.0f), \
.spread = 0.1f, \
.defgrp_name = "", \

View File

@ -481,6 +481,12 @@ typedef struct BevelModifierData {
struct CurveProfile *custom_profile;
void *_pad2;
/** Custom bevel edge weight name. */
char edge_weight_name[64];
/** Custom bevel vertex weight name. */
char vertex_weight_name[64];
} BevelModifierData;
/** #BevelModifierData.flags and BevelModifierData.lim_flags */

View File

@ -952,6 +952,20 @@ static bool rna_HookModifier_object_override_apply(Main *bmain,
return true;
}
static void rna_BevelModifier_edge_weight_name_set(PointerRNA *ptr, const char *value)
{
BevelModifierData *bmd = static_cast<BevelModifierData *>(ptr->data);
Mike93 marked this conversation as resolved Outdated

Remove this line; you never used this result.

Remove this line; you never used this result.
STRNCPY(bmd->edge_weight_name, value);
}
static void rna_BevelModifier_vertex_weight_name_set(PointerRNA *ptr, const char *value)
{
BevelModifierData *bmd = static_cast<BevelModifierData *>(ptr->data);
STRNCPY(bmd->vertex_weight_name, value);
}
static void rna_HookModifier_subtarget_set(PointerRNA *ptr, const char *value)
{
Object *owner = (Object *)ptr->owner_id;
@ -4312,6 +4326,20 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Limit Method", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "edge_weight", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "edge_weight_name");
RNA_def_property_ui_text(prop, "Edge Attribute", "Edge weight attribute");
RNA_def_property_string_funcs(
prop, nullptr, nullptr, "rna_BevelModifier_edge_weight_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "vertex_weight", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, nullptr, "vertex_weight_name");
RNA_def_property_ui_text(prop, "Vertex Attribute", "Vertex weight attribute");
RNA_def_property_string_funcs(
prop, nullptr, nullptr, "rna_BevelModifier_vertex_weight_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "angle_limit", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, nullptr, "bevel_angle");
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));

View File

@ -10,6 +10,7 @@
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@ -90,6 +91,14 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
int vgroup = -1;
const MDeformVert *dvert = nullptr;
BevelModifierData *bmd = (BevelModifierData *)md;
if (bmd->vertex_weight_name == "") {
STRNCPY(bmd->vertex_weight_name, "bevel_weight_vert");
}
if (bmd->edge_weight_name == "") {
STRNCPY(bmd->edge_weight_name, "bevel_weight_edge");
}
const float threshold = cosf(bmd->bevel_angle + 0.000000175f);
const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
const int offset_type = bmd->val_flags;
@ -124,9 +133,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
}
const int bweight_offset_vert = CustomData_get_offset_named(
&bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
&bm->vdata, CD_PROP_FLOAT, bmd->vertex_weight_name);
const int bweight_offset_edge = CustomData_get_offset_named(
&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
&bm->edata, CD_PROP_FLOAT, bmd->edge_weight_name);
if (bmd->affect_type == MOD_BEVEL_AFFECT_VERTICES) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@ -214,7 +223,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
miter_inner,
spread,
bmd->custom_profile,
bmd->vmesh_method);
bmd->vmesh_method,
bmd->edge_weight_name,
bmd->vertex_weight_name);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
@ -281,6 +292,20 @@ static void panel_draw(const bContext * /*C*/, Panel *panel)
uiLayoutSetActive(sub, edge_bevel);
uiItemR(col, ptr, "angle_limit", UI_ITEM_NONE, nullptr, ICON_NONE);
}
else if (limit_method == MOD_BEVEL_WEIGHT) {
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, edge_bevel);
const char *weight_type = "edge_weight";
int domain_filter = 1;
if (!edge_bevel) {
weight_type = "vertex_weight";
domain_filter = 0;
}
PointerRNA object_data_ptr = RNA_pointer_get(&ob_ptr, "data");
uiItemPointerR_att(col, ptr, weight_type, &object_data_ptr, "attributes", nullptr, ICON_NONE, domain_filter);
}
else if (limit_method == MOD_BEVEL_VGROUP) {
modifier_vgroup_ui(col, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
}