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...
This commit is contained in:
@@ -228,6 +228,22 @@ typedef enum eAnimFilter_Flags {
|
||||
/* channel toggle-buttons */
|
||||
#define ACHANNEL_BUTTON_WIDTH 16
|
||||
|
||||
|
||||
/* -------------- NLA Channel Defines -------------- */
|
||||
|
||||
/* NLA channel heights */
|
||||
#define NLACHANNEL_FIRST -16
|
||||
#define NLACHANNEL_HEIGHT 24
|
||||
#define NLACHANNEL_HEIGHT_HALF 12
|
||||
#define NLACHANNEL_SKIP 2
|
||||
#define NLACHANNEL_STEP (NLACHANNEL_HEIGHT + NLACHANNEL_SKIP)
|
||||
|
||||
/* channel widths */
|
||||
#define NLACHANNEL_NAMEWIDTH 200
|
||||
|
||||
/* channel toggle-buttons */
|
||||
#define NLACHANNEL_BUTTON_WIDTH 16
|
||||
|
||||
/* ---------------- API -------------------- */
|
||||
|
||||
/* Obtain list of filtered Animation channels to operate on.
|
||||
|
||||
@@ -139,7 +139,7 @@ static void nla_selectmenu(bContext *C, uiLayout *layout, void *arg_unused)
|
||||
static void nla_edit_transformmenu(bContext *C, uiLayout *layout, void *arg_unused)
|
||||
{
|
||||
// XXX these operators may change for NLA...
|
||||
uiItemEnumO(layout, "Grab/Move", 0, "TFM_OT_transform", "mode", TFM_TIME_TRANSLATE);
|
||||
uiItemEnumO(layout, "Grab/Move", 0, "TFM_OT_transform", "mode", TFM_TRANSLATION);
|
||||
uiItemEnumO(layout, "Extend", 0, "TFM_OT_transform", "mode", TFM_TIME_EXTEND);
|
||||
uiItemEnumO(layout, "Scale", 0, "TFM_OT_transform", "mode", TFM_TIME_SCALE);
|
||||
}
|
||||
|
||||
@@ -33,21 +33,6 @@
|
||||
/* **************************************** */
|
||||
/* Macros, etc. only used by NLA */
|
||||
|
||||
/* -------------- NLA Channel Defines -------------- */
|
||||
|
||||
/* NLA channel heights */
|
||||
#define NLACHANNEL_FIRST -16
|
||||
#define NLACHANNEL_HEIGHT 24
|
||||
#define NLACHANNEL_HEIGHT_HALF 12
|
||||
#define NLACHANNEL_SKIP 2
|
||||
#define NLACHANNEL_STEP (NLACHANNEL_HEIGHT + NLACHANNEL_SKIP)
|
||||
|
||||
/* channel widths */
|
||||
#define NLACHANNEL_NAMEWIDTH 200
|
||||
|
||||
/* channel toggle-buttons */
|
||||
#define NLACHANNEL_BUTTON_WIDTH 16
|
||||
|
||||
/* **************************************** */
|
||||
/* space_nla.c / nla_buttons.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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -340,69 +340,153 @@ 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 if (nExceeded) {
|
||||
/* move backwards */
|
||||
float offset= tdn->h2[0] - strip->next->start;
|
||||
|
||||
tdn->h1[0] -= offset;
|
||||
tdn->h2[0] -= offset;
|
||||
}
|
||||
else if (pExceeded) {
|
||||
/* more forwards */
|
||||
float offset= strip->prev->end - tdn->h1[0];
|
||||
|
||||
tdn->h1[0] += offset;
|
||||
tdn->h2[0] += offset;
|
||||
}
|
||||
else /* all is fine and well */
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 {
|
||||
PointerRNA strip_ptr;
|
||||
/* make delta 'positive' before using it, since we now know to go backwards */
|
||||
delta= -delta;
|
||||
|
||||
/* make RNA-pointer */
|
||||
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
// TODO: this may flush some things twice, but that's fine as there's no impact from that
|
||||
BKE_nlameta_flush_transforms(strip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (t->obedit) {
|
||||
if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user