Bugfixes:
[blender.git] / source / blender / editors / object / object_shapekey.c
index 2ec3edd846adebb60ca65b473e62ce5aeaefb108..f8eff578839fc6a5d1f50de62451edfddc8f833b 100644 (file)
@@ -37,7 +37,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 
 #include "DNA_action_types.h"
 #include "DNA_curve_types.h"
 #include "BLO_sys_types.h" // for intptr_t support
 
 #include "ED_object.h"
+#include "ED_mesh.h"
 
 #include "RNA_access.h"
+#include "RNA_define.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
 
 #include "object_intern.h"
 
-#if 0 // XXX old animation system
-static void default_key_ipo(Scene *scene, Key *key)
-{
-       IpoCurve *icu;
-       BezTriple *bezt;
-       
-       key->ipo= add_ipo(scene, "KeyIpo", ID_KE);
-       
-       icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
-                       
-       icu->blocktype= ID_KE;
-       icu->adrcode= KEY_SPEED;
-       icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
-       set_icu_vars(icu);
-       
-       BLI_addtail( &(key->ipo->curve), icu);
-       
-       icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
-       icu->totvert= 2;
-       
-       bezt->hide= IPO_BEZ;
-       bezt->f1=bezt->f2= bezt->f3= SELECT;
-       bezt->h1= bezt->h2= HD_AUTO;
-       bezt++;
-       bezt->vec[1][0]= 100.0;
-       bezt->vec[1][1]= 1.0;
-       bezt->hide= IPO_BEZ;
-       bezt->f1=bezt->f2= bezt->f3= SELECT;
-       bezt->h1= bezt->h2= HD_AUTO;
-       
-       calchandles_ipocurve(icu);
-}
-#endif // XXX old animation system
-       
-
 /************************* Mesh ************************/
 
 void mesh_to_key(Mesh *me, KeyBlock *kb)
@@ -152,67 +119,30 @@ void key_to_mesh(KeyBlock *kb, Mesh *me)
        }
 }
 
-static KeyBlock *add_keyblock(Scene *scene, Key *key)
-{
-       KeyBlock *kb;
-       float curpos= -0.1;
-       int tot;
-       
-       kb= key->block.last;
-       if(kb) curpos= kb->pos;
-       
-       kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
-       BLI_addtail(&key->block, kb);
-       kb->type= KEY_CARDINAL;
-       
-       tot= BLI_countlist(&key->block);
-       if(tot==1) strcpy(kb->name, "Basis");
-       else sprintf(kb->name, "Key %d", tot-1);
-       
-               // XXX this is old anim system stuff? (i.e. the 'index' of the shapekey)
-       kb->adrcode= tot-1;
-       
-       key->totkey++;
-       if(key->totkey==1) key->refkey= kb;
-       
-       kb->slidermin= 0.0f;
-       kb->slidermax= 1.0f;
-       
-       // XXX kb->pos is the confusing old horizontal-line RVK crap in old IPO Editor...
-       if(key->type == KEY_RELATIVE) 
-               kb->pos= curpos+0.1;
-       else {
-#if 0 // XXX old animation system
-               curpos= bsystem_time(scene, 0, (float)CFRA, 0.0);
-               if(calc_ipo_spec(key->ipo, KEY_SPEED, &curpos)==0) {
-                       curpos /= 100.0;
-               }
-               kb->pos= curpos;
-               
-               sort_keys(key);
-#endif // XXX old animation system
-       }
-       return kb;
-}
-
-void insert_meshkey(Scene *scene, Mesh *me, short rel)
+static void insert_meshkey(Scene *scene, Object *ob)
 {
-       Key *key;
+       Mesh *me= ob->data;
+       Key *key= me->key;
        KeyBlock *kb;
+       int newkey= 0;
 
-       if(me->key==NULL) {
-               me->key= add_key( (ID *)me);
-
-               if(rel)
-                       me->key->type = KEY_RELATIVE;
-//             else
-//                     default_key_ipo(scene, me->key); // XXX old animation system
+       if(key == NULL) {
+               key= me->key= add_key((ID *)me);
+               key->type= KEY_RELATIVE;
+               newkey= 1;
        }
-       key= me->key;
        
        kb= add_keyblock(scene, key);
        
-       mesh_to_key(me, kb);
+       if(newkey) {
+               /* create from mesh */
+               mesh_to_key(me, kb);
+       }
+       else {
+               /* copy from current values */
+               kb->data= do_ob_key(scene, ob);
+               kb->totelem= me->totvert;
+       }
 }
 
 /************************* Lattice ************************/
@@ -253,24 +183,32 @@ void key_to_latt(KeyBlock *kb, Lattice *lt)
        for(a=0; a<tot; a++, fp+=3, bp++) {
                VECCOPY(bp->vec, fp);
        }
-       
 }
 
