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