diff options
author | Joshua Leung <aligorith@gmail.com> | 2007-09-24 15:29:25 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2007-09-24 15:29:25 +0400 |
commit | c4860afba3d1bf18dfc36bf2ec76332267394f5b (patch) | |
tree | 9b35ac6619f0a13a7122c326d50701404f4128e6 | |
parent | 1fde6d457091b4ea94e40245eff6d62881eb55bf (diff) |
== Action and NLA Editor Transform ==
I've refactored the Action and NLA Editor Transform tools to use the Transform System instead of setting up their own transform loops. This should have happened ages ago, but no-one got around to doing so.
* There are still a few bugs left to iron out of a few features, but on the whole it should work as well as it used to. These are: the values which get displayed when working with NLA-scaled actions may not all be correct yet; and the Time-Slide tool in the Action Editor is currently kindof broken.
* One of the main benefits of this work, is that it is now possible to use Numeric Input during Transforms.
* Also, a bug that meant that it was not possible to negatively scale keyframes in the Action Editor has been resolved.
-rw-r--r-- | source/blender/include/BIF_transform.h | 3 | ||||
-rw-r--r-- | source/blender/include/transform.h | 9 | ||||
-rw-r--r-- | source/blender/src/editaction.c | 420 | ||||
-rw-r--r-- | source/blender/src/editnla.c | 294 | ||||
-rw-r--r-- | source/blender/src/header_action.c | 4 | ||||
-rw-r--r-- | source/blender/src/transform.c | 501 | ||||
-rw-r--r-- | source/blender/src/transform_conversions.c | 331 | ||||
-rw-r--r-- | source/blender/src/transform_generics.c | 45 |
8 files changed, 918 insertions, 689 deletions
diff --git a/source/blender/include/BIF_transform.h b/source/blender/include/BIF_transform.h index 9b277942528..eeb465135de 100644 --- a/source/blender/include/BIF_transform.h +++ b/source/blender/include/BIF_transform.h @@ -55,6 +55,9 @@ #define TFM_BONE_ENVELOPE 16 #define TFM_CURVE_SHRINKFATTEN 17 #define TFM_BONE_ROLL 18 +#define TFM_TIME_TRANSLATE 19 +#define TFM_TIME_SLIDE 20 +#define TFM_TIME_SCALE 21 /* TRANSFORM CONTEXTS */ #define CTX_NONE 0 diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h index a06356e6531..b81ec202210 100644 --- a/source/blender/include/transform.h +++ b/source/blender/include/transform.h @@ -339,6 +339,15 @@ int BoneEnvelope(TransInfo *t, short mval[2]); void initBoneRoll(TransInfo *t); int BoneRoll(TransInfo *t, short mval[2]); +void initTimeTranslate(TransInfo *t); +int TimeTranslate(TransInfo *t, short mval[2]); + +void initTimeSlide(TransInfo *t); +int TimeSlide(TransInfo *t, short mval[2]); + +void initTimeScale(TransInfo *t); +int TimeScale(TransInfo *t, short mval[2]); + /*********************** transform_conversions.c ********** */ struct ListBase; void flushTransUVs(TransInfo *t); diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c index 76fc21b13e6..23e2a5aab6b 100644 --- a/source/blender/src/editaction.c +++ b/source/blender/src/editaction.c @@ -80,6 +80,7 @@ #include "BIF_screen.h" #include "BIF_space.h" #include "BIF_toolbox.h" +#include "BIF_transform.h" #include "BSE_edit.h" #include "BSE_drawipo.h" @@ -186,19 +187,6 @@ static void remake_meshaction_ipos (Ipo *ipo) } } -static void meshkey_do_redraw (Key *key) -{ - if(key->ipo) - remake_meshaction_ipos(key->ipo); - - DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); - - allspace(REMAKEIPO, 0); - allqueue(REDRAWACTION, 0); - allqueue(REDRAWIPO, 0); - allqueue(REDRAWNLA, 0); - -} /* **************************************************** */ /* FILTER->EDIT STRUCTURES */ @@ -737,361 +725,9 @@ void *get_action_context (short *datatype) /* **************************************************** */ /* TRANSFORM TOOLS */ -/* initialise the transform data - create transverts */ -static TransVert *transform_action_init (int *tvtot, float *minx, float *maxx) -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - TransVert *tv; - void *data; - short datatype; - int filter; - int count= 0; - float min= 0, max= 0; - int i; - - /* initialise the values being passed by reference */ - *tvtot = *minx = *maxx = 0; - - /* determine what type of data we are operating on */ - data = get_action_context(&datatype); - if (data == NULL) return NULL; - - /* filter data */ - filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS); - actdata_filter(&act_data, filter, data, datatype); - - /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ - for (ale= act_data.first; ale; ale= ale->next) - count += fullselect_ipo_keys(ale->key_data); - - /* stop if trying to build list if nothing selected */ - if (count == 0) { - /* cleanup temp list */ - BLI_freelistN(&act_data); - return NULL; - } - - /* Build the transvert structure */ - tv = MEM_callocN (sizeof(TransVert) * count, "transVert"); - - /* loop 2: build transvert structure */ - for (ale= act_data.first; ale; ale= ale->next) - *tvtot = add_trans_ipo_keys(ale->key_data, tv, *tvtot); - - /* min max, only every other three */ - min= max= tv[1].loc[0]; - for (i=1; i<count; i+=3) { - if(min>tv[i].loc[0]) min= tv[i].loc[0]; - if(max<tv[i].loc[0]) max= tv[i].loc[0]; - } - *minx= min; - *maxx= max; - - /* cleanup temp list */ - BLI_freelistN(&act_data); - - /* return created transverts */ - return tv; -} - -/* main transform loop for action editor - * NOTE: yes, this is a very long function that really should be converted to - * using the transform system proper - */ -static short transform_action_loop (TransVert *tv, int tvtot, char mode, short context, float minx, float maxx) -{ - Object *ob= OBACT; - float deltax, startx; - float cenf[2]; - float sval[2], cval[2], lastcval[2]={0,0}; - float fac=0.0f, secf= ((float)G.scene->r.frs_sec); - int loop=1, invert=0; - int i; - short cancel=0, firsttime=1; - short mvals[2], mvalc[2], cent[2]; - char str[256]; - - /* Do the event loop */ - cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2; - cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2; - areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]); - - getmouseco_areawin (mvals); - areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]); - - if (NLA_ACTION_SCALED) - sval[0]= get_action_frame(OBACT, sval[0]); - - /* used for drawing */ - if (mode=='t') { - G.saction->flag |= SACTION_MOVING; - G.saction->timeslide= sval[0]; - } - - startx=sval[0]; - while (loop) { - if (mode=='t' && minx==maxx) - break; - - /* Get the input: - * - If we're cancelling, reset transformations - * - Else calc new transformation - * Perform the transformations - */ - while (qtest()) { - short val; - unsigned short event= extern_qread(&val); - - if (val) { - switch (event) { - case LEFTMOUSE: - case SPACEKEY: - case RETKEY: - loop=0; - break; - case XKEY: - break; - case ESCKEY: - case RIGHTMOUSE: - cancel=1; - loop=0; - break; - default: - arrows_move_cursor(event); - break; - }; - } - } - - if (cancel) { - for (i=0; i<tvtot; i++) { - tv[i].loc[0]=tv[i].oldloc[0]; - tv[i].loc[1]=tv[i].oldloc[1]; - } - } - else { - getmouseco_areawin (mvalc); - areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]); - - if (NLA_ACTION_SCALED) - cval[0]= get_action_frame(OBACT, cval[0]); - - if (mode=='t') - G.saction->timeslide= cval[0]; - - if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) { - PIL_sleep_ms(1); - } - else { - short autosnap= 0; - - /* determine mode of keyframe snapping/autosnap */ - if (mode != 't') { - switch (G.saction->autosnap) { - case SACTSNAP_OFF: - if (G.qual == LR_CTRLKEY) - autosnap= SACTSNAP_STEP; - else if (G.qual == LR_SHIFTKEY) - autosnap= SACTSNAP_FRAME; - else - autosnap= SACTSNAP_OFF; - break; - case SACTSNAP_STEP: - autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP; - break; - case SACTSNAP_FRAME: - autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME; - break; - } - } - - for (i=0; i<tvtot; i++) { - tv[i].loc[0]=tv[i].oldloc[0]; - - switch (mode) { - case 't': - if( sval[0] > minx && sval[0] < maxx) { - float timefac, cvalc= CLAMPIS(cval[0], minx, maxx); - - /* left half */ - if(tv[i].oldloc[0] < sval[0]) { - timefac= ( sval[0] - tv[i].oldloc[0])/(sval[0] - minx); - tv[i].loc[0]= cvalc - timefac*( cvalc - minx); - } - else { - timefac= (tv[i].oldloc[0] - sval[0])/(maxx - sval[0]); - tv[i].loc[0]= cvalc + timefac*(maxx- cvalc); - } - } - break; - case 'g': - if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) { - deltax = get_action_frame_inv(OBACT, cval[0]); - deltax -= get_action_frame_inv(OBACT, sval[0]); - - if (autosnap == SACTSNAP_STEP) { - if (G.saction->flag & SACTION_DRAWTIME) - deltax= (float)( floor((deltax/secf) + 0.5f) * secf ); - else - deltax= (float)( floor(deltax + 0.5f) ); - } - - fac = get_action_frame_inv(OBACT, tv[i].loc[0]); - fac += deltax; - tv[i].loc[0] = get_action_frame(OBACT, fac); - } - else { - deltax = cval[0] - sval[0]; - fac= deltax; - - if (autosnap == SACTSNAP_STEP) { - if (G.saction->flag & SACTION_DRAWTIME) - fac= (float)( floor((deltax/secf) + 0.5f) * secf ); - else - fac= (float)( floor(fac + 0.5f) ); - } - - tv[i].loc[0]+=fac; - } - break; - case 's': - startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); - deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); - fac= fabs(deltax/startx); - - if (autosnap == SACTSNAP_STEP) { - if (G.saction->flag & SACTION_DRAWTIME) - fac= (float)( floor(fac/secf + 0.5f) * secf ); - else - fac= (float)( floor(fac + 0.5f) ); - } - - if (invert) { - if (i % 03 == 0) { - memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc)); - } - if (i % 03 == 2) { - memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc)); - } - - fac *= -1; - } - startx= (G.scene->r.cfra); - if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) - startx= get_action_frame(OBACT, startx); - - tv[i].loc[0]-= startx; - tv[i].loc[0]*=fac; - tv[i].loc[0]+= startx; - - break; - } - - /* snap key to nearest frame? */ - if (autosnap == SACTSNAP_FRAME) { - float snapval; - - /* convert frame to nla-action time (if needed) */ - if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) - snapval= get_action_frame_inv(OBACT, tv[i].loc[0]); - else - snapval= tv[i].loc[0]; - - /* snap to nearest frame */ - if (G.saction->flag & SACTION_DRAWTIME) - snapval= (float)( floor((snapval/secf) + 0.5f) * secf ); - else - snapval= (float)( floor(snapval+0.5f) ); - - /* convert frame out of nla-action time */ - if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) - tv[i].loc[0]= get_action_frame(OBACT, snapval); - else - tv[i].loc[0]= snapval; - } - } - - if (mode=='s') { - sprintf(str, "scaleX: %.3f", fac); - headerprint(str); - } - else if (mode=='g') { - if (NLA_ACTION_SCALED && context==ACTCONT_ACTION) { - /* recalculate the delta based on 'visual' times */ - fac = get_action_frame_inv(OBACT, cval[0]); - fac -= get_action_frame_inv(OBACT, sval[0]); - } - - if (autosnap == SACTSNAP_STEP) { - if (G.saction->flag & SACTION_DRAWTIME) - fac= floor(fac/secf + 0.5f); - else - fac= floor(fac + 0.5f); - } - else if (autosnap == SACTSNAP_FRAME) { - if (G.saction->flag & SACTION_DRAWTIME) - fac= fac / secf; - } - - sprintf(str, "deltaX: %.3f", fac); - headerprint(str); - } - else if (mode=='t') { - fac= 2.0*(cval[0]-sval[0])/(maxx-minx); - CLAMP(fac, -1.0f, 1.0f); - - sprintf(str, "TimeSlide: %.3f", fac); - headerprint(str); - } - - if (G.saction->lock) { - if (context == ACTCONT_ACTION) { - if(ob) { - ob->ctime= -1234567.0f; - if(ob->pose || ob_get_key(ob)) - DAG_object_flush_update(G.scene, ob, OB_RECALC); - else - DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); - } - force_draw_plus(SPACE_VIEW3D, 0); - } - else if (context == ACTCONT_SHAPEKEY) { - DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA); - allqueue (REDRAWVIEW3D, 0); - allqueue (REDRAWACTION, 0); - allqueue (REDRAWIPO, 0); - allqueue(REDRAWNLA, 0); - allqueue(REDRAWTIME, 0); - force_draw_all(0); - } - } - else { - force_draw(0); - } - } - } - - lastcval[0]= cval[0]; - lastcval[1]= cval[1]; - firsttime= 0; - } - - return cancel; -} - /* main call to start transforming keyframes */ -/* NOTE: someday, this should be integrated with the transform system - * instead of relying on our own methods - */ void transform_action_keys (int mode, int dummy) { - Object *ob= OBACT; - TransVert *tv; - int tvtot= 0; - short cancel; - float minx, maxx; - void *data; short datatype; @@ -1099,44 +735,26 @@ void transform_action_keys (int mode, int dummy) data = get_action_context(&datatype); if (data == NULL) return; - /* initialise transform */ - tv= transform_action_init(&tvtot, &minx, &maxx); - if (tv == NULL) return; - - /* do transform loop */ - cancel= transform_action_loop(tv, tvtot, mode, datatype, minx, maxx); - - /* cleanup */ - if (datatype == ACTCONT_ACTION) { - /* Update the curve */ - /* Depending on the lock status, draw necessary views */ - if(ob) { - ob->ctime= -1234567.0f; - - if(ob->pose || ob_get_key(ob)) - DAG_object_flush_update(G.scene, ob, OB_RECALC); - else - DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); + switch (mode) { + case 'g': + { + initTransform(TFM_TIME_TRANSLATE, CTX_NONE); + Transform(); } - - remake_action_ipos((bAction *)data); - - G.saction->flag &= ~SACTION_MOVING; - - if (cancel==0) BIF_undo_push("Transform Action"); // does it have to be here? - allqueue(REDRAWVIEW3D, 0); - allqueue(REDRAWACTION, 0); - allqueue(REDRAWNLA, 0); - allqueue(REDRAWIPO, 0); - allqueue(REDRAWTIME, 0); - } - else if (datatype == ACTCONT_SHAPEKEY) { - /* fix up the Ipocurves and redraw stuff */ - meshkey_do_redraw((Key *)data); - if (cancel==0) BIF_undo_push("Transform Action"); + break; + case 's': + { + initTransform(TFM_TIME_SCALE, CTX_NONE); + Transform(); + } + break; + case 't': + { + initTransform(TFM_TIME_SLIDE, CTX_NONE); + Transform(); + } + break; } - - MEM_freeN(tv); } /* ----------------------------------------- */ diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c index 9115665afa0..8c506b2c925 100644 --- a/source/blender/src/editnla.c +++ b/source/blender/src/editnla.c @@ -73,6 +73,7 @@ #include "BIF_toolbox.h" #include "BIF_editnla.h" #include "BIF_editaction.h" +#include "BIF_transform.h" #include "BSE_editipo.h" #include "BSE_editnla_types.h" @@ -975,291 +976,20 @@ static void recalc_all_ipos(void) void transform_nlachannel_keys(int mode, int dummy) { - Base *base; - TransVert *tv; - bActionChannel *chan; - bActionStrip *strip; - bConstraintChannel *conchan; - float sval[2], cval[2], lastcval[2]= {0.0f, 0.0f}; - float fac=0.0F; - float deltax, startx; - int i; - int loop=1; - int tvtot=0; - int invert=0, firsttime=1; - short mvals[2], mvalc[2]; - short cancel=0; - char str[256]; - - /* Ensure that partial selections result in beztriple selections */ - for (base=G.scene->base.first; base; base=base->next){ - /* Check object ipos */ - i= fullselect_ipo_keys(base->object->ipo); - if(i) base->flag |= BA_HAS_RECALC_OB; - tvtot+=i; - - /* Check object constraint ipos */ - for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) - tvtot+=fullselect_ipo_keys(conchan->ipo); - - /* skip actions and nlastrips if object is collapsed */ - if (base->object->nlaflag & OB_NLA_COLLAPSED) - continue; - - /* Check action ipos */ - if (base->object->action){ - /* exclude if strip is selected too */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) - if(strip->act==base->object->action) - break; - } - if(strip==NULL) { - - for (chan=base->object->action->chanbase.first; chan; chan=chan->next) { - if (EDITABLE_ACHAN(chan)) { - i= fullselect_ipo_keys(chan->ipo); - if(i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; - tvtot+=i; - - /* Check action constraint ipos */ - if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) { - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { - if (EDITABLE_CONCHAN(conchan)) - tvtot+=fullselect_ipo_keys(conchan->ipo); - } - } - } - } - } - } - - /* Check nlastrips */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next){ - if (strip->flag & ACTSTRIP_SELECT) { - base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; - tvtot+=2; - } - } - } - - /* If nothing is selected, bail out */ - if (!tvtot) - return; - - - /* Build the transvert structure */ - tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert"); - tvtot=0; - for (base=G.scene->base.first; base; base=base->next){ - /* Manipulate object ipos */ - tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot); - - /* Manipulate object constraint ipos */ - for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) - tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot); - - /* skip actions and nlastrips if object collapsed */ - if (base->object->nlaflag & OB_NLA_COLLAPSED) - continue; - - /* Manipulate action ipos */ - if (base->object->action){ - /* exclude if strip is selected too */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next){ - if (strip->flag & ACTSTRIP_SELECT) - if(strip->act==base->object->action) - break; - } - - /* can include - no selected strip is action */ - if(strip==NULL) { - for (chan=base->object->action->chanbase.first; chan; chan=chan->next){ - if (EDITABLE_ACHAN(chan)) { - tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot); - - /* Manipulate action constraint ipos */ - if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) { - for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) { - if (EDITABLE_CONCHAN(conchan)) - tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot); - } - } - } - } - } - } - - /* Manipulate nlastrips */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next){ - if (strip->flag & ACTSTRIP_SELECT){ - tv[tvtot+0].val=&strip->start; - tv[tvtot+1].val=&strip->end; - - tv[tvtot+0].oldval = strip->start; - tv[tvtot+1].oldval = strip->end; - - tvtot+=2; - } - } - } - - /* Do the event loop */ - // cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2; - // cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2; - - // areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]); - - getmouseco_areawin (mvals); - areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]); - - startx=sval[0]; - while (loop) { - /* Get the input */ - /* If we're cancelling, reset transformations */ - /* Else calc new transformation */ - /* Perform the transformations */ - while (qtest()) { - short val; - unsigned short event= extern_qread(&val); - - if (val) { - switch (event) { - case LEFTMOUSE: - case SPACEKEY: - case RETKEY: - loop=0; - break; - case XKEY: - break; - case ESCKEY: - case RIGHTMOUSE: - cancel=1; - loop=0; - break; - default: - arrows_move_cursor(event); - break; - }; - } - } - - if (cancel) { - for (i=0; i<tvtot; i++) { - if (tv[i].loc){ - tv[i].loc[0]=tv[i].oldloc[0]; - tv[i].loc[1]=tv[i].oldloc[1]; - } - if (tv[i].val) - tv[i].val[0]=tv[i].oldval; - } + switch (mode) { + case 'g': + { + initTransform(TFM_TIME_TRANSLATE, CTX_NONE); + Transform(); } - else { - getmouseco_areawin (mvalc); - areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]); - - if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) { - PIL_sleep_ms(10); - } - else { - for (i=0; i<tvtot; i++){ - if (tv[i].loc) - tv[i].loc[0]=tv[i].oldloc[0]; - if (tv[i].val) - tv[i].val[0]=tv[i].oldval; - - switch (mode){ - case 'g': - deltax = cval[0]-sval[0]; - fac= deltax; - - apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & USER_AUTOGRABGRID); - - if (tv[i].loc) - tv[i].loc[0]+=fac; - if (tv[i].val) - tv[i].val[0]+=fac; - break; - case 's': - startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); - deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); - fac= (float)fabs(deltax/startx); - - apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & USER_AUTOSIZEGRID); - - if (invert){ - if (i % 03 == 0){ - memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc)); - } - if (i % 03 == 2){ - memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc)); - } - - fac*=-1; - } - startx= (G.scene->r.cfra); - - if (tv[i].loc){ - tv[i].loc[0]-= startx; - tv[i].loc[0]*=fac; - tv[i].loc[0]+= startx; - } - if (tv[i].val){ - tv[i].val[0]-= startx; - tv[i].val[0]*=fac; - tv[i].val[0]+= startx; - } - - break; - } - } - - if (mode=='s'){ - sprintf(str, "scaleX: %.3f", fac); - headerprint(str); - } - else if (mode=='g'){ - sprintf(str, "deltaX: %.3f", fac); - headerprint(str); - } - - if (G.snla->lock) { - for (base=G.scene->base.first; base; base=base->next){ - if(base->flag & BA_HAS_RECALC_OB) - base->object->recalc |= OB_RECALC_OB; - if(base->flag & BA_HAS_RECALC_DATA) - base->object->recalc |= OB_RECALC_DATA; - - if(base->object->recalc) base->object->ctime= -1234567.0f; // eveil! - } - - DAG_scene_flush_update(G.scene, screen_view3d_layers()); - - force_draw_all(0); - } - else { - force_draw(0); - } - } + break; + case 's': + { + initTransform(TFM_TIME_SCALE, CTX_NONE); + Transform(); } - - lastcval[0]= cval[0]; - lastcval[1]= cval[1]; - firsttime= 0; + break; } - - synchronize_action_strips(); - - /* cleanup */ - for (base=G.scene->base.first; base; base=base->next) - base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA); - - if(cancel==0) BIF_undo_push("Select all NLA"); - recalc_all_ipos(); // bad - allqueue (REDRAWVIEW3D, 0); - allqueue (REDRAWNLA, 0); - allqueue (REDRAWIPO, 0); - MEM_freeN (tv); } void delete_nlachannel_keys(void) diff --git a/source/blender/src/header_action.c b/source/blender/src/header_action.c index d8afe0fd1f1..71aac0e81bb 100644 --- a/source/blender/src/header_action.c +++ b/source/blender/src/header_action.c @@ -597,10 +597,10 @@ static void do_action_keymenu_transformmenu(void *arg, int event) transform_action_keys('g', 0); break; case ACTMENU_KEY_TRANSFORM_SCALE: - transform_action_keys ('s', 0); + transform_action_keys('s', 0); break; case ACTMENU_KEY_TRANSFORM_SLIDE: - transform_action_keys ('t', 0); + transform_action_keys('t', 0); break; } diff --git a/source/blender/src/transform.c b/source/blender/src/transform.c index e8512d08d04..3189e959ede 100644 --- a/source/blender/src/transform.c +++ b/source/blender/src/transform.c @@ -48,6 +48,7 @@ #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" +#include "DNA_action_types.h" /* for some special action-editor settings */ #include "DNA_ipo_types.h" /* some silly ipo flag */ #include "DNA_listBase.h" #include "DNA_meshdata_types.h" @@ -75,11 +76,15 @@ #include "BIF_editmesh.h" #include "BIF_editsima.h" #include "BIF_drawimage.h" /* uvco_to_areaco_noclip */ +#include "BIF_editaction.h" +#include "BKE_action.h" /* get_action_frame */ #include "BKE_global.h" #include "BKE_utildefines.h" #include "BKE_bad_level_calls.h"/* popmenu and error */ +#include "BSE_drawipo.h" +#include "BSE_editnla_types.h" /* for NLAWIDTH */ #include "BSE_view.h" #include "BLI_arithb.h" @@ -350,7 +355,7 @@ void convertDisplayNumToVec(float *num, float *vec) static void viewRedrawForce(TransInfo *t) { - if(t->spacetype==SPACE_VIEW3D) + if(ELEM4(t->spacetype, SPACE_VIEW3D, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) force_draw(0); else if(t->spacetype==SPACE_IMAGE) { if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0); @@ -368,6 +373,14 @@ static void viewRedrawPost(TransInfo *t) allqueue(REDRAWIMAGE, 0); allqueue(REDRAWVIEW3D, 0); } + else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + allqueue(REDRAWIPO, 0); + allqueue(REDRAWTIME, 0); + allqueue(REDRAWBUTSOBJECT, 0); + } scrarea_queue_headredraw(curarea); } @@ -492,6 +505,12 @@ static char *transform_to_undostr(TransInfo *t) return "Bone Width"; case TFM_BONE_ENVELOPE: return "Bone Envelope"; + case TFM_TIME_TRANSLATE: + return "Translate Anim. Data"; + case TFM_TIME_SCALE: + return "Scale Anim. Data"; + case TFM_TIME_SLIDE: + return "Time Slide"; } return "Transform"; } @@ -884,6 +903,15 @@ void initTransform(int mode, int context) { case TFM_BONE_ROLL: initBoneRoll(&Trans); break; + case TFM_TIME_TRANSLATE: + initTimeTranslate(&Trans); + break; + case TFM_TIME_SLIDE: + initTimeSlide(&Trans); + break; + case TFM_TIME_SCALE: + initTimeScale(&Trans); + break; } } @@ -3191,6 +3219,477 @@ void Mirror(short mode) viewRedrawPost(&Trans); } +/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */ + +/* ---------------- Special Helpers for Various Settings ------------- */ + +/* This function returns the snapping 'mode' for Animation Editors only + * We cannot use the standard snapping due to NLA-strip scaling complexities. + */ +static short getAnimEdit_SnapMode(TransInfo *t) +{ + short autosnap= SACTSNAP_OFF; + + /* currently, some of these are only for the action editor */ + if (t->spacetype == SPACE_ACTION && G.saction) { + switch (G.saction->autosnap) { + case SACTSNAP_OFF: + if (G.qual == LR_CTRLKEY) + autosnap= SACTSNAP_STEP; + else if (G.qual == LR_SHIFTKEY) + autosnap= SACTSNAP_FRAME; + else + autosnap= SACTSNAP_OFF; + break; + case SACTSNAP_STEP: + autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP; + break; + case SACTSNAP_FRAME: + autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME; + break; + } + } + else { + if (G.qual == LR_CTRLKEY) + autosnap= SACTSNAP_STEP; + else if (G.qual == LR_SHIFTKEY) + autosnap= SACTSNAP_FRAME; + else + autosnap= SACTSNAP_OFF; + } + + return autosnap; +} + +/* This function is used for testing if an Animation Editor is displaying + * its data in frames or seconds (and the data needing to be edited as such). + * Returns 1 if in seconds, 0 if in frames + */ +static short getAnimEdit_DrawTime(TransInfo *t) +{ + short drawtime; + + /* currently, some of these are only for the action editor */ + if (t->spacetype == SPACE_ACTION && G.saction) { + if (G.saction->flag & SACTION_DRAWTIME) + drawtime = 1; + else + drawtime = 0; + } + else { + drawtime = 0; + } + + return drawtime; +} + + +/* This function is used by Animation Editor specific transform functions to do + * the Snap Keyframe to Nearest Keyframe + */ +static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap) +{ + /* snap key to nearest frame? */ + if (autosnap == SACTSNAP_FRAME) { + short doTime= getAnimEdit_DrawTime(t); + float secf= ((float)G.scene->r.frs_sec); + float val; + + /* convert frame to nla-action time (if needed) */ + if (ob) + val= get_action_frame_inv(ob, *(td->val)); + else + val= *(td->val); + + /* do the snapping to nearest frame/second */ + if (doTime) + val= (float)( floor((val/secf) + 0.5f) * secf ); + else + val= (float)( floor(val+0.5f) ); + + /* convert frame out of nla-action time */ + if (ob) + *(td->val)= get_action_frame(ob, val); + else + *(td->val)= val; + } +} + +/* ----------------- Translation ----------------------- */ + +void initTimeTranslate(TransInfo *t) +{ + t->mode = TFM_TIME_TRANSLATE; + t->transform = TimeTranslate; + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialise snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; +} + +static void headerTimeTranslate(TransInfo *t, char *str) +{ + char tvec[60]; + + /* if numeric input is active, use results from that, otherwise apply snapping to result */ + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec); + } + else { + short autosnap= getAnimEdit_SnapMode(t); + short doTime = getAnimEdit_DrawTime(t); + float secf= ((float)G.scene->r.frs_sec); + float val= t->fac; + + /* take into account scaling (for Action Editor only) */ + if ((t->spacetype == SPACE_ACTION) && (NLA_ACTION_SCALED)) { + float cval, sval[2]; + + /* recalculate the delta based on 'visual' times */ + areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]); + cval= sval[0] + t->fac; + + val = get_action_frame_inv(OBACT, cval); + val -= get_action_frame_inv(OBACT, sval[0]); + } + + /* apply snapping + frame->seconds conversions */ + if (autosnap == SACTSNAP_STEP) { + if (doTime) + val= floor(val/secf + 0.5f); + else + val= floor(val + 0.5f); + } + else { + if (doTime) + val= val / secf; + } + + sprintf(&tvec[0], "%.4f", val); + } + + sprintf(str, "DeltaX: %s", &tvec[0]); +} + +static void applyTimeTranslate(TransInfo *t, float sval) +{ + TransData *td = t->data; + int i; + + short doTime= getAnimEdit_DrawTime(t); + float secf= ((float)G.scene->r.frs_sec); + + short autosnap= getAnimEdit_SnapMode(t); + float cval= sval + t->fac; + + float deltax, val; + + /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */ + for (i = 0 ; i < t->total; i++, td++) { + /* it is assumed that td->ob is a pointer to the object, + * whose active action is where this keyframe comes from + */ + Object *ob= td->ob; + + /* check if any need to apply nla-scaling */ + if (ob) { + deltax = get_action_frame_inv(ob, cval); + deltax -= get_action_frame_inv(ob, sval); + + if (autosnap == SACTSNAP_STEP) { + if (doTime) + deltax= (float)( floor((deltax/secf) + 0.5f) * secf ); + else + deltax= (float)( floor(deltax + 0.5f) ); + } + + val = get_action_frame_inv(ob, td->ival); + val += deltax; + *(td->val) = get_action_frame(ob, val); + } + else { + deltax = val = t->fac; + + if (autosnap == SACTSNAP_STEP) { + if (doTime) + val= (float)( floor((deltax/secf) + 0.5f) * secf ); + else + val= (float)( floor(val + 0.5f) ); + } + + *(td->val) = td->ival + val; + } + + /* apply snap-to-nearest-frame? */ + doAnimEdit_SnapFrame(t, td, ob, autosnap); + } +} + +int TimeTranslate(TransInfo *t, short mval[2]) +{ + float cval[2], sval[2]; + char str[200]; + + /* calculate translation amount from mouse movement - in 'time-grid space' */ + areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]); + areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]); + + /* we only need to calculate effect for time (applyTimeTranslate only needs that) */ + t->fac= cval[0] - sval[0]; + + /* handle numeric-input stuff */ + t->vec[0] = t->fac; + applyNumInput(&t->num, &t->vec[0]); + t->fac = t->vec[0]; + headerTimeTranslate(t, str); + + applyTimeTranslate(t, sval[0]); + + recalcData(t); + + headerprint(str); + + viewRedrawForce(t); + + return 1; +} + +/* ----------------- Time Slide ----------------------- */ + +void initTimeSlide(TransInfo *t) +{ + /* this tool is only really available in the Action Editor... */ + if (t->spacetype == SPACE_ACTION) { + /* set flag for drawing stuff*/ + G.saction->flag |= SACTION_MOVING; + } + + t->mode = TFM_TIME_SLIDE; + t->transform = TimeSlide; + t->flag |= T_FREE_CUSTOMDATA; + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialise snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; +} + +static void headerTimeSlide(TransInfo *t, float sval, char *str) +{ + char tvec[60]; + + if (hasNumInput(&t->num)) { + outputNumInput(&(t->num), tvec); + } + else { + float minx= *((float *)(t->customData)); + float maxx= *((float *)(t->customData + 1)); + float cval= t->fac; + float val; + + val= 2.0*(cval-sval) / (maxx-minx); + CLAMP(val, -1.0f, 1.0f); + + sprintf(&tvec[0], "%.4f", val); + } + + sprintf(str, "TimeSlide: %s", &tvec[0]); +} + +static void applyTimeSlide(TransInfo *t, float sval) +{ + TransData *td = t->data; + int i; + + float minx= *((float *)(t->customData)); + float maxx= *((float *)(t->customData + 1)); + + /* set value for drawing black line */ + if (t->spacetype == SPACE_ACTION) { + G.saction->timeslide= t->fac; + + if (NLA_ACTION_SCALED) + sval= get_action_frame(OBACT, sval); + } + + /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */ + for (i = 0 ; i < t->total; i++, td++) { + /* it is assumed that td->ob is a pointer to the object, + * whose active action is where this keyframe comes from + */ + Object *ob= td->ob; + float cval = t->fac; + + /* apply scaling to necessary values */ + if (ob) + cval= get_action_frame(ob, cval); + + /* only apply to data if in range */ + if (sval > minx && sval < maxx) { + float cvalc= CLAMPIS(cval, minx, maxx); + float timefac; + + /* left half? */ + if (td->ival < sval) { + timefac= (sval - td->ival) / (sval - minx); + *(td->val)= cvalc - timefac * (cvalc - minx); + } + else { + timefac= (td->ival - sval) / (maxx - sval); + *(td->val)= cvalc + timefac * (maxx - cvalc); + } + } + } +} + +int TimeSlide(TransInfo *t, short mval[2]) +{ + float cval[2], sval[2]; + char str[200]; + + /* calculate mouse co-ordinates */ + areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]); + areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]); + + /* calculate fake value to work with */ + t->fac= cval[0]; + + /* handle numeric-input stuff */ + t->vec[0] = t->fac; + applyNumInput(&t->num, &t->vec[0]); + t->fac = t->vec[0]; + headerTimeSlide(t, sval[0], str); + + applyTimeSlide(t, sval[0]); + + recalcData(t); + + headerprint(str); + + viewRedrawForce(t); + + return 1; +} + +/* ----------------- Scaling ----------------------- */ + +void initTimeScale(TransInfo *t) +{ + t->mode = TFM_TIME_SCALE; + t->transform = TimeScale; + + t->flag |= T_NULL_ONE; + t->num.flag |= NUM_NULL_ONE; + + /* num-input has max of (n-1) */ + t->idx_max = 0; + t->num.flag = 0; + t->num.idx_max = t->idx_max; + + /* initialise snap like for everything else */ + t->snap[0] = 0.0f; + t->snap[1] = t->snap[2] = 1.0f; +} + +static void headerTimeScale(TransInfo *t, char *str) { + char tvec[60]; + + if (hasNumInput(&t->num)) + outputNumInput(&(t->num), tvec); + else + sprintf(&tvec[0], "%.4f", t->fac); + + sprintf(str, "ScaleX: %s", &tvec[0]); +} + +static void applyTimeScale(TransInfo *t) { + TransData *td = t->data; + int i; + + short autosnap= getAnimEdit_SnapMode(t); + short doTime= getAnimEdit_DrawTime(t); + float secf= ((float)G.scene->r.frs_sec); + + + for (i = 0 ; i < t->total; i++, td++) { + /* it is assumed that td->ob is a pointer to the object, + * whose active action is where this keyframe comes from + */ + Object *ob= td->ob; + float startx= CFRA; + float fac= t->fac; + + if (autosnap == SACTSNAP_STEP) { + if (doTime) + fac= (float)( floor(fac/secf + 0.5f) * secf ); + else + fac= (float)( floor(fac + 0.5f) ); + } + + /* check if any need to apply nla-scaling */ + if (ob) + startx= get_action_frame(ob, startx); + + /* now, calculate the new value */ + *(td->val) = td->ival - startx; + *(td->val) *= fac; + *(td->val) += startx; + + /* apply snap-to-nearest-frame? */ + doAnimEdit_SnapFrame(t, td, ob, autosnap); + } +} + +int TimeScale(TransInfo *t, short mval[2]) +{ + float cval, sval; + float deltax, startx; + float width= 0.0f; + char str[200]; + + sval= t->imval[0]; + cval= mval[0]; + + switch (t->spacetype) { + case SPACE_ACTION: + width= ACTWIDTH; + break; + case SPACE_NLA: + width= NLAWIDTH; + break; + } + + /* calculate scaling factor */ + startx= sval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); + deltax= cval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); + t->fac = deltax / startx; + + /* handle numeric-input stuff */ + t->vec[0] = t->fac; + applyNumInput(&t->num, &t->vec[0]); + t->fac = t->vec[0]; + headerTimeScale(t, str); + + applyTimeScale(t); + + recalcData(t); + + headerprint(str); + + viewRedrawForce(t); + + return 1; +} + /* ************************************ */ void BIF_TransformSetUndo(char *str) diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c index ce572d56ce4..618c1908762 100644 --- a/source/blender/src/transform_conversions.c +++ b/source/blender/src/transform_conversions.c @@ -58,6 +58,7 @@ #include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_modifier_types.h" +#include "DNA_nla_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_scene_types.h" @@ -85,6 +86,8 @@ #include "BKE_global.h" #include "BKE_ipo.h" #include "BKE_lattice.h" +#include "BKE_key.h" +#include "BKE_main.h" #include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_modifier.h" @@ -98,6 +101,7 @@ #include "BIF_editconstraint.h" #include "BIF_editarmature.h" #include "BIF_editmesh.h" +#include "BIF_editnla.h" #include "BIF_editsima.h" #include "BIF_gl.h" #include "BIF_poseobject.h" @@ -112,6 +116,7 @@ #include "BSE_edit.h" #include "BSE_editipo.h" #include "BSE_editipo_types.h" +#include "BSE_editaction_types.h" #include "BDR_editobject.h" // reset_slowparents() #include "BDR_unwrapper.h" @@ -1982,6 +1987,256 @@ int clipUVTransform(TransInfo *t, float *vec, int resize) return (clipx || clipy); } +/* ********************* ACTION/NLA EDITOR ****************** */ + + +static void TimeToTransData(TransData *td, float *time, Object *ob) +{ + /* memory is calloc'ed, so that should zero everything nicely for us */ + td->val = time; + td->ival = *(time); + + /* store the Object where this keyframe exists as a keyframe of the + * active action as td->ob. Usually, this member is only used for constraints + * drawing + */ + td->ob= ob; +} + +/* This function advances the address to which td points to, so it must return + * the new address so that the next time new transform data is added, it doesn't + * overwrite the existing ones... i.e. td = IpoToTransData(td, ipo, ob); + */ +static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob) +{ + IpoCurve *icu; + BezTriple *bezt; + int i; + + if (ipo == NULL) + return td; + + for (icu= ipo->curve.first; icu; icu= icu->next) { + /* only add selected keyframes (for now, proportional edit is not enabled) */ + for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) { + if (BEZSELECTED(bezt)) { + /* each control point needs to be added separetely */ + TimeToTransData(td, bezt->vec[0], ob); + td++; + + TimeToTransData(td, bezt->vec[1], ob); + td++; + + TimeToTransData(td, bezt->vec[2], ob); + td++; + } + } + } + + return td; +} + +static void createTransActionData(TransInfo *t) +{ + TransData *td = NULL; + Object *ob= NULL; + + ListBase act_data = {NULL, NULL}; + bActListElem *ale; + void *data; + short datatype; + int filter; + + int count=0; + + /* determine what type of data we are operating on */ + data = get_action_context(&datatype); + if (data == NULL) return; + + /* filter data */ + filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS); + actdata_filter(&act_data, filter, data, datatype); + + /* is the action scaled? if so, the it should belong to the active object */ + if (NLA_ACTION_SCALED) + ob= OBACT; + + /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ + for (ale= act_data.first; ale; ale= ale->next) + count += fullselect_ipo_keys(ale->key_data); + + /* stop if trying to build list if nothing selected */ + if (count == 0) { + /* cleanup temp list */ + BLI_freelistN(&act_data); + return; + } + + /* allocate memory for data */ + t->total= count; + t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)"); + if (t->mode == TFM_TIME_SLIDE) + t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max"); + + td= t->data; + /* loop 2: build transdata array */ + for (ale= act_data.first; ale; ale= ale->next) { + Ipo *ipo= (Ipo *)ale->key_data; + + td= IpoToTransData(td, ipo, ob); + } + + /* check if we're supposed to be setting minx/maxx for TimeSlide */ + if (t->mode == TFM_TIME_SLIDE) { + float min = 0, max = 0; + int i; + + td= (t->data + 1); + for (i=1; i < count; i+=3, td+=3) { + if (min > *(td->val)) min= *(td->val); + if (max < *(td->val)) max= *(td->val); + } + + /* minx/maxx values used by TimeSlide are stored as a + * calloced 2-float array in t->customData. This gets freed + * in postTrans (T_FREE_CUSTOMDATA). + */ + *((float *)(t->customData)) = min; + *((float *)(t->customData + 1)) = max; + } + + /* cleanup temp list */ + BLI_freelistN(&act_data); +} + +static void createTransNLAData(TransInfo *t) +{ + Base *base; + bActionStrip *strip; + bActionChannel *achan; + bConstraintChannel *conchan; + + TransData *td = NULL; + int count=0, i; + + /* Ensure that partial selections result in beztriple selections */ + for (base=G.scene->base.first; base; base=base->next) { + /* Check object ipos */ + i= fullselect_ipo_keys(base->object->ipo); + if (i) base->flag |= BA_HAS_RECALC_OB; + count += i; + + /* Check object constraint ipos */ + for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) + count += fullselect_ipo_keys(conchan->ipo); + + /* skip actions and nlastrips if object is collapsed */ + if (base->object->nlaflag & OB_NLA_COLLAPSED) + continue; + + /* Check action ipos */ + if (base->object->action) { + /* exclude if strip is selected too */ + for (strip=base->object->nlastrips.first; strip; strip=strip->next) { + if (strip->flag & ACTSTRIP_SELECT) + if (strip->act == base->object->action) + break; + } + if (strip==NULL) { + for (achan=base->object->action->chanbase.first; achan; achan=achan->next) { + if (EDITABLE_ACHAN(achan)) { + i= fullselect_ipo_keys(achan->ipo); + if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; + count += i; + + /* Check action constraint ipos */ + if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { + if (EDITABLE_CONCHAN(conchan)) + count += fullselect_ipo_keys(conchan->ipo); + } + } + } + } + } + } + + /* Check nlastrips */ + for (strip=base->object->nlastrips.first; strip; strip=strip->next) { + if (strip->flag & ACTSTRIP_SELECT) { + base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; + count += 2; + } + } + } + + /* If nothing is selected, bail out */ + if (count == 0) + return; + + /* allocate memory for data */ + t->total= count; + t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (NLA Editor)"); + + /* build the transdata structure */ + td= t->data; + for (base=G.scene->base.first; base; base=base->next) { + /* Manipulate object ipos */ + /* - no scaling of keyframe times is allowed here */ + td= IpoToTransData(td, base->object->ipo, NULL); + + /* Manipulate object constraint ipos */ + /* - no scaling of keyframe times is allowed here */ + for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) + td= IpoToTransData(td, conchan->ipo, NULL); + + /* skip actions and nlastrips if object collapsed */ + if (base->object->nlaflag & OB_NLA_COLLAPSED) + continue; + + /* Manipulate action ipos */ + if (base->object->action) { + /* exclude if strip that active action belongs to is selected too */ + for (strip=base->object->nlastrips.first; strip; strip=strip->next) { + if (strip->flag & ACTSTRIP_SELECT) + if (strip->act == base->object->action) + break; + } + + /* can include if no strip found */ + if (strip==NULL) { + for (achan=base->object->action->chanbase.first; achan; achan=achan->next) { + if (EDITABLE_ACHAN(achan)) { + td= IpoToTransData(td, achan->ipo, base->object); + + /* Manipulate action constraint ipos */ + if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { + if (EDITABLE_CONCHAN(conchan)) + td= IpoToTransData(td, conchan->ipo, base->object); + } + } + } + } + } + } + + /* Manipulate nlastrips */ + for (strip=base->object->nlastrips.first; strip; strip=strip->next) { + if (strip->flag & ACTSTRIP_SELECT) { + /* first TransData is the start, second is the end */ + td->val = &strip->start; + td->ival = strip->start; + td++; + + td->val = &strip->end; + td->ival = strip->end; + td++; + } + } + } +} + /* **************** IpoKey stuff, for Object TransData ********** */ /* storage of bezier triple. thats why -3 and +3! */ @@ -2414,8 +2669,23 @@ void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik) } } +/* very bad call!!! - copied from editnla.c! */ +static void recalc_all_ipos(void) +{ + Ipo *ipo; + IpoCurve *icu; + + /* Go to each ipo */ + for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){ + for (icu = ipo->curve.first; icu; icu=icu->next){ + sort_time_ipocurve(icu); + testhandles_ipocurve(icu); + } + } +} + /* inserting keys, refresh ipo-keys, softbody, redraw events... (ton) */ -/* note; transdata has been freed already! */ +/* note: transdata has been freed already! */ void special_aftertrans_update(TransInfo *t) { Object *ob; @@ -2423,7 +2693,56 @@ void special_aftertrans_update(TransInfo *t) int redrawipo=0; int cancelled= (t->state == TRANS_CANCEL); - if(G.obedit) { + if(t->spacetype == SPACE_ACTION) { + void *data; + short datatype; + + /* determine what type of data we are operating on */ + data = get_action_context(&datatype); + if (data == NULL) return; + ob = OBACT; + + if (datatype == ACTCONT_ACTION) { + /* Update the curve */ + /* Depending on the lock status, draw necessary views */ + if (ob) { + ob->ctime= -1234567.0f; + + if(ob->pose || ob_get_key(ob)) + DAG_object_flush_update(G.scene, ob, OB_RECALC); + else + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); + } + + remake_action_ipos((bAction *)data); + + G.saction->flag &= ~SACTION_MOVING; + } + else if (datatype == ACTCONT_SHAPEKEY) { + /* fix up the Ipocurves and redraw stuff */ + Key *key= (Key *)data; + if (key->ipo) { + IpoCurve *icu; + + for (icu = key->ipo->curve.first; icu; icu=icu->next) { + sort_time_ipocurve(icu); + testhandles_ipocurve(icu); + } + } + + DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); + } + } + else if(t->spacetype == SPACE_NLA) { + synchronize_action_strips(); + + /* cleanup */ + for (base=G.scene->base.first; base; base=base->next) + base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA); + + recalc_all_ipos(); // bad + } + else if(G.obedit) { if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) allqueue(REDRAWBUTSEDIT, 0); @@ -2657,6 +2976,14 @@ void createTransData(TransInfo *t) sort_trans_data_dist(t); } } + else if (t->spacetype == SPACE_ACTION) { + t->flag |= T_POINTS|T_2D_EDIT; + createTransActionData(t); + } + else if (t->spacetype == SPACE_NLA) { + t->flag |= T_POINTS|T_2D_EDIT; + createTransNLAData(t); + } else if (G.obedit) { t->ext = NULL; if (G.obedit->type == OB_MESH) { diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index 357623ea494..562277ecff5 100644 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -54,8 +54,10 @@ #include "BIF_resources.h" #include "BIF_mywindow.h" #include "BIF_gl.h" +#include "BIF_editaction.h" #include "BIF_editarmature.h" #include "BIF_editmesh.h" +#include "BIF_editnla.h" #include "BIF_editsima.h" #include "BIF_meshtools.h" #include "BIF_retopo.h" @@ -75,6 +77,7 @@ #include "BKE_group.h" #include "BKE_ipo.h" #include "BKE_lattice.h" +#include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -85,6 +88,7 @@ #endif #include "BSE_view.h" +#include "BSE_editaction_types.h" #include "BDR_unwrapper.h" #include "BLI_arithb.h" @@ -215,8 +219,47 @@ void recalcData(TransInfo *t) #ifdef WITH_VERSE struct TransData *td; #endif + + if (t->spacetype == SPACE_ACTION) { + Object *ob= OBACT; + void *data; + short context; - if (G.obedit) { + /* determine what type of data we are operating on */ + data = get_action_context(&context); + if (data == NULL) return; + + if (G.saction->lock) { + if (context == ACTCONT_ACTION) { + if(ob) { + ob->ctime= -1234567.0f; + if(ob->pose || ob_get_key(ob)) + DAG_object_flush_update(G.scene, ob, OB_RECALC); + else + DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); + } + } + else if (context == ACTCONT_SHAPEKEY) { + DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA); + } + } + } + else if (t->spacetype == SPACE_NLA) { + if (G.snla->lock) { + for (base=G.scene->base.first; base; base=base->next) { + if (base->flag & BA_HAS_RECALC_OB) + base->object->recalc |= OB_RECALC_OB; + if (base->flag & BA_HAS_RECALC_DATA) + base->object->recalc |= OB_RECALC_DATA; + + if (base->object->recalc) + base->object->ctime= -1234567.0f; // eveil! + } + + DAG_scene_flush_update(G.scene, screen_view3d_layers()); + } + } + else if (G.obedit) { if (G.obedit->type == OB_MESH) { if(t->spacetype==SPACE_IMAGE) { flushTransUVs(t); |