Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2014-10-21 13:59:14 +0400
committerBastien Montagne <montagne29@wanadoo.fr>2014-10-21 14:07:24 +0400
commit00ff9da2eecd7a0edeca60c03e1b5e7ddabf2226 (patch)
tree3952728b5d87666253e795a6aeae4f4789bf47ab /source
parentbe4b2e42c627a7631c9f02866806bd1702554255 (diff)
ShapeKeys: rework 'move skey' code, and add options to move to first/last position.
Main moving logic is moved to new `BKE_keyblock_move()`, which makes it available from anywhere. In addition, move code was reworked so that it only loops once on whole keyblocks list, and it accepts arbitrary org and dest indices, not only neighbor ones. Partly based on work by revzin (Grigory Revzin) in his soc-2014-shapekey GSoC branch, thanks!
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/intern/key.c88
-rw-r--r--source/blender/editors/object/object_shapekey.c122
3 files changed, 136 insertions, 78 deletions
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 6183df8666d..892c42b4588 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -97,6 +97,10 @@ float (*BKE_key_convert_to_vertcos(struct Object *ob, struct KeyBlock *kb))[3];
void BKE_key_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void BKE_key_convert_from_offset(struct Object *ob, struct KeyBlock *kb, float (*ofs)[3]);
+/* other management */
+bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
+
+
/* key.c */
extern int slurph_opt;
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 2dc615c19f9..5cca948cd49 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2055,3 +2055,91 @@ void BKE_key_convert_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
}
}
}
+
+/* ==========================================================*/
+
+/** 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;
+ const int act_index = ob->shapenr - 1;
+ const int totkey = key->totkey;
+ int i;
+ bool rev, in_range = false;
+
+ 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 == org_index) {
+ return false;
+ }
+
+ rev = ((new_index - org_index) < 0) ? true : false;
+
+ /* 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! */
+ for (kb = (rev ? key->block.last : key->block.first), i = (rev ? totkey - 1 : 0);
+ kb;
+ kb = (rev ? kb->prev : kb->next), rev ? i-- : i++)
+ {
+ if (i == org_index) {
+ in_range = true; /* Start list items swapping... */
+ }
+ else if (i == new_index) {
+ in_range = false; /* End list items swapping. */
+ }
+
+ if (in_range) {
+ KeyBlock *other_kb = rev ? kb->prev : kb->next;
+
+ /* Swap with previous/next list item. */
+ BLI_swaplinks(&key->block, kb, other_kb);
+
+ /* Swap absolute positions. */
+ SWAP(float, kb->pos, other_kb->pos);
+
+ kb = other_kb;
+ }
+
+ /* Adjust relative indices, this has to be done on the whole list! */
+ if (kb->relative == org_index) {
+ kb->relative = new_index;
+ }
+ else if (kb->relative < org_index && kb->relative >= new_index) {
+ /* remove after, insert before this index */
+ kb->relative++;
+ }
+ else if (kb->relative > org_index && kb->relative <= new_index) {
+ /* remove before, insert after this index */
+ kb->relative--;
+ }
+ }
+
+ /* 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/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 85104c14395..4a24ab66721 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -301,6 +301,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);
@@ -482,86 +492,40 @@ void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
}
+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)
{
Object *ob = ED_object_context(C);
- Key *key = BKE_key_from_object(ob);
- if (!key) {
- return OPERATOR_CANCELLED;
+ Key *key = BKE_key_from_object(ob);
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int totkey = key->totkey;
+ const int act_index = ob->shapenr - 1;
+ int new_index;
+
+ switch (type) {
+ case KB_MOVE_TOP:
+ /* Replace the ref key only if we're at the top already (only for relative keys) */
+ new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1;
+ break;
+ case KB_MOVE_BOTTOM:
+ new_index = totkey - 1;
+ break;
+ case KB_MOVE_UP:
+ case KB_MOVE_DOWN:
+ default:
+ new_index = (totkey + act_index + type) % totkey;
+ break;
}
- {
- KeyBlock *kb, *kb_other, *kb_iter;
- const int type = RNA_enum_get(op->ptr, "type");
- const int shape_tot = key->totkey;
- const int shapenr_act = ob->shapenr - 1;
- const int shapenr_swap = (shape_tot + shapenr_act + type) % shape_tot;
-
- kb = BLI_findlink(&key->block, shapenr_act);
- if (!kb || shape_tot == 1) {
- return OPERATOR_CANCELLED;
- }
-
- if (type == -1) {
- /* move back */
- kb_other = kb->prev;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkbefore(&key->block, kb_other, kb);
- }
- else {
- /* move next */
- kb_other = kb->next;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkafter(&key->block, kb_other, kb);
- }
-
- ob->shapenr = shapenr_swap + 1;
-
- /* for relative shape keys */
- if (kb_other) {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- if (kb_iter->relative == shapenr_act) {
- kb_iter->relative = shapenr_swap;
- }
- else if (kb_iter->relative == shapenr_swap) {
- kb_iter->relative = shapenr_act;
- }
- }
- }
- /* First key became last, or vice-versa, we have to change all keys' relative value. */
- else {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- if (kb_iter->relative == shapenr_act) {
- kb_iter->relative = shapenr_swap;
- }
- else {
- kb_iter->relative += type;
- }
- }
- }
-
- /* for absolute shape keys */
- if (kb_other) {
- SWAP(float, kb_other->pos, kb->pos);
- }
- /* First key became last, or vice-versa, we have to change all keys' pos value. */
- else {
- float pos = kb->pos;
- if (type == -1) {
- for (kb_iter = key->block.first; kb_iter; kb_iter = kb_iter->next) {
- SWAP(float, kb_iter->pos, pos);
- }
- }
- else {
- for (kb_iter = key->block.last; kb_iter; kb_iter = kb_iter->prev) {
- SWAP(float, kb_iter->pos, pos);
- }
- }
- }
-
- /* First key is refkey, matches interface and BKE_key_sort */
- key->refkey = key->block.first;
+ if (!BKE_keyblock_move(ob, act_index, new_index)) {
+ return OPERATOR_CANCELLED;
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -573,9 +537,11 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
void OBJECT_OT_shape_key_move(wmOperatorType *ot)
{
static EnumPropertyItem slot_move[] = {
- {-1, "UP", 0, "Up", ""},
- {1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
+ {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {KB_MOVE_UP, "UP", 0, "Up", ""},
+ {KB_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
};
/* identifiers */
@@ -584,7 +550,7 @@ void OBJECT_OT_shape_key_move(wmOperatorType *ot)
ot->description = "Move the active shape key up/down in the list";
/* api callbacks */
- ot->poll = shape_key_mode_poll;
+ ot->poll = shape_key_move_poll;
ot->exec = shape_key_move_exec;
/* flags */