Fix/workaround 'convert object' messing up linked data.
authorBastien Montagne <montagne29@wanadoo.fr>
Thu, 15 Jun 2017 13:40:24 +0000 (15:40 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Thu, 15 Jun 2017 13:47:16 +0000 (15:47 +0200)
'Convert To...' Object operation has very weird effect of actually
working at obdata level, not object level, which means *all* objects
(even unselected/hidden/in other scenes/...) using same obdata will be
converted to new selected type.

IMHO this is very bad behavior, but... not a bug really, so do not
change this for now.

But at least, do not do that when working on some linked data, else it
leaves Blend file in invalid (incoherent) state until next reload.

So workaround for now is to enforce the 'Keep Original' option when some
linked object/obdata is affected by the operation.

Also fixed somewhat broken usercount handling in Curve->Mesh part.

source/blender/blenkernel/intern/mesh.c
source/blender/editors/object/object_add.c

index 89e988782d26da66427d28ed48b5943970e85932..171ae4485a0b41526a968bbd6b2f5774ab864b4d 100644 (file)
@@ -1398,9 +1398,7 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
        cu->mat = NULL;
        cu->totcol = 0;
 
-       if (ob->data) {
-               BKE_libblock_free_us(bmain, ob->data);
-       }
+       /* Do not decrement ob->data usercount here, it's done at end of func with BKE_libblock_free_us() call. */
        ob->data = me;
        ob->type = OB_MESH;
 
@@ -1410,11 +1408,14 @@ void BKE_mesh_from_nurbs_displist(Object *ob, ListBase *dispbase, const bool use
                if (ob1->data == cu) {
                        ob1->type = OB_MESH;
                
+                       id_us_min((ID *)ob1->data);
                        ob1->data = ob->data;
-                       id_us_plus((ID *)ob->data);
+                       id_us_plus((ID *)ob1->data);
                }
                ob1 = ob1->id.next;
        }
+
+       BKE_libblock_free_us(bmain, cu);
 }
 
 void BKE_mesh_from_nurbs(Object *ob)
index b278d6e1e87dde2e7d609c03e17c9dce30b65b87..a901560079aebb63f946f0ad5ab4ee1c15602126 100644 (file)
@@ -1640,7 +1640,7 @@ static int convert_exec(bContext *C, wmOperator *op)
        MetaBall *mb;
        Mesh *me;
        const short target = RNA_enum_get(op->ptr, "target");
-       const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
+       bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
        int a, mballConverted = 0;
 
        /* don't forget multiple users! */
@@ -1678,6 +1678,19 @@ static int convert_exec(bContext *C, wmOperator *op)
        {
                for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
                        Base *base = link->ptr.data;
+                       ob = base->object;
+
+                       /* The way object type conversion works currently (enforcing conversion of *all* objetcs using converted
+                        * obdata, even some un-selected/hidden/inother scene ones, sounds totally bad to me.
+                        * However, changing this is more design than bugfix, not to mention convoluted code below,
+                        * so that will be for later.
+                        * But at the very least, do not do that with linked IDs! */
+                       if ((ID_IS_LINKED_DATABLOCK(ob) || ID_IS_LINKED_DATABLOCK(ob->data)) && !keep_original) {
+                               keep_original = true;
+                               BKE_reportf(op->reports, RPT_INFO,
+                                           "Converting some linked object/object data, enforcing 'Keep Original' option to True");
+                       }
+
                        DAG_id_tag_update(&base->object->id, OB_RECALC_DATA);
                }