Fix T65295: Convert curve to mesh fails with Keep Original.
authorBastien Montagne <montagne29@wanadoo.fr>
Mon, 10 Jun 2019 09:06:16 +0000 (11:06 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Mon, 10 Jun 2019 09:16:54 +0000 (11:16 +0200)
This code now expects to wrok from fully evaluated data, however when we
keep original, we are actually working from data just copied from orig
one.

Ideally, we'd do a single depsgraph update/eval *after* we have created
all new required data, but that is tricky to do properly in that code
without risking breaking one thing or another.

So for now, just going for the simple, if not optimal solution, and just
repeatedly re-evaluating whole deg every time we duplicate an object to
be converted. Yep, dummy, but simple and... safe. ;)

source/blender/editors/object/object_add.c

index 2881163574b7901c2e295869884209121a7c00cb..0b9ced84a59e171b8b226be248c10819a19a377e 100644 (file)
@@ -2009,7 +2009,7 @@ static bool convert_poll(bContext *C)
 
 /* Helper for convert_exec */
 static Base *duplibase_for_convert(
-    Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob)
+    Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob)
 {
   Object *obn;
   Base *basen;
@@ -2019,12 +2019,27 @@ static Base *duplibase_for_convert(
   }
 
   obn = BKE_object_copy(bmain, ob);
-  DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
+  DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
   BKE_collection_object_add_from(bmain, scene, ob, obn);
 
   basen = BKE_view_layer_base_find(view_layer, obn);
   ED_object_base_select(basen, BA_SELECT);
   ED_object_base_select(base, BA_DESELECT);
+
+  /* XXX Doing that here is stupid, it means we update and re-evaluate the whole depsgraph every
+   * time we need to duplicate an object to convert it. Even worse, this is not 100% correct, since
+   * we do not yet have duplicated obdata.
+   * However, that is a safe solution for now. Proper, longer-term solution is to refactor
+   * convert_exec to:
+   *  - duplicate all data it needs to in a first loop.
+   *  - do a single update.
+   *  - convert data in a second loop. */
+  DEG_graph_tag_relations_update(depsgraph);
+  CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask;
+  CustomData_MeshMasks_update(&scene->customdata_mask, &CD_MASK_MESH);
+  BKE_scene_graph_update_tagged(depsgraph, bmain);
+  scene->customdata_mask = customdata_mask_prev;
+
   return basen;
 }
 
@@ -2131,7 +2146,7 @@ static int convert_exec(bContext *C, wmOperator *op)
       ob->flag |= OB_DONE;
 
       if (keep_original) {
-        basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
+        basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
         newob = basen->object;
 
         /* decrement original mesh's usage count  */
@@ -2156,7 +2171,7 @@ static int convert_exec(bContext *C, wmOperator *op)
       ob->flag |= OB_DONE;
 
       if (keep_original) {
-        basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
+        basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
         newob = basen->object;
 
         /* decrement original mesh's usage count  */
@@ -2186,7 +2201,7 @@ static int convert_exec(bContext *C, wmOperator *op)
       ob->flag |= OB_DONE;
 
       if (keep_original) {
-        basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
+        basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
         newob = basen->object;
 
         /* decrement original curve's usage count  */
@@ -2261,7 +2276,7 @@ static int convert_exec(bContext *C, wmOperator *op)
 
       if (target == OB_MESH) {
         if (keep_original) {
-          basen = duplibase_for_convert(bmain, scene, view_layer, base, NULL);
+          basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, NULL);
           newob = basen->object;
 
           /* decrement original curve's usage count  */
@@ -2296,7 +2311,7 @@ static int convert_exec(bContext *C, wmOperator *op)
       if (!(baseob->flag & OB_DONE)) {
         baseob->flag |= OB_DONE;
 
-        basen = duplibase_for_convert(bmain, scene, view_layer, base, baseob);
+        basen = duplibase_for_convert(bmain, depsgraph, scene, view_layer, base, baseob);
         newob = basen->object;
 
         mb = newob->data;