Blender V2.61 - r43446

keyframes_edit.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation
00019  *
00020  * Contributor(s): Joshua Leung
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <math.h>
00033 #include <float.h>
00034 
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "BLI_blenlib.h"
00038 #include "BLI_math.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "DNA_anim_types.h"
00042 #include "DNA_armature_types.h"
00043 #include "DNA_camera_types.h"
00044 #include "DNA_key_types.h"
00045 #include "DNA_lamp_types.h"
00046 #include "DNA_lattice_types.h"
00047 #include "DNA_mesh_types.h"
00048 #include "DNA_material_types.h"
00049 #include "DNA_object_types.h"
00050 #include "DNA_meta_types.h"
00051 #include "DNA_node_types.h"
00052 #include "DNA_particle_types.h"
00053 #include "DNA_scene_types.h"
00054 #include "DNA_space_types.h"
00055 #include "DNA_world_types.h"
00056 
00057 #include "BKE_fcurve.h"
00058 #include "BKE_key.h"
00059 #include "BKE_material.h"
00060 
00061 
00062 #include "ED_anim_api.h"
00063 #include "ED_keyframes_edit.h"
00064 #include "ED_markers.h"
00065 
00066 /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data.
00067  *
00068  * Two API functions are defined for actually performing the operations on the data:
00069  *          ANIM_fcurve_keyframes_loop()
00070  * which take the data they operate on, a few callbacks defining what operations to perform.
00071  *
00072  * As operators which work on keyframes usually apply the same operation on all BezTriples in 
00073  * every channel, the code has been optimised providing a set of functions which will get the 
00074  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
00075  * to be called before getting any channels.
00076  * 
00077  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
00078  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which 
00079  * don't check existing selection status).
00080  * 
00081  * - Joshua Leung, Dec 2008
00082  */
00083 
00084 /* ************************************************************************** */
00085 /* Keyframe Editing Loops - Exposed API */
00086 
00087 /* --------------------------- Base Functions ------------------------------------ */
00088 
00089 /* This function is used to loop over BezTriples in the given F-Curve, applying a given 
00090  * operation on them, and optionally applies an F-Curve validation function afterwards.
00091  */
00092 // TODO: make this function work on samples too...
00093 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) 
00094 {
00095     BezTriple *bezt;
00096     short ok = 0;
00097     unsigned int i;
00098 
00099     /* sanity check */
00100     if (ELEM(NULL, fcu, fcu->bezt))
00101         return 0;
00102 
00103     /* set the F-Curve into the editdata so that it can be accessed */
00104     if (ked) {
00105         ked->fcu= fcu;
00106         ked->curIndex= 0;
00107         ked->curflags= ok;
00108     }
00109 
00110     /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
00111     if (key_cb) {
00112         /* if there's a validation func, include that check in the loop 
00113          * (this is should be more efficient than checking for it in every loop)
00114          */
00115         if (key_ok) {
00116             for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
00117                 if (ked) {
00118                     /* advance the index, and reset the ok flags (to not influence the result) */
00119                     ked->curIndex= i;
00120                     ked->curflags= 0;
00121                 }
00122                 
00123                 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
00124                 if ( (ok = key_ok(ked, bezt)) ) {
00125                     if (ked) ked->curflags= ok;
00126                     
00127                     /* Exit with return-code '1' if function returns positive
00128                      * This is useful if finding if some BezTriple satisfies a condition.
00129                      */
00130                     if (key_cb(ked, bezt)) return 1;
00131                 }
00132             }
00133         }
00134         else {
00135             for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
00136                 if (ked) ked->curIndex= i;
00137                 
00138                 /* Exit with return-code '1' if function returns positive
00139                 * This is useful if finding if some BezTriple satisfies a condition.
00140                 */
00141                 if (key_cb(ked, bezt)) return 1;
00142             }
00143         }
00144     }
00145     
00146     /* unset the F-Curve from the editdata now that it's done */
00147     if (ked) {
00148         ked->fcu= NULL;
00149         ked->curIndex= 0;
00150         ked->curflags= 0;
00151     }
00152 
00153     /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
00154     if (fcu_cb)
00155         fcu_cb(fcu);
00156     
00157     /* done */  
00158     return 0;
00159 }
00160 
00161 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
00162 
00163 /* This function is used to loop over the keyframe data in an Action Group */
00164 static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00165 {
00166     FCurve *fcu;
00167     
00168     /* sanity check */
00169     if (agrp == NULL)
00170         return 0;
00171     
00172     /* only iterate over the F-Curves that are in this group */
00173     for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
00174         if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
00175             return 1;
00176     }
00177     
00178     return 0;
00179 }
00180 
00181 /* This function is used to loop over the keyframe data in an Action */
00182 static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00183 {
00184     FCurve *fcu;
00185     
00186     /* sanity check */
00187     if (act == NULL)
00188         return 0;
00189     
00190     /* just loop through all F-Curves */
00191     for (fcu= act->curves.first; fcu; fcu= fcu->next) {
00192         if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
00193             return 1;
00194     }
00195     
00196     return 0;
00197 }
00198 
00199 /* This function is used to loop over the keyframe data in an Object */
00200 static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00201 {
00202     bAnimContext ac = {NULL};
00203     ListBase anim_data = {NULL, NULL};
00204     bAnimListElem *ale;
00205     int filter;
00206     int ret=0;
00207     
00208     bAnimListElem dummychan = {NULL};
00209     Base dummybase = {NULL};
00210     
00211     if (ob == NULL)
00212         return 0;
00213     
00214     /* create a dummy wrapper data to work with */
00215     dummybase.object = ob;
00216     
00217     dummychan.type = ANIMTYPE_OBJECT;
00218     dummychan.data = &dummybase;
00219     dummychan.id = &ob->id;
00220     dummychan.adt = ob->adt;
00221     
00222     ac.ads = ads;
00223     ac.data = &dummychan;
00224     ac.datatype = ANIMCONT_CHANNEL;
00225     
00226     /* get F-Curves to take keyframes from */
00227     filter= ANIMFILTER_DATA_VISIBLE; // curves only
00228     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00229     
00230     /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
00231     for (ale= anim_data.first; ale; ale= ale->next) {
00232         if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
00233             ret = 1;
00234             break;
00235         }
00236     }
00237     
00238     BLI_freelistN(&anim_data);
00239     
00240     /* return return code - defaults to zero if nothing happened */
00241     return ret;
00242 }
00243 
00244 /* This function is used to loop over the keyframe data in a Scene */
00245 static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00246 {
00247     bAnimContext ac = {NULL};
00248     ListBase anim_data = {NULL, NULL};
00249     bAnimListElem *ale;
00250     int filter;
00251     int ret=0;
00252     
00253     bAnimListElem dummychan = {NULL};
00254     
00255     if (sce == NULL)
00256         return 0;
00257     
00258     /* create a dummy wrapper data to work with */
00259     dummychan.type = ANIMTYPE_SCENE;
00260     dummychan.data = sce;
00261     dummychan.id = &sce->id;
00262     dummychan.adt = sce->adt;
00263     
00264     ac.ads = ads;
00265     ac.data = &dummychan;
00266     ac.datatype = ANIMCONT_CHANNEL;
00267     
00268     /* get F-Curves to take keyframes from */
00269     filter= ANIMFILTER_DATA_VISIBLE; // curves only
00270     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00271     
00272     /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
00273     for (ale= anim_data.first; ale; ale= ale->next) {
00274         if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
00275             ret = 1;
00276             break;
00277         }
00278     }
00279     
00280     BLI_freelistN(&anim_data);
00281     
00282     /* return return code - defaults to zero if nothing happened */
00283     return ret;
00284 }
00285 
00286 /* This function is used to loop over the keyframe data in a DopeSheet summary */
00287 static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00288 {
00289     ListBase anim_data = {NULL, NULL};
00290     bAnimListElem *ale;
00291     int filter, ret_code=0;
00292     
00293     /* sanity check */
00294     if (ac == NULL)
00295         return 0;
00296     
00297     /* get F-Curves to take keyframes from */
00298     filter= ANIMFILTER_DATA_VISIBLE;
00299     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00300     
00301     /* loop through each F-Curve, working on the keyframes until the first curve aborts */
00302     for (ale= anim_data.first; ale; ale= ale->next) {
00303         ret_code= ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
00304         
00305         if (ret_code)
00306             break;
00307     }
00308     
00309     BLI_freelistN(&anim_data);
00310     
00311     return ret_code;
00312 }
00313 
00314 /* --- */
00315 
00316 /* This function is used to apply operation to all keyframes, regardless of the type */
00317 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00318 {
00319     /* sanity checks */
00320     if (ale == NULL)
00321         return 0;
00322     
00323     /* method to use depends on the type of keyframe data */
00324     switch (ale->datatype) {
00325         /* direct keyframe data (these loops are exposed) */
00326         case ALE_FCURVE: /* F-Curve */
00327             return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
00328         
00329         /* indirect 'summaries' (these are not exposed directly) 
00330          * NOTE: must keep this code in sync with the drawing code and also the filtering code!
00331          */
00332         case ALE_GROUP: /* action group */
00333             return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
00334         case ALE_ACT: /* action */
00335             return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
00336             
00337         case ALE_OB: /* object */
00338             return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
00339         case ALE_SCE: /* scene */
00340             return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
00341         case ALE_ALL: /* 'all' (DopeSheet summary) */
00342             return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
00343     }
00344     
00345     return 0;
00346 }
00347 
00348 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
00349 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
00350 {
00351     /* sanity checks */
00352     if (data == NULL)
00353         return 0;
00354     
00355     /* method to use depends on the type of keyframe data */
00356     switch (keytype) {
00357         /* direct keyframe data (these loops are exposed) */
00358         case ALE_FCURVE: /* F-Curve */
00359             return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb);
00360         
00361         /* indirect 'summaries' (these are not exposed directly) 
00362          * NOTE: must keep this code in sync with the drawing code and also the filtering code!
00363          */
00364         case ALE_GROUP: /* action group */
00365             return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
00366         case ALE_ACT: /* action */
00367             return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
00368             
00369         case ALE_OB: /* object */
00370             return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
00371         case ALE_SCE: /* scene */
00372             return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
00373         case ALE_ALL: /* 'all' (DopeSheet summary) */
00374             return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
00375     }
00376     
00377     return 0;
00378 }
00379 
00380 /* ************************************************************************** */
00381 /* Keyframe Integrity Tools */
00382 
00383 /* Rearrange keyframes if some are out of order */
00384 // used to be recalc_*_ipos() where * was object or action
00385 void ANIM_editkeyframes_refresh(bAnimContext *ac)
00386 {
00387     ListBase anim_data = {NULL, NULL};
00388     bAnimListElem *ale;
00389     int filter;
00390     /* when not in graph view, don't use handles */
00391     SpaceIpo *sipo= (ac->spacetype == SPACE_IPO) ? (SpaceIpo *)ac->sl : NULL;
00392     const short use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : FALSE;
00393     
00394     /* filter animation data */
00395     filter= ANIMFILTER_DATA_VISIBLE; 
00396     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00397     
00398     /* loop over F-Curves that are likely to have been edited, and check them */
00399     for (ale= anim_data.first; ale; ale= ale->next) {
00400         FCurve *fcu= ale->key_data;
00401         
00402         /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
00403         sort_time_fcurve(fcu);
00404         testhandles_fcurve(fcu, use_handle);
00405     }
00406     
00407     /* free temp data */
00408     BLI_freelistN(&anim_data);
00409 }
00410 
00411 /* ************************************************************************** */
00412 /* BezTriple Validation Callbacks */
00413 
00414 /* ------------------------ */
00415 /* Some macros to make this easier... */
00416 
00417 /* run the given check on the 3 handles 
00418  *  - check should be a macro, which takes the handle index as its single arg, which it substitutes later
00419  *  - requires that a var, of type short, is named 'ok', and has been initialized to 0
00420  */
00421 #define KEYFRAME_OK_CHECKS(check) \
00422     { \
00423         if (check(1)) \
00424             ok |= KEYFRAME_OK_KEY; \
00425          \
00426         if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
00427             if (check(0)) \
00428                 ok |= KEYFRAME_OK_H1; \
00429             if (check(2)) \
00430                 ok |= KEYFRAME_OK_H2; \
00431         } \
00432     }   
00433  
00434 /* ------------------------ */
00435  
00436 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
00437 {
00438     short ok = 0;
00439     
00440     /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
00441     #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
00442         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
00443     #undef KEY_CHECK_OK
00444     
00445     /* return ok flags */
00446     return ok;
00447 }
00448 
00449 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
00450 {
00451     short ok = 0;
00452     
00453     /* frame range is stored in float properties */
00454     #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
00455         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
00456     #undef KEY_CHECK_OK
00457     
00458     /* return ok flags */
00459     return ok;
00460 }
00461 
00462 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
00463 {
00464     /* this macro checks all beztriple handles for selection... 
00465      *  only one of the verts has to be selected for this to be ok...
00466      */
00467     if (BEZSELECTED(bezt))
00468         return KEYFRAME_OK_ALL;
00469     else
00470         return 0;
00471 }
00472 
00473 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
00474 {   
00475     short ok = 0;
00476     
00477     /* value is stored in f1 property 
00478      *  - this float accuracy check may need to be dropped?
00479      *  - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
00480      */
00481     #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
00482         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
00483     #undef KEY_CHECK_OK
00484     
00485     /* return ok flags */
00486     return ok;
00487 }
00488 
00489 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
00490 {
00491     short ok = 0;
00492     
00493     /* value range is stored in float properties */
00494     #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
00495         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
00496     #undef KEY_CHECK_OK
00497     
00498     /* return ok flags */
00499     return ok;
00500 }
00501 
00502 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
00503 {
00504     /* rect is stored in data property (it's of type rectf, but may not be set) */
00505     if (ked->data) {
00506         short ok = 0;
00507         
00508         #define KEY_CHECK_OK(_index) BLI_in_rctf(ked->data, bezt->vec[_index][0], bezt->vec[_index][1])
00509             KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
00510         #undef KEY_CHECK_OK
00511         
00512         /* return ok flags */
00513         return ok;
00514     }
00515     else 
00516         return 0;
00517 }
00518 
00519 
00520 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
00521 {
00522     /* eEditKeyframes_Validate */
00523     switch (mode) {
00524         case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
00525             return ok_bezier_frame;
00526         case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
00527             return ok_bezier_framerange;
00528         case BEZT_OK_SELECTED:  /* only if bezt is selected (self) */
00529             return ok_bezier_selected;
00530         case BEZT_OK_VALUE: /* only if bezt value matches (float) */
00531             return ok_bezier_value;
00532         case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
00533             return ok_bezier_valuerange;
00534         case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
00535             return ok_bezier_region;
00536         default: /* nothing was ok */
00537             return NULL;
00538     }
00539 }
00540 
00541 /* ******************************************* */
00542 /* Assorted Utility Functions */
00543 
00544 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
00545 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
00546 {
00547     /* only if selected */
00548     if (bezt->f2 & SELECT) {
00549         /* store average time in float 1 (only do rounding at last step) */
00550         ked->f1 += bezt->vec[1][0];
00551         
00552         /* store average value in float 2 (only do rounding at last step) 
00553          *  - this isn't always needed, but some operators may also require this
00554          */
00555         ked->f2 += bezt->vec[1][1];
00556         
00557         /* increment number of items */
00558         ked->i1++;
00559     }
00560     
00561     return 0;
00562 }
00563 
00564 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
00565 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
00566 {
00567     /* only if selected */
00568     if (bezt->f2 & SELECT) {
00569         CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
00570         BLI_addtail(&ked->list, ce);
00571         
00572         ce->cfra= bezt->vec[1][0];
00573     }
00574     
00575     return 0;
00576 }
00577 
00578 /* used to remap times from one range to another
00579  * requires:  ked->data = KeyframeEditCD_Remap  
00580  */
00581 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
00582 {
00583     KeyframeEditCD_Remap *rmap= (KeyframeEditCD_Remap*)ked->data;
00584     const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
00585     
00586     /* perform transform on all three handles unless indicated otherwise */
00587     // TODO: need to include some checks for that
00588     
00589     bezt->vec[0][0]= scale*(bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
00590     bezt->vec[1][0]= scale*(bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
00591     bezt->vec[2][0]= scale*(bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
00592 }
00593 
00594 /* ******************************************* */
00595 /* Transform */
00596 
00597 /* snaps the keyframe to the nearest frame */
00598 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
00599 {
00600     if (bezt->f2 & SELECT)
00601         bezt->vec[1][0]= (float)(floorf(bezt->vec[1][0]+0.5f));
00602     return 0;
00603 }
00604 
00605 /* snaps the keyframe to the neares second */
00606 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
00607 {
00608     const Scene *scene= ked->scene;
00609     const float secf = (float)FPS;
00610     
00611     if (bezt->f2 & SELECT)
00612         bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
00613     return 0;
00614 }
00615 
00616 /* snaps the keyframe to the current frame */
00617 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
00618 {
00619     const Scene *scene= ked->scene;
00620     if (bezt->f2 & SELECT)
00621         bezt->vec[1][0]= (float)CFRA;
00622     return 0;
00623 }
00624 
00625 /* snaps the keyframe time to the nearest marker's frame */
00626 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
00627 {
00628     if (bezt->f2 & SELECT)
00629         bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
00630     return 0;
00631 }
00632 
00633 /* make the handles have the same value as the key */
00634 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
00635 {
00636     if (bezt->f2 & SELECT) {
00637         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
00638         
00639         if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1= HD_ALIGN;
00640         if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2= HD_ALIGN;
00641     }
00642     return 0;   
00643 }
00644 
00645 /* value to snap to is stored in the custom data -> first float value slot */
00646 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
00647 {
00648     if (bezt->f2 & SELECT)
00649         bezt->vec[1][1]= ked->f1;
00650     return 0;
00651 }
00652 
00653 KeyframeEditFunc ANIM_editkeyframes_snap(short type)
00654 {
00655     /* eEditKeyframes_Snap */
00656     switch (type) {
00657         case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
00658             return snap_bezier_nearest;
00659         case SNAP_KEYS_CURFRAME: /* snap to current frame */
00660             return snap_bezier_cframe;
00661         case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
00662             return snap_bezier_nearmarker;
00663         case SNAP_KEYS_NEARSEC: /* snap to nearest second */
00664             return snap_bezier_nearestsec;
00665         case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
00666             return snap_bezier_horizontal;
00667         case SNAP_KEYS_VALUE: /* snap to given value */
00668             return snap_bezier_value;
00669         default: /* just in case */
00670             return snap_bezier_nearest;
00671     }
00672 }
00673 
00674 /* --------- */
00675 
00676 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
00677 {
00678     const Scene *scene= ked->scene;
00679     float diff;
00680     
00681     if (bezt->f2 & SELECT) {
00682         diff= ((float)CFRA - bezt->vec[1][0]);
00683         bezt->vec[1][0]= ((float)CFRA + diff);
00684     }
00685     
00686     return 0;
00687 }
00688 
00689 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
00690 {
00691     float diff;
00692     
00693     if (bezt->f2 & SELECT) {
00694         diff= (0.0f - bezt->vec[1][0]);
00695         bezt->vec[1][0]= (0.0f + diff);
00696     }
00697     
00698     return 0;
00699 }
00700 
00701 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
00702 {
00703     float diff;
00704     
00705     if (bezt->f2 & SELECT) {
00706         diff= (0.0f - bezt->vec[1][1]);
00707         bezt->vec[1][1]= (0.0f + diff);
00708     }
00709     
00710     return 0;
00711 }
00712 
00713 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
00714 {
00715     /* mirroring time stored in f1 */
00716     if (bezt->f2 & SELECT) {
00717         const float diff= (ked->f1 - bezt->vec[1][0]);
00718         bezt->vec[1][0]= (ked->f1 + diff);
00719     }
00720     
00721     return 0;
00722 }
00723 
00724 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
00725 {
00726     float diff;
00727     
00728     /* value to mirror over is stored in the custom data -> first float value slot */
00729     if (bezt->f2 & SELECT) {
00730         diff= (ked->f1 - bezt->vec[1][1]);
00731         bezt->vec[1][1]= (ked->f1 + diff);
00732     }
00733     
00734     return 0;
00735 }
00736 
00737 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
00738 // calchandles_fcurve
00739 KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
00740 {
00741     switch (type) {
00742         case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
00743             return mirror_bezier_cframe;
00744         case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
00745             return mirror_bezier_yaxis;
00746         case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
00747             return mirror_bezier_xaxis;
00748         case MIRROR_KEYS_MARKER: /* mirror over marker */
00749             return mirror_bezier_marker; 
00750         case MIRROR_KEYS_VALUE: /* mirror over given value */
00751             return mirror_bezier_value;
00752         default: /* just in case */
00753             return mirror_bezier_yaxis;
00754             break;
00755     }
00756 }
00757 
00758 /* ******************************************* */
00759 /* Settings */
00760 
00761 /* standard validation step for a few of these (implemented as macro for inlining without fn-call overhead):
00762  *  "if the handles are not of the same type, set them to type free"
00763  */
00764 #define ENSURE_HANDLES_MATCH(bezt) \
00765         if (bezt->h1 != bezt->h2) { \
00766             if ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h1= HD_FREE; \
00767             if ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h2= HD_FREE; \
00768         }
00769 
00770 /* Sets the selected bezier handles to type 'auto' */
00771 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00772 {
00773     if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
00774         if (bezt->f1 & SELECT) bezt->h1= HD_AUTO;
00775         if (bezt->f3 & SELECT) bezt->h2= HD_AUTO;
00776         
00777         ENSURE_HANDLES_MATCH(bezt);
00778     }
00779     return 0;
00780 }
00781 
00782 /* Sets the selected bezier handles to type 'auto-clamped'
00783  * NOTE: this is like auto above, but they're handled a bit different
00784  */
00785 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00786 {
00787     if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
00788         if (bezt->f1 & SELECT) bezt->h1= HD_AUTO_ANIM;
00789         if (bezt->f3 & SELECT) bezt->h2= HD_AUTO_ANIM;
00790         
00791         ENSURE_HANDLES_MATCH(bezt);
00792     }
00793     return 0;
00794 }
00795 
00796 /* Sets the selected bezier handles to type 'vector'  */
00797 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00798 {
00799     if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
00800     if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
00801     return 0;
00802 }
00803 
00804 /* Queries if the handle should be set to 'free' or 'align' */
00805 // NOTE: this was used for the 'toggle free/align' option
00806 //      currently this isn't used, but may be restored later
00807 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00808 {
00809     if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
00810     if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
00811     return 0;
00812 }
00813 
00814 /* Sets selected bezier handles to type 'align' */
00815 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00816 {   
00817     if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
00818     if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
00819     return 0;
00820 }
00821 
00822 /* Sets selected bezier handles to type 'free'  */
00823 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00824 {
00825     if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
00826     if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
00827     return 0;
00828 }
00829 
00830 /* Set all selected Bezier Handles to a single type */
00831 // calchandles_fcurve
00832 KeyframeEditFunc ANIM_editkeyframes_handles(short code)
00833 {
00834     switch (code) {
00835         case HD_AUTO: /* auto */
00836             return set_bezier_auto;
00837         case HD_AUTO_ANIM: /* auto clamped */
00838             return set_bezier_auto_clamped;
00839             
00840         case HD_VECT: /* vector */
00841             return set_bezier_vector;
00842         case HD_FREE: /* free */
00843             return set_bezier_free;
00844         case HD_ALIGN: /* align */
00845             return set_bezier_align;
00846         
00847         default: /* check for toggle free or align? */
00848             return bezier_isfree;
00849     }
00850 }
00851 
00852 /* ------- */
00853 
00854 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00855 {
00856     if (bezt->f2 & SELECT) 
00857         bezt->ipo= BEZT_IPO_CONST;
00858     return 0;
00859 }
00860 
00861 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00862 {
00863     if (bezt->f2 & SELECT) 
00864         bezt->ipo= BEZT_IPO_LIN;
00865     return 0;
00866 }
00867 
00868 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00869 {
00870     if (bezt->f2 & SELECT) 
00871         bezt->ipo= BEZT_IPO_BEZ;
00872     return 0;
00873 }
00874 
00875 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
00876 // ANIM_editkeyframes_ipocurve_ipotype() !
00877 KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
00878 {
00879     switch (code) {
00880         case BEZT_IPO_CONST: /* constant */
00881             return set_bezt_constant;
00882         case BEZT_IPO_LIN: /* linear */ 
00883             return set_bezt_linear;
00884         default: /* bezier */
00885             return set_bezt_bezier;
00886     }
00887 }
00888 
00889 /* ------- */
00890 
00891 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00892 {
00893     if (bezt->f2 & SELECT) 
00894         BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
00895     return 0;
00896 }
00897 
00898 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00899 {
00900     if (bezt->f2 & SELECT) 
00901         BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
00902     return 0;
00903 }
00904 
00905 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00906 {
00907     if (bezt->f2 & SELECT) 
00908         BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME;
00909     return 0;
00910 }
00911 
00912 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00913 {
00914     if (bezt->f2 & SELECT) 
00915         BEZKEYTYPE(bezt)= BEZT_KEYTYPE_JITTER;
00916     return 0;
00917 }
00918 
00919 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
00920 KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
00921 {
00922     switch (code) {
00923         case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
00924             return set_keytype_breakdown;
00925             
00926         case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
00927             return set_keytype_extreme;
00928             
00929         case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
00930             return set_keytype_jitter;
00931             
00932         case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */   
00933         default:
00934             return set_keytype_keyframe;
00935     }
00936 }
00937 
00938 /* ******************************************* */
00939 /* Selection */
00940 
00941 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt) 
00942 {
00943     /* if we've got info on what to select, use it, otherwise select all */
00944     if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
00945         if (ked->curflags & KEYFRAME_OK_KEY)
00946             bezt->f2 |= SELECT;
00947         if (ked->curflags & KEYFRAME_OK_H1)
00948             bezt->f1 |= SELECT;
00949         if (ked->curflags & KEYFRAME_OK_H2)
00950             bezt->f3 |= SELECT;
00951     }
00952     else {
00953         BEZ_SEL(bezt);
00954     }
00955     
00956     return 0;
00957 }
00958 
00959 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt) 
00960 {
00961     /* if we've got info on what to deselect, use it, otherwise deselect all */
00962     if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
00963         if (ked->curflags & KEYFRAME_OK_KEY)
00964             bezt->f2 &= ~SELECT;
00965         if (ked->curflags & KEYFRAME_OK_H1)
00966             bezt->f1 &= ~SELECT;
00967         if (ked->curflags & KEYFRAME_OK_H2)
00968             bezt->f3 &= ~SELECT;
00969     }
00970     else {
00971         BEZ_DESEL(bezt);
00972     }
00973     
00974     return 0;
00975 }
00976 
00977 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
00978 {
00979     /* Invert the selection for the whole bezier triple */
00980     bezt->f2 ^= SELECT;
00981     if (bezt->f2 & SELECT) {
00982         bezt->f1 |= SELECT;
00983         bezt->f3 |= SELECT;
00984     }
00985     else {
00986         bezt->f1 &= ~SELECT;
00987         bezt->f3 &= ~SELECT;
00988     }
00989     return 0;
00990 }
00991 
00992 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
00993 {
00994     switch (selectmode) {
00995         case SELECT_ADD: /* add */
00996             return select_bezier_add;
00997         case SELECT_SUBTRACT: /* subtract */
00998             return select_bezier_subtract;
00999         case SELECT_INVERT: /* invert */
01000             return select_bezier_invert;
01001         default: /* replace (need to clear all, then add) */
01002             return select_bezier_add;
01003     }
01004 }
01005 
01006 /* ******************************************* */
01007 /* Selection Maps */
01008 
01009 /* Selection maps are simply fancy names for char arrays that store on/off
01010  * info for whether the selection status. The main purpose for these is to
01011  * allow extra info to be tagged to the keyframes without influencing their
01012  * values or having to be removed later.
01013  */
01014 
01015 /* ----------- */
01016 
01017 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
01018 {
01019     FCurve *fcu= ked->fcu;
01020     char *map= ked->data;
01021     int i= ked->curIndex;
01022     
01023     /* if current is selected, just make sure it stays this way */
01024     if (BEZSELECTED(bezt)) {
01025         map[i]= 1;
01026         return 0;
01027     }
01028     
01029     /* if previous is selected, that means that selection should extend across */
01030     if (i > 0) {
01031         BezTriple *prev= bezt - 1;
01032         
01033         if (BEZSELECTED(prev)) {
01034             map[i]= 1;
01035             return 0;
01036         }
01037     }
01038     
01039     /* if next is selected, that means that selection should extend across */
01040     if (i < (fcu->totvert-1)) {
01041         BezTriple *next= bezt + 1;
01042         
01043         if (BEZSELECTED(next)) {
01044             map[i]= 1;
01045             return 0;
01046         }
01047     }
01048     
01049     return 0;
01050 }
01051 
01052 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
01053 {
01054     FCurve *fcu= ked->fcu;
01055     char *map= ked->data;
01056     int i= ked->curIndex;
01057     
01058     /* if current is selected, check the left/right keyframes
01059      * since it might need to be deselected (but otherwise no)
01060      */
01061     if (BEZSELECTED(bezt)) {
01062         /* if previous is not selected, we're on the tip of an iceberg */
01063         if (i > 0) {
01064             BezTriple *prev= bezt - 1;
01065             
01066             if (BEZSELECTED(prev) == 0)
01067                 return 0;
01068         }
01069         else if (i == 0) {
01070             /* current keyframe is selected at an endpoint, so should get deselected */
01071             return 0;
01072         }
01073         
01074         /* if next is not selected, we're on the tip of an iceberg */
01075         if (i < (fcu->totvert-1)) {
01076             BezTriple *next= bezt + 1;
01077             
01078             if (BEZSELECTED(next) == 0)
01079                 return 0;
01080         }
01081         else if (i == (fcu->totvert-1)) {
01082             /* current keyframe is selected at an endpoint, so should get deselected */
01083             return 0;
01084         }
01085         
01086         /* if we're still here, that means that keyframe should remain untouched */
01087         map[i]= 1;
01088     }
01089     
01090     return 0;
01091 }
01092 
01093 /* Get callback for building selection map */
01094 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
01095 {
01096     switch (mode) {
01097         case SELMAP_LESS: /* less */
01098             return selmap_build_bezier_less;
01099         
01100         case SELMAP_MORE: /* more */
01101         default:
01102             return selmap_build_bezier_more;
01103     }
01104 }
01105 
01106 /* ----------- */
01107 
01108 /* flush selection map values to the given beztriple */
01109 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
01110 {
01111     char *map= ked->data;
01112     short on= map[ked->curIndex];
01113     
01114     /* select or deselect based on whether the map allows it or not */
01115     if (on) {
01116         BEZ_SEL(bezt);
01117     }
01118     else {
01119         BEZ_DESEL(bezt);
01120     }
01121     
01122     return 0;
01123 }
01124