diff options
Diffstat (limited to 'source/blender/editors/animation/keyframing.c')
-rw-r--r-- | source/blender/editors/animation/keyframing.c | 1056 |
1 files changed, 377 insertions, 679 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 5121932d0cc..4f62368c2b2 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1,123 +1,48 @@ -/** - * $Id: keyframing.c 17745 2008-12-08 09:16:09Z aligorith $ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2008, Blender Foundation - * This is a new part of Blender (with some old code) - * - * Contributor(s): Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** +/* Testing code for 2.5 animation system + * Copyright 2009, Joshua Leung */ - - - + #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <stddef.h> #include <math.h> #include <float.h> -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #include "MEM_guardedalloc.h" -#include "BLI_arithb.h" #include "BLI_blenlib.h" +#include "BLI_arithb.h" #include "BLI_dynstr.h" -#include "DNA_listBase.h" -#include "DNA_ID.h" +#include "DNA_anim_types.h" #include "DNA_action_types.h" -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" #include "DNA_constraint_types.h" -#include "DNA_curve_types.h" -#include "DNA_ipo_types.h" #include "DNA_key_types.h" -#include "DNA_lamp_types.h" #include "DNA_object_types.h" -#include "DNA_object_fluidsim.h" -#include "DNA_particle_types.h" #include "DNA_material_types.h" -#include "DNA_screen_types.h" #include "DNA_scene_types.h" -#include "DNA_sequence_types.h" -#include "DNA_space_types.h" -#include "DNA_texture_types.h" #include "DNA_userdef_types.h" -#include "DNA_vec_types.h" -#include "DNA_view3d_types.h" -#include "DNA_world_types.h" #include "DNA_windowmanager_types.h" -#include "BKE_context.h" -#include "BKE_utildefines.h" -#include "BKE_blender.h" +#include "BKE_animsys.h" #include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_constraint.h" -#include "BKE_curve.h" -#include "BKE_depsgraph.h" -#include "BKE_ipo.h" +#include "BKE_fcurve.h" +#include "BKE_utildefines.h" +#include "BKE_context.h" #include "BKE_key.h" -#include "BKE_object.h" -#include "BKE_particle.h" #include "BKE_material.h" -#include "BKE_modifier.h" #include "ED_anim_api.h" #include "ED_keyframing.h" #include "ED_keyframes_edit.h" +#include "ED_screen.h" +#include "ED_util.h" #include "WM_api.h" #include "WM_types.h" -#if 0 // XXX resolve these old dependencies! - #include "BIF_butspace.h" - #include "BIF_editaction.h" - #include "BIF_editkey.h" - #include "BIF_interface.h" - #include "BIF_mywindow.h" - #include "BIF_poseobject.h" - #include "BIF_screen.h" - #include "BIF_space.h" - #include "BIF_toolbox.h" - #include "BIF_toets.h" - - #include "BSE_editipo.h" - #include "BSE_node.h" - #include "BSE_time.h" - #include "BSE_view.h" - - #include "blendef.h" - - #include "PIL_time.h" /* sleep */ - #include "mydevice.h" -#endif // XXX resolve these old dependencies! - -/* ****************************************** */ - -/* note for Joshua: add_ipo() wants scene pointer to init the view2d 'cur' for - the ipo data, which restores views. Needs to be resolved nicer? */ +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_types.h" /* ************************************************** */ /* LOCAL TYPES AND DEFINES */ @@ -130,34 +55,15 @@ typedef struct bCommonKeySrc { /* general data/destination-source settings */ ID *id; /* id-block this comes from */ - char *actname; /* name of action channel */ - char *constname; /* name of constraint channel */ + char *rna_path; /* base path to use */ // xxx.... maybe we don't need this? - /* general destination source settings */ - Ipo *ipo; /* ipo-block that id-block has (optional) */ - bAction *act; /* action-block that id-block has (optional) */ - - /* pose-level settings */ - bPoseChannel *pchan; /* pose channel */ - - /* buttons-window settings */ - int map; /* offset to apply to certain adrcodes */ + /* specific cases */ + bPoseChannel *pchan; /* only needed when doing recalcs... */ } bCommonKeySrc; /* -------------- Keying Sets ------------------- */ -/* storage for iterator for looping over keyingset channels */ -typedef struct bKS_AdrcodeGetter { - struct bKeyingSet *ks; /* keyingset this applies to */ - struct bCommonKeySrc *cks; /* data to insert/delete keyframes... */ - - short index; /* index of current channel to resume from */ - short tot; /* index after which we start returning from some special collection */ -} bKS_AdrcodeGetter; - -/* flags to look out for in keyingset channels... */ -#define KAG_CHAN_EXTEND (-1) - +#if 0 // XXX I'm not sure how these will work for now... /* keying set - a set of channels that will be keyframed together */ // TODO: move this to a header to allow custom sets someday? @@ -168,11 +74,11 @@ typedef struct bKeyingSet { short (*include_cb)(struct bKeyingSet *, const char *); char name[48]; /* name of keyingset */ - int blocktype; /* blocktype that all channels belong to */ // in future, this may be eliminated + int blocktype; /* nearest ID-blocktype to where data can be found */ short flag; /* flags to use when setting keyframes */ short chan_num; /* number of channels to insert keyframe in */ - short adrcodes[32]; /* adrcodes for channels to insert keys for (ideally would be variable-len, but limit of 32 will suffice) */ + char (*paths)[256]; /* adrcodes for channels to insert keys for (ideally would be variable-len, but limit of 32 will suffice) */ } bKeyingSet; /* keying set context - an array of keying sets and the number of them */ @@ -182,282 +88,57 @@ typedef struct bKeyingContext { int tot; /* number of keyingsets in */ } bKeyingContext; +#endif -/* ************************************************** */ -/* IPO DATA VERIFICATION */ -// XXX these will need to be modified for use with RNA-IPO... - -/* depending type, it returns ipo, if needed it creates one */ -/* returns either action ipo or "real" ipo */ -/* arguments define full context; - - *from has to be set always, to Object in case of Actions - - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too) - - if actname, use this to locate actionchannel, and optional constname - - if bonename, the constname is the ipo to the constraint -*/ - -/* note: check header_ipo.c, spaceipo_assign_ipo() too */ -Ipo *verify_ipo(ID *from, short blocktype, char actname[], char constname[], char bonename[], short add) -{ - /* lib-linked data is not appropriate here */ - if ((from==NULL) || (from->lib)) - return NULL; - - /* first check action ipos */ - if (actname && actname[0]) { - Object *ob= (Object *)from; - bActionChannel *achan; - - if (GS(from->name)!=ID_OB) { - printf("called ipo system for action with wrong base pointer\n"); - return NULL; - } - - if ((ob->action==NULL) && (add)) - ob->action= add_empty_action("Action"); - - if (add) - achan= verify_action_channel(ob->action, actname); - else - achan= get_action_channel(ob->action, actname); - - if (achan) { - /* automatically assign achan to act-group based on pchan's grouping */ - //if ((blocktype == ID_PO) && (add)) - // verify_pchan2achan_grouping(ob->action, ob->pose, actname); - - /* constraint exception */ - if (blocktype==ID_CO) { - bConstraintChannel *conchan; - - if (add) - conchan= verify_constraint_channel(&achan->constraintChannels, constname); - else - conchan= get_constraint_channel(&achan->constraintChannels, constname); - - if (conchan) { - if ((conchan->ipo==NULL) && (add)) - conchan->ipo= add_ipo(NULL, "CoIpo", ID_CO); - return conchan->ipo; - } - } - else { - if ((achan->ipo==NULL) && (add)) - achan->ipo= add_ipo(NULL, "ActIpo", blocktype); - return achan->ipo; - } - } - } - else { - switch (GS(from->name)) { - case ID_OB: - { - Object *ob= (Object *)from; - - /* constraint exception */ - if (blocktype==ID_CO) { - /* check the local constraint ipo */ - if (bonename && bonename[0] && ob->pose) { - bPoseChannel *pchan= get_pose_channel(ob->pose, bonename); - bConstraint *con; - - for (con= pchan->constraints.first; con; con= con->next) { - if (strcmp(con->name, constname)==0) - break; - } - - if (con) { - if ((con->ipo==NULL) && (add)) - con->ipo= add_ipo(NULL, "CoIpo", ID_CO); - return con->ipo; - } - } - else { /* the actionchannel */ - bConstraintChannel *conchan; - - if (add) - conchan= verify_constraint_channel(&ob->constraintChannels, constname); - else - conchan= get_constraint_channel(&ob->constraintChannels, constname); - - if (conchan) { - if ((conchan->ipo==NULL) && (add)) - conchan->ipo= add_ipo(NULL, "CoIpo", ID_CO); - return conchan->ipo; - } - } - } - else if (blocktype==ID_OB) { - if ((ob->ipo==NULL) && (add)) - ob->ipo= add_ipo(NULL, "ObIpo", ID_OB); - return ob->ipo; - } - else if (blocktype==ID_KE) { - Key *key= ob_get_key((Object *)from); - - if (key) { - if ((key->ipo==NULL) && (add)) - key->ipo= add_ipo(NULL, "KeyIpo", ID_KE); - return key->ipo; - } - return NULL; - } - else if (blocktype== ID_FLUIDSIM) { - Object *ob= (Object *)from; - - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); - if(fluidmd) { - FluidsimSettings *fss= fluidmd->fss; - - if ((fss->ipo==NULL) && (add)) - fss->ipo= add_ipo(NULL, "FluidsimIpo", ID_FLUIDSIM); - return fss->ipo; - } - } - else if(blocktype== ID_PA) { - Object *ob= (Object *)from; - ParticleSystem *psys= psys_get_current(ob); - - if (psys) { - if ((psys->part->ipo==NULL) && (add)) - psys->part->ipo= add_ipo(NULL, "ParticleIpo", ID_PA); - return psys->part->ipo; - } - return NULL; - } - } - break; - case ID_MA: - { - Material *ma= (Material *)from; - - if ((ma->ipo==NULL) && (add)) - ma->ipo= add_ipo(NULL, "MatIpo", ID_MA); - return ma->ipo; - } - break; - case ID_TE: - { - Tex *tex= (Tex *)from; - - if ((tex->ipo==NULL) && (add)) - tex->ipo= add_ipo(NULL, "TexIpo", ID_TE); - return tex->ipo; - } - break; - case ID_SEQ: - { - Sequence *seq= (Sequence *)from; /* note, sequence is mimicing Id */ - - if ((seq->ipo==NULL) && (add)) - seq->ipo= add_ipo(NULL, "SeqIpo", ID_SEQ); - //update_seq_ipo_rect(seq); // XXX - return seq->ipo; - } - break; - case ID_CU: - { - Curve *cu= (Curve *)from; - - if ((cu->ipo==NULL) && (add)) - cu->ipo= add_ipo(NULL, "CuIpo", ID_CU); - return cu->ipo; - } - break; - case ID_WO: - { - World *wo= (World *)from; - - if ((wo->ipo==NULL) && (add)) - wo->ipo= add_ipo(NULL, "WoIpo", ID_WO); - return wo->ipo; - } - break; - case ID_LA: - { - Lamp *la= (Lamp *)from; - - if ((la->ipo==NULL) && (add)) - la->ipo= add_ipo(NULL, "LaIpo", ID_LA); - return la->ipo; - } - break; - case ID_CA: - { - Camera *ca= (Camera *)from; - - if ((ca->ipo==NULL) && (add)) - ca->ipo= add_ipo(NULL, "CaIpo", ID_CA); - return ca->ipo; - } - break; - case ID_SO: - { -#if 0 // depreceated - bSound *snd= (bSound *)from; - - if ((snd->ipo==NULL) && (add)) - snd->ipo= add_ipo(NULL, "SndIpo", ID_SO); - return snd->ipo; -#endif // depreceated - } - break; - } - } - - return NULL; -} +/* ******************************************* */ +/* Animation Data Validation */ -/* Returns and creates - * Make sure functions check for NULL or they will crash! +/* Get (or add relevant data to be able to do so) F-Curve from the Active Action, + * for the given Animation Data block */ -IpoCurve *verify_ipocurve(ID *from, short blocktype, char actname[], char constname[], char bonename[], int adrcode, short add) +// TODO: should we check if path is valid? For now, assume that it's already set OK by caller... +FCurve *verify_fcurve (AnimData *adt, const char rna_path[], const int array_index, short add) { - Ipo *ipo; - IpoCurve *icu= NULL; + nAction *act; + FCurve *fcu; - /* return 0 if lib */ - /* creates ipo too (if add) */ - ipo= verify_ipo(from, blocktype, actname, constname, bonename, add); + /* sanity checks */ + if ELEM(NULL, adt, rna_path) + return NULL; + + /* init action if none available yet */ + // TODO: need some wizardry to handle NLA stuff correct + if ((adt->action == NULL) && (add)) + adt->action= add_empty_action("Action"); + act= adt->action; + + /* try to find f-curve matching for this setting + * - add if not found and allowed to add one + * TODO: add auto-grouping support? how this works will need to be resolved + */ + if (act) + fcu= list_find_fcurve(&act->curves, rna_path, array_index); + else + fcu= NULL; - if ((ipo) && (ipo->id.lib==NULL) && (from->lib==NULL)) { - /* try to find matching curve */ - icu= find_ipocurve(ipo, adrcode); + if ((fcu == NULL) && (add)) { + /* use default settings */ + fcu= MEM_callocN(sizeof(FCurve), "FCurve"); - /* make a new one if none found (and can add) */ - if ((icu==NULL) && (add)) { - icu= MEM_callocN(sizeof(IpoCurve), "ipocurve"); - - /* set default settings */ - icu->flag |= (IPO_VISIBLE|IPO_AUTO_HORIZ); - if (ipo->curve.first==NULL) - icu->flag |= IPO_ACTIVE; /* first one added active */ - - icu->blocktype= blocktype; - icu->adrcode= adrcode; + fcu->flag |= (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES); + if (act->curves.first==NULL) + fcu->flag |= FCURVE_ACTIVE; /* first one added active */ - set_icu_vars(icu); - - /* default curve interpolation - from userpref */ - icu->ipo= U.ipo_new; - - /* add curve to IPO-block */ - BLI_addtail(&ipo->curve, icu); - - /* special type-dependent stuff */ - switch (GS(from->name)) { - case ID_SEQ: { - //Sequence *seq= (Sequence *)from; - - //update_seq_icu_rects(seq); // XXX - break; - } - } - } + /* store path - make copy, and store that */ + fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path)); + fcu->array_index= array_index; + + /* add curve */ + BLI_addtail(&act->curves, fcu); // XXX it might be better to add this in order, for easier UI coding... } - /* return ipo-curve */ - return icu; + /* return the F-Curve */ + return fcu; } /* ************************************************** */ @@ -544,54 +225,55 @@ static int binarysearch_bezt_index (BezTriple array[], float frame, int arraylen return start; } -/* This function adds a given BezTriple to an IPO-Curve. It will allocate +/* This function adds a given BezTriple to an F-Curve. It will allocate * memory for the array if needed, and will insert the BezTriple into a * suitable place in chronological order. * - * NOTE: any recalculate of the IPO-Curve that needs to be done will need to + * NOTE: any recalculate of the F-Curve that needs to be done will need to * be done by the caller. */ -int insert_bezt_icu (IpoCurve *icu, BezTriple *bezt) +int insert_bezt_fcurve (FCurve *fcu, BezTriple *bezt) { BezTriple *newb; int i= 0; - if (icu->bezt) { + if (fcu->bezt) { short replace = -1; - i = binarysearch_bezt_index(icu->bezt, bezt->vec[1][0], icu->totvert, &replace); + i = binarysearch_bezt_index(fcu->bezt, bezt->vec[1][0], fcu->totvert, &replace); if (replace) { /* sanity check: 'i' may in rare cases exceed arraylen */ // FIXME: do not overwrite handletype if just replacing...? - if ((i >= 0) && (i < icu->totvert)) - *(icu->bezt + i) = *bezt; + if ((i >= 0) && (i < fcu->totvert)) + *(fcu->bezt + i) = *bezt; } else { /* add new */ - newb= MEM_callocN((icu->totvert+1)*sizeof(BezTriple), "beztriple"); + newb= MEM_callocN((fcu->totvert+1)*sizeof(BezTriple), "beztriple"); /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */ if (i > 0) - memcpy(newb, icu->bezt, i*sizeof(BezTriple)); + memcpy(newb, fcu->bezt, i*sizeof(BezTriple)); /* add beztriple to paste at index i */ *(newb + i)= *bezt; /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */ - if (i < icu->totvert) - memcpy(newb+i+1, icu->bezt+i, (icu->totvert-i)*sizeof(BezTriple)); + if (i < fcu->totvert) + memcpy(newb+i+1, fcu->bezt+i, (fcu->totvert-i)*sizeof(BezTriple)); /* replace (+ free) old with new */ - MEM_freeN(icu->bezt); - icu->bezt= newb; + MEM_freeN(fcu->bezt); + fcu->bezt= newb; - icu->totvert++; + fcu->totvert++; } } else { - icu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple"); - *(icu->bezt)= *bezt; - icu->totvert= 1; + // TODO: need to check for old sample-data now... + fcu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple"); + *(fcu->bezt)= *bezt; + fcu->totvert= 1; } @@ -607,10 +289,10 @@ int insert_bezt_icu (IpoCurve *icu, BezTriple *bezt) * * 'fast' - is only for the python API where importing BVH's would take an extreamly long time. */ -void insert_vert_icu (IpoCurve *icu, float x, float y, short fast) +void insert_vert_fcurve (FCurve *fcu, float x, float y, short fast) { BezTriple beztr; - int a, h1, h2; + int a; /* set all three points, for nicer start position */ memset(&beztr, 0, sizeof(BezTriple)); @@ -620,12 +302,12 @@ void insert_vert_icu (IpoCurve *icu, float x, float y, short fast) beztr.vec[1][1]= y; beztr.vec[2][0]= x; beztr.vec[2][1]= y; - beztr.hide= IPO_BEZ; + beztr.ipo= U.ipo_new; /* use default interpolation mode here... */ beztr.f1= beztr.f2= beztr.f3= SELECT; - beztr.h1= beztr.h2= HD_AUTO; + beztr.h1= beztr.h2= HD_AUTO; // XXX what about when we replace an old one? /* add temp beztriple to keyframes */ - a= insert_bezt_icu(icu, &beztr); + a= insert_bezt_fcurve(fcu, &beztr); /* what if 'a' is a negative index? * for now, just exit to prevent any segfaults @@ -636,125 +318,34 @@ void insert_vert_icu (IpoCurve *icu, float x, float y, short fast) * - this is a hack to make importers faster * - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations) */ - if (!fast) calchandles_ipocurve(icu); + if (!fast) calchandles_fcurve(fcu); /* set handletype and interpolation */ - if (icu->totvert > 2) { - BezTriple *bezt= (icu->bezt + a); + if (fcu->totvert > 2) { + BezTriple *bezt= (fcu->bezt + a); + short h1, h2; /* set handles (autohandles by default) */ h1= h2= HD_AUTO; if (a > 0) h1= (bezt-1)->h2; - if (a < icu->totvert-1) h2= (bezt+1)->h1; + if (a < fcu->totvert-1) h2= (bezt+1)->h1; bezt->h1= h1; bezt->h2= h2; - /* set interpolation (if curve is using IPO_MIXED, then take from previous) */ - if (icu->ipo == IPO_MIXED) { - if (a > 0) bezt->ipo= (bezt-1)->ipo; - else if (a < icu->totvert-1) bezt->ipo= (bezt+1)->ipo; - } - else - bezt->ipo= icu->ipo; + /* set interpolation from previous (if available) */ + if (a > 0) bezt->ipo= (bezt-1)->ipo; + else if (a < fcu->totvert-1) bezt->ipo= (bezt+1)->ipo; /* don't recalculate handles if fast is set * - this is a hack to make importers faster * - we may calculate twice (see editipo_changed(), due to autohandle needing two calculations) */ - if (!fast) calchandles_ipocurve(icu); - } - else { - BezTriple *bezt= (icu->bezt + a); - - /* set interpolation directly from ipo-curve */ - bezt->ipo= icu->ipo; - } -} - - -/* ------------------- Get Data ------------------------ */ - -/* Get pointer to use to get values from */ -// FIXME: this should not be possible with Data-API -static void *get_context_ipo_poin (ID *id, int blocktype, char *actname, char *constname, IpoCurve *icu, int *vartype) -{ - switch (blocktype) { - case ID_PO: /* posechannel */ - if (GS(id->name)==ID_OB) { - Object *ob= (Object *)id; - bPoseChannel *pchan= get_pose_channel(ob->pose, actname); - - if (pchan) { - if (ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) - *vartype= IPO_FLOAT_DEGR; - else - *vartype= IPO_FLOAT; - return get_pchan_ipo_poin(pchan, icu->adrcode); - } - } - break; - - case ID_CO: /* constraint */ - if ((GS(id->name)==ID_OB) && (constname && constname[0])) { - Object *ob= (Object *)id; - bConstraint *con; - - /* assume that we only want the influence (as only used for Constraint Channels) */ - if ((ob->ipoflag & OB_ACTION_OB) && !strcmp(actname, "Object")) { - for (con= ob->constraints.first; con; con= con->next) { - if (strcmp(constname, con->name)==0) { - *vartype= IPO_FLOAT; - return &con->enforce; - } - } - } - else if (ob->pose) { - bPoseChannel *pchan= get_pose_channel(ob->pose, actname); - - if (pchan) { - for (con= pchan->constraints.first; con; con= con->next) { - if (strcmp(constname, con->name)==0) { - *vartype= IPO_FLOAT; - return &con->enforce; - } - } - } - } - } - break; - - case ID_OB: /* object */ - /* hack: layer channels for object need to be keyed WITHOUT localview flag... - * tsk... tsk... why must we just dump bitflags upon users :/ - */ - if ((GS(id->name)==ID_OB) && (icu->adrcode==OB_LAY)) { - Object *ob= (Object *)id; - static int layer = 0; - - /* init layer to be the object's layer var, then remove local view from it */ - layer = ob->lay; - layer &= 0xFFFFFF; - *vartype= IPO_INT_BIT; - - /* return pointer to this static var - * - assumes that this pointer won't be stored for use later, so may not be threadsafe - * if multiple keyframe calls are made, but that is unlikely to happen in the near future - */ - return (void *)(&layer); - } - /* no break here for other ob channel-types - as they can be done normally */ - - default: /* normal data-source */ - return get_ipo_poin(id, icu, vartype); + if (!fast) calchandles_fcurve(fcu); } - - /* not valid... */ - return NULL; } - /* -------------- 'Smarter' Keyframing Functions -------------------- */ /* return codes for new_key_needed */ enum { @@ -770,19 +361,19 @@ enum { * 2. Keyframe to be added on frame where two keyframes are already situated * 3. Keyframe lies at point that intersects the linear line between two keyframes */ -static short new_key_needed (IpoCurve *icu, float cFrame, float nValue) +static short new_key_needed (FCurve *fcu, float cFrame, float nValue) { BezTriple *bezt=NULL, *prev=NULL; int totCount, i; float valA = 0.0f, valB = 0.0f; /* safety checking */ - if (icu == NULL) return KEYNEEDED_JUSTADD; - totCount= icu->totvert; + if (fcu == NULL) return KEYNEEDED_JUSTADD; + totCount= fcu->totvert; if (totCount == 0) return KEYNEEDED_JUSTADD; /* loop through checking if any are the same */ - bezt= icu->bezt; + bezt= fcu->bezt; for (i=0; i<totCount; i++) { float prevPosi=0.0f, prevVal=0.0f; float beztPosi=0.0f, beztVal=0.0f; @@ -813,7 +404,7 @@ static short new_key_needed (IpoCurve *icu, float cFrame, float nValue) float realVal; /* get real value of curve at that point */ - realVal= eval_icu(icu, cFrame); + realVal= evaluate_fcurve(fcu, cFrame); /* compare whether it's the same as proposed */ if (IS_EQ(realVal, nValue)) @@ -859,7 +450,7 @@ static short new_key_needed (IpoCurve *icu, float cFrame, float nValue) * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last * keyframe is not equal to last keyframe. */ - bezt= (icu->bezt + (icu->totvert - 1)); + bezt= (fcu->bezt + (fcu->totvert - 1)); valA= bezt->vec[1][1]; if (prev) @@ -873,13 +464,49 @@ static short new_key_needed (IpoCurve *icu, float cFrame, float nValue) return KEYNEEDED_JUSTADD; } +/* ------------------ RNA Data-Access Functions ------------------ */ + +/* Try to read value using RNA-properties obtained already */ +static float setting_get_rna_value (PointerRNA *ptr, PropertyRNA *prop, int index) +{ + float value= 0.0f; + + switch (RNA_property_type(ptr, prop)) { + case PROP_BOOLEAN: + if (RNA_property_array_length(ptr, prop)) + value= (float)RNA_property_boolean_get_array(ptr, prop, index); + else + value= (float)RNA_property_boolean_get(ptr, prop); + break; + case PROP_INT: + if (RNA_property_array_length(ptr, prop)) + value= (float)RNA_property_int_get_array(ptr, prop, index); + else + value= (float)RNA_property_int_get(ptr, prop); + break; + case PROP_FLOAT: + if (RNA_property_array_length(ptr, prop)) + value= RNA_property_float_get_array(ptr, prop, index); + else + value= RNA_property_float_get(ptr, prop); + break; + case PROP_ENUM: + value= (float)RNA_property_enum_get(ptr, prop); + break; + default: + break; + } + + return value; +} + /* ------------------ 'Visual' Keyframing Functions ------------------ */ /* internal status codes for visualkey_can_use */ enum { VISUALKEY_NONE = 0, VISUALKEY_LOC, - VISUALKEY_ROT + VISUALKEY_ROT, }; /* This helper function determines if visual-keyframing should be used when @@ -888,15 +515,16 @@ enum { * blocktypes, when using "standard" keying but 'Visual Keying' option in Auto-Keying * settings is on. */ -static short visualkey_can_use (ID *id, int blocktype, char *actname, char *constname, int adrcode) +static short visualkey_can_use (PointerRNA *ptr, PropertyRNA *prop) { - Object *ob= NULL; + //Object *ob= NULL; bConstraint *con= NULL; short searchtype= VISUALKEY_NONE; +#if 0 // XXX old animation system /* validate data */ if ((id == NULL) || (GS(id->name)!=ID_OB) || !(ELEM(blocktype, ID_OB, ID_PO))) - return 0; + return 0; /* get first constraint and determine type of keyframe constraints to check for*/ ob= (Object *)id; @@ -918,6 +546,7 @@ static short visualkey_can_use (ID *id, int blocktype, char *actname, char *cons else if (ELEM4(adrcode, AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z)) searchtype= VISUALKEY_ROT; } +#endif /* only search if a searchtype and initial constraint are available */ if (searchtype && con) { @@ -976,10 +605,12 @@ static short visualkey_can_use (ID *id, int blocktype, char *actname, char *cons /* This helper function extracts the value to use for visual-keyframing * In the event that it is not possible to perform visual keying, try to fall-back - * to using the poin method. Assumes that all data it has been passed is valid. + * to using the default method. Assumes that all data it has been passed is valid. */ -static float visualkey_get_value (ID *id, int blocktype, char *actname, char *constname, int adrcode, IpoCurve *icu) +// xxx... ptr here should be struct that data is in.... prop is the channel that's being used +static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_index) { +#if 0 // XXX old animation system Object *ob; void *poin = NULL; int index, vartype; @@ -1053,13 +684,10 @@ static float visualkey_get_value (ID *id, int blocktype, char *actname, char *co return quat[index]; } } +#endif // XXX old animation system - /* as the function hasn't returned yet, try reading from poin */ - poin= get_context_ipo_poin(id, blocktype, actname, constname, icu, &vartype); - if (poin) - return read_ipo_poin(poin, vartype); - else - return 0.0; + /* as the function hasn't returned yet, read value from system in the default way */ + return setting_get_rna_value(ptr, prop, array_index); } /* ------------------------- Insert Key API ------------------------- */ @@ -1072,25 +700,35 @@ static float visualkey_get_value (ID *id, int blocktype, char *actname, char *co * the keyframe insertion. These include the 'visual' keyframing modes, quick refresh, * and extra keyframe filtering. */ -short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag) +short insertkey (ID *id, const char rna_path[], int array_index, float cfra, short flag) { - IpoCurve *icu; + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + AnimData *adt; + FCurve *fcu; + + /* validate pointer first - exit if failure*/ + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) { + printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID \n"); + return 0; + } - /* get ipo-curve */ - icu= verify_ipocurve(id, blocktype, actname, constname, NULL, adrcode, 1); + /* get F-Curve */ + adt= BKE_animdata_from_id(id); + fcu= verify_fcurve(adt, rna_path, array_index, 1); - /* only continue if we have an ipo-curve to add keyframe to */ - if (icu) { - float cfra =1.0f;//= frame_to_float(CFRA); + /* only continue if we have an F-Curve to add keyframe to */ + if (fcu) { float curval= 0.0f; /* apply special time tweaking */ + // XXX check on this stuff... if (GS(id->name) == ID_OB) { - Object *ob= (Object *)id; + //Object *ob= (Object *)id; /* apply NLA-scaling (if applicable) */ - if (actname && actname[0]) - cfra= get_action_frame(ob, cfra); + //cfra= get_action_frame(ob, cfra); /* ancient time-offset cruft */ //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) { @@ -1101,29 +739,17 @@ short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrc /* obtain value to give keyframe */ if ( (flag & INSERTKEY_MATRIX) && - (visualkey_can_use(id, blocktype, actname, constname, adrcode)) ) + (visualkey_can_use(&ptr, prop)) ) { /* visual-keying is only available for object and pchan datablocks, as * it works by keyframing using a value extracted from the final matrix * instead of using the kt system to extract a value. */ - curval= visualkey_get_value(id, blocktype, actname, constname, adrcode, icu); + curval= visualkey_get_value(&ptr, prop, array_index); } else { - void *poin; - int vartype; - - /* get pointer to data to read from */ - poin = get_context_ipo_poin(id, blocktype, actname, constname, icu, &vartype); - if (poin == NULL) { - printf("Insert Key: No pointer to variable obtained \n"); - return 0; - } - - /* use kt's read_poin function to extract value (kt->read_poin should - * exist in all cases, but it never hurts to check) - */ - curval= read_ipo_poin(poin, vartype); + /* read value from system */ + curval= setting_get_rna_value(&ptr, prop, array_index); } /* only insert keyframes where they are needed */ @@ -1131,19 +757,19 @@ short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrc short insert_mode; /* check whether this curve really needs a new keyframe */ - insert_mode= new_key_needed(icu, cfra, curval); + insert_mode= new_key_needed(fcu, cfra, curval); /* insert new keyframe at current frame */ if (insert_mode) - insert_vert_icu(icu, cfra, curval, (flag & INSERTKEY_FAST)); + insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST)); /* delete keyframe immediately before/after newly added */ switch (insert_mode) { case KEYNEEDED_DELPREV: - delete_icu_key(icu, icu->totvert-2, 1); + delete_fcurve_key(fcu, fcu->totvert-2, 1); break; case KEYNEEDED_DELNEXT: - delete_icu_key(icu, 1, 1); + delete_fcurve_key(fcu, 1, 1); break; } @@ -1153,7 +779,7 @@ short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrc } else { /* just insert keyframe */ - insert_vert_icu(icu, cfra, curval, (flag & INSERTKEY_FAST)); + insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST)); /* return success */ return 1; @@ -1164,7 +790,6 @@ short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrc return 0; } - /* ************************************************** */ /* KEYFRAME DELETION */ @@ -1175,31 +800,31 @@ short insertkey (ID *id, int blocktype, char *actname, char *constname, int adrc * The flag argument is used for special settings that alter the behaviour of * the keyframe deletion. These include the quick refresh options. */ -short deletekey (ID *id, int blocktype, char *actname, char *constname, int adrcode, short flag) +short deletekey (ID *id, const char rna_path[], int array_index, float cfra, short flag) { - Ipo *ipo; - IpoCurve *icu; + AnimData *adt= BKE_animdata_from_id(id); + nAction *act; + FCurve *fcu; - /* get ipo-curve - * Note: here is one of the places where we don't want new ipo + ipo-curve added! + /* get F-Curve + * Note: here is one of the places where we don't want new Action + F-Curve added! * so 'add' var must be 0 */ - ipo= verify_ipo(id, blocktype, actname, constname, NULL, 0); - icu= verify_ipocurve(id, blocktype, actname, constname, NULL, adrcode, 0); + // XXX we don't check the validity of the path here yet, but it should be ok... + fcu= verify_fcurve(adt, rna_path, array_index, 0); + act= adt->action; /* only continue if we have an ipo-curve to remove keyframes from */ - if (icu) { - float cfra = 1.0f;//frame_to_float(CFRA); + if (act && fcu) { short found = -1; int i; /* apply special time tweaking */ if (GS(id->name) == ID_OB) { - Object *ob= (Object *)id; + //Object *ob= (Object *)id; /* apply NLA-scaling (if applicable) */ - if (actname && actname[0]) - cfra= get_action_frame(ob, cfra); + // cfra= get_action_frame(ob, cfra); /* ancient time-offset cruft */ //if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) { @@ -1209,15 +834,16 @@ short deletekey (ID *id, int blocktype, char *actname, char *constname, int adrc } /* try to find index of beztriple to get rid of */ - i = binarysearch_bezt_index(icu->bezt, cfra, icu->totvert, &found); + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); if (found) { - /* delete the key at the index (will sanity check + do recalc afterwards ) */ - delete_icu_key(icu, i, 1); - - /* Only delete curve too if there isn't an ipo-driver still hanging around on an empty curve */ - if (icu->totvert==0 && icu->driver==NULL) { - BLI_remlink(&ipo->curve, icu); - free_ipo_curve(icu); + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + + /* Only delete curve too if there are no points (we don't need to check for drivers, as they're kept separate) */ + // XXX how do we handle drivers then? + if (fcu->totvert == 0) { + BLI_remlink(&act->curves, fcu); + free_fcurve(fcu); } /* return success */ @@ -1229,8 +855,8 @@ short deletekey (ID *id, int blocktype, char *actname, char *constname, int adrc return 0; } -/* ************************************************** */ -/* COMMON KEYFRAME MANAGEMENT (common_insertkey/deletekey) */ +/* ******************************************* */ +/* KEYFRAME MODIFICATION */ /* mode for common_modifykey */ enum { @@ -1238,6 +864,8 @@ enum { COMMONKEY_MODE_DELETE, } eCommonModifyKey_Modes; +#if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course + /* --------- KeyingSet Adrcode Getters ------------ */ /* initialise a channel-getter storage */ @@ -2096,7 +1724,7 @@ static void commonkey_context_finish (const bContext *C, ListBase *sources) } /* flush refreshes after undo */ -static void commonkey_context_refresh (const bContext *C) +static void commonkey_context_refresh (bContext *C) { ScrArea *curarea= CTX_wm_area(C); @@ -2190,7 +1818,7 @@ static bKeyingSet *get_keyingset_fromcontext (bKeyingContext *ksc, short index) /* ---------------- Keyframe Management API -------------------- */ /* Display a menu for handling the insertion of keyframes based on the active view */ -void common_modifykey (const bContext *C, short mode) +void common_modifykey (bContext *C, short mode) { ListBase dsources = {NULL, NULL}; bKeyingContext *ksc= NULL; @@ -2349,46 +1977,176 @@ void common_modifykey (const bContext *C, short mode) ob->pose->flag |= POSE_RECALCPATHS; /* clear unkeyed flag (it doesn't matter if it's set or not) */ - if (pchan->bone) - pchan->bone->flag &= ~BONE_UNKEYED; + // XXX old animation system + //if (pchan->bone) + // pchan->bone->flag &= ~BONE_UNKEYED; } + + // XXX for new system, need to remove overrides } } /* apply post-keying flushes for this data sources */ commonkey_context_finish(C, &dsources); - ksc->lastused= ks; /* free temp data */ BLI_freelistN(&dsources); - /* undo pushes */ - if (mode == COMMONKEY_MODE_DELETE) - BLI_snprintf(buf, 64, "Delete %s Key", ks->name); - else - BLI_snprintf(buf, 64, "Insert %s Key", ks->name); - //BIF_undo_push(buf); - /* queue updates for contexts */ commonkey_context_refresh(C); } -/* ---- */ +#endif // XXX old keyingsets code based on adrcodes... to be restored in due course + +/* Insert Key Operator ------------------------ */ + +/* XXX WARNING: + * This is currently just a basic operator, which work in 3d-view context on objects only + * and will insert keyframes for a few settings only. This is until it becomes clear how + * to separate (or not) the process for RNA-path creation between context + keyingsets. + * + * -- Joshua Leung, Jan 2009 + */ + +/* defines for basic insert-key testing operator */ + // XXX this will definitely be replaced +EnumPropertyItem prop_insertkey_types[] = { + {0, "LOC", "Location", ""}, + {1, "ROT", "Rotation", ""}, + {2, "SCALE", "Scale", ""}, + {3, "MAT_COL", "Active Material - Color", ""}, + {0, NULL, NULL, NULL} +}; + +static int insert_key_exec (bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + short mode= RNA_enum_get(op->ptr, "type"); + float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + + // XXX more comprehensive tests will be needed + CTX_DATA_BEGIN(C, Base*, base, selected_bases) + { + Object *ob= base->object; + ID *id= (ID *)ob; + short success= 0; + + /* check which keyframing mode chosen for this object */ + switch (mode) { + case 3: /* color of active material */ + // NOTE: this is just a demo... but ideally we'd go through materials instead of active one only so reference stays same + success+= insertkey(id, "active_material.diffuse_color", 0, cfra, 0); + success+= insertkey(id, "active_material.diffuse_color", 1, cfra, 0); + success+= insertkey(id, "active_material.diffuse_color", 2, cfra, 0); + break; + case 2: /* scale */ + success+= insertkey(id, "scale", 0, cfra, 0); + success+= insertkey(id, "scale", 1, cfra, 0); + success+= insertkey(id, "scale", 2, cfra, 0); + case 1: /* rotation */ + success+= insertkey(id, "rotation", 0, cfra, 0); + success+= insertkey(id, "rotation", 1, cfra, 0); + success+= insertkey(id, "rotation", 2, cfra, 0); + default: /* location */ + success+= insertkey(id, "location", 0, cfra, 0); + success+= insertkey(id, "location", 1, cfra, 0); + success+= insertkey(id, "location", 2, cfra, 0); + break; + } + + printf("Ob '%s' - Successfully added %d Keyframes \n", id->name+2, success); + + ob->recalc |= OB_RECALC_OB; + } + CTX_DATA_END; + + /* send updates */ + ED_anim_dag_flush_update(C); + ED_undo_push(C, "Insert Keyframe"); + + if (mode == 3) // material color requires different notifiers + WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING_DRAW, NULL); + else + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; +} -/* used to insert keyframes from any view */ -void common_insertkey (const bContext *C) +void ANIM_OT_insert_keyframe (wmOperatorType *ot) { - common_modifykey(C, COMMONKEY_MODE_INSERT); + PropertyRNA *prop; + + /* identifiers */ + ot->name= "Insert Keyframe"; + ot->idname= "ANIM_OT_insert_keyframe"; + + /* callbacks */ + ot->invoke= WM_menu_invoke; // XXX we will need our own one eventually, to cope with the dynamic menus... + ot->exec= insert_key_exec; + + /* properties */ + // XXX update this for the latest RNA stuff styles... + prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_insertkey_types); } -/* used to insert keyframes from any view */ -void common_deletekey (const bContext *C) +/* Delete Key Operator ------------------------ */ + +/* XXX WARNING: + * This is currently just a basic operator, which work in 3d-view context on objects only. + * -- Joshua Leung, Jan 2009 + */ + +static int delete_key_exec (bContext *C, wmOperator *op) { - common_modifykey(C, COMMONKEY_MODE_DELETE); + Scene *scene= CTX_data_scene(C); + float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap + + // XXX more comprehensive tests will be needed + CTX_DATA_BEGIN(C, Base*, base, selected_bases) + { + Object *ob= base->object; + ID *id= (ID *)ob; + nAction *act= ob->adt.action; + FCurve *fcu, *fcn; + short success= 0; + + /* loop through all curves in animdata and delete keys on this frame */ + if (act) { + for (fcu= act->curves.first; fcu; fcu= fcn) { + fcn= fcu->next; + success+= deletekey(id, fcu->rna_path, fcu->array_index, cfra, 0); + } + } + + printf("Ob '%s' - Successfully removed %d keyframes \n", id->name+2, success); + + ob->recalc |= OB_RECALC_OB; + } + CTX_DATA_END; + + /* send updates */ + ED_anim_dag_flush_update(C); + ED_undo_push(C, "Delete Keyframe"); + + // XXX what if it was a material keyframe? + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + + return OPERATOR_FINISHED; } +void ANIM_OT_delete_keyframe (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete Keyframe"; + ot->idname= "ANIM_OT_delete_keyframe"; + + /* callbacks */ + ot->invoke= WM_operator_confirm; // XXX we will need our own one eventually, to cope with the dynamic menus... + ot->exec= delete_key_exec; +} -/* ************************************************** */ +/* ******************************************* */ /* KEYFRAME DETECTION */ /* --------------- API/Per-Datablock Handling ------------------- */ @@ -2396,35 +2154,35 @@ void common_deletekey (const bContext *C) /* Checks whether an IPO-block has a keyframe for a given frame * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found... */ -short ipo_frame_has_keyframe (Ipo *ipo, float frame, short filter) +short action_frame_has_keyframe (nAction *act, float frame, short filter) { - IpoCurve *icu; + FCurve *fcu; /* can only find if there is data */ - if (ipo == NULL) + if (act == NULL) return 0; /* if only check non-muted, check if muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (ipo->muteipo)) + if ((filter & ANIMFILTER_KEYS_MUTED) || (act->flag & ACT_MUTED)) return 0; - /* loop over IPO-curves, using binary-search to try to find matches + /* loop over F-Curves, using binary-search to try to find matches * - this assumes that keyframes are only beztriples */ - for (icu= ipo->curve.first; icu; icu= icu->next) { + for (fcu= act->curves.first; fcu; fcu= fcu->next) { /* only check if there are keyframes (currently only of type BezTriple) */ - if (icu->bezt) { + if (fcu->bezt) { /* we either include all regardless of muting, or only non-muted */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (icu->flag & IPO_MUTE)==0) { + if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) { short replace = -1; - int i = binarysearch_bezt_index(icu->bezt, frame, icu->totvert, &replace); + int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace); /* binarysearch_bezt_index will set replace to be 0 or 1 * - obviously, 1 represents a match */ if (replace) { /* sanity check: 'i' may in rare cases exceed arraylen */ - if ((i >= 0) && (i < icu->totvert)) + if ((i >= 0) && (i < fcu->totvert)) return 1; } } @@ -2435,32 +2193,6 @@ short ipo_frame_has_keyframe (Ipo *ipo, float frame, short filter) return 0; } -/* Checks whether an action-block has a keyframe for a given frame - * Since we're only concerned whether a keyframe exists, we can simply loop until a match is found... - */ -short action_frame_has_keyframe (bAction *act, float frame, short filter) -{ - bActionChannel *achan; - - /* error checking */ - if (act == NULL) - return 0; - - /* check thorugh action-channels for match */ - for (achan= act->chanbase.first; achan; achan= achan->next) { - /* we either include all regardless of muting, or only non-muted - * - here we include 'hidden' channels in the muted definition - */ - if ((filter & ANIMFILTER_KEYS_MUTED) || (achan->flag & ACHAN_HIDDEN)==0) { - if (ipo_frame_has_keyframe(achan->ipo, frame, filter)) - return 1; - } - } - - /* nothing found */ - return 0; -} - /* Checks whether an Object has a keyframe for a given frame */ short object_frame_has_keyframe (Object *ob, float frame, short filter) { @@ -2468,35 +2200,9 @@ short object_frame_has_keyframe (Object *ob, float frame, short filter) if (ob == NULL) return 0; - /* check for an action - actions take priority over normal IPO's */ - if (ob->action) { - float aframe; - - /* apply nla-action scaling if needed */ - if ((ob->nlaflag & OB_NLA_OVERRIDE) && (ob->nlastrips.first)) - aframe= get_action_frame(ob, frame); - else - aframe= frame; - - /* priority check here goes to pose-channel checks (for armatures) */ - if ((ob->pose) && (ob->flag & OB_POSEMODE)) { - /* only relevant check here is to only show active... */ - if (filter & ANIMFILTER_KEYS_ACTIVE) { - bPoseChannel *pchan= get_active_posechannel(ob); - bActionChannel *achan= (pchan) ? get_action_channel(ob->action, pchan->name) : NULL; - - /* since we're only interested in whether the selected one has any keyframes... */ - return (achan && ipo_frame_has_keyframe(achan->ipo, aframe, filter)); - } - } - - /* for everything else, just use the standard test (only return if success) */ - if (action_frame_has_keyframe(ob->action, aframe, filter)) - return 1; - } - else if (ob->ipo) { - /* only return if success */ - if (ipo_frame_has_keyframe(ob->ipo, frame, filter)) + /* check own animation data - specifically, the action it contains */ + if (ob->adt.action) { + if (action_frame_has_keyframe(ob->adt.action, frame, filter)) return 1; } @@ -2548,40 +2254,32 @@ short object_frame_has_keyframe (Object *ob, float frame, short filter) /* Checks whether a keyframe exists for the given ID-block one the given frame */ short id_frame_has_keyframe (ID *id, float frame, short filter) { - /* error checking */ + /* sanity checks */ if (id == NULL) return 0; - /* check for a valid id-type */ + /* perform special checks for 'macro' types */ switch (GS(id->name)) { - /* animation data-types */ - case ID_IP: /* ipo */ - return ipo_frame_has_keyframe((Ipo *)id, frame, filter); - case ID_AC: /* action */ - return action_frame_has_keyframe((bAction *)id, frame, filter); - case ID_OB: /* object */ return object_frame_has_keyframe((Object *)id, frame, filter); - - case ID_MA: /* material */ - { - Material *ma= (Material *)id; - - /* currently, material's only have an ipo-block */ - return ipo_frame_has_keyframe(ma->ipo, frame, filter); - } break; - case ID_KE: /* shapekey */ + case ID_SCE: /* scene */ + // XXX TODO... for now, just use 'normal' behaviour + // break; + + default: /* 'normal type' */ { - Key *key= (Key *)id; + AnimData *adt= BKE_animdata_from_id(id); - /* currently, shapekey's only have an ipo-block */ - return ipo_frame_has_keyframe(key->ipo, frame, filter); + /* only check keyframes in active action */ + if (adt) + return action_frame_has_keyframe(adt->action, frame, filter); } break; } + /* no keyframe found */ return 0; } |