-/* exported to python... hrms, should not, use object levels! (ton) */
-void insert_lattkey(Scene *scene, Lattice *lt, short rel)
+static void insert_lattkey(Scene *scene, Object *ob)
 {
-       Key *key;
+       Lattice *lt= ob->data;
+       Key *key= lt->key;
        KeyBlock *kb;
+       int newkey= 0;
        
-       if(lt->key==NULL) {
-               lt->key= add_key( (ID *)lt);
-//             default_key_ipo(scene, lt->key); // XXX old animation system
+       if(key==NULL) {
+               key= lt->key= add_key( (ID *)lt);
+               key->type= KEY_RELATIVE;
+               newkey= 1;
        }
-       key= lt->key;
-       
+
        kb= add_keyblock(scene, key);
        
-       latt_to_key(lt, kb);
+       if(newkey) {
+               /* create from lattice */
+               latt_to_key(lt, kb);
+       }
+       else {
+               /* copy from current values */
+               kb->totelem= lt->pntsu*lt->pntsv*lt->pntsw;
+               kb->data= do_ob_key(scene, ob);
+       }
 }
 
 /************************* Curve ************************/
@@ -377,36 +315,43 @@ void key_to_curve(KeyBlock *kb, Curve  *cu, ListBase *nurb)
 }
 
 
