[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