diff options
author | Campbell Barton <ideasman42@gmail.com> | 2020-07-25 09:35:52 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2020-07-25 10:19:13 +0300 |
commit | 2308668bac049dbf0e7056f9849e67f52ddb3f9d (patch) | |
tree | 93d5920dfe56df784cf17998c10f083c21be8e93 | |
parent | d7c4e9649320fdca19d1fa3474a393749d2d7fee (diff) |
Fix T72622: Transform object origin ignores shape keys
D8367 by @paul2t with edits.
-rw-r--r-- | source/blender/blenkernel/BKE_key.h | 32 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/key.c | 159 | ||||
-rw-r--r-- | source/blender/editors/include/ED_object.h | 2 | ||||
-rw-r--r-- | source/blender/editors/object/object_data_transform.c | 179 |
4 files changed, 369 insertions, 3 deletions
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 6581891062c..b0eef02611b 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -51,6 +51,12 @@ void key_curve_normal_weights(float t, float data[4], int type); float *BKE_key_evaluate_object_ex(struct Object *ob, int *r_totelem, float *arr, size_t arr_size); float *BKE_key_evaluate_object(struct Object *ob, int *r_totelem); +int BKE_keyblock_element_count_from_shape(const struct Key *key, const int shape_index); +int BKE_keyblock_element_count(const struct Key *key); + +size_t BKE_keyblock_element_calc_size_from_shape(const struct Key *key, const int shape_index); +size_t BKE_keyblock_element_calc_size(const struct Key *key); + bool BKE_key_idtype_support(const short id_type); struct Key **BKE_key_from_id_p(struct ID *id); @@ -74,6 +80,10 @@ void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb); void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt); int BKE_keyblock_curve_element_count(struct ListBase *nurb); +void BKE_keyblock_curve_data_transform(const struct ListBase *nurb, + const float mat[4][4], + const void *src, + void *dst); void BKE_keyblock_update_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb); void BKE_keyblock_convert_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb); void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb); @@ -104,6 +114,28 @@ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index); bool BKE_keyblock_is_basis(struct Key *key, const int index); +/* -------------------------------------------------------------------- */ +/** \name Key-Block Data Access + * \{ */ + +void BKE_keyblock_data_get_from_shape(const struct Key *key, + float (*arr)[3], + const int shape_index); +void BKE_keyblock_data_get(const struct Key *key, float (*arr)[3]); + +void BKE_keyblock_data_set_with_mat4(struct Key *key, + const int shape_index, + const float (*vertices)[3], + const float mat[4][4]); +void BKE_keyblock_curve_data_set_with_mat4(struct Key *key, + const struct ListBase *nurb, + const int shape_index, + const void *data, + const float mat[4][4]); +void BKE_keyblock_data_set(struct Key *key, const int shape_index, const void *data); + +/** \} */ + #ifdef __cplusplus }; #endif diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 46a41df0391..a71b9cc2a1d 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1547,6 +1547,134 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem) return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0); } +/** + * \param shape_index: The index to use or all (when -1). + */ +int BKE_keyblock_element_count_from_shape(const Key *key, const int shape_index) +{ + int result = 0; + int index = 0; + for (const KeyBlock *kb = key->block.first; kb; kb = kb->next, index++) { + if ((shape_index == -1) || (index == shape_index)) { + result += kb->totelem; + } + } + return result; +} + +int BKE_keyblock_element_count(const Key *key) +{ + return BKE_keyblock_element_count_from_shape(key, -1); +} + +/** + * \param shape_index: The index to use or all (when -1). + */ +size_t BKE_keyblock_element_calc_size_from_shape(const Key *key, const int shape_index) +{ + return (size_t)BKE_keyblock_element_count_from_shape(key, shape_index) * key->elemsize; +} + +size_t BKE_keyblock_element_calc_size(const Key *key) +{ + return BKE_keyblock_element_calc_size_from_shape(key, -1); +} + +/* -------------------------------------------------------------------- */ +/** \name Key-Block Data Access + * + * Utilities for getting/setting key data as a single array, + * use #BKE_keyblock_element_calc_size to allocate the size of the data needed. + * \{ */ + +/** + * \param shape_index: The index to use or all (when -1). + */ +void BKE_keyblock_data_get_from_shape(const Key *key, float (*arr)[3], const int shape_index) +{ + uint8_t *elements = (uint8_t *)arr; + int index = 0; + for (const KeyBlock *kb = key->block.first; kb; kb = kb->next, index++) { + if ((shape_index == -1) || (index == shape_index)) { + const int block_elem_len = kb->totelem * key->elemsize; + memcpy(elements, kb->data, block_elem_len); + elements += block_elem_len; + } + } +} + +void BKE_keyblock_data_get(const Key *key, float (*arr)[3]) +{ + BKE_keyblock_data_get_from_shape(key, arr, -1); +} + +/** + * Set the data to all key-blocks (or shape_index if != -1). + */ +void BKE_keyblock_data_set_with_mat4(Key *key, + const int shape_index, + const float (*coords)[3], + const float mat[4][4]) +{ + if (key->elemsize != sizeof(float[3])) { + BLI_assert(!"Invalid elemsize"); + return; + } + + const float(*elements)[3] = coords; + + int index = 0; + for (KeyBlock *kb = key->block.first; kb; kb = kb->next, index++) { + if ((shape_index == -1) || (index == shape_index)) { + const int block_elem_len = kb->totelem; + float(*block_data)[3] = (float(*)[3])kb->data; + for (int data_offset = 0; data_offset < block_elem_len; ++data_offset) { + const float *src_data = (const float *)(elements + data_offset); + float *dst_data = (float *)(block_data + data_offset); + mul_v3_m4v3(dst_data, mat, src_data); + } + elements += block_elem_len; + } + } +} + +/** + * Set the data for all key-blocks (or shape_index if != -1), + * transforming by \a mat. + */ +void BKE_keyblock_curve_data_set_with_mat4( + Key *key, const ListBase *nurb, const int shape_index, const void *data, const float mat[4][4]) +{ + const uint8_t *elements = data; + + int index = 0; + for (KeyBlock *kb = key->block.first; kb; kb = kb->next, index++) { + if ((shape_index == -1) || (index == shape_index)) { + const int block_elem_size = kb->totelem * key->elemsize; + BKE_keyblock_curve_data_transform(nurb, mat, elements, kb->data); + elements += block_elem_size; + } + } +} + +/** + * Set the data for all key-blocks (or shape_index if != -1). + */ +void BKE_keyblock_data_set(Key *key, const int shape_index, const void *data) +{ + const uint8_t *elements = data; + int index = 0; + for (KeyBlock *kb = key->block.first; kb; kb = kb->next, index++) { + if ((shape_index == -1) || (index == shape_index)) { + const int block_elem_size = kb->totelem * key->elemsize; + memcpy(kb->data, elements, block_elem_size); + elements += block_elem_size; + } + } +} + +/** \} */ + bool BKE_key_idtype_support(const short id_type) { switch (id_type) { @@ -1903,6 +2031,37 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n } } +void BKE_keyblock_curve_data_transform(const ListBase *nurb, + const float mat[4][4], + const void *src_data, + void *dst_data) +{ + const float *src = src_data; + float *dst = dst_data; + for (Nurb *nu = nurb->first; nu; nu = nu->next) { + if (nu->bezt) { + for (int a = nu->pntsu; a; a--) { + for (int i = 0; i < 3; i++) { + mul_v3_m4v3(&dst[i * 3], mat, &src[i * 3]); + } + dst[9] = src[9]; + dst[10] = src[10]; + src += KEYELEM_FLOAT_LEN_BEZTRIPLE; + dst += KEYELEM_FLOAT_LEN_BEZTRIPLE; + } + } + else { + for (int a = nu->pntsu * nu->pntsv; a; a--) { + mul_v3_m4v3(dst, mat, src); + dst[3] = src[3]; + dst[4] = src[4]; + src += KEYELEM_FLOAT_LEN_BPOINT; + dst += KEYELEM_FLOAT_LEN_BPOINT; + } + } + } +} + void BKE_keyblock_convert_from_curve(Curve *cu, KeyBlock *kb, ListBase *nurb) { int tot; diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index d8f55a0f60a..e08be5937fe 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -492,7 +492,7 @@ struct XFormObjectData *ED_object_data_xform_create_ex(struct ID *id, bool is_ed struct XFormObjectData *ED_object_data_xform_create(struct ID *id); struct XFormObjectData *ED_object_data_xform_create_from_edit_mode(ID *id); -void ED_object_data_xform_destroy(struct XFormObjectData *xod); +void ED_object_data_xform_destroy(struct XFormObjectData *xod_base); void ED_object_data_xform_by_mat4(struct XFormObjectData *xod, const float mat[4][4]); diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c index 1e030a50f38..8ea35c7a92c 100644 --- a/source/blender/editors/object/object_data_transform.c +++ b/source/blender/editors/object/object_data_transform.c @@ -48,6 +48,7 @@ #include "BKE_curve.h" #include "BKE_editmesh.h" #include "BKE_gpencil_geom.h" +#include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_mball.h" #include "BKE_mesh.h" @@ -282,16 +283,22 @@ struct XFormObjectData { struct XFormObjectData_Mesh { struct XFormObjectData base; + /* Optional data for shape keys. */ + void *key_data; float elem_array[0][3]; }; struct XFormObjectData_Lattice { struct XFormObjectData base; + /* Optional data for shape keys. */ + void *key_data; float elem_array[0][3]; }; struct XFormObjectData_Curve { struct XFormObjectData base; + /* Optional data for shape keys. */ + void *key_data; float elem_array[0][3]; }; @@ -316,48 +323,98 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode if (id == NULL) { return xod_base; } + switch (GS(id->name)) { case ID_ME: { Mesh *me = (Mesh *)id; + struct Key *key = me->key; + const int key_index = -1; + if (is_edit_mode) { BMesh *bm = me->edit_mesh->bm; + /* Always operate on all keys for the moment. */ + // key_index = bm->shapenr - 1; const int elem_array_len = bm->totvert; struct XFormObjectData_Mesh *xod = MEM_mallocN( sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__); + memset(xod, 0x0, sizeof(*xod)); + BM_mesh_vert_coords_get(bm, xod->elem_array); xod_base = &xod->base; + + if (key != NULL) { + const size_t key_size = BKE_keyblock_element_calc_size_from_shape(key, key_index); + if (key_size) { + xod->key_data = MEM_mallocN(key_size, __func__); + BKE_keyblock_data_get_from_shape(key, xod->key_data, key_index); + } + } } else { const int elem_array_len = me->totvert; struct XFormObjectData_Mesh *xod = MEM_mallocN( sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__); + memset(xod, 0x0, sizeof(*xod)); + BKE_mesh_vert_coords_get(me, xod->elem_array); xod_base = &xod->base; + + if (key != NULL) { + const size_t key_size = BKE_keyblock_element_calc_size_from_shape(key, key_index); + if (key_size) { + xod->key_data = MEM_mallocN(key_size, __func__); + BKE_keyblock_data_get_from_shape(key, xod->key_data, key_index); + } + } } break; } case ID_LT: { Lattice *lt_orig = (Lattice *)id; Lattice *lt = is_edit_mode ? lt_orig->editlatt->latt : lt_orig; + struct Key *key = lt->key; + const int key_index = -1; + + if (is_edit_mode) { + /* Always operate on all keys for the moment. */ + // key_index = lt_orig->editlatt->shapenr - 1; + } + 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__); + memset(xod, 0x0, sizeof(*xod)); + BKE_lattice_vert_coords_get(lt, xod->elem_array); xod_base = &xod->base; + + if (key != NULL) { + const size_t key_size = BKE_keyblock_element_calc_size_from_shape(key, key_index); + if (key_size) { + xod->key_data = MEM_mallocN(key_size, __func__); + BKE_keyblock_data_get_from_shape(key, xod->key_data, key_index); + } + } + break; } case ID_CU: { Curve *cu = (Curve *)id; + struct Key *key = cu->key; + const short ob_type = BKE_curve_type_get(cu); if (ob_type == OB_FONT) { /* We could support translation. */ break; } + const int key_index = -1; ListBase *nurbs; if (is_edit_mode) { EditNurb *editnurb = cu->editnurb; nurbs = &editnurb->nurbs; + /* Always operate on all keys for the moment. */ + // key_index = editnurb->shapenr - 1; } else { nurbs = &cu->nurb; @@ -366,8 +423,19 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode const int elem_array_len = BKE_nurbList_verts_count(nurbs); struct XFormObjectData_Curve *xod = MEM_mallocN( sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__); + memset(xod, 0x0, sizeof(*xod)); + BKE_curve_nurbs_vert_coords_get(nurbs, xod->elem_array, elem_array_len); xod_base = &xod->base; + + if (key != NULL) { + const size_t key_size = BKE_keyblock_element_calc_size_from_shape(key, key_index); + if (key_size) { + xod->key_data = MEM_mallocN(key_size, __func__); + BKE_keyblock_data_get_from_shape(key, xod->key_data, key_index); + } + } + break; } case ID_AR: { @@ -376,6 +444,8 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode const int elem_array_len = BLI_listbase_count(arm->edbo); struct XFormObjectData_Armature *xod = MEM_mallocN( sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__); + memset(xod, 0x0, sizeof(*xod)); + edit_armature_coords_and_quats_get(arm, xod->elem_array); xod_base = &xod->base; } @@ -383,6 +453,8 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode 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__); + memset(xod, 0x0, sizeof(*xod)); + armature_coords_and_quats_get(arm, xod->elem_array); xod_base = &xod->base; } @@ -394,6 +466,8 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode 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__); + memset(xod, 0x0, sizeof(*xod)); + metaball_coords_and_quats_get(mb, xod->elem_array); xod_base = &xod->base; break; @@ -403,6 +477,8 @@ struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode const int elem_array_len = BKE_gpencil_stroke_point_count(gpd); struct XFormObjectData_GPencil *xod = MEM_mallocN( sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__); + memset(xod, 0x0, sizeof(*xod)); + BKE_gpencil_point_coords_get(gpd, xod->elem_array); xod_base = &xod->base; break; @@ -428,9 +504,35 @@ struct XFormObjectData *ED_object_data_xform_create_from_edit_mode(ID *id) return ED_object_data_xform_create_ex(id, true); } -void ED_object_data_xform_destroy(struct XFormObjectData *xod) +void ED_object_data_xform_destroy(struct XFormObjectData *xod_base) { - MEM_freeN(xod); + switch (GS(xod_base->id->name)) { + case ID_ME: { + struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base; + if (xod->key_data != NULL) { + MEM_freeN(xod->key_data); + } + break; + } + case ID_LT: { + struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base; + if (xod->key_data != NULL) { + MEM_freeN(xod->key_data); + } + break; + } + case ID_CU: { + struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base; + if (xod->key_data != NULL) { + MEM_freeN(xod->key_data); + } + break; + } + default: { + break; + } + } + MEM_freeN(xod_base); } void ED_object_data_xform_by_mat4(struct XFormObjectData *xod_base, const float mat[4][4]) @@ -438,34 +540,72 @@ void ED_object_data_xform_by_mat4(struct XFormObjectData *xod_base, const float switch (GS(xod_base->id->name)) { case ID_ME: { Mesh *me = (Mesh *)xod_base->id; + + struct Key *key = me->key; + const int key_index = -1; + struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base; if (xod_base->is_edit_mode) { BMesh *bm = me->edit_mesh->bm; BM_mesh_vert_coords_apply_with_mat4(bm, xod->elem_array, mat); + /* Always operate on all keys for the moment. */ + // key_index = bm->shapenr - 1; } else { BKE_mesh_vert_coords_apply_with_mat4(me, xod->elem_array, mat); } + + if (key != NULL) { + BKE_keyblock_data_set_with_mat4(key, key_index, xod->key_data, mat); + } + break; } case ID_LT: { Lattice *lt_orig = (Lattice *)xod_base->id; Lattice *lt = xod_base->is_edit_mode ? lt_orig->editlatt->latt : lt_orig; + + struct Key *key = lt->key; + const int key_index = -1; + struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base; BKE_lattice_vert_coords_apply_with_mat4(lt, xod->elem_array, mat); + if (xod_base->is_edit_mode) { + /* Always operate on all keys for the moment. */ + // key_index = lt_orig->editlatt->shapenr - 1; + } + + if ((key != NULL) && (xod->key_data != NULL)) { + BKE_keyblock_data_set_with_mat4(key, key_index, xod->key_data, mat); + } + break; } case ID_CU: { BLI_assert(xod_base->is_edit_mode == false); /* Not used currently. */ Curve *cu = (Curve *)xod_base->id; + + struct Key *key = cu->key; + const int key_index = -1; + ListBase *nurb = NULL; + struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base; if (xod_base->is_edit_mode) { EditNurb *editnurb = cu->editnurb; + nurb = &editnurb->nurbs; BKE_curve_nurbs_vert_coords_apply_with_mat4(&editnurb->nurbs, xod->elem_array, mat, true); + /* Always operate on all keys for the moment. */ + // key_index = editnurb->shapenr - 1; } else { + nurb = &cu->nurb; BKE_curve_nurbs_vert_coords_apply_with_mat4(&cu->nurb, xod->elem_array, mat, true); } + + if ((key != NULL) && (xod->key_data != NULL)) { + BKE_keyblock_curve_data_set_with_mat4(key, nurb, key_index, xod->key_data, mat); + } + break; } case ID_AR: { @@ -504,33 +644,68 @@ void ED_object_data_xform_restore(struct XFormObjectData *xod_base) switch (GS(xod_base->id->name)) { case ID_ME: { Mesh *me = (Mesh *)xod_base->id; + + struct Key *key = me->key; + const int key_index = -1; + struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base; if (xod_base->is_edit_mode) { BMesh *bm = me->edit_mesh->bm; BM_mesh_vert_coords_apply(bm, xod->elem_array); + /* Always operate on all keys for the moment. */ + // key_index = bm->shapenr - 1; } else { BKE_mesh_vert_coords_apply(me, xod->elem_array); } + + if ((key != NULL) && (xod->key_data != NULL)) { + BKE_keyblock_data_set(key, key_index, xod->key_data); + } + break; } case ID_LT: { Lattice *lt_orig = (Lattice *)xod_base->id; Lattice *lt = xod_base->is_edit_mode ? lt_orig->editlatt->latt : lt_orig; + + struct Key *key = lt->key; + const int key_index = -1; + struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base; BKE_lattice_vert_coords_apply(lt, xod->elem_array); + if (xod_base->is_edit_mode) { + /* Always operate on all keys for the moment. */ + // key_index = lt_orig->editlatt->shapenr - 1; + } + + if ((key != NULL) && (xod->key_data != NULL)) { + BKE_keyblock_data_set(key, key_index, xod->key_data); + } + break; } case ID_CU: { Curve *cu = (Curve *)xod_base->id; + + struct Key *key = cu->key; + const int key_index = -1; + struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base; if (xod_base->is_edit_mode) { EditNurb *editnurb = cu->editnurb; BKE_curve_nurbs_vert_coords_apply(&editnurb->nurbs, xod->elem_array, true); + /* Always operate on all keys for the moment. */ + // key_index = editnurb->shapenr - 1; } else { BKE_curve_nurbs_vert_coords_apply(&cu->nurb, xod->elem_array, true); } + + if ((key != NULL) && (xod->key_data != NULL)) { + BKE_keyblock_data_set(key, key_index, xod->key_data); + } + break; } case ID_AR: { |