From 2edef129be18fa8cb7d9c33b8bd76dc60d9e1dcf Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 7 Jul 2009 05:41:59 +0000 Subject: NLA SoC: Transform Code for NLA-Strips recoded (still buggy) Recoded the Transform code for NLA-Strips so that they can now be moved between strips and will not get truncated when they get moved into other non-moving strips. Todos: * The current code for moving strips between tracks is buggy (only goes up, and has a tendency to move up without being told to) * Auto-snapping doesn't work yet... --- source/blender/editors/transform/transform.c | 10 +- source/blender/editors/transform/transform.h | 14 +- .../editors/transform/transform_conversions.c | 103 ++++++++++-- .../blender/editors/transform/transform_generics.c | 176 +++++++++++++++------ source/blender/editors/transform/transform_ops.c | 4 +- 5 files changed, 236 insertions(+), 71 deletions(-) (limited to 'source/blender/editors/transform') diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9d8371afd61..9fbcfc71082 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -162,7 +162,7 @@ void convertViewVec(TransInfo *t, float *vec, short dx, short dy) vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy; vec[2]= 0.0f; } - else if(t->spacetype==SPACE_IPO) { + else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { View2D *v2d = t->view; float divx, divy; @@ -212,7 +212,7 @@ void projectIntView(TransInfo *t, float *vec, int *adr) UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr+1); } - else if(t->spacetype==SPACE_IPO) { + else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { int out[2] = {0, 0}; UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], out, out+1); @@ -241,7 +241,7 @@ void projectFloatView(TransInfo *t, float *vec, float *adr) adr[0]= a[0]; adr[1]= a[1]; } - else if(t->spacetype==SPACE_IPO) { + else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { int a[2]; projectIntView(t, vec, a); @@ -1324,10 +1324,10 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int case TFM_TIME_EXTEND: /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION - * (for Graph Editor only since it uses 'standard' transforms to get 2D movement) + * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) * depending on which editor this was called from */ - if (t->spacetype == SPACE_IPO) + if ELEM(t->spacetype, SPACE_IPO, SPACE_NLA) initTranslation(t); else initTimeTranslate(t); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 1b35701a753..65edae6fca8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -163,9 +163,17 @@ typedef struct TransDataSeq { /* for NLA transform (stored in td->extra pointer) */ typedef struct TransDataNla { - struct NlaStrip *strip; /* NLA-strip that handle belongs to */ - float val; /* value for the handle that the transform tools write to */ - int handle; /* handle-index, 0 for start, 1 for end */ + struct NlaTrack *oldTrack; /* Original NLA-Track that the strip belongs to */ + struct NlaTrack *nlt; /* Current NLA-Track that the strip belongs to */ + + struct NlaStrip *strip; /* NLA-strip this data represents */ + + /* dummy values for transform to write in - must have 3 elements... */ + float h1[3]; /* start handle */ + float h2[3]; /* end handle */ + + int trackIndex; /* index of track that strip is currently in */ + int handle; /* handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends */ } TransDataNla; typedef struct TransData { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 758be545fd0..76720600327 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2661,34 +2661,104 @@ static void createTransNlaData(bContext *C, TransInfo *t) /* transition strips can't get directly transformed */ if (strip->type != NLASTRIP_TYPE_TRANSITION) { if (strip->flag & NLASTRIP_FLAG_SELECT) { + /* our transform data is constructed as follows: + * - only the handles on the right side of the current-frame get included + * - td structs are transform-elements operated on by the transform system + * and represent a single handle. The storage/pointer used (val or loc) depends on + * whether we're scaling or transforming. Ultimately though, the handles + * the td writes to will simply be a dummy in tdn + * - for each strip being transformed, a single tdn struct is used, so in some + * cases, there will need to be 1 of these tdn elements in the array skipped... + */ + float center[3], yval; + + /* firstly, init tdn settings */ + tdn->oldTrack= tdn->nlt= nlt; + tdn->strip= strip; + tdn->trackIndex= BLI_findindex(&nlt->strips, strip); + + yval= (float)(tdn->trackIndex * NLACHANNEL_SKIP); + + tdn->h1[0]= strip->start; + tdn->h1[1]= yval; + tdn->h2[0]= strip->end; + tdn->h2[1]= yval; + + center[0]= (float)CFRA; + center[1]= yval; + center[2]= 0.0f; + + /* set td's based on which handles are applicable */ if (FrameOnMouseSide(side, strip->start, (float)CFRA)) { - /* init the 'extra' data for NLA strip handles first */ - tdn->strip= strip; - tdn->val= strip->start; - tdn->handle= 0; + /* just set tdn to assume that it only has one handle for now */ + tdn->handle= -1; /* now, link the transform data up to this data */ - td->val= &tdn->val; - td->ival= tdn->val; + if (t->mode == TFM_TRANSLATION) { + td->loc= tdn->h1; + VECCOPY(td->iloc, tdn->h1); + + /* store all the other gunk that is required by transform */ + VECCOPY(td->center, center); + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext= NULL; td->tdi= NULL; td->val= NULL; + + td->flag |= TD_SELECTED; + td->dist= 0.0f; + + Mat3One(td->mtx); + Mat3One(td->smtx); + } + else { + td->val= &tdn->h1[0]; + td->ival= tdn->h1[0]; + } + td->extra= tdn; td++; - tdn++; } if (FrameOnMouseSide(side, strip->end, (float)CFRA)) { - /* init the 'extra' data for NLA strip handles first */ - tdn->strip= strip; - tdn->val= strip->end; - tdn->handle= 1; + /* if tdn is already holding the start handle, then we're doing both, otherwise, only end */ + tdn->handle= (tdn->handle) ? 2 : 1; /* now, link the transform data up to this data */ - td->val= &tdn->val; - td->ival= tdn->val; + if (t->mode == TFM_TRANSLATION) { + td->loc= tdn->h2; + VECCOPY(td->iloc, tdn->h2); + + /* store all the other gunk that is required by transform */ + VECCOPY(td->center, center); + memset(td->axismtx, 0, sizeof(td->axismtx)); + td->axismtx[2][2] = 1.0f; + + td->ext= NULL; td->tdi= NULL; td->val= NULL; + + td->flag |= TD_SELECTED; + td->dist= 0.0f; + + Mat3One(td->mtx); + Mat3One(td->smtx); + } + else { + td->val= &tdn->h2[0]; + td->ival= tdn->h2[0]; + } + td->extra= tdn; td++; - tdn++; } + + /* if both handles were used, skip the next tdn (i.e. leave it blank) since the counting code is dumb... + * otherwise, just advance to the next one... + */ + if (tdn->handle == 2) + tdn += 2; + else + tdn++; } } } @@ -4739,7 +4809,6 @@ void special_aftertrans_update(TransInfo *t) ANIM_editkeyframes_refresh(&ac); } else if (t->spacetype == SPACE_NLA) { - SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first; Scene *scene; bAnimContext ac; @@ -4769,6 +4838,10 @@ void special_aftertrans_update(TransInfo *t) for (ale= anim_data.first; ale; ale= ale->next) { NlaTrack *nlt= (NlaTrack *)ale->data; + /* make sure strips are in order again */ + // FIXME: this is buggy + //BKE_nlatrack_sort_strips(nlt); + /* remove the temp metas */ BKE_nlastrips_clear_metas(&nlt->strips, 0, 1); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index e228dc2b13a..9928aea21d0 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -340,67 +340,151 @@ void recalcData(TransInfo *t) } } else if (t->spacetype == SPACE_NLA) { - TransData *td= t->data; + TransDataNla *tdn= (TransDataNla *)t->customData; int i; - /* for each point we've captured, look at its 'extra' data, which is basically a wrapper around the strip - * it is for + some extra storage for the values that get set, and use RNA to set this value (performing validation - * work so that we don't need to repeat it here) + /* for each strip we've got, perform some additional validation of the values that got set before + * using RNA to set the value (which does some special operations when setting these values to make + * sure that everything works ok) */ - for (i = 0; i < t->total; i++, td++) - { - if (td->extra) - { - TransDataNla *tdn= td->extra; - NlaStrip *strip= tdn->strip; + for (i = 0; i < t->total; i++, tdn++) { + NlaStrip *strip= tdn->strip; + PointerRNA strip_ptr; + short pExceeded, nExceeded, iter; + int delta_y1, delta_y2; + + /* if this tdn has no handles, that means it is just a dummy that should be skipped */ + if (tdn->handle == 0) + continue; - /* if we're just cancelling (i.e. the user aborted the transform), - * just restore the data by directly overwriting the values with the original - * ones (i.e. don't go through RNA), as we get some artifacts... + /* if cancelling transform, just write the values without validating, then move on */ + if (t->state == TRANS_CANCEL) { + /* clear the values by directly overwriting the originals, but also need to restore + * endpoints of neighboring transition-strips */ - if (t->state == TRANS_CANCEL) { - /* clear the values by directly overwriting the originals, but also need to restore - * endpoints of neighboring transition-strips + + /* start */ + strip->start= tdn->h1[0]; + + if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) + strip->prev->end= tdn->h1[0]; + + /* end */ + strip->end= tdn->h2[0]; + + if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION)) + strip->next->start= tdn->h2[0]; + + /* restore to original track (if needed) */ + if (tdn->oldTrack != tdn->nlt) { + /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */ + BLI_remlink(&tdn->nlt->strips, strip); + BLI_addtail(&tdn->oldTrack->strips, strip); + } + + continue; + } + + /* firstly, check if the proposed transform locations would overlap with any neighbouring strips + * (barring transitions) which are absolute barriers since they are not being moved + * + * this is done as a iterative procedure (done 5 times max for now) + */ + for (iter=0; iter < 5; iter++) { + pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end)); + nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start)); + + if ((pExceeded && nExceeded) || (iter == 4) ) { + /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise) + * - simply crop strip to fit within the bounds of the strips bounding it + * - if there were no neighbours, clear the transforms (make it default to the strip's current values) */ - if (tdn->handle) { - strip->end= tdn->val; - - if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION)) - strip->next->start= tdn->val; + if (strip->prev && strip->next) { + tdn->h1[0]= strip->prev->end; + tdn->h2[0]= strip->next->start; } else { - strip->start= tdn->val; - - if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) - strip->prev->end= tdn->val; + tdn->h1[0]= strip->start; + tdn->h2[0]= strip->end; } } - else { - PointerRNA strip_ptr; + else if (nExceeded) { + /* move backwards */ + float offset= tdn->h2[0] - strip->next->start; - /* make RNA-pointer */ - RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); + tdn->h1[0] -= offset; + tdn->h2[0] -= offset; + } + else if (pExceeded) { + /* more forwards */ + float offset= strip->prev->end - tdn->h1[0]; - /* write the value set by the transform tools to the appropriate property using RNA */ - if (tdn->handle) - RNA_float_set(&strip_ptr, "end_frame", tdn->val); - else - RNA_float_set(&strip_ptr, "start_frame", tdn->val); + tdn->h1[0] += offset; + tdn->h2[0] += offset; } + else /* all is fine and well */ + break; } - } - - /* loop over the TransDataNla again, flushing the transforms (since we use Metas to make transforms easier) */ - td= t->data; - for (i = 0; i < t->total; i++, td++) - { - if (td->extra) - { - TransDataNla *tdn= td->extra; - NlaStrip *strip= tdn->strip; + + /* use RNA to write the values... */ + // TODO: do we need to write in 2 passes to make sure that no truncation goes on? + RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr); + + RNA_float_set(&strip_ptr, "start_frame", tdn->h1[0]); + RNA_float_set(&strip_ptr, "end_frame", tdn->h2[0]); + + /* flush transforms to child strips (since this should be a meta) */ + BKE_nlameta_flush_transforms(strip); + + + /* now, check if we need to try and move track + * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved + */ + // FIXME: the conversion from vertical distance to track index needs work! + delta_y1= ((int)tdn->h1[0] / NLACHANNEL_SKIP - tdn->trackIndex); + delta_y2= ((int)tdn->h2[0] / NLACHANNEL_SKIP - tdn->trackIndex); + + if (delta_y1 || delta_y2) { + NlaTrack *track; + int delta = (delta_y2) ? delta_y2 : delta_y1; + int n; - // TODO: this may flush some things twice, but that's fine as there's no impact from that - BKE_nlameta_flush_transforms(strip); + /* move in the requested direction, checking at each layer if there's space for strip to pass through, + * stopping on the last track available or that we're able to fit in + */ + if (delta > 0) { + for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) { + /* check if space in this track for the strip */ + if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + /* move strip to this track */ + BLI_remlink(&tdn->nlt->strips, strip); + BKE_nlatrack_add_strip(track, strip); + + tdn->nlt= track; + tdn->trackIndex += (n + 1); /* + 1, since n==0 would mean that we didn't change track */ + } + else /* can't move any further */ + break; + } + } + else { + /* make delta 'positive' before using it, since we now know to go backwards */ + delta= -delta; + + for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) { + /* check if space in this track for the strip */ + if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + /* move strip to this track */ + BLI_remlink(&tdn->nlt->strips, strip); + BKE_nlatrack_add_strip(track, strip); + + tdn->nlt= track; + tdn->trackIndex -= (n - 1); /* - 1, since n==0 would mean that we didn't change track */ + } + else /* can't move any further */ + break; + } + } } } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 28606932c64..ecb58831118 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -609,10 +609,10 @@ void transform_keymap_for_space(struct wmWindowManager *wm, struct ListBase *key break; case SPACE_NLA: km= WM_keymap_add_item(keymap, "TFM_OT_transform", GKEY, KM_PRESS, 0, 0); - RNA_int_set(km->ptr, "mode", TFM_TIME_TRANSLATE); + RNA_int_set(km->ptr, "mode", TFM_TRANSLATION); km= WM_keymap_add_item(keymap, "TFM_OT_transform", EVT_TWEAK_S, KM_ANY, 0, 0); - RNA_int_set(km->ptr, "mode", TFM_TIME_TRANSLATE); + RNA_int_set(km->ptr, "mode", TFM_TRANSLATION); km= WM_keymap_add_item(keymap, "TFM_OT_transform", EKEY, KM_PRESS, 0, 0); RNA_int_set(km->ptr, "mode", TFM_TIME_EXTEND); -- cgit v1.2.3