fix [#36349] Separate mesh by material creates meshes with all the materials from the original
This commit is contained in:
parent
503b7d5b9a
commit
7a6f3d9e43
|
@ -50,7 +50,7 @@ void init_def_material(void);
|
|||
void BKE_material_free(struct Material *sc);
|
||||
void BKE_material_free_ex(struct Material *ma, int do_id_user);
|
||||
void test_object_materials(struct Main *bmain, struct ID *id);
|
||||
void resize_object_material(struct Object *ob, const short totcol);
|
||||
void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
|
||||
void init_material(struct Material *ma);
|
||||
struct Material *BKE_material_add(struct Main *bmain, const char *name);
|
||||
struct Material *BKE_material_copy(struct Material *ma);
|
||||
|
@ -87,6 +87,7 @@ int object_add_material_slot(struct Object *ob);
|
|||
int object_remove_material_slot(struct Object *ob);
|
||||
|
||||
/* rna api */
|
||||
void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user);
|
||||
void BKE_material_append_id(struct ID *id, struct Material *ma);
|
||||
struct Material *BKE_material_pop_id(struct ID *id, int index, bool update_data); /* index is an int because of RNA */
|
||||
void BKE_material_clear_id(struct ID *id, bool update_data);
|
||||
|
|
|
@ -573,6 +573,34 @@ static void material_data_index_clear_id(ID *id)
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user)
|
||||
{
|
||||
Material ***matar = give_matarar_id(id);
|
||||
short *totcolp = give_totcolp_id(id);
|
||||
|
||||
if (matar == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (do_id_user && totcol < (*totcolp)) {
|
||||
short i;
|
||||
for (i = totcol; i < (*totcolp); i++) {
|
||||
id_us_min((ID *)(*matar)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (totcol == 0) {
|
||||
if (*totcolp) {
|
||||
MEM_freeN(*matar);
|
||||
*matar = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
*matar = MEM_recallocN(*matar, sizeof(void *) * totcol);
|
||||
}
|
||||
*totcolp = totcol;
|
||||
}
|
||||
|
||||
void BKE_material_append_id(ID *id, Material *ma)
|
||||
{
|
||||
Material ***matar;
|
||||
|
@ -708,11 +736,18 @@ Material *give_node_material(Material *ma)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void resize_object_material(Object *ob, const short totcol)
|
||||
void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user)
|
||||
{
|
||||
Material **newmatar;
|
||||
char *newmatbits;
|
||||
|
||||
if (do_id_user && totcol < ob->totcol) {
|
||||
short i;
|
||||
for (i = totcol; i < ob->totcol; i++) {
|
||||
id_us_min((ID *)ob->mat[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (totcol == 0) {
|
||||
if (ob->totcol) {
|
||||
MEM_freeN(ob->mat);
|
||||
|
@ -733,6 +768,8 @@ void resize_object_material(Object *ob, const short totcol)
|
|||
ob->mat = newmatar;
|
||||
ob->matbits = newmatbits;
|
||||
}
|
||||
/* XXX, why not realloc on shrink? - campbell */
|
||||
|
||||
ob->totcol = totcol;
|
||||
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
|
||||
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
|
||||
|
@ -750,7 +787,7 @@ void test_object_materials(Main *bmain, ID *id)
|
|||
|
||||
for (ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
if (ob->data == id) {
|
||||
resize_object_material(ob, *totcol);
|
||||
BKE_material_resize_object(ob, *totcol, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4345,7 +4345,7 @@ static void lib_link_object(FileData *fd, Main *main)
|
|||
/* Only expand so as not to loose any object materials that might be set. */
|
||||
if (totcol_data && (*totcol_data > ob->totcol)) {
|
||||
/* printf("'%s' %d -> %d\n", ob->id.name, ob->totcol, *totcol_data); */
|
||||
resize_object_material(ob, *totcol_data);
|
||||
BKE_material_resize_object(ob, *totcol_data, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2399,7 +2399,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
|
|||
RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
|
||||
}
|
||||
|
||||
static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
|
||||
static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
|
||||
{
|
||||
Base *base_new;
|
||||
Object *obedit = base_old->object;
|
||||
|
@ -2441,7 +2441,7 @@ static int mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh
|
|||
BM_mesh_free(bm_new);
|
||||
((Mesh *)base_new->object->data)->edit_btmesh = NULL;
|
||||
|
||||
return true;
|
||||
return base_new;
|
||||
}
|
||||
|
||||
static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
|
||||
|
@ -2452,7 +2452,7 @@ static bool mesh_separate_selected(Main *bmain, Scene *scene, Base *base_old, BM
|
|||
/* sel -> tag */
|
||||
BM_mesh_elem_hflag_enable_test(bm_old, BM_FACE | BM_EDGE | BM_VERT, BM_ELEM_TAG, true, BM_ELEM_SELECT);
|
||||
|
||||
return mesh_separate_tagged(bmain, scene, base_old, bm_old);
|
||||
return (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
|
||||
}
|
||||
|
||||
/* flush a hflag to from verts to edges/faces */
|
||||
|
@ -2492,6 +2492,63 @@ static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object to a single material. from one of its slots.
|
||||
*
|
||||
* \note This could be used for split-by-material for non mesh types.
|
||||
* \note This could take material data from another object or args.
|
||||
*/
|
||||
static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
|
||||
{
|
||||
ID *obdata = ob->data;
|
||||
|
||||
Material ***matarar;
|
||||
short *totcolp;
|
||||
|
||||
totcolp = give_totcolp_id(obdata);
|
||||
matarar = give_matarar_id(obdata);
|
||||
|
||||
if ((totcolp && matarar) == 0) {
|
||||
BLI_assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*totcolp) {
|
||||
Material *ma_ob;
|
||||
Material *ma_obdata;
|
||||
char matbit;
|
||||
|
||||
if (mat_nr < ob->totcol) {
|
||||
ma_ob = ob->mat[mat_nr];
|
||||
matbit = ob->matbits[mat_nr];
|
||||
}
|
||||
else {
|
||||
ma_ob = NULL;
|
||||
matbit = 0;
|
||||
}
|
||||
|
||||
if (mat_nr < *totcolp) {
|
||||
ma_obdata = (*matarar)[mat_nr];
|
||||
}
|
||||
else {
|
||||
ma_obdata = NULL;
|
||||
}
|
||||
|
||||
BKE_material_clear_id(obdata, true);
|
||||
BKE_material_resize_object(ob, 1, true);
|
||||
BKE_material_resize_id(obdata, 1, true);
|
||||
|
||||
ob->mat[0] = ma_ob;
|
||||
ob->matbits[0] = matbit;
|
||||
(*matarar)[0] = ma_obdata;
|
||||
}
|
||||
else {
|
||||
BKE_material_clear_id(obdata, true);
|
||||
BKE_material_resize_object(ob, 0, true);
|
||||
BKE_material_resize_id(obdata, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
|
||||
{
|
||||
BMFace *f_cmp, *f;
|
||||
|
@ -2499,6 +2556,7 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
|
|||
bool result = false;
|
||||
|
||||
while ((f_cmp = BM_iter_at_index(bm_old, BM_FACES_OF_MESH, NULL, 0))) {
|
||||
Base *base_new;
|
||||
const short mat_nr = f_cmp->mat_nr;
|
||||
int tot = 0;
|
||||
|
||||
|
@ -2522,11 +2580,22 @@ static bool mesh_separate_material(Main *bmain, Scene *scene, Base *base_old, BM
|
|||
|
||||
/* leave the current object with some materials */
|
||||
if (tot == bm_old->totface) {
|
||||
mesh_separate_material_assign_mat_nr(base_old->object, mat_nr);
|
||||
|
||||
/* since we're in editmode, must set faces here */
|
||||
BM_ITER_MESH (f, &iter, bm_old, BM_FACES_OF_MESH) {
|
||||
f->mat_nr = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Move selection into a separate object */
|
||||
result |= mesh_separate_tagged(bmain, scene, base_old, bm_old);
|
||||
base_new = mesh_separate_tagged(bmain, scene, base_old, bm_old);
|
||||
if (base_new) {
|
||||
mesh_separate_material_assign_mat_nr(base_new->object, mat_nr);
|
||||
}
|
||||
|
||||
result |= (base_new != NULL);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -2585,7 +2654,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh
|
|||
bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG);
|
||||
|
||||
/* Move selection into a separate object */
|
||||
result |= mesh_separate_tagged(bmain, scene, base_old, bm_old);
|
||||
result |= (mesh_separate_tagged(bmain, scene, base_old, bm_old) != NULL);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
Loading…
Reference in New Issue