diff options
-rw-r--r-- | source/blender/blenkernel/BKE_material.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/material.c | 41 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 79 |
4 files changed, 116 insertions, 9 deletions
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index f52dc030873..91c1715cca6 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -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); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 1bda662a8b0..c23b4ac4408 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -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); } } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 1f8bbfbec88..22ab7e49973 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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); } } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 4610bb89ae4..38ce56b4bc7 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -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; |