== Action Editor - Copy/Paste ==
Now the Copy/Paste functionality stores more info about where keyframes came from. This allows users to copy full poses in the Action Editor and paste them in another action. Peach request/bugfix for William.
This commit is contained in:
@@ -1144,10 +1144,9 @@ void clean_action (void)
|
||||
|
||||
/* **************************************************** */
|
||||
/* COPY/PASTE FOR ACTIONS */
|
||||
/* - The copy/paste buffer currently stores a set of IPO curves, with no
|
||||
* repeating curve-types (i.e. no curves with the same adrcode).
|
||||
* - Only selected keyframes from the source curves are placed here.
|
||||
* - Only 'compatible' pastes are done.
|
||||
/* - The copy/paste buffer currently stores a set of Action Channels, with temporary
|
||||
* IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes.
|
||||
* - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.)
|
||||
*/
|
||||
|
||||
/* globals for copy/paste data (like for other copy/paste buffers) */
|
||||
@@ -1156,16 +1155,34 @@ ListBase actcopybuf = {NULL, NULL};
|
||||
/* This function frees any MEM_calloc'ed copy/paste buffer data */
|
||||
void free_actcopybuf ()
|
||||
{
|
||||
IpoCurve *icu;
|
||||
bActionChannel *achan, *anext;
|
||||
bConstraintChannel *conchan, *cnext;
|
||||
|
||||
while( (icu= actcopybuf.first) ) {
|
||||
BLI_remlink(&actcopybuf, icu);
|
||||
free_ipo_curve(icu);
|
||||
for (achan= actcopybuf.first; achan; achan= next) {
|
||||
next= achan->next;
|
||||
|
||||
if (achan->ipo) {
|
||||
free_ipo(achan->ipo);
|
||||
MEM_freeN(achan->ipo);
|
||||
}
|
||||
|
||||
for (conchan=achan->constraintChannels.first; conchan; conchan=cnext) {
|
||||
cnext= conchan->next;
|
||||
|
||||
if (conchan->ipo) {
|
||||
free_ipo(conchan->ipo);
|
||||
MEM_freeN(conchan->ipo);
|
||||
}
|
||||
|
||||
BLI_freelistN(&achan->constraintChannels, conchan);
|
||||
}
|
||||
|
||||
BLI_freelinkN(&actcopybuf, achan);
|
||||
}
|
||||
}
|
||||
|
||||
/* This function adds data to the copy/paste buffer, freeing existing data first
|
||||
* Only the active action channel gets its selected keyframes copied.
|
||||
* Only the selected action channels gets their selected keyframes copied.
|
||||
*/
|
||||
void copy_actdata ()
|
||||
{
|
||||
@@ -1183,40 +1200,61 @@ void copy_actdata ()
|
||||
if (data == NULL) return;
|
||||
|
||||
/* filter data */
|
||||
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_ONLYICU);
|
||||
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_IPOKEYS);
|
||||
actdata_filter(&act_data, filter, data, datatype);
|
||||
|
||||
/* each of these entries should be an ipo curve */
|
||||
/* assume that each of these is an ipo-block */
|
||||
for (ale= act_data.first; ale; ale= ale->next) {
|
||||
IpoCurve *icu= ale->key_data;
|
||||
IpoCurve *icn;
|
||||
bActionChannel *achan;
|
||||
Ipo *ipo= ale->key_data;
|
||||
Ipo *ipn;
|
||||
IpoCurve *icu, *icn;
|
||||
BezTriple *bezt;
|
||||
short nin_buffer= 1;
|
||||
int i;
|
||||
|
||||
/* check if a curve like this exists already in buffer */
|
||||
for (icn= actcopybuf.first; icn; icn= icn->next) {
|
||||
if ((icn->blocktype==icu->blocktype) && (icn->adrcode==icu->adrcode)) {
|
||||
nin_buffer= 0;
|
||||
break;
|
||||
}
|
||||
/* coerce an action-channel out of owner */
|
||||
if (ale->ownertype == ACTTYPE_ACHAN) {
|
||||
bActionChannel *achanO= ale->owner;
|
||||
achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
|
||||
strcpy(achan->name, achanO->name);
|
||||
}
|
||||
/* allocate memory for a new curve if a valid one wasn't found */
|
||||
if (nin_buffer) {
|
||||
icn= MEM_callocN(sizeof(IpoCurve), "actcopybuf");
|
||||
|
||||
*icn= *icu;
|
||||
icn->totvert= 0;
|
||||
icn->bezt = NULL;
|
||||
icn->driver = NULL;
|
||||
|
||||
BLI_addtail(&actcopybuf, icn);
|
||||
else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
|
||||
achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
|
||||
strcpy(achan->name, "#ACP_ShapeKey");
|
||||
}
|
||||
else
|
||||
continue;
|
||||
BLI_addtail(&actcopybuf, achan);
|
||||
|
||||
/* find selected BezTriples to add to the buffer */
|
||||
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
|
||||
if (BEZSELECTED(bezt))
|
||||
insert_bezt_icu(icn, bezt);
|
||||
/* add constraint channel if needed, then add new ipo-block */
|
||||
if (ale->type == ACTTYPE_CONCHAN) {
|
||||
bConstraintChannel *conchanO= ale->data;
|
||||
bConstraintChannel *conchan;
|
||||
|
||||
conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan");
|
||||
strcpy(conchan->name, conchanO->name);
|
||||
BLI_addtail(&achan->constraintChannels, conchan);
|
||||
|
||||
conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
|
||||
}
|
||||
else {
|
||||
achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
|
||||
}
|
||||
ipn->blocktype = ipo->blocktype;
|
||||
|
||||
/* now loop through curves, and only copy selected keyframes */
|
||||
for (icu= ipo->curve.first; icu; icu= icu->next) {
|
||||
/* allocate a new curve */
|
||||
icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu");
|
||||
icn->blocktype = icu->blocktype;
|
||||
icn->adrcode = icu->adrcode;
|
||||
BLI_addtail(&ipn->curve, icn);
|
||||
|
||||
/* find selected BezTriples to add to the buffer */
|
||||
for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
|
||||
if (BEZSELECTED(bezt))
|
||||
insert_bezt_icu(icn, bezt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,48 +1285,88 @@ void paste_actdata ()
|
||||
if (data == NULL) return;
|
||||
|
||||
/* filter data */
|
||||
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
|
||||
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
|
||||
actdata_filter(&act_data, filter, data, datatype);
|
||||
|
||||
/* from selected channels */
|
||||
for (ale= act_data.first; ale; ale= ale->next) {
|
||||
IpoCurve *icu= ale->key_data;
|
||||
IpoCurve *ico;
|
||||
Ipo *ipo_src=NULL, *ipo_dst=ale->key_data;
|
||||
bActionChannel *achan;
|
||||
IpoCurve *ico, *icu;
|
||||
BezTriple *bezt;
|
||||
int i;
|
||||
float offset= 0.0f;
|
||||
short offsetInit= 1;
|
||||
|
||||
/* find matching ipo-curve */
|
||||
for (ico= actcopybuf.first; ico; ico= ico->next) {
|
||||
if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
|
||||
/* just start pasting, with the the first keyframe on the current frame, and so on */
|
||||
for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
|
||||
/* initialise offset (if not already done) */
|
||||
if (offsetInit) {
|
||||
offset= CFRA - bezt->vec[1][0];
|
||||
offsetInit= 0;
|
||||
/* find matching ipo-block */
|
||||
for (achan= actcopybuf.first; achan; achan= achan->next) {
|
||||
/* try to match data */
|
||||
if (ale->ownertype == ACTTYPE_ACHAN) {
|
||||
bActionChannel *achant= ale->owner;
|
||||
|
||||
/* check if we have a corresponding action channel */
|
||||
if (strcmp(achan->name, achant->name)==0) {
|
||||
/* check if this is a constraint channel */
|
||||
if (ale->type == ACTTYPE_CONCHAN) {
|
||||
bConstraintChannel *conchant= ale->data;
|
||||
bConstraintChannel *conchan;
|
||||
|
||||
for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
|
||||
if (strcmp(conchan->name, conchant->name)==0) {
|
||||
ipo_src= conchan->ipo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ipo_src) break;
|
||||
}
|
||||
else {
|
||||
ipo_src= achan->ipo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
|
||||
/* check if this action channel is "#ACP_ShapeKey" */
|
||||
if (strcmp(achan->name, "#ACP_ShapeKey")==0) {
|
||||
ipo_src= achan->ipo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* loop over curves, pasting keyframes */
|
||||
for (icu= ipo_dst->curve.first; icu; icu= icu->next) {
|
||||
for (ico= ipo_src->curve.first; ico; ico= ico->next) {
|
||||
/* only paste if compatable blocktype + adrcode */
|
||||
if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
|
||||
/* just start pasting, with the the first keyframe on the current frame, and so on */
|
||||
for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
|
||||
/* initialise offset (if not already done) */
|
||||
if (offsetInit) {
|
||||
offset= CFRA - bezt->vec[1][0];
|
||||
offsetInit= 0;
|
||||
}
|
||||
|
||||
/* temporarily apply offset to src beztriple while copying */
|
||||
bezt->vec[0][0] += offset;
|
||||
bezt->vec[1][0] += offset;
|
||||
bezt->vec[2][0] += offset;
|
||||
|
||||
/* insert the keyframe */
|
||||
insert_bezt_icu(icu, bezt);
|
||||
|
||||
/* un-apply offset from src beztriple after copying */
|
||||
bezt->vec[0][0] -= offset;
|
||||
bezt->vec[1][0] -= offset;
|
||||
bezt->vec[2][0] -= offset;
|
||||
}
|
||||
|
||||
/* temporarily apply offset to src beztriple while copying */
|
||||
bezt->vec[0][0] += offset;
|
||||
bezt->vec[1][0] += offset;
|
||||
bezt->vec[2][0] += offset;
|
||||
/* recalculate channel's handles? */
|
||||
calchandles_ipocurve(icu);
|
||||
|
||||
/* insert the keyframe */
|
||||
insert_bezt_icu(icu, bezt);
|
||||
|
||||
/* un-apply offset from src beztriple after copying */
|
||||
bezt->vec[0][0] -= offset;
|
||||
bezt->vec[1][0] -= offset;
|
||||
bezt->vec[2][0] -= offset;
|
||||
/* done for this channel */
|
||||
break;
|
||||
}
|
||||
|
||||
/* recalculate channel's handles? */
|
||||
calchandles_ipocurve(icu);
|
||||
|
||||
/* done for this channel */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user