Fix T54544: "Copy Materials to Selected" only works when materials are defined on the mesh.

Build a temp matarray storing materials from obdata and source object
(depending on slots 'allocation' of source object), and assign those to
targets.

Also remove limitation of 'using same obdata is forbidden', just never
edit obdata materials in that case...

Certainly not perfect, but already much better than existing code.
This commit is contained in:
Bastien Montagne 2020-07-28 18:26:56 +02:00
parent 5d88f8eba2
commit 9c1da81a4c
4 changed files with 34 additions and 10 deletions

@ -84,7 +84,8 @@ void BKE_object_material_assign(
void BKE_object_material_array_assign(struct Main *bmain,
struct Object *ob,
struct Material ***matar,
short totcol);
int totcol,
const bool to_object_only);
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);

@ -955,7 +955,8 @@ void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap
void BKE_object_material_array_assign(Main *bmain,
struct Object *ob,
struct Material ***matar,
short totcol)
int totcol,
const bool to_object_only)
{
int actcol_orig = ob->actcol;
short i;
@ -966,7 +967,15 @@ void BKE_object_material_array_assign(Main *bmain,
/* now we have the right number of slots */
for (i = 0; i < totcol; i++) {
BKE_object_material_assign(bmain, ob, (*matar)[i], i + 1, BKE_MAT_ASSIGN_USERPREF);
if (to_object_only && ob->matbits[i] == 0) {
/* If we only assign to object, and that slot uses obdata material, do nothing. */
continue;
}
BKE_object_material_assign(bmain,
ob,
(*matar)[i],
i + 1,
to_object_only ? BKE_MAT_ASSIGN_OBJECT : BKE_MAT_ASSIGN_USERPREF);
}
if (actcol_orig > ob->totcol) {

@ -4172,7 +4172,8 @@ static Base *mesh_separate_tagged(
BKE_object_material_array_assign(bmain,
base_new->object,
BKE_object_material_array_p(obedit),
*BKE_object_material_len_p(obedit));
*BKE_object_material_len_p(obedit),
false);
ED_object_base_select(base_new, BA_SELECT);
@ -4244,7 +4245,8 @@ static Base *mesh_separate_arrays(Main *bmain,
BKE_object_material_array_assign(bmain,
base_new->object,
BKE_object_material_array_p(obedit),
*BKE_object_material_len_p(obedit));
*BKE_object_material_len_p(obedit),
false);
ED_object_base_select(base_new, BA_SELECT);

@ -465,17 +465,27 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Object *ob = ED_object_context(C);
Material ***matar;
Material ***matar_obdata;
if (!ob || !(matar = BKE_object_material_array_p(ob))) {
if (!ob || !(matar_obdata = BKE_object_material_array_p(ob))) {
return OPERATOR_CANCELLED;
}
BLI_assert(ob->totcol == *BKE_object_material_len_p(ob));
Material ***matar_object = &ob->mat;
Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__);
for (int i = ob->totcol; i--;) {
matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i];
}
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
if (ob != ob_iter && BKE_object_material_array_p(ob_iter)) {
if (ob->data != ob_iter->data) {
BKE_object_material_array_assign(bmain, ob_iter, matar, ob->totcol);
}
/* If we are using the same obdata, we only assign slots in ob_iter that are using object
* materials, and not obdata ones. */
const bool is_same_obdata = ob->data == ob_iter->data;
BKE_object_material_array_assign(bmain, ob_iter, &matar, ob->totcol, is_same_obdata);
if (ob_iter->totcol == ob->totcol) {
ob_iter->actcol = ob->actcol;
@ -486,6 +496,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
}
CTX_DATA_END;
MEM_freeN(matar);
return OPERATOR_FINISHED;
}