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.
This commit is contained in:
@@ -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)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user