diff options
Diffstat (limited to 'source')
19 files changed, 514 insertions, 54 deletions
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 3c3abe11da3..89e5f1af7e1 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -59,9 +59,13 @@ void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt); short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end); void BKE_nlatrack_sort_strips(struct NlaTrack *nlt); +struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt); short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max); void BKE_nla_action_pushdown(struct AnimData *adt); +short BKE_nla_tweakmode_enter(struct AnimData *adt); +void BKE_nla_tweakmode_exit(struct AnimData *adt); + #endif diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 652f733d553..dbc38d2fc7e 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -118,6 +118,9 @@ void BKE_free_animdata (ID *id) /* unlink action (don't free, as it's in its own list) */ if (adt->action) adt->action->id.us--; + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + adt->tmpact->id.us--; /* free nla data */ free_nladata(&adt->nla_tracks); @@ -151,6 +154,7 @@ AnimData *BKE_copy_animdata (AnimData *adt) // XXX review this... it might not be optimal behaviour yet... //id_us_plus((ID *)dadt->action); dadt->action= copy_action(adt->action); + dadt->tmpact= copy_action(adt->action); /* duplicate NLA data */ copy_nladata(&dadt->nla_tracks, &adt->nla_tracks); @@ -595,7 +599,7 @@ static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert) scale = (float)fabs(strip->scale); /* scale must be positive - we've got a special flag for reversing */ /* length of referenced action */ - actlength = strip->actend-strip->actstart; + actlength = strip->actend - strip->actstart; if (actlength == 0.0f) actlength = 1.0f; /* length of strip */ @@ -630,11 +634,11 @@ static float nlastrip_get_influence (NlaStrip *strip, float cframe) // the +0.0001 factors are to combat rounding errors if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) { /* there is some blend-in */ - return (float)(fabs(cframe - strip->start) + 0.0001) / (strip->blendin); + return (float)fabs(cframe - strip->start) / (strip->blendin); } else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) { /* there is some blend-out */ - return (float)(fabs(strip->end - cframe) + 0.0001) / (strip->blendout); + return (float)fabs(strip->end - cframe) / (strip->blendout); } else { /* in the middle of the strip, we should be full strength */ @@ -674,8 +678,8 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index NlaEvalStrip *nes; short side= 0; - /* skip if track is muted */ - if (nlt->flag & NLATRACK_MUTED) + /* skip if track is muted or disabled */ + if (nlt->flag & (NLATRACK_MUTED|NLATRACK_DISABLED)) return; /* loop over strips, checking if they fall within the range */ @@ -1104,6 +1108,7 @@ void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short re * - NLA before Active Action, as Active Action behaves as 'tweaking track' * that overrides 'rough' work in NLA */ + // TODO: need to double check that this all works correctly if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM)) { /* evaluate NLA data */ diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 6235ec58d40..84f98096364 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -583,4 +583,104 @@ void BKE_nla_action_pushdown (AnimData *adt) } } + +/* Find the active strip + track combo, and set them up as the tweaking track, + * and return if successful or not. + */ +short BKE_nla_tweakmode_enter (AnimData *adt) +{ + NlaTrack *nlt, *activeTrack=NULL; + NlaStrip *strip, *activeStrip=NULL; + + /* verify that data is valid */ + if ELEM(NULL, adt, adt->nla_tracks.first) + return 0; + + /* if block is already in tweakmode, just leave, but we should report + * that this block is in tweakmode (as our returncode) + */ + // FIXME: hopefully the flag is correct! + if (adt->flag & ADT_NLA_EDIT_ON) + return 1; + + /* go over the tracks, finding the active one, and its active strip + * - if we cannot find both, then there's nothing to do + */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) { + /* check if active */ + if (nlt->flag & NLATRACK_ACTIVE) { + /* store reference to this active track */ + activeTrack= nlt; + + /* now try to find active strip */ + activeStrip= BKE_nlastrip_find_active(nlt); + break; + } + } + if ELEM3(NULL, activeTrack, activeStrip, activeStrip->act) { + printf("NLA tweakmode enter - neither active requirement found \n"); + return 0; + } + + /* go over all the tracks up to the active one, tagging each strip that uses the same + * action as the active strip, but leaving everything else alone + */ + for (nlt= activeTrack->prev; nlt; nlt= nlt->prev) { + for (strip= nlt->strips.first; strip; strip= strip->next) { + if (strip->act == activeStrip->act) + strip->flag |= NLASTRIP_FLAG_TWEAKUSER; + else + strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER; // XXX probably don't need to clear this... + } + } + + + /* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled + * - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on + */ + for (nlt= activeTrack; nlt; nlt= nlt->next) + nlt->flag |= NLATRACK_DISABLED; + + /* handle AnimData level changes: + * - 'real' active action to temp storage (no need to change user-counts) + * - action of active strip set to be the 'active action' + * - editing-flag for this AnimData block should also get turned on (for more efficient restoring) + */ + adt->tmpact= adt->action; + adt->action= activeStrip->act; + adt->flag |= ADT_NLA_EDIT_ON; + + /* done! */ + return 1; +} + +/* Exit tweakmode for this AnimData block */ +void BKE_nla_tweakmode_exit (AnimData *adt) +{ + NlaTrack *nlt; + + /* verify that data is valid */ + if ELEM(NULL, adt, adt->nla_tracks.first) + return; + + /* hopefully the flag is correct - skip if not on */ + if ((adt->flag & ADT_NLA_EDIT_ON) == 0) + return; + + // TODO: need to sync the user-strip with the new state of the action! + + /* for all NLA-tracks, clear the 'disabled' flag */ + for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) + nlt->flag &= ~NLATRACK_DISABLED; + + /* handle AnimData level changes: + * - 'real' active action is restored from storage + * - storage pointer gets cleared (to avoid having bad notes hanging around) + * - editing-flag for this AnimData block should also get turned off + */ + adt->action= adt->tmpact; + adt->tmpact= NULL; + adt->flag &= ~ADT_NLA_EDIT_ON; +} + /* *************************************************** */ diff --git a/source/blender/editors/animation/anim_channels.c b/source/blender/editors/animation/anim_channels.c index 658bff73978..59fb56f3c35 100644 --- a/source/blender/editors/animation/anim_channels.c +++ b/source/blender/editors/animation/anim_channels.c @@ -90,14 +90,13 @@ /* -------------------------- Exposed API ----------------------------------- */ /* Set the given animation-channel as the active one for the active context */ -void ANIM_set_active_channel (void *data, short datatype, int filter, void *channel_data, short channel_type) +void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type) { ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; /* try to build list of filtered items */ - // XXX we don't need/supply animcontext for now, since in this case, there's nothing really essential there that isn't already covered - ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype); + ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); if (anim_data.first == NULL) return; @@ -151,8 +150,7 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan case ANIMTYPE_NLATRACK: { NlaTrack *nlt= (NlaTrack *)channel_data; - - ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); + nlt->flag |= NLATRACK_ACTIVE; } break; } @@ -1474,7 +1472,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s /* if group is selected now, make group the 'active' one in the visible list */ if (agrp->flag & AGRP_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } } break; @@ -1520,7 +1518,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ if (fcu->flag & FCURVE_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } break; diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index ed526bd99a0..32405571b57 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -343,19 +343,33 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) /* quick macro to test if AnimData is usable for NLA */ #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first) -/* quick macro to test for all three avove usability tests, performing the appropriate provided + +/* Quick macro to test for all three avove usability tests, performing the appropriate provided * action for each when the AnimData context is appropriate. * - * Priority order for this goes (most important, to least): NLA, Drivers, Keyframes + * Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes. + * + * For this to work correctly, a standard set of data needs to be available within the scope that this + * gets called in: + * - ListBase anim_data; + * - bDopeSheet *ads; + * - bAnimListElem *ale; + * - int items; * * - id: ID block which should have an AnimData pointer following it immediately, to use + * - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA) * - nlaOk: line or block of code to execute for NLA case * - driversOk: line or block of code to execute for Drivers case * - keysOk: line or block of code for Keyframes case */ -#define ANIMDATA_FILTER_CASES(id, nlaOk, driversOk, keysOk) \ +#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \ {\ - if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ + if (filter_mode & ANIMFILTER_ANIMDATA) {\ + if ((id)->adt) {\ + adtOk\ + }\ + }\ + else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\ if (ANIMDATA_HAS_NLA(id)) {\ nlaOk\ }\ @@ -376,6 +390,18 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) } +/* quick macro to add a pointer to an AnimData block as a channel */ +#define ANIMDATA_ADD_ANIMDATA(id) \ + {\ + ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\ + if (ale) {\ + BLI_addtail(anim_data, ale);\ + items++;\ + }\ + } + + + /* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */ #define ANIMCHANNEL_SELOK(test_func) \ ( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \ @@ -713,6 +739,11 @@ static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_m items++; } } + + /* if we're in NLA-tweakmode, if this track was active, that means that it was the last active one */ + // FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel + if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_ACTIVE)) + break; } } } @@ -890,6 +921,7 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* check if ok */ ANIMDATA_FILTER_CASES(ma, + { /* AnimData blocks - do nothing... */ }, ok=1;, ok=1;, ok=1;) @@ -933,6 +965,7 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, /* add material's animation data */ if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) { ANIMDATA_FILTER_CASES(ma, + { /* AnimData blocks - do nothing... */ }, items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);, items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);, items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);) @@ -998,6 +1031,7 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) { /* filtering for channels - nla, drivers, keyframes */ ANIMDATA_FILTER_CASES(iat, + { /* AnimData blocks - do nothing... */ }, items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);, items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);, items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);) @@ -1036,6 +1070,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if (ob->adt) { adt= ob->adt; ANIMDATA_FILTER_CASES(ob, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1091,6 +1126,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) { adt= key->adt; ANIMDATA_FILTER_CASES(key, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1151,6 +1187,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) { ANIMDATA_FILTER_CASES(ca, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1163,6 +1200,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) { ANIMDATA_FILTER_CASES(la, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1175,6 +1213,7 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) { ANIMDATA_FILTER_CASES(cu, + { /* AnimData blocks - do nothing... */ }, obdata_ok= 1;, obdata_ok= 1;, obdata_ok= 1;) @@ -1216,6 +1255,7 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) { adt= sce->adt; ANIMDATA_FILTER_CASES(sce, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1266,9 +1306,10 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads /* world */ if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) { - /* Action, Drivers, or NLA for World */ + /* Action, Drivers, or NLA for World */ adt= wo->adt; ANIMDATA_FILTER_CASES(wo, + { /* AnimData blocks - do nothing... */ }, { /* nla */ #if 0 /* include nla-expand widget? */ @@ -1327,6 +1368,7 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int { Scene *sce= (Scene *)ads->source; Base *base; + bAnimListElem *ale; int items = 0; /* check that we do indeed have a scene */ @@ -1342,11 +1384,25 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int /* check filtering-flags if ok */ ANIMDATA_FILTER_CASES(sce, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(sce); + sceOk=0; + }, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);, sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);) if (sce->world) { ANIMDATA_FILTER_CASES(sce->world, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(sce->world); + worOk=0; + }, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);, worOk= !(ads->filterflag & ADS_FILTER_NOWOR);) @@ -1395,12 +1451,26 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int actOk= 0; keyOk= 0; ANIMDATA_FILTER_CASES(ob, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ob); + actOk=0; + }, actOk= 1;, actOk= 1;, actOk= 1;) if (key) { /* shapekeys */ ANIMDATA_FILTER_CASES(key, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(key); + keyOk=0; + }, keyOk= 1;, keyOk= 1;, keyOk= 1;) @@ -1419,6 +1489,13 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int /* if material has relevant animation data, break */ ANIMDATA_FILTER_CASES(ma, + { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ma); + matOk=0; + }, matOk= 1;, matOk= 1;, matOk= 1;) @@ -1435,6 +1512,13 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int Camera *ca= (Camera *)ob->data; dataOk= 0; ANIMDATA_FILTER_CASES(ca, + if ((ads->filterflag & ADS_FILTER_NOCAM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(ca); + dataOk=0; + }, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);) @@ -1445,11 +1529,35 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int Lamp *la= (Lamp *)ob->data; dataOk= 0; ANIMDATA_FILTER_CASES(la, + if ((ads->filterflag & ADS_FILTER_NOLAM)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(la); + dataOk=0; + }, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);, dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);) } break; + case OB_CURVE: /* ------- Curve ---------- */ + { + Curve *cu= (Curve *)ob->data; + dataOk= 0; + ANIMDATA_FILTER_CASES(cu, + if ((ads->filterflag & ADS_FILTER_NOCUR)==0) { + /* for the special AnimData blocks only case, we only need to add + * the block if it is valid... then other cases just get skipped (hence ok=0) + */ + ANIMDATA_ADD_ANIMDATA(cu); + dataOk=0; + }, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);, + dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);) + } + break; default: /* --- other --- */ dataOk= 0; break; diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index cdd8b5c368c..dcaabb4b369 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -107,6 +107,7 @@ typedef struct bAnimListElem { // XXX was ACTTYPE_* typedef enum eAnim_ChannelType { ANIMTYPE_NONE= 0, + ANIMTYPE_ANIMDATA, ANIMTYPE_SPECIALDATA, ANIMTYPE_SCENE, @@ -162,6 +163,7 @@ typedef enum eAnimFilter_Flags { ANIMFILTER_ACTGROUPED = (1<<6), /* belongs to the active actiongroup */ ANIMFILTER_CURVEVISIBLE = (1<<7), /* F-Curve is visible for editing/viewing in Graph Editor */ ANIMFILTER_ACTIVE = (1<<8), /* channel should be 'active' */ // FIXME: this is only relevant for F-Curves for now + ANIMFILTER_ANIMDATA = (1<<9), /* only return the underlying AnimData blocks (not the tracks, etc.) data comes from */ } eAnimFilter_Flags; @@ -254,7 +256,7 @@ short ANIM_animdata_context_getdata(bAnimContext *ac); void ANIM_deselect_anim_channels(void *data, short datatype, short test, short sel); /* Set the 'active' channel of type channel_type, in the given action */ -void ANIM_set_active_channel(void *data, short datatype, int filter, void *channel_data, short channel_type); +void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type); /* --------------- Settings and/or Defines -------------- */ @@ -308,6 +310,8 @@ void ipo_rainbow(int cur, int tot, float *out); /* ------------- NLA-Mapping ----------------------- */ /* anim_draw.c */ +// XXX these are soon to be depreceated? + /* Obtain the Object providing NLA-scaling for the given channel if applicable */ struct Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index c2beb34e7b5..e3b6572c03a 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -118,6 +118,7 @@ int ED_operator_node_active(struct bContext *C); int ED_operator_ipo_active(struct bContext *C); int ED_operator_sequencer_active(struct bContext *C); int ED_operator_image_active(struct bContext *C); +int ED_operator_nla_active(struct bContext *C); int ED_operator_object_active(struct bContext *C); int ED_operator_editmesh(struct bContext *C); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index be952558b6c..db1a39ed056 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -164,6 +164,7 @@ int ED_operator_node_active(bContext *C) return 0; } +// XXX rename int ED_operator_ipo_active(bContext *C) { return ed_spacetype_test(C, SPACE_IPO); @@ -179,6 +180,11 @@ int ED_operator_image_active(bContext *C) return ed_spacetype_test(C, SPACE_IMAGE); } +int ED_operator_nla_active(bContext *C) +{ + return ed_spacetype_test(C, SPACE_NLA); +} + int ED_operator_object_active(bContext *C) { return NULL != CTX_data_active_object(C); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f64cd0f707c..d8ed3fd1068 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -862,13 +862,13 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode, bActionGroup *agrp= ale->data; agrp->flag |= AGRP_SELECTED; - ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); } else if (ale->type == ANIMTYPE_FCURVE) { FCurve *fcu= ale->data; fcu->flag |= FCURVE_SELECTED; - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } else if (ac->datatype == ANIMCONT_GPENCIL) { diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index bb923ca6f95..21320b60ead 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -722,7 +722,7 @@ static void mouse_graph_keys (bAnimContext *ac, int mval[], short select_mode, s /* set active F-Curve (NOTE: sync the filter flags with findnearest_fcurve_vert) */ if (fcu->flag & FCURVE_SELECTED) { filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY); - ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); } } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index a839ccbf3d6..8db85ffa0b1 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -349,7 +349,7 @@ static void mouse_nla_channels (bAnimContext *ac, float x, int channel_index, sh /* if NLA-Track is selected now, make NLA-Track the 'active' one in the visible list */ if (nlt->flag & NLATRACK_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); } } break; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 85bf733df87..6c4c64ea272 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -137,7 +137,7 @@ static void nla_draw_strip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, View2 /* only need to draw here if there's no strip before since * it only applies in such a situation */ - if (strip->prev) { + if (strip->prev == NULL) { /* set the drawing color to the color of the strip, but with very faint alpha */ glColor4f(color[0], color[1], color[2], 0.15f); @@ -563,15 +563,20 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) else special= ICON_LAYER_USED; - if (nlt->flag & NLATRACK_MUTED) - mute = ICON_MUTE_IPO_ON; - else - mute = ICON_MUTE_IPO_OFF; - - if (EDITABLE_NLT(nlt)) - protect = ICON_UNLOCKED; - else - protect = ICON_LOCKED; + /* if this track is active and we're tweaking it, don't draw these toggles */ + // TODO: need a special macro for this... + if ( ((nlt->flag & NLATRACK_ACTIVE) && (nlt->flag & NLATRACK_DISABLED)) == 0 ) + { + if (nlt->flag & NLATRACK_MUTED) + mute = ICON_MUTE_IPO_ON; + else + mute = ICON_MUTE_IPO_OFF; + + if (EDITABLE_NLT(nlt)) + protect = ICON_UNLOCKED; + else + protect = ICON_LOCKED; + } sel = SEL_NLT(nlt); strcpy(name, nlt->name); @@ -636,18 +641,29 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) } else if (group == 5) { /* Action Line */ - if (ale->data) - glColor3f(0.8f, 0.2f, 0.0f); // reddish color - hardcoded for now - else - glColor3f(0.6f, 0.5f, 0.5f); // greyish-red color - hardcoded for now - + AnimData *adt= BKE_animdata_from_id(ale->id); + + // TODO: if tweaking some action, use the same color as for the tweaked track (quick hack done for now) + if (adt && (adt->flag & ADT_NLA_EDIT_ON)) { + // greenish color (same as tweaking strip) - hardcoded for now + glColor3f(0.3f, 0.95f, 0.1f); + } + else { + if (ale->data) + glColor3f(0.8f, 0.2f, 0.0f); // reddish color - hardcoded for now + else + glColor3f(0.6f, 0.5f, 0.5f); // greyish-red color - hardcoded for now + } + offset += 7 * indent; /* only on top two corners, to show that this channel sits on top of the preceeding ones */ uiSetRoundBox((1|2)); - /* draw slightly shifted up vertically to look like it has more separtion from other channels */ - gl_round_box(GL_POLYGON, x+offset, yminc+NLACHANNEL_SKIP, (float)NLACHANNEL_NAMEWIDTH, ymaxc+NLACHANNEL_SKIP, 8); + /* draw slightly shifted up vertically to look like it has more separtion from other channels, + * but we then need to slightly shorten it so that it doesn't look like it overlaps + */ + gl_round_box(GL_POLYGON, x+offset, yminc+NLACHANNEL_SKIP, (float)NLACHANNEL_NAMEWIDTH, ymaxc+NLACHANNEL_SKIP-1, 8); /* clear group value, otherwise we cause errors... */ group = 0; @@ -709,20 +725,29 @@ void draw_nla_channel_list (bAnimContext *ac, SpaceNla *snla, ARegion *ar) UI_icon_draw((float)(NLACHANNEL_NAMEWIDTH-offset), ydatac, mute); } - /* draw action 'push-down' - only for NLA-Action lines, and only when there's an action */ + /* draw NLA-action line 'status-icons' - only when there's an action */ if ((ale->type == ANIMTYPE_NLAACTION) && (ale->data)) { - offset += 16; + AnimData *adt= BKE_animdata_from_id(ale->id); - /* XXX firstly draw a little rect to help identify that it's different from the toggles */ - glBegin(GL_LINE_LOOP); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9); - glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7); - glEnd(); // GL_LINES + offset += 16; - /* now draw the icon */ - UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE); + /* now draw some indicator icons */ + if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) { + /* 'tweaking action' - not a button */ + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_EDIT); + } + else { + /* XXX firstly draw a little rect to help identify that it's different from the toggles */ + glBegin(GL_LINE_LOOP); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y-7); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-offset-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y+9); + glVertex2f((float)NLACHANNEL_NAMEWIDTH-1, y-7); + glEnd(); // GL_LINES + + /* 'push down' icon for normal active-actions */ + UI_icon_draw((float)NLACHANNEL_NAMEWIDTH-offset, ydatac, ICON_FREEZE); + } } glDisable(GL_BLEND); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index ce9ae7de7a9..f7053957667 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -68,6 +68,143 @@ #include "nla_intern.h" // own include /* *********************************************** */ +/* General Editing */ + +/* ******************** Tweak-Mode Operators ***************************** */ +/* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited + * as if it were the normal Active-Action of its AnimData block. + */ + +static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + int ok=0; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get a list of the AnimData blocks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* if no blocks, popup error? */ + if (anim_data.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for"); + return OPERATOR_CANCELLED; + } + + /* for each AnimData block with NLA-data, try setting it in tweak-mode */ + for (ale= anim_data.first; ale; ale= ale->next) { + AnimData *adt= ale->data; + + /* try entering tweakmode if valid */ + ok += BKE_nla_tweakmode_enter(adt); + } + + /* free temp data */ + BLI_freelistN(&anim_data); + + /* if we managed to enter tweakmode on at least one AnimData block, + * set the flag for this in the active scene and send notifiers + */ + if (ac.scene && ok) { + /* set editing flag */ + ac.scene->flag |= SCE_NLA_EDIT_ON; + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + WM_event_add_notifier(C, NC_SCENE, NULL); + } + + /* done */ + return OPERATOR_FINISHED; +} + +void NLAEDIT_OT_tweakmode_enter (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Enter Tweak Mode"; + ot->idname= "NLAEDIT_OT_tweakmode_enter"; + ot->description= "Enter tweaking mode for the action referenced by the active strip."; + + /* api callbacks */ + ot->exec= nlaedit_enable_tweakmode_exec; + ot->poll= nlaop_poll_tweakmode_off; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* ------------- */ + +static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + /* get a list of the AnimData blocks being shown in the NLA */ + filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* if no blocks, popup error? */ + if (anim_data.first == NULL) { + BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for"); + return OPERATOR_CANCELLED; + } + + /* for each AnimData block with NLA-data, try exitting tweak-mode */ + for (ale= anim_data.first; ale; ale= ale->next) { + AnimData *adt= ale->data; + + /* try entering tweakmode if valid */ + BKE_nla_tweakmode_exit(adt); + } + + /* free temp data */ + BLI_freelistN(&anim_data); + + /* if we managed to enter tweakmode on at least one AnimData block, + * set the flag for this in the active scene and send notifiers + */ + if (ac.scene) { + /* clear editing flag */ + ac.scene->flag &= ~SCE_NLA_EDIT_ON; + + /* set notifier that things have changed */ + ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH); + WM_event_add_notifier(C, NC_SCENE, NULL); + } + + /* done */ + return OPERATOR_FINISHED; +} + +void NLAEDIT_OT_tweakmode_exit (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Exit Tweak Mode"; + ot->idname= "NLAEDIT_OT_tweakmode_exit"; + ot->description= "Exit tweaking mode for the action referenced by the active strip."; + + /* api callbacks */ + ot->exec= nlaedit_disable_tweakmode_exec; + ot->poll= nlaop_poll_tweakmode_on; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} /* *********************************************** */ diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 448b823bd4b..a7188a7cccd 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -76,6 +76,9 @@ void NLAEDIT_OT_click_select(wmOperatorType *ot); /* **************************************** */ /* nla_edit.c */ +void NLAEDIT_OT_tweakmode_enter(wmOperatorType *ot); +void NLAEDIT_OT_tweakmode_exit(wmOperatorType *ot); + /* **************************************** */ /* nla_channels.c */ @@ -85,6 +88,11 @@ void NLA_OT_channels_click(wmOperatorType *ot); /* **************************************** */ /* nla_ops.c */ +int nlaop_poll_tweakmode_off(bContext *C); +int nlaop_poll_tweakmode_on (bContext *C); + +/* --- */ + void nla_operatortypes(void); void nla_keymap(wmWindowManager *wm); diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 167686c99f9..057e4b05656 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -65,6 +65,51 @@ #include "nla_intern.h" // own include +/* ************************** poll callbacks for operators **********************************/ + +/* tweakmode is NOT enabled */ +int nlaop_poll_tweakmode_off (bContext *C) +{ + Scene *scene; + + /* for now, we check 2 things: + * 1) active editor must be NLA + * 2) tweakmode is currently set as a 'per-scene' flag + * so that it will affect entire NLA data-sets, + * but not all AnimData blocks will be in tweakmode for + * various reasons + */ + if (ED_operator_nla_active(C) == 0) + return 0; + + scene= CTX_data_scene(C); + if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) + return 0; + + return 1; +} + +/* tweakmode IS enabled */ +int nlaop_poll_tweakmode_on (bContext *C) +{ + Scene *scene; + + /* for now, we check 2 things: + * 1) active editor must be NLA + * 2) tweakmode is currently set as a 'per-scene' flag + * so that it will affect entire NLA data-sets, + * but not all AnimData blocks will be in tweakmode for + * various reasons + */ + if (ED_operator_nla_active(C) == 0) + return 0; + + scene= CTX_data_scene(C); + if ((scene == NULL) || !(scene->flag & SCE_NLA_EDIT_ON)) + return 0; + + return 1; +} /* ************************** registration - operator types **********************************/ @@ -77,6 +122,10 @@ void nla_operatortypes(void) /* select */ WM_operatortype_append(NLAEDIT_OT_click_select); WM_operatortype_append(NLAEDIT_OT_select_all_toggle); + + /* edit */ + WM_operatortype_append(NLAEDIT_OT_tweakmode_enter); + WM_operatortype_append(NLAEDIT_OT_tweakmode_exit); } /* ************************** registration - keymaps **********************************/ @@ -130,6 +179,13 @@ static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap) WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "NLAEDIT_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1); + /* editing */ + /* tweakmode + * - enter and exit are separate operators with the same hotkey... + * This works as they use different poll()'s + */ + WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0); /* transform system */ //transform_keymap_for_space(wm, keymap, SPACE_NLA); diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 0626d9febe4..2e3d5572711 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -300,8 +300,7 @@ static void mouse_nla_strips (bAnimContext *ac, int mval[2], short select_mode) NlaTrack *nlt= (NlaTrack *)ale->data; nlt->flag |= NLATRACK_SELECTED; - if (nlt->flag & NLATRACK_SELECTED) - ANIM_set_active_channel(ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); + ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); } } diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index e41ab5ac492..a566f733978 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -269,6 +269,7 @@ typedef enum eAction_Flags { /* flags for evaluation/editing */ ACT_MUTED = (1<<9), ACT_PROTECTED = (1<<10), + ACT_DISABLED = (1<<11), } eAction_Flags; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index ffc1561e7ab..c19318629f6 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -506,6 +506,9 @@ enum { NLATRACK_SOLO = (1<<3), /* track's settings (and strips) cannot be edited (to guard against unwanted changes) */ NLATRACK_PROTECTED = (1<<4), + + /* track is not allowed to execute, usually as result of tweaking being enabled (internal flag) */ + NLATRACK_DISABLED = (1<<10), } eNlaTrack_Flag; @@ -648,11 +651,15 @@ typedef struct AnimOverride { * blocks may override local settings. * * This datablock should be placed immediately after the ID block where it is used, so that - * the code which retrieves this data can do so in an easier manner. See blenkernel/internal/anim_sys.c for details. + * the code which retrieves this data can do so in an easier manner. See blenkernel/intern/anim_sys.c for details. */ typedef struct AnimData { /* active action - acts as the 'tweaking track' for the NLA */ - bAction *action; + bAction *action; + /* temp-storage for the 'real' active action (i.e. the one used before the tweaking-action + * took over to be edited in the Animation Editors) + */ + bAction *tmpact; /* remapping-info for active action - should only be used if needed * (for 'foreign' actions that aren't working correctly) */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 6f88a98fee8..8acefdad9a2 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -832,6 +832,7 @@ typedef struct Scene { /* sce->flag */ #define SCE_DS_SELECTED (1<<0) #define SCE_DS_COLLAPSED (1<<1) +#define SCE_NLA_EDIT_ON (1<<2) /* return flag next_object function */ |