From 1a650fdcb286ad3759c65a9952aa2e02966eba0b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 30 Aug 2020 13:33:35 +1000 Subject: Object: support removing unused material slots for selected objects This is useful to run in object-mode, instead of from the property editor, note that this still only used the current object when activated from the property editor. --- source/blender/editors/render/render_shading.c | 187 +++++++++++++++++-------- 1 file changed, 131 insertions(+), 56 deletions(-) (limited to 'source/blender/editors/render') diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 3f31cbf7e48..078817e091a 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -56,6 +56,7 @@ #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_material.h" +#include "BKE_object.h" #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -95,42 +96,114 @@ #include "render_intern.h" // own include +static bool object_materials_supported_poll_ex(bContext *C, const Object *ob); + /* -------------------------------------------------------------------- */ /** \name Local Utilities * \{ */ -/** - * Object list for material operations. - * has exception for pinned object. - */ -static Object **object_array_for_shading(bContext *C, uint *r_objects_len) -{ - ScrArea *area = CTX_wm_area(C); - SpaceProperties *sbuts = NULL; - View3D *v3d = NULL; - if (area != NULL) { - if (area->spacetype == SPACE_PROPERTIES) { - sbuts = area->spacedata.first; - } - else if (area->spacetype == SPACE_VIEW3D) { - v3d = area->spacedata.first; - } +static Object **object_array_for_shading_impl(bContext *C, + bool (*filter_fn)(struct Object *ob, + void *user_data), + void *filter_user_data, + uint *r_objects_len) +{ + Object **objects; + + Object *ob = NULL; + bool use_ob = true; + if (CTX_wm_space_properties(C)) { + /* May return pinned object. */ + ob = ED_object_context(C); + } + else { + /* Otherwise use full selection. */ + use_ob = false; } - Object **objects; - if (sbuts != NULL && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) { - objects = MEM_mallocN(sizeof(*objects), __func__); - objects[0] = (Object *)sbuts->pinid; - *r_objects_len = 1; + if (use_ob) { + if (!filter_fn(ob, filter_user_data)) { + ob = NULL; + } + *r_objects_len = (ob != NULL) ? 1 : 0; + objects = MEM_mallocN(sizeof(*objects) * *r_objects_len, __func__); + if (ob != NULL) { + objects[0] = ob; + } } else { ViewLayer *view_layer = CTX_data_view_layer(C); - objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - view_layer, v3d, r_objects_len); + const View3D *v3d = CTX_wm_view3d(C); /* may be NULL. */ + objects = BKE_view_layer_array_selected_objects_params( + view_layer, + v3d, + r_objects_len, + &((const struct ObjectsInViewLayerParams){ + .no_dup_data = true, + .filter_fn = filter_fn, + .filter_userdata = filter_user_data, + })); } return objects; } +static bool object_array_for_shading_edit_mode_enabled_filter(Object *ob, void *user_data) +{ + bContext *C = user_data; + if (object_materials_supported_poll_ex(C, ob)) { + if (BKE_object_is_in_editmode(ob) == true) { + return true; + } + } + return false; +} + +static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_objects_len) +{ + return object_array_for_shading_impl( + C, object_array_for_shading_edit_mode_enabled_filter, C, r_objects_len); +} + +static bool object_array_for_shading_edit_mode_disabled_filter(Object *ob, void *user_data) +{ + bContext *C = user_data; + if (object_materials_supported_poll_ex(C, ob)) { + if (BKE_object_is_in_editmode(ob) == false) { + return true; + } + } + return false; +} + +static Object **object_array_for_shading_edit_mode_disabled(bContext *C, uint *r_objects_len) +{ + return object_array_for_shading_impl( + C, object_array_for_shading_edit_mode_disabled_filter, C, r_objects_len); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Shared Operator Poll Functions + * \{ */ + +static bool object_materials_supported_poll_ex(bContext *C, const Object *ob) +{ + if (!ED_operator_object_active_local_editable_ex(C, ob)) { + return false; + } + const ID *data = ob->data; + return (OB_TYPE_SUPPORT_MATERIAL(ob->type) && + /* Object data checks. */ + data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data)); +} + +static bool object_materials_supported_poll(bContext *C) +{ + Object *ob = ED_object_context(C); + return object_materials_supported_poll_ex(C, ob); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -170,7 +243,7 @@ void OBJECT_OT_material_slot_add(wmOperatorType *ot) /* api callbacks */ ot->exec = material_slot_add_exec; - ot->poll = ED_operator_object_active_local_editable; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -221,7 +294,7 @@ void OBJECT_OT_material_slot_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = material_slot_remove_exec; - ot->poll = ED_operator_object_active_local_editable; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -242,7 +315,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; uint objects_len = 0; - Object **objects = object_array_for_shading(C, &objects_len); + Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; short mat_nr_active = -1; @@ -330,7 +403,7 @@ void OBJECT_OT_material_slot_assign(wmOperatorType *ot) /* api callbacks */ ot->exec = material_slot_assign_exec; - ot->poll = ED_operator_object_active_local_editable; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; @@ -349,7 +422,7 @@ static int material_slot_de_select(bContext *C, bool select) const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; uint objects_len = 0; - Object **objects = object_array_for_shading(C, &objects_len); + Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; short mat_nr_active = -1; @@ -614,8 +687,8 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot) ot->description = "Move the active material up/down in the list"; /* api callbacks */ - ot->poll = ED_operator_object_active_local_editable; ot->exec = material_slot_move_exec; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -636,35 +709,38 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot) static int material_slot_remove_unused_exec(bContext *C, wmOperator *op) { - Object *ob = CTX_data_active_object(C); - - if (!ob) { - return OPERATOR_CANCELLED; - } - /* Removing material slots in edit mode screws things up, see bug #21822.*/ - if (ob == CTX_data_edit_object(C)) { + Object *ob_active = CTX_data_active_object(C); + if (ob_active && BKE_object_is_in_editmode(ob_active)) { BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode"); return OPERATOR_CANCELLED; } - int actcol = ob->actcol; - + Main *bmain = CTX_data_main(C); int removed = 0; - for (int slot = 1; slot <= ob->totcol; slot++) { - while (slot <= ob->totcol && !BKE_object_material_slot_used(ob->data, slot)) { - ob->actcol = slot; - BKE_object_material_slot_remove(CTX_data_main(C), ob); - if (actcol >= slot) { - actcol--; - } + uint objects_len = 0; + Object **objects = object_array_for_shading_edit_mode_disabled(C, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + int actcol = ob->actcol; + for (int slot = 1; slot <= ob->totcol; slot++) { + while (slot <= ob->totcol && !BKE_object_material_slot_used(ob->data, slot)) { + ob->actcol = slot; + BKE_object_material_slot_remove(bmain, ob); + + if (actcol >= slot) { + actcol--; + } - removed++; + removed++; + } } - } + ob->actcol = actcol; - ob->actcol = actcol; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + MEM_freeN(objects); if (!removed) { return OPERATOR_CANCELLED; @@ -672,16 +748,15 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_INFO, "Removed %d slots", removed); - if (ob->mode & OB_MODE_TEXTURE_PAINT) { + if (ob_active->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + BKE_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL); WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); } - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active); + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob_active); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob_active); return OPERATOR_FINISHED; } @@ -695,7 +770,7 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) /* api callbacks */ ot->exec = material_slot_remove_unused_exec; - ot->poll = ED_operator_object_active_local_editable; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -768,8 +843,8 @@ void MATERIAL_OT_new(wmOperatorType *ot) ot->description = "Add a new material"; /* api callbacks */ - ot->poll = ED_operator_object_active_local_editable; ot->exec = new_material_exec; + ot->poll = object_materials_supported_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; -- cgit v1.2.3