[Bf-blender-cvs] [a8aa291] soc-2014-shapekey: Full rewrite of 'move shapekeys' code.
Bastien Montagne
noreply at git.blender.org
Mon Oct 20 17:06:11 CEST 2014
Commit: a8aa291e13c1e7bed523dca19e0e838683453192
Author: Bastien Montagne
Date: Mon Oct 20 17:04:17 2014 +0200
Branches: soc-2014-shapekey
https://developer.blender.org/rBa8aa291e13c1e7bed523dca19e0e838683453192
Full rewrite of 'move shapekeys' code.
Now handles correctly position of absolute skeys in all cases. Also only does one
full loop over whole list.
Ans some more cleanup.
===================================================================
M source/blender/blenkernel/BKE_key.h
M source/blender/blenkernel/intern/key.c
M source/blender/blenlib/BLI_listbase.h
M source/blender/blenlib/intern/listbase.c
M source/blender/editors/object/object_shapekey.c
M source/blender/makesdna/DNA_key_types.h
===================================================================
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 720e49f..5a22ef6 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -129,16 +129,14 @@ void BKE_key_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, flo
void BKE_key_convert_from_offset(struct Object *ob, struct KeyBlock *kb, float (*ofs)[3]);
/* other management */
-/* moves a shape key to new_index. safe, clamps index to key->totkey, updates reference keys and
- * the object's active shape index */
-void BKE_keyblock_move(struct Object *ob, struct KeyBlock *key_block, int new_index);
+bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
/* basic key math */
-float (*BKE_keyblock_math_deltas(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis))[3];
-float (*BKE_keyblock_math_deltas_mult(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis, float mult, float dists[]))[3];
+float (*BKE_keyblock_math_deltas(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis))[3];
+float (*BKE_keyblock_math_deltas_mult(struct Object *ob, struct KeyBlock *a, struct KeyBlock *basis, float mult, float dists[]))[3];
-void BKE_keyblock_math_add(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, struct KeyBlock* basis, float mult);
-void BKE_keyblock_math_interp(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, float mult);
+void BKE_keyblock_math_add(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, struct KeyBlock* basis, float mult);
+void BKE_keyblock_math_interp(struct Object *ob, struct KeyBlock *r, struct KeyBlock *a, float mult);
/* key.c */
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index c10d515..27779e3 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2338,72 +2338,102 @@ void BKE_key_eval_editmesh_rel(BMEditMesh *edbm, bool pinned)
/* ==========================================================*/
-void BKE_keyblock_move(Object *ob, KeyBlock *key_block, int new_index)
+/** Move shape key from org_index to new_index. Safe, clamps index to valid range, updates reference keys,
+ * the object's active shape index, the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
+bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
{
Key *key = BKE_key_from_object(ob);
KeyBlock *kb;
- int delete_index, insert_index;
- int act_shape_index = ob->shapenr - 1;
+ const int act_index = ob->shapenr - 1;
+ const int totkey = key->totkey;
+ int i;
+ bool rev, in_range = false;
- /* find where to put */
- delete_index = BLI_findindex(&key->block, key_block);
- insert_index = new_index - 1;
+ if (org_index < 0) {
+ org_index = act_index;
+ }
CLAMP(new_index, 0, key->totkey - 1);
+ CLAMP(org_index, 0, key->totkey - 1);
- if (new_index == delete_index)
- return;
+ if (new_index == org_index) {
+ return false;
+ }
- BLI_remlink(&key->block, key_block);
+ rev = ((new_index - org_index) < 0) ? true : false;
- if (insert_index >= key->totkey - 1) {
- insert_index = key->totkey - 1;
+ /* We swap 'org' element with its previous/next neighbor (depending on direction of the move) repeatedly,
+ * until we reach final position.
+ * This allows us to only loop on the list once! */
+ if (rev) {
kb = key->block.last;
- BLI_insertlinkafter(&key->block, kb, key_block);
- }
- else if (insert_index < 0) {
- /* special case -- position 0 */
- insert_index = 0;
- kb = key->block.first;
- BLI_insertlinkbefore(&key->block, kb, key_block);
+ i = totkey - 1;
}
else {
- kb = BLI_findlink(&key->block, insert_index);
- BLI_insertlinkafter(&key->block, kb, key_block);
+ kb = key->block.first;
+ i = 0;
}
+ while (kb) {
+ if (i == org_index) {
+ in_range = true; /* Start list items swapping... */
+ }
+ else if (i == new_index) {
+ in_range = false; /* End list items swapping. */
+ }
- /* patch refkey */
- key->refkey = key->block.first;
+ if (in_range) {
+ KeyBlock *other_kb = rev ? kb->prev : kb->next;
- /* fix abs positions */
- SWAP(float, kb->pos, key_block->pos);
+ /* Swap with previous/next list item. */
+ BLI_swaplinks(&key->block, kb, other_kb);
- /* need to update active shape number if it's affected */
- if (act_shape_index == delete_index) {
- ob->shapenr = new_index + 1;
- }
- else if (insert_index <= act_shape_index && delete_index > act_shape_index) {
- /* insert before, remove after */
- ob->shapenr++;
- }
- else if (insert_index >= act_shape_index && delete_index < act_shape_index) {
- /* insert after, remove before */
- ob->shapenr--;
- }
+ /* Swap absolute positions. */
+ SWAP(float, kb->pos, other_kb->pos);
- /* patch basis indeces*/
- LISTBASE_ITER_FWD(key->block, kb) {
- if (kb->relative == delete_index) {
+ kb = other_kb;
+ }
+
+ /* Adjust relative indices, this has to be done on the whole list! */
+ if (kb->relative == org_index) {
kb->relative = new_index;
- continue;
}
- if (new_index <= kb->relative && delete_index > kb->relative) {
- /* insert before, remove after */
+ else if (kb->relative < org_index && kb->relative >= new_index) {
+ /* remove after, insert before this index */
kb->relative++;
}
- else if (new_index >= kb->relative && delete_index < kb->relative) {
- /* insert after, remove before */
+ else if (kb->relative > org_index && kb->relative <= new_index) {
+ /* remove before, insert after this index */
kb->relative--;
}
+
+ if (rev) {
+ kb = kb->prev;
+ i--;
+ }
+ else {
+ kb = kb->next;
+ i++;
+ }
+ }
+
+ /* Need to update active shape number if it's affected, same principle as for relative indices above. */
+ if (org_index == act_index) {
+ ob->shapenr = new_index + 1;
+ }
+ else if (act_index < org_index && act_index >= new_index) {
+ ob->shapenr++;
+ }
+ else if (act_index > org_index && act_index <= new_index) {
+ ob->shapenr--;
}
+
+ /* First key is always refkey, matches interface and BKE_key_sort */
+ key->refkey = key->block.first;
+
+ return true;
}
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 739787d..16022f2 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -73,6 +73,8 @@ void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_countlist(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+void BLI_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb) ATTR_NONNULL(1, 2);
+
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index d9cf897..6d61a04 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -130,6 +130,44 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
}
/**
+ * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
+ */
+void BLI_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
+{
+ Link *linka = vlinka;
+ Link *linkb = vlinkb;
+
+ if (!linka || !linkb)
+ return;
+
+ if (linkb->next == linka) {
+ SWAP(Link *, linka, linkb);
+ }
+
+ if (linka->next == linkb) {
+ linka->next = linkb->next;
+ linkb->prev = linka->prev;
+ linka->prev = linkb;
+ linkb->next = linka;
+ }
+ else { /* Non-contiguous items, we can safely swap. */
+ SWAP(Link *, linka->prev, linkb->prev);
+ SWAP(Link *, linka->next, linkb->next);
+ }
+
+ /* Update neighbors of linka and linkb. */
+ if (linka->prev) linka->prev->next = linka;
+ if (linka->next) linka->next->prev = linka;
+ if (linkb->prev) linkb->prev->next = linkb;
+ if (linkb->next) linkb->next->prev = linkb;
+
+ if (listbase->last == linka) listbase->last = linkb;
+ else if (listbase->last == linkb) listbase->last = linka;
+ if (listbase->first == linka) listbase->first = linkb;
+ else if (listbase->first == linkb) listbase->first = linka;
+}
+
+/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase)
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 072d4f7..07d413c 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -309,6 +309,16 @@ static int shape_key_mode_exists_poll(bContext *C)
(BKE_keyblock_from_object(ob) != NULL);
}
+static int shape_key_move_poll(bContext *C)
+{
+ /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ Key *key = BKE_key_from_object(ob);
+
+ return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+}
+
static int shape_key_poll(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -490,21 +500,11 @@ void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
}
-static int shape_key_move_poll(bContext *C)
-{
- Object *ob = ED_object_context(C);
- ID *data = (ob) ? ob->data : NULL;
- Key *key = BKE_key_from_object(ob);
-
- return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
-}
-
-static EnumPropertyItem slot_move[] = {
- { -2, "TOP", 0, "Top of the list", "" },
- { -1, "UP", 0, "Up", "" },
- { 1, "DOWN", 0, "Down", "" },
- { 2, "BOTTOM", 0, "Bottom of the list", "" },
- { 0, NULL, 0, NULL, NULL }
+enum {
+ KB_MOVE_TOP = -2,
+ KB_MOVE_UP = -1,
+ KB_MOVE_DOWN = 1,
+ KB_MOVE_BOTTOM = 2,
};
static int shape_key_move_exec(bContext *C, wmOperator *op)
@@ -512,26 +512,29 @@ st
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list