[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [48247] trunk/blender/source/blender: Fixes for modifier data in multi-user meshes.

Nicholas Bishop nicholasbishop at gmail.com
Sun Jun 24 22:18:39 CEST 2012


Revision: 48247
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=48247
Author:   nicholasbishop
Date:     2012-06-24 20:18:32 +0000 (Sun, 24 Jun 2012)
Log Message:
-----------
Fixes for modifier data in multi-user meshes.

When removing a skin or multires modifier, it skips deletion of the
associated CustomData layer if the object has any other modifiers of
that type. This check has been extended to all objects that use the
object's data.

Similarly, deleting higher multires levels and multires subdivision
will not update the maximum level of any other multires modifiers on
objects that link to the same mesh.

Note that modifier_apply_obdata() doesn't need any changes as it
does not allow applying to multi-user data.

Object joining has also been modified to synchronize multires levels
objects that share a mesh. This is needed because joining can
subdivide or delete levels in order to match the maximum level of the
join-from object to the join-to object.

Fixes bug [#31880] instance multiresolution modifier error.
http://projects.blender.org/tracker/index.php?func=detail&aid=31880&group_id=9&atid=498

Reviewed by Sergey:
http://codereview.appspot.com/6332047/

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/BKE_multires.h
    trunk/blender/source/blender/blenkernel/intern/multires.c
    trunk/blender/source/blender/editors/include/ED_object.h
    trunk/blender/source/blender/editors/mesh/meshtools.c
    trunk/blender/source/blender/editors/object/object_modifier.c

Modified: trunk/blender/source/blender/blenkernel/BKE_multires.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_multires.h	2012-06-24 18:01:46 UTC (rev 48246)
+++ trunk/blender/source/blender/blenkernel/BKE_multires.h	2012-06-24 20:18:32 UTC (rev 48247)
@@ -47,6 +47,9 @@
 /* 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);

Modified: trunk/blender/source/blender/blenkernel/intern/multires.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/multires.c	2012-06-24 18:01:46 UTC (rev 48246)
+++ trunk/blender/source/blender/blenkernel/intern/multires.c	2012-06-24 20:18:32 UTC (rev 48247)
@@ -347,7 +347,7 @@
 		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 @@
 	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 @@
 		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])

Modified: trunk/blender/source/blender/editors/include/ED_object.h
===================================================================
--- trunk/blender/source/blender/editors/include/ED_object.h	2012-06-24 18:01:46 UTC (rev 48246)
+++ trunk/blender/source/blender/editors/include/ED_object.h	2012-06-24 20:18:32 UTC (rev 48247)
@@ -176,6 +176,12 @@
                              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

Modified: trunk/blender/source/blender/editors/mesh/meshtools.c
===================================================================
--- trunk/blender/source/blender/editors/mesh/meshtools.c	2012-06-24 18:01:46 UTC (rev 48246)
+++ trunk/blender/source/blender/editors/mesh/meshtools.c	2012-06-24 20:18:32 UTC (rev 48247)
@@ -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 @@
 			}
 
 			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);

Modified: trunk/blender/source/blender/editors/object/object_modifier.c
===================================================================
--- trunk/blender/source/blender/editors/object/object_modifier.c	2012-06-24 18:01:46 UTC (rev 48246)
+++ trunk/blender/source/blender/editors/object/object_modifier.c	2012-06-24 20:18:32 UTC (rev 48247)
@@ -173,8 +173,101 @@
 	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;
 
 	/* It seems on rapid delete it is possible to
@@ -218,33 +311,13 @@
 		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 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 @@
 
 		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 @@
 		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 @@
 	
 	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);
 	




More information about the Bf-blender-cvs mailing list