diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-08-22 06:45:31 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-08-24 00:34:43 +0300 |
commit | acdb14d264c8b4eced645673f8ae8af1a96b1a90 (patch) | |
tree | 0be0b3490fe79105892e309be48f608e6ed19fc5 | |
parent | 71c43e92257c671065125330f93ed4d03b2b8250 (diff) |
Transform: option to transform origins in object mode
Currently supports mesh, armature, lattice, curve & metaballs.
Access from pivot popover.
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_curve.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_lattice.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve.c | 51 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/displist.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lattice.c | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh.c | 13 | ||||
-rw-r--r-- | source/blender/editors/include/ED_object.h | 7 | ||||
-rw-r--r-- | source/blender/editors/object/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/object/object_data_transform.c | 333 | ||||
-rw-r--r-- | source/blender/editors/object/object_modifier.c | 2 | ||||
-rw-r--r-- | source/blender/editors/transform/transform.h | 17 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_conversions.c | 147 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_generics.c | 9 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_scene_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 8 |
17 files changed, 613 insertions, 7 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 6ef268f9321..b684e4aa2dd 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -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): diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 67efeea02cb..af783a6ae8a 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -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, diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 8395b182171..a3befa6f3bb 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -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, diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index b2ae7a6dac0..7986bf947e5 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -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]); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 1f21d796220..0126c261fa1 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -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); } } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index bc235768bc7..5904fa2d814 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -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 */ diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 0ceca1206f6..e46b7ca5130 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -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; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 9c5ae9b8ca6..38e4527fd17 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -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. */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 7b9a96e4d07..de590d124ea 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -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 diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 2490f88b5eb..aabfa78cf58 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -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 index 00000000000..ee86c79ead5 --- /dev/null +++ b/source/blender/editors/object/object_data_transform.c @@ -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; + } + } +} + +/** \} */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 82af30e32fd..f77d9874c06 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -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); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 4e245588f53..ff7c8c506e6 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -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 diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 2684b6e279d..4fe79dc3202 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -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; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 969e2558abb..9c564bcfa54 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -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); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8fd02ccda6c..bda74f9abe0 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -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 */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 208bcaab007..7d9a3cf06b8 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -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); |