Transform: option to transform origins in object mode
authorCampbell Barton <ideasman42@gmail.com>
Thu, 22 Aug 2019 03:45:31 +0000 (13:45 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 23 Aug 2019 21:34:43 +0000 (07:34 +1000)
Currently supports mesh, armature, lattice, curve & metaballs.

Access from pivot popover.

17 files changed:
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_lattice.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/mesh.c
source/blender/editors/include/ED_object.h
source/blender/editors/object/CMakeLists.txt
source/blender/editors/object/object_data_transform.c [new file with mode: 0644]
source/blender/editors/object/object_modifier.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_scene.c

index 6ef268f9321b4b5d9dda6d6ab41a0f6cf5f8117f..b684e4aa2dd2f6ac6abf8ee5544c27265914cd78 100644 (file)
@@ -5890,7 +5890,9 @@ class VIEW3D_PT_pivot_point(Panel):
         if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}):
             col.separator()
 
-            col.prop(tool_settings, "use_transform_pivot_point_align")
+            col.label(text="Affect Only")
+            col.prop(tool_settings, "use_transform_data_origin", text="Origins")
+            col.prop(tool_settings, "use_transform_pivot_point_align", text="Locations")
 
 
 class VIEW3D_PT_snapping(Panel):
index 67efeea02cb45caa200b681a176f7f58e6ff7383..af783a6ae8a0644128647fa99f4bb91e385de3cc 100644 (file)
@@ -127,7 +127,14 @@ void BKE_curve_nurb_vert_active_validate(struct Curve *cu);
 float (*BKE_curve_nurbs_vert_coords_alloc(struct ListBase *lb, int *r_vert_len))[3];
 void BKE_curve_nurbs_vert_coords_get(struct ListBase *lb, float (*vert_coords)[3], int vert_len);
 
-void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb, const float (*vert_coords)[3]);
+void BKE_curve_nurbs_vert_coords_apply_with_mat4(struct ListBase *lb,
+                                                 const float (*vert_coords)[3],
+                                                 const float mat[4][4],
+                                                 const bool constrain_2d);
+
+void BKE_curve_nurbs_vert_coords_apply(struct ListBase *lb,
+                                       const float (*vert_coords)[3],
+                                       const bool constrain_2d);
 
 float (*BKE_curve_nurbs_key_vert_coords_alloc(struct ListBase *lb,
                                               float *key,
index 8395b182171c9f43aad800701c11ecd9cc7a25ec..a3befa6f3bbc9840ee95397f1cb45cdc15074077 100644 (file)
@@ -90,6 +90,9 @@ void armature_deform_verts(struct Object *armOb,
 
 float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3];
 void BKE_lattice_vert_coords_get(const struct Lattice *lt, float (*vert_coords)[3]);
+void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt,
+                                             const float (*vert_coords)[3],
+                                             const float mat[4][4]);
 void BKE_lattice_vert_coords_apply(struct Lattice *lt, const float (*vert_coords)[3]);
 void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph,
                                 struct Scene *scene,
index b2ae7a6dac09638ef181a7f73648554871bacb81..7986bf947e51ed8e05b876b2712b1b8260d35689 100644 (file)
@@ -269,6 +269,9 @@ void BKE_mesh_count_selected_items(const struct Mesh *mesh, int r_count[3]);
 float (*BKE_mesh_vert_coords_alloc(const struct Mesh *mesh, int *r_vert_len))[3];
 void BKE_mesh_vert_coords_get(const struct Mesh *mesh, float (*vert_coords)[3]);
 
+void BKE_mesh_vert_coords_apply_with_mat4(struct Mesh *mesh,
+                                          const float (*vert_coords)[3],
+                                          const float mat[4][4]);
 void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3]);
 void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vertNormals)[3]);
 
index 1f21d7962205cf67949298427c81d9eedc32f46a..0126c261fa1bf375e7674edf613bd2c2dcb3174b 100644 (file)
@@ -4641,7 +4641,50 @@ float (*BKE_curve_nurbs_vert_coords_alloc(ListBase *lb, int *r_vert_len))[3]
   return vert_coords;
 }
 
