Add operator for removing unused material slots

Reviewers: campbellbarton, brecht

Reviewed By: brecht

Subscribers: brecht

Differential Revision: https://developer.blender.org/D4991
This commit is contained in:
Lukas Stockner 2019-07-31 12:04:52 -07:00
parent feed46c4ae
commit a2f357edc2
12 changed files with 157 additions and 0 deletions

View File

@ -32,6 +32,7 @@ class MATERIAL_MT_context_menu(Menu):
layout.operator("material.copy", icon='COPYDOWN')
layout.operator("object.material_slot_copy")
layout.operator("material.paste", icon='PASTEDOWN')
layout.operator("object.material_slot_remove_unused")
class MATERIAL_UL_matslots(UIList):

View File

@ -109,6 +109,7 @@ void BKE_curve_transform(struct Curve *cu,
const bool do_props);
void BKE_curve_translate(struct Curve *cu, float offset[3], const bool do_keys);
void BKE_curve_material_index_remove(struct Curve *cu, int index);
bool BKE_curve_material_index_used(struct Curve *cu, int index);
void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);

View File

@ -87,6 +87,7 @@ void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe
/* materials */
void BKE_gpencil_material_index_reassign(struct bGPdata *gpd, int totcol, int index);
bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len);

View File

@ -90,6 +90,7 @@ void assign_matarar(struct Main *bmain, struct Object *ob, struct Material ***ma
short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma);
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_used(struct ID *id, short actcol);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);

View File

@ -182,6 +182,7 @@ void BKE_mesh_to_curve(struct Main *bmain,
struct Scene *scene,
struct Object *ob);
void BKE_mesh_material_index_remove(struct Mesh *me, short index);
bool BKE_mesh_material_index_used(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth);

View File

@ -5313,6 +5313,32 @@ void BKE_curve_material_index_remove(Curve *cu, int index)
}
}
bool BKE_curve_material_index_used(Curve *cu, int index)
{
const int curvetype = BKE_curve_type_get(cu);
if (curvetype == OB_FONT) {
struct CharInfo *info = cu->strinfo;
int i;
for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
if (info->mat_nr == index) {
return true;
}
}
}
else {
Nurb *nu;
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->mat_nr == index) {
return true;
}
}
}
return false;
}
void BKE_curve_material_index_clear(Curve *cu)
{
const int curvetype = BKE_curve_type_get(cu);

View File

@ -1662,6 +1662,22 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
}
}
/* remove strokes using a material */
bool BKE_gpencil_material_index_used(bGPdata *gpd, int index)
{
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
if (gps->mat_nr == index) {
return true;
}
}
}
}
return false;
}
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len)

View File

@ -366,6 +366,26 @@ static void material_data_index_remove_id(ID *id, short index)
}
}
bool BKE_object_material_slot_used(ID *id, short actcol)
{
/* ensure we don't try get materials from non-obdata */
BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
switch (GS(id->name)) {
case ID_ME:
return BKE_mesh_material_index_used((Mesh *)id, actcol - 1);
case ID_CU:
return BKE_curve_material_index_used((Curve *)id, actcol - 1);
case ID_MB:
/* meta-elems don't have materials atm */
return false;
case ID_GD:
return BKE_gpencil_material_index_used((bGPdata *)id, actcol - 1);
default:
return false;
}
}
static void material_data_index_clear_id(ID *id)
{
/* ensure we don't try get materials from non-obdata */

View File

@ -1206,6 +1206,27 @@ void BKE_mesh_material_index_remove(Mesh *me, short index)
}
}
bool BKE_mesh_material_index_used(Mesh *me, short index)
{
MPoly *mp;
MFace *mf;
int i;
for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) {
if (mp->mat_nr == index) {
return true;
}
}
for (mf = me->mface, i = 0; i < me->totface; i++, mf++) {
if (mf->mat_nr == index) {
return true;
}
}
return false;
}
void BKE_mesh_material_index_clear(Mesh *me)
{
MPoly *mp;

View File

@ -37,6 +37,7 @@ void OBJECT_OT_material_slot_select(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_move(struct wmOperatorType *ot);
void OBJECT_OT_material_slot_remove_unused(struct wmOperatorType *ot);
void MATERIAL_OT_new(struct wmOperatorType *ot);
void TEXTURE_OT_new(struct wmOperatorType *ot);

View File

@ -42,6 +42,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(OBJECT_OT_material_slot_deselect);
WM_operatortype_append(OBJECT_OT_material_slot_copy);
WM_operatortype_append(OBJECT_OT_material_slot_move);
WM_operatortype_append(OBJECT_OT_material_slot_remove_unused);
WM_operatortype_append(MATERIAL_OT_new);
WM_operatortype_append(TEXTURE_OT_new);

View File

@ -549,6 +549,73 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
"Direction to move the active material towards");
}
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)) {
BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode");
return OPERATOR_CANCELLED;
}
int actcol = ob->actcol;
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--;
}
removed++;
}
}
ob->actcol = actcol;
if (!removed) {
return OPERATOR_CANCELLED;
}
BKE_reportf(op->reports, RPT_INFO, "Removed %d slots", removed);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
BKE_paint_proj_mesh_data_check(scene, ob, 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);
return OPERATOR_FINISHED;
}
void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Unused Slots";
ot->idname = "OBJECT_OT_material_slot_remove_unused";
ot->description = "Remove unused material slots";
/* api callbacks */
ot->exec = material_slot_remove_unused_exec;
ot->poll = ED_operator_object_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/********************** new material operator *********************/
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))