== 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.
This commit is contained in:
2007-09-24 11:29:25 +00:00
parent 1fde6d4570
commit c4860afba3
8 changed files with 918 additions and 689 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
break;
case 's':
{
initTransform(TFM_TIME_SCALE, CTX_NONE);
Transform();
}
break;
case 't':
{
initTransform(TFM_TIME_SLIDE, CTX_NONE);
Transform();
}
break;
}
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");
}
MEM_freeN(tv);
}
/* ----------------------------------------- */

View File

@@ -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);
}
}
}
}
}
switch (mode) {
case 'g':
{
initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
Transform();
}
/* 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;
}
break;
case 's':
{
initTransform(TFM_TIME_SCALE, CTX_NONE);
Transform();
}
break;
}
/* 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;
}
}
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);
}
}
}
lastcval[0]= cval[0];
lastcval[1]= cval[1];
firsttime= 0;
}
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)

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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) {

View File

@@ -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"
@@ -216,7 +220,46 @@ void recalcData(TransInfo *t)
struct TransData *td;
#endif
if (G.obedit) {
if (t->spacetype == SPACE_ACTION) {
Object *ob= OBACT;
void *data;
short context;
/* 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);