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:
parent
feed46c4ae
commit
a2f357edc2
|
@ -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):
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue