diff options
-rw-r--r-- | source/blender/blenkernel/BKE_multires.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires.c | 14 | ||||
-rw-r--r-- | source/blender/editors/include/ED_object.h | 6 | ||||
-rw-r--r-- | source/blender/editors/mesh/meshtools.c | 12 | ||||
-rw-r--r-- | source/blender/editors/object/object_modifier.c | 135 |
5 files changed, 137 insertions, 33 deletions
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 1ff53291044..82a791348dd 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -47,6 +47,9 @@ struct Scene; /* Delete mesh mdisps and grid paint masks */ void multires_customdata_delete(struct Mesh *me); +void multires_set_tot_level(struct Object *ob, + struct MultiresModifierData *mmd, int lvl); + void multires_mark_as_modified(struct Object *ob, enum MultiresModifiedFlags flags); void multires_force_update(struct Object *ob); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index cb6f6823f48..2bc5c37b41b 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -347,7 +347,7 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render) return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl) : mmd->lvl; } -static void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) +void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) { mmd->totlvl = lvl; @@ -2105,6 +2105,8 @@ void multires_load_old(Object *ob, Mesh *me) me->mr = NULL; } +/* If 'ob' and 'to_ob' both have multires modifiers, syncronize them + * such that 'ob' has the same total number of levels as 'to_ob'. */ static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob) { MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1); @@ -2119,10 +2121,12 @@ static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob) multires_customdata_delete(ob->data); } - if (!mmd || !to_mmd) return; - - if (mmd->totlvl > to_mmd->totlvl) multires_del_higher(mmd, ob, to_mmd->totlvl); - else multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple); + if (mmd && to_mmd) { + if (mmd->totlvl > to_mmd->totlvl) + multires_del_higher(mmd, ob, to_mmd->totlvl); + else + multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple); + } } static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 9c10a270ef8..9209bbb2db7 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -176,6 +176,12 @@ int ED_object_modifier_apply(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct ModifierData *md, int mode); int ED_object_modifier_copy(struct ReportList *reports, struct Object *ob, struct ModifierData *md); +int ED_object_iter_other(struct Main *bmain, struct Object *orig_ob, int include_orig, + int (*callback)(struct Object *ob, void *callback_data), + void *callback_data); + +int ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 59a0475ebb5..6d6165e2729 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -45,6 +45,7 @@ #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -418,8 +419,17 @@ int join_mesh_exec(bContext *C, wmOperator *op) } if (me->totloop) { - if (base->object != ob) + if (base->object != ob) { + MultiresModifierData *mmd; + multiresModifier_prepare_join(scene, base->object, ob); + + if ((mmd = get_multires_modifier(scene, base->object, TRUE))) { + ED_object_iter_other(bmain, base->object, TRUE, + ED_object_multires_update_totlevels_cb, + &mmd->totlvl); + } + } CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop); CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index d6b5fb9fc10..b3be18dfb9c 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -173,7 +173,100 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc return new_md; } -static int object_modifier_remove(Object *ob, ModifierData *md, int *sort_depsgraph) +/* Return TRUE if the object has a modifier of type 'type' other than + * the modifier pointed to be 'exclude', otherwise returns FALSE. */ +static int object_has_modifier(const Object *ob, const ModifierData *exclude, + ModifierType type) +{ + ModifierData *md; + + for (md = ob->modifiers.first; md; md = md->next) { + if ((md != exclude) && (md->type == type)) + return TRUE; + } + + return FALSE; +} + +/* If the object data of 'orig_ob' has other users, run 'callback' on + * each of them. + * + * If include_orig is TRUE, the callback will run on 'orig_ob' too. + * + * If the callback ever returns TRUE, iteration will stop and the + * function value will be TRUE. Otherwise the function returns FALSE. +*/ +int ED_object_iter_other(Main *bmain, Object *orig_ob, int include_orig, + int (*callback)(Object *ob, void *callback_data), + void *callback_data) +{ + ID *ob_data_id = orig_ob->data; + int users = ob_data_id->us; + + if (ob_data_id->flag & LIB_FAKEUSER) + users--; + + /* First check that the object's data has multiple users */ + if (users > 1) { + Object *ob; + int totfound = include_orig ? 0 : 1; + + for (ob = bmain->object.first; ob && totfound < users; + ob = ob->id.next) + { + if (((ob != orig_ob) || include_orig) && + (ob->data == orig_ob->data)) + { + if (callback(ob, callback_data)) + return TRUE; + + totfound++; + } + } + } + else if (include_orig) { + return callback(orig_ob, callback_data); + } + + return FALSE; +} + +static int object_has_modifier_cb(Object *ob, void *data) +{ + ModifierType type = *((ModifierType*)data); + + return object_has_modifier(ob, NULL, type); +} + +/* Use with ED_object_iter_other(). Sets the total number of levels + for any multires modifiers on the object to the int pointed to by + callback_data. */ +int ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) +{ + ModifierData *md; + int totlevel = *((int*)totlevel_v); + + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Multires) { + multires_set_tot_level(ob, (MultiresModifierData *)md, totlevel); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + } + return FALSE; +} + +/* Return TRUE if no modifier of type 'type' other than 'exclude' */ +static int object_modifier_safe_to_delete(Main *bmain, Object *ob, + ModifierData *exclude, + ModifierType type) +{ + return (!object_has_modifier(ob, exclude, type) && + !ED_object_iter_other(bmain, ob, FALSE, + object_has_modifier_cb, &type)); +} + +static int object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, + int *sort_depsgraph) { ModifierData *obmd; @@ -218,33 +311,13 @@ static int object_modifier_remove(Object *ob, ModifierData *md, int *sort_depsgr ob->dt = OB_TEXTURE; } else if (md->type == eModifierType_Multires) { - int ok = 1; - ModifierData *tmpmd; - - /* ensure MDISPS CustomData layer isn't used by another multires modifiers */ - for (tmpmd = ob->modifiers.first; tmpmd; tmpmd = tmpmd->next) - if (tmpmd != md && tmpmd->type == eModifierType_Multires) { - ok = 0; - break; - } - - if (ok) { + /* Delete MDisps layer if not used by another multires modifier */ + if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Multires)) multires_customdata_delete(ob->data); - } } else if (md->type == eModifierType_Skin) { - int ok = 1; - ModifierData *tmpmd; - - /* ensure skin CustomData layer isn't used by another skin modifier */ - for (tmpmd = ob->modifiers.first; tmpmd; tmpmd = tmpmd->next) { - if (tmpmd != md && tmpmd->type == eModifierType_Skin) { - ok = 0; - break; - } - } - - if (ok) + /* Delete MVertSkin layer if not used by another skin modifier */ + if (object_modifier_safe_to_delete(bmain, ob, md, eModifierType_Skin)) modifier_skin_customdata_delete(ob); } @@ -265,7 +338,7 @@ int ED_object_modifier_remove(ReportList *reports, Main *bmain, Scene *scene, Ob int sort_depsgraph = 0; int ok; - ok = object_modifier_remove(ob, md, &sort_depsgraph); + ok = object_modifier_remove(bmain, ob, md, &sort_depsgraph); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", ob->id.name, md->name); @@ -294,7 +367,7 @@ void ED_object_modifier_clear(Main *bmain, Scene *scene, Object *ob) next_md = md->next; - object_modifier_remove(ob, md, &sort_depsgraph); + object_modifier_remove(bmain, ob, md, &sort_depsgraph); md = next_md; } @@ -1071,6 +1144,10 @@ static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; multiresModifier_del_levels(mmd, ob, 1); + + ED_object_iter_other(CTX_data_main(C), ob, TRUE, + ED_object_multires_update_totlevels_cb, + &mmd->totlvl); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1112,6 +1189,10 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) multiresModifier_subdivide(mmd, ob, 0, mmd->simple); + ED_object_iter_other(CTX_data_main(C), ob, TRUE, + ED_object_multires_update_totlevels_cb, + &mmd->totlvl); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); |