-void BKE_curve_nurbs_vert_coords_apply(ListBase *lb, const float (*vert_coords)[3])
+void BKE_curve_nurbs_vert_coords_apply_with_mat4(ListBase *lb,
+                                                 const float (*vert_coords)[3],
+                                                 const float mat[4][4],
+                                                 const bool constrain_2d)
+{
+  const float *co = vert_coords[0];
+  Nurb *nu;
+  int i;
+
+  for (nu = lb->first; nu; nu = nu->next) {
+    if (nu->type == CU_BEZIER) {
+      BezTriple *bezt = nu->bezt;
+
+      for (i = 0; i < nu->pntsu; i++, bezt++) {
+        mul_v3_m4v3(bezt->vec[0], mat, co);
+        co += 3;
+        mul_v3_m4v3(bezt->vec[1], mat, co);
+        co += 3;
+        mul_v3_m4v3(bezt->vec[2], mat, co);
+        co += 3;
+      }
+    }
+    else {
+      BPoint *bp = nu->bp;
+
+      for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
+        mul_v3_m4v3(bp->vec, mat, co);
+        co += 3;
+      }
+    }
+
+    if (constrain_2d) {
+      if (nu->flag & CU_2D) {
+        BKE_nurb_test_2d(nu);
+      }
+    }
+
+    calchandlesNurb_intern(nu, true);
+  }
+}
+
+void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
+                                       const float (*vert_coords)[3],
+                                       const bool constrain_2d)
 {
   const float *co = vert_coords[0];
 
@@ -4667,6 +4710,12 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb, const float (*vert_coords)[
       }
     }
 
+    if (constrain_2d) {
+      if (nu->flag & CU_2D) {
+        BKE_nurb_test_2d(nu);
+      }
+    }
+
     calchandlesNurb_intern(nu, true);
   }
 }
index bc235768bc7dbe001ff0f58fd06497c1dffc9026..5904fa2d814a212c472a2627c2d92b7facc01d2f 100644 (file)
@@ -920,7 +920,7 @@ static void curve_calc_modifiers_pre(
   }
 
   if (deformedVerts) {
-    BKE_curve_nurbs_vert_coords_apply(nurb, deformedVerts);
+    BKE_curve_nurbs_vert_coords_apply(nurb, deformedVerts, false);
     MEM_freeN(deformedVerts);
   }
   if (keyVerts) { /* these are not passed through modifier stack */
index 0ceca1206f69ae2d39de5eb22094331f1dd93923..e46b7ca5130f219d96bfec1b8ec52c6d3a0561dc 100644 (file)
@@ -1073,6 +1073,16 @@ float (*BKE_lattice_vert_coords_alloc(const Lattice *lt, int *r_vert_len))[3]
   return vert_coords;
 }
 
+void BKE_lattice_vert_coords_apply_with_mat4(struct Lattice *lt,
+                                             const float (*vertexCos)[3],
+                                             const float mat[4][4])
+{
+  int i, numVerts = lt->pntsu * lt->pntsv * lt->pntsw;
+  for (i = 0; i < numVerts; i++) {
+    mul_v3_m4v3(lt->def[i].vec, mat, vertexCos[i]);
+  }
+}
+
 void BKE_lattice_vert_coords_apply(Lattice *lt, const float (*vert_coords)[3])
 {
   const int vert_len = lt->pntsu * lt->pntsv * lt->pntsw;
index 9c5ae9b8ca617d2c64989317a14d618f801d280c..38e4527fd17991a82f52e16778001e501667d2f4 100644 (file)
@@ -1675,6 +1675,19 @@ void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3])
   mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
 }
 
+void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
+                                          const float (*vert_coords)[3],
+                                          const float mat[4][4])
+{
+  /* This will just return the pointer if it wasn't a referenced layer. */
+  MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+  mesh->mvert = mv;
+  for (int i = 0; i < mesh->totvert; i++, mv++) {
+    mul_v3_m4v3(mv->co, mat, vert_coords[i]);
+  }
+  mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+}
+
 void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
 {
   /* This will just return the pointer if it wasn't a referenced layer. */
index 7b9a96e4d07be1af1cb433a880d5c6771d6a43ea..de590d124ea8f43db1c611813912c6c131b3bb95 100644 (file)
@@ -44,6 +44,7 @@ struct Scene;
 struct ShaderFxData;
 struct View3D;
 struct ViewLayer;
+struct XFormObjectData;
 struct bConstraint;
 struct bContext;
 struct bFaceMap;
@@ -403,6 +404,12 @@ bool ED_object_jump_to_bone(struct bContext *C,
 void ED_object_facemap_face_add(struct Object *ob, struct bFaceMap *fmap, int facenum);
 void ED_object_facemap_face_remove(struct Object *ob, struct bFaceMap *fmap, int facenum);
 
+/* object_data_transform.c */
+struct XFormObjectData *ED_object_data_xform_create(struct ID *id);
+void ED_object_data_xform_destroy(struct XFormObjectData *xod);
+
+void ED_object_data_xform_by_mat4(struct XFormObjectData *xod, const float mat[4][4]);
+
 #ifdef __cplusplus
 }
 #endif
index 2490f88b5eb5bc5a335661a082de408d735a3350..aabfa78cf582d17f3757ab999cb91a6a5304f2f1 100644 (file)
@@ -48,6 +48,7 @@ set(SRC
   object_collection.c
   object_constraint.c
   object_data_transfer.c
+  object_data_transform.c
   object_edit.c
   object_facemap_ops.c
   object_gpencil_modifier.c
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
new file mode 100644 (file)
index 0000000..ee86c79
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edobj
+ *
+ * Use to transform object origins only.
+ *
+ * This is a small API to store & apply transformations to object data,
+ * where a transformation matrix can be continually applied ontop of the original values
+ * so we don't loose precision over time.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_lattice_types.h"
+
+#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_curve.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_armature.h"
+#include "BKE_lattice.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_types.h"
+
+#include "ED_object.h"
+
+#include "MEM_guardedalloc.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Transform Get/Apply
+ *
+ * Some object data types don't have utility functions to access their transformation data.
+ * Define these locally.
+ *
+ * \{ */
+
+/* Armature */
+
+struct ElemData_Armature {
+  float tail[3];
+  float head[3];
+  float roll;
+  float arm_tail[3];
+  float arm_head[3];
+  float arm_roll;
+  float rad_tail;
+  float rad_head;
+  float dist;
+  float xwidth;
+  float zwidth;
+};
+
+static struct ElemData_Armature *armature_coords_and_quats_get_recurse(
+    const ListBase *bone_base, struct ElemData_Armature *elem_array)
+{
+  struct ElemData_Armature *elem = elem_array;
+  for (const Bone *bone = bone_base->first; bone; bone = bone->next) {
+
+#define COPY_PTR(member) memcpy(elem->member, bone->member, sizeof(bone->member))
+#define COPY_VAL(member) memcpy(&elem->member, &bone->member, sizeof(bone->member))
+    COPY_PTR(head);
+    COPY_PTR(tail);
+    COPY_VAL(roll);
+    COPY_PTR(arm_head);
+    COPY_PTR(arm_tail);
+    COPY_VAL(arm_roll);
+    COPY_VAL(rad_tail);
+    COPY_VAL(rad_head);
+    COPY_VAL(dist);
+    COPY_VAL(xwidth);
+    COPY_VAL(zwidth);
+#undef COPY_PTR
+#undef COPY_VAL
+
+    elem = armature_coords_and_quats_get_recurse(&bone->childbase, elem + 1);
+  }
+  return elem;
+}
+
+static void armature_coords_and_quats_get(const bArmature *arm,
+                                          struct ElemData_Armature *elem_array)
+{
+  armature_coords_and_quats_get_recurse(&arm->bonebase, elem_array);
+}
+
+static const struct ElemData_Armature *armature_coords_and_quats_apply_with_mat4_recurse(
+    ListBase *bone_base, const struct ElemData_Armature *elem_array, const float mat[4][4])
+{
+  const struct ElemData_Armature *elem = elem_array;
+  for (Bone *bone = bone_base->first; bone; bone = bone->next) {
+
+#define COPY_PTR(member) memcpy(bone->member, elem->member, sizeof(bone->member))
+#define COPY_VAL(member) memcpy(&bone->member, &elem->member, sizeof(bone->member))
+    COPY_PTR(head);
+    COPY_PTR(tail);
+    COPY_VAL(roll);
+    COPY_PTR(arm_head);
+    COPY_PTR(arm_tail);
+    COPY_VAL(arm_roll);
+    COPY_VAL(rad_tail);
+    COPY_VAL(rad_head);
+    COPY_VAL(dist);
+    COPY_VAL(xwidth);
+    COPY_VAL(zwidth);
+#undef COPY_PTR
+#undef COPY_VAL
+
+    elem = armature_coords_and_quats_apply_with_mat4_recurse(&bone->childbase, elem + 1, mat);
+  }
+  return elem;
+}
+
+static void armature_coords_and_quats_apply_with_mat4(bArmature *arm,
+                                                      const struct ElemData_Armature *elem_array,
+                                                      const float mat[4][4])
+{
+  armature_coords_and_quats_apply_with_mat4_recurse(&arm->bonebase, elem_array, mat);
+  BKE_armature_transform(arm, mat, true);
+}
+
+/* MetaBall */
+
+struct ElemData_MetaBall {
+  float co[3];
+  float quat[4];
+  float exp[3];
+  float rad;
+};
+
+static void metaball_coords_and_quats_get(const MetaBall *mb, struct ElemData_MetaBall *elem_array)
+{
+  struct ElemData_MetaBall *elem = elem_array;
+  for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next, elem++) {
+    copy_v3_v3(elem->co, &ml->x);
+    copy_qt_qt(elem->quat, ml->quat);
+    copy_v3_v3(elem->exp, &ml->expx);
+    elem->rad = ml->rad;
+  }
+}
+
+static void metaball_coords_and_quats_apply_with_mat4(MetaBall *mb,
+                                                      const struct ElemData_MetaBall *elem_array,
+                                                      const float mat[4][4])
+{
+  const struct ElemData_MetaBall *elem = elem_array;
+  for (MetaElem *ml = mb->elems.first; ml; ml = ml->next, elem++) {
+    copy_v3_v3(&ml->x, elem->co);
+    copy_qt_qt(ml->quat, elem->quat);
+    copy_v3_v3(&ml->expx, elem->exp);
+    ml->rad = elem->rad;
+  }
+  BKE_mball_transform(mb, mat, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Object Data Storage API
+ *
+ * Used for interactively transforming object data.
+ *
+ * Store object data transformation in an opaque struct.
+ * \{ */
+
+struct XFormObjectData {
+  ID *id;
+};
+
+struct XFormObjectData_Mesh {
+  struct XFormObjectData base;
+  float elem_array[0][3];
+};
+
+struct XFormObjectData_Lattice {
+  struct XFormObjectData base;
+  float elem_array[0][3];
+};
+
+struct XFormObjectData_Curve {
+  struct XFormObjectData base;
+  float elem_array[0][3];
+};
+
+struct XFormObjectData_Armature {
+  struct XFormObjectData base;
+  struct ElemData_Armature elem_array[0];
+};
+
+struct XFormObjectData_MetaBall {
+  struct XFormObjectData base;
+  struct ElemData_MetaBall elem_array[0];
+};
+
+struct XFormObjectData *ED_object_data_xform_create(ID *id)
+{
+  struct XFormObjectData *xod_base = NULL;
+  switch (GS(id->name)) {
+    case ID_ME: {
+      Mesh *me = (Mesh *)id;
+      const int elem_array_len = me->totvert;
+      struct XFormObjectData_Mesh *xod = MEM_mallocN(
+          sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
+      BKE_mesh_vert_coords_get(me, xod->elem_array);
+      xod_base = &xod->base;
+      break;
+    }
+    case ID_LT: {
+      Lattice *lt = (Lattice *)id;
+      const int elem_array_len = lt->pntsu * lt->pntsv * lt->pntsw;
+      struct XFormObjectData_Lattice *xod = MEM_mallocN(
+          sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
+      BKE_lattice_vert_coords_get(lt, xod->elem_array);
+      xod_base = &xod->base;
+      break;
+    }
+    case ID_CU: {
+      Curve *cu = (Curve *)id;
+      const short ob_type = BKE_curve_type_get(cu);
+      if (ob_type == OB_FONT) {
+        /* We could support translation. */
+        break;
+      }
+      const int elem_array_len = BKE_nurbList_verts_count(&cu->nurb);
+      struct XFormObjectData_Curve *xod = MEM_mallocN(
+          sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
+      BKE_curve_nurbs_vert_coords_get(&cu->nurb, xod->elem_array, elem_array_len);
+      xod_base = &xod->base;
+      break;
+    }
+    case ID_AR: {
+      bArmature *arm = (bArmature *)id;
+      const int elem_array_len = BKE_armature_bonelist_count(&arm->bonebase);
+      struct XFormObjectData_Armature *xod = MEM_mallocN(
+          sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
+      armature_coords_and_quats_get(arm, xod->elem_array);
+      xod_base = &xod->base;
+      break;
+    }
+    case ID_MB: {
+      MetaBall *mb = (MetaBall *)id;
+      const int elem_array_len = BLI_listbase_count(&mb->elems);
+      struct XFormObjectData_MetaBall *xod = MEM_mallocN(
+          sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
+      metaball_coords_and_quats_get(mb, xod->elem_array);
+      xod_base = &xod->base;
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+  if (xod_base) {
+    xod_base->id = id;
+  }
+  return xod_base;
+}
+
+void ED_object_data_xform_destroy(struct XFormObjectData *xod)
+{
+  MEM_freeN(xod);
+}
+
+void ED_object_data_xform_by_mat4(struct XFormObjectData *xod_base, const float mat[4][4])
+{
+  switch (GS(xod_base->id->name)) {
+    case ID_ME: {
+      Mesh *me = (Mesh *)xod_base->id;
+      struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base;
+      BKE_mesh_vert_coords_apply_with_mat4(me, xod->elem_array, mat);
+      break;
+    }
+    case ID_LT: {
+      Lattice *lt = (Lattice *)xod_base->id;
+      struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base;
+      BKE_lattice_vert_coords_apply_with_mat4(lt, xod->elem_array, mat);
+      break;
+    }
+    case ID_CU: {
+      Curve *cu = (Curve *)xod_base->id;
+      struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base;
+      BKE_curve_nurbs_vert_coords_apply_with_mat4(&cu->nurb, xod->elem_array, mat, true);
+      break;
+    }
+    case ID_AR: {
+      bArmature *arm = (bArmature *)xod_base->id;
+      struct XFormObjectData_Armature *xod = (struct XFormObjectData_Armature *)xod_base;
+      armature_coords_and_quats_apply_with_mat4(arm, xod->elem_array, mat);
+      break;
+    }
+    case ID_MB: {
+      MetaBall *mb = (MetaBall *)xod_base->id;
+      struct XFormObjectData_MetaBall *xod = (struct XFormObjectData_MetaBall *)xod_base;
+      metaball_coords_and_quats_apply_with_mat4(mb, xod->elem_array, mat);
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+}
+
+/** \} */
index 82af30e32fd85a4e784252d8666fac09016c5d27..f77d9874c065db801ac869e16137e4bb3280b1d1 100644 (file)
@@ -716,7 +716,7 @@ static int modifier_apply_obdata(
 
     vertexCos = BKE_curve_nurbs_vert_coords_alloc(&curve_eval->nurb, &numVerts);
     mti->deformVerts(md_eval, &mectx, NULL, vertexCos, numVerts);
-    BKE_curve_nurbs_vert_coords_apply(&curve->nurb, vertexCos);
+    BKE_curve_nurbs_vert_coords_apply(&curve->nurb, vertexCos, false);
 
     MEM_freeN(vertexCos);
 
index 4e245588f53acf63013ddb1ca0bd76926b07c0cc..ff7c8c506e65ddd8a10328713cfd8ebcdb2fe239 100644 (file)
@@ -723,6 +723,16 @@ typedef struct TransInfo {
 
   /** Typically for mode settings. */
   TransCustomDataContainer custom;
+
+  /**
+   * Object to object data transform table.
+   * Don't add these to transform data because we may want to include child objects
+   * which aren't being transformed.
+   * - The key is object data #ID.
+   * - The value is #XFormObjectData_Extra.
+   */
+  struct GHash *obdata_in_obmode_map;
+
 } TransInfo;
 
 /* ******************** Macros & Prototypes *********************** */
@@ -794,6 +804,10 @@ enum {
   T_MODAL_CURSOR_SET = 1 << 26,
 
   T_CLNOR_REBUILD = 1 << 27,
+
+  /** When transforming object's, adjust the object data so it stays in the same place. */
+  T_OBJECT_DATA_IN_OBJECT_MODE = 1 << 28,
+
 };
 
 /** #TransInfo.modifiers */
@@ -1167,4 +1181,7 @@ bool checkUseAxisMatrix(TransInfo *t);
        th != tc_end; \
        th++, i++)
 
+void trans_obdata_in_obmode_free_all(struct TransInfo *t);
+void trans_obdata_in_obmode_update_all(struct TransInfo *t);
+
 #endif
index 2684b6e279d495d50c5316b708406f0968076c60..4fe79dc32026395b89e333ee388e4dbf1535ee00 100644 (file)
@@ -7678,6 +7678,90 @@ int special_transform_moving(TransInfo *t)
   return 0;
 }
 
+/* -------------------------------------------------------------------- */
+/** \name Object Data in Object Mode
+ *
+ * Use to implement 'Affect Only Origins' feature.
+ * We need this to be detached from transform data because,
+ * unlike transforming regular objects, we need to transform the children.
+ *
+ * \{ */
+
+struct XFormObjectData_Extra {
+  Object *ob;
+  float obmat_orig[4][4];
+  bool ob_dtx_axis_orig;
+  struct XFormObjectData *xod;
+};
+
+static void trans_obdata_in_obmode_ensure_object(TransInfo *t, Object *ob)
+{
+  if (t->obdata_in_obmode_map == NULL) {
+    t->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
+  }
+
+  void **xf_p;
+  if (!BLI_ghash_ensure_p(t->obdata_in_obmode_map, ob->data, &xf_p)) {
+    struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
+    copy_m4_m4(xf->obmat_orig, ob->obmat);
+    xf->ob = ob;
+    /* Result may be NULL, that's OK. */
+    xf->xod = ED_object_data_xform_create(ob->data);
+    if (xf->xod) {
+      xf->ob_dtx_axis_orig = ob->dtx & OB_AXIS;
+      ob->dtx |= OB_AXIS;
+    }
+    *xf_p = xf;
+  }
+}
+
+void trans_obdata_in_obmode_update_all(TransInfo *t)
+{
+  struct Main *bmain = CTX_data_main(t->context);
+  BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
+
+  GHashIterator gh_iter;
+  GHASH_ITER (gh_iter, t->obdata_in_obmode_map) {
+    ID *id = BLI_ghashIterator_getKey(&gh_iter);
+    struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
+    if (xf->xod == NULL) {
+      continue;
+    }
+
+    Object *ob_eval = DEG_get_evaluated_object(t->depsgraph, xf->ob);
+    float imat[4][4], dmat[4][4];
+    invert_m4_m4(imat, xf->obmat_orig);
+    mul_m4_m4m4(dmat, imat, ob_eval->obmat);
+    invert_m4(dmat);
+
+    ED_object_data_xform_by_mat4(xf->xod, dmat);
+    DEG_id_tag_update(id, 0);
+  }
+}
+
+/** Callback for #GHash free. */
+static void trans_obdata_in_obmode_free_elem(void *xf_p)
+{
+  struct XFormObjectData_Extra *xf = xf_p;
+  if (xf->xod) {
+    if (!xf->ob_dtx_axis_orig) {
+      xf->ob->dtx &= ~OB_AXIS;
+      DEG_id_tag_update(&xf->ob->id, ID_RECALC_COPY_ON_WRITE);
+    }
+    ED_object_data_xform_destroy(xf->xod);
+  }
+  MEM_freeN(xf);
+}
+
+void trans_obdata_in_obmode_free_all(TransInfo *t)
+{
+  if (t->obdata_in_obmode_map != NULL) {
+    BLI_ghash_free(t->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
+  }
+}
+
+/** \} */
+
 static void createTransObject(bContext *C, TransInfo *t)
 {
   TransData *td = NULL;
@@ -7722,6 +7806,24 @@ static void createTransObject(bContext *C, TransInfo *t)
       td->flag |= TD_SKIP;
     }
 
+    if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+      ID *id = ob->data;
+      if (!id || id->lib) {
+        td->flag |= TD_SKIP;
+      }
+      else if (BKE_object_is_in_editmode(ob)) {
+        /* The object could have edit-mode data from another view-layer,
+         * it's such a corner-case it can be skipped for now - Campbell. */
+        td->flag |= TD_SKIP;
+      }
+    }
+
+    if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+      if ((td->flag & TD_SKIP) == 0) {
+        trans_obdata_in_obmode_ensure_object(t, ob);
+      }
+    }
+
     ObjectToTransData(t, td, ob);
     td->val = NULL;
     td++;
@@ -7753,6 +7855,47 @@ static void createTransObject(bContext *C, TransInfo *t)
       }
     }
   }
+
+  if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+    GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
+    td = tc->data;
+    for (int i = 0; i < tc->data_len; i++, td++) {
+      if ((td->flag & TD_SKIP) == 0) {
+        BLI_gset_add(objects_in_transdata, td->ob);
+      }
+    }
+
+    ViewLayer *view_layer = t->view_layer;
+    View3D *v3d = t->view;
+
+    for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+      Object *ob = base->object;
+
+      /* if base is not selected, not a parent of selection
+       * or not a child of selection and it is editable and selectable */
+      if ((base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
+          BASE_SELECTABLE(v3d, base)) {
+
+        Object *ob_parent = ob->parent;
+        if (ob_parent != NULL) {
+          if (!BLI_gset_haskey(objects_in_transdata, ob)) {
+            bool parent_in_transdata = false;
+            while (ob_parent != NULL) {
+              if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
+                parent_in_transdata = true;
+                break;
+              }
+              ob_parent = ob_parent->parent;
+            }
+            if (parent_in_transdata) {
+              trans_obdata_in_obmode_ensure_object(t, ob);
+            }
+          }
+        }
+      }
+    }
+    BLI_gset_free(objects_in_transdata, NULL);
+  }
 }
 
 /* transcribe given node into TransData2D for Transforming */
@@ -9739,6 +9882,10 @@ void createTransData(bContext *C, TransInfo *t)
     /* Needed for correct Object.obmat after duplication, see: T62135. */
     BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
 
+    if ((scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) != 0) {
+      t->flag |= T_OBJECT_DATA_IN_OBJECT_MODE;
+    }
+
     createTransObject(C, t);
     countAndCleanTransDataContainer(t);
     t->flag |= T_OBJECT;
index 969e2558abb1dc4b237434fefcfe4f4f3eff82db..9c564bcfa545f818b4c770e6fae26ab5e97be358 100644 (file)
@@ -81,6 +81,7 @@
 #include "BKE_workspace.h"
 
 #include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
 
 #include "ED_anim_api.h"
 #include "ED_armature.h"
@@ -1149,6 +1150,10 @@ static void recalcData_objects(TransInfo *t)
       /* Update motion paths once for all transformed objects. */
       ED_objects_recalculate_paths(t->context, t->scene, true);
     }
+
+    if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+      trans_obdata_in_obmode_update_all(t);
+    }
   }
 }
 
@@ -1918,6 +1923,10 @@ void postTrans(bContext *C, TransInfo *t)
     BLI_rng_free(t->rng);
   }
 
+  if (t->flag & T_OBJECT_DATA_IN_OBJECT_MODE) {
+    trans_obdata_in_obmode_free_all(t);
+  }
+
   freeSnapping(t);
 }
 
index 8fd02ccda6ce8934a906a0160d9a68ec5e471738..bda74f9abe051f9163584742bccff3c440ea51f3 100644 (file)
@@ -2020,6 +2020,7 @@ extern const char *RE_engine_id_CYCLES;
 /* ToolSettings.transform_flag */
 enum {
   SCE_XFORM_AXIS_ALIGN = (1 << 0),
+  SCE_XFORM_DATA_ORIGIN = (1 << 1),
 };
 
 /* ToolSettings.object_flag */
index 208bcaab007b0a3046ddc5c52e2280b73316c794..7d9a3cf06b811e61794440eecf6ad8bd9d6089eb 100644 (file)
@@ -2935,8 +2935,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
   prop = RNA_def_property(srna, "use_transform_pivot_point_align", PROP_BOOLEAN, PROP_NONE);
   RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_AXIS_ALIGN);
   RNA_def_property_ui_text(
-      prop, "Only Origins", "Manipulate origins (object, pose and weight paint mode only)");
-  RNA_def_property_ui_icon(prop, ICON_CENTER_ONLY, 0);
+      prop, "Only Locations", "Manipulate origins (object, pose and weight paint mode only)");
+  RNA_def_property_update(prop, NC_SCENE, NULL);
+
+  prop = RNA_def_property(srna, "use_transform_data_origin", PROP_BOOLEAN, PROP_NONE);
+  RNA_def_property_boolean_sdna(prop, NULL, "transform_flag", SCE_XFORM_DATA_ORIGIN);
+  RNA_def_property_ui_text(prop, "Data Origins", "Manipulate object data");
   RNA_def_property_update(prop, NC_SCENE, NULL);
 
   prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE);