Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/include/BIF_transform.h3
-rw-r--r--source/blender/include/transform.h9
-rw-r--r--source/blender/src/editaction.c420
-rw-r--r--source/blender/src/editnla.c294
-rw-r--r--source/blender/src/header_action.c4
-rw-r--r--source/blender/src/transform.c501
-rw-r--r--source/blender/src/transform_conversions.c331
-rw-r--r--source/blender/src/transform_generics.c45
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);