-void insert_curvekey(Scene *scene, Curve *cu, short rel) 
+static void insert_curvekey(Scene *scene, Object *ob)
 {
-       Key *key;
+       Curve *cu= ob->data;
+       Key *key= cu->key;
        KeyBlock *kb;
+       ListBase *lb= (cu->editnurb)? cu->editnurb: &cu->nurb;
+       int newkey= 0;
        
-       if(cu->key==NULL) {
-               cu->key= add_key( (ID *)cu);
-
-               if(rel)
-                       cu->key->type = KEY_RELATIVE;
-//             else
-//                     default_key_ipo(scene, cu->key);        // XXX old animation system
+       if(key==NULL) {
+               key= cu->key= add_key( (ID *)cu);
+               key->type = KEY_RELATIVE;
+               newkey= 1;
        }
-       key= cu->key;
        
        kb= add_keyblock(scene, key);
        
-       if(cu->editnurb->first) curve_to_key(cu, kb, cu->editnurb);
-       else curve_to_key(cu, kb, &cu->nurb);
+       if(newkey) {
+               /* create from curve */
+               curve_to_key(cu, kb, lb);
+       }
+       else {
+               /* copy from current values */
+               kb->totelem= count_curveverts(lb);
+               kb->data= do_ob_key(scene, ob);
+       }
+
 }
 
 /*********************** add shape key ***********************/
 
-void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob)
+static void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob)
 {
        Key *key;
 
-       if(ob->type==OB_MESH) insert_meshkey(scene, ob->data, 1);
-       else if ELEM(ob->type, OB_CURVE, OB_SURF) insert_curvekey(scene, ob->data, 1);
-       else if(ob->type==OB_LATTICE) insert_lattkey(scene, ob->data, 1);
+       if(ob->type==OB_MESH) insert_meshkey(scene, ob);
+       else if ELEM(ob->type, OB_CURVE, OB_SURF) insert_curvekey(scene, ob);
+       else if(ob->type==OB_LATTICE) insert_lattkey(scene, ob);
 
        key= ob_get_key(ob);
        ob->shapenr= BLI_countlist(&key->block);
@@ -416,7 +361,7 @@ void ED_object_shape_key_add(bContext *C, Scene *scene, Object *ob)
 
 /*********************** remove shape key ***********************/
 
-int ED_object_shape_key_remove(bContext *C, Scene *scene, Object *ob)
+static int ED_object_shape_key_remove(bContext *C, Object *ob)
 {
        Main *bmain= CTX_data_main(C);
        KeyBlock *kb, *rkb;
@@ -479,8 +424,76 @@ int ED_object_shape_key_remove(bContext *C, Scene *scene, Object *ob)
        return 1;
 }
 
+static int ED_object_shape_key_mirror(bContext *C, Scene *scene, Object *ob)
+{
+       KeyBlock *kb;
+       Key *key;
+
+       key= ob_get_key(ob);
+       if(key==NULL)
+               return 0;
+       
+       kb= BLI_findlink(&key->block, ob->shapenr-1);
+
+       if(kb) {
+               int i1, i2;
+               float *fp1, *fp2;
+               float tvec[3];
+               char *tag_elem= MEM_callocN(sizeof(char) * kb->totelem, "shape_key_mirror");
+
+
+               if(ob->type==OB_MESH) {
+                       Mesh *me= ob->data;
+                       MVert *mv;
+
+                       mesh_octree_table(ob, NULL, NULL, 's');
+
+                       for(i1=0, mv=me->mvert; i1<me->totvert; i1++, mv++) {
+                               i2= mesh_get_x_mirror_vert(ob, i1);
+                               if(i2==i1) {
+                                       fp1= ((float *)kb->data) + i1*3;
+                                       fp1[0] = -fp1[0];
+                                       tag_elem[i1]= 1;
+                               }
+                               else if(i2 != -1) {
+                                       if(tag_elem[i1]==0 && tag_elem[i2]==0) {
+                                               fp1= ((float *)kb->data) + i1*3;
+                                               fp2= ((float *)kb->data) + i2*3;
+
+                                               VECCOPY(tvec,   fp1);
+                                               VECCOPY(fp1,    fp2);
+                                               VECCOPY(fp2,    tvec);
+
+                                               /* flip x axis */
+                                               fp1[0] = -fp1[0];
+                                               fp2[0] = -fp2[0];
+                                       }
+                                       tag_elem[i1]= tag_elem[i2]= 1;
+                               }
+                       }
+
+                       mesh_octree_table(ob, NULL, NULL, 'e');
+               }
+               /* todo, other types? */
+
+               MEM_freeN(tag_elem);
+       }
+       
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+       return 1;
+}
+
 /********************** shape key operators *********************/
 
+static int shape_key_mode_poll(bContext *C)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       ID *data= (ob)? ob->data: NULL;
+       return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT);
+}
+
 static int shape_key_poll(bContext *C)
 {
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
@@ -502,10 +515,11 @@ void OBJECT_OT_shape_key_add(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Add Shape Key";
+       ot->name= "Add shape key to the object.";
        ot->idname= "OBJECT_OT_shape_key_add";
        
        /* api callbacks */
-       ot->poll= shape_key_poll;
+       ot->poll= shape_key_mode_poll;
        ot->exec= shape_key_add_exec;
 
        /* flags */
@@ -514,10 +528,9 @@ void OBJECT_OT_shape_key_add(wmOperatorType *ot)
 
 static int shape_key_remove_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
 
-       if(!ED_object_shape_key_remove(C, scene, ob))
+       if(!ED_object_shape_key_remove(C, ob))
                return OPERATOR_CANCELLED;
        
        return OPERATOR_FINISHED;
@@ -527,13 +540,132 @@ void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Remove Shape Key";
+       ot->name= "Remove shape key from the object.";
        ot->idname= "OBJECT_OT_shape_key_remove";
        
        /* api callbacks */
-       ot->poll= shape_key_poll;
+       ot->poll= shape_key_mode_poll;
        ot->exec= shape_key_remove_exec;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+static int shape_key_clear_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+       Key *key= ob_get_key(ob);
+       KeyBlock *kb= ob_get_keyblock(ob);
+
+       if(!key || !kb)
+               return OPERATOR_CANCELLED;
+       
+       for(kb=key->block.first; kb; kb=kb->next)
+               kb->curval= 0.0f;
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+       
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_shape_key_clear(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Clear Shape Keys";
+       ot->description= "Clear weights for all shape keys.";
+       ot->idname= "OBJECT_OT_shape_key_clear";
+       
+       /* api callbacks */
+       ot->poll= shape_key_poll;
+       ot->exec= shape_key_clear_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int shape_key_mirror_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+
+       if(!ED_object_shape_key_mirror(C, scene, ob))
+               return OPERATOR_CANCELLED;
+
+       return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Mirror Shape Key";
+       ot->idname= "OBJECT_OT_shape_key_mirror";
+
+       /* api callbacks */
+       ot->poll= shape_key_mode_poll;
+       ot->exec= shape_key_mirror_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int shape_key_move_exec(bContext *C, wmOperator *op)
+{
+       Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
+
+       int type= RNA_enum_get(op->ptr, "type");
+       Key *key= ob_get_key(ob);
+
+       if(key) {
+               KeyBlock *kb, *kb_other;
+               kb= BLI_findlink(&key->block, ob->shapenr-1);
+
+               if(type==-1) {
+                       /* move back */
+                       if(kb->prev) {
+                               kb_other= kb->prev;
+                               BLI_remlink(&key->block, kb);
+                               BLI_insertlinkbefore(&key->block, kb_other, kb);
+                               ob->shapenr--;
+                       }
+               }
+               else {
+                       /* move next */
+                       if(kb->next) {
+                               kb_other= kb->next;
+                               BLI_remlink(&key->block, kb);
+                               BLI_insertlinkafter(&key->block, kb_other, kb);
+                               ob->shapenr++;
+                       }
+               }
+       }
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
+
+       return OPERATOR_FINISHED;
+}
+
+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}
+       };
+
+       /* identifiers */
+       ot->name= "Move Shape Key";
+       ot->idname= "OBJECT_OT_shape_key_move";
+
+       /* api callbacks */
+       ot->poll= shape_key_mode_poll;
+       ot->exec= shape_key_move_exec;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
+