2002-10-12 11:37:38 +00:00
|
|
|
/**
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version. The Blender
|
|
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
|
|
* about this.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
2002-11-25 12:02:15 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
#include "BLI_winstuff.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "PIL_time.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
|
|
|
|
#include "DNA_action_types.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_ipo_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_userdef_types.h"
|
|
|
|
#include "DNA_constraint_types.h"
|
|
|
|
|
|
|
|
#include "BKE_armature.h"
|
|
|
|
#include "BKE_constraint.h"
|
|
|
|
#include "BKE_displist.h"
|
|
|
|
#include "BKE_curve.h"
|
|
|
|
#include "BKE_ipo.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_action.h"
|
|
|
|
|
|
|
|
#include "BIF_gl.h"
|
|
|
|
#include "BIF_mywindow.h"
|
|
|
|
#include "BIF_toolbox.h"
|
|
|
|
#include "BIF_screen.h"
|
|
|
|
#include "BIF_space.h"
|
|
|
|
#include "BIF_buttons.h"
|
|
|
|
#include "BIF_interface.h"
|
|
|
|
#include "BIF_editview.h"
|
|
|
|
#include "BIF_poseobject.h"
|
|
|
|
#include "BIF_editarmature.h"
|
|
|
|
|
|
|
|
#include "BSE_edit.h"
|
|
|
|
#include "BSE_drawipo.h"
|
|
|
|
#include "BSE_headerbuttons.h"
|
|
|
|
#include "BSE_editipo.h"
|
|
|
|
#include "BSE_editaction.h"
|
|
|
|
#include "BSE_trans_types.h"
|
|
|
|
#include "BSE_editaction_types.h"
|
|
|
|
|
|
|
|
#include "BDR_editobject.h"
|
|
|
|
|
|
|
|
#include "blendertimer.h"
|
|
|
|
|
|
|
|
#include "interface.h"
|
|
|
|
#include "mydevice.h"
|
|
|
|
#include "blendef.h"
|
|
|
|
#include "nla.h"
|
|
|
|
|
|
|
|
static bPose *g_posebuf=NULL;
|
|
|
|
extern int count_action_levels (bAction *act);
|
|
|
|
|
|
|
|
#define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
|
|
|
|
|
|
|
|
/* Local Function prototypes */
|
|
|
|
|
|
|
|
static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float time);
|
|
|
|
static void flip_name (char *name);
|
|
|
|
static void mouse_actionchannels(bAction *act, short *mval);
|
|
|
|
static void borderselect_action(void);
|
|
|
|
static void mouse_action(void);
|
|
|
|
static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **conchan);
|
|
|
|
static void delete_actionchannels(void);
|
|
|
|
static void delete_actionchannel_keys(void);
|
|
|
|
static void duplicate_actionchannel_keys(void);
|
|
|
|
static void transform_actionchannel_keys(char mode);
|
|
|
|
static void select_poseelement_by_name (char *name, int select);
|
|
|
|
static void hilight_channel (bAction *act, bActionChannel *chan, short hilight);
|
|
|
|
static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time);
|
|
|
|
|
|
|
|
/* Implementation */
|
|
|
|
|
|
|
|
static void select_poseelement_by_name (char *name, int select)
|
|
|
|
{
|
|
|
|
/* Synchs selection of channels with selection of object elements in posemode */
|
|
|
|
|
|
|
|
Object *ob;
|
|
|
|
|
|
|
|
ob = G.obpose;
|
|
|
|
if (!ob)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (ob->type){
|
|
|
|
case OB_ARMATURE:
|
|
|
|
select_bone_by_name ((bArmature*)ob->data, name, select);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef __NLA_BAKE
|
|
|
|
bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
|
|
|
|
{
|
|
|
|
bAction *result=NULL;
|
|
|
|
bActionChannel *achan;
|
|
|
|
float actlen;
|
|
|
|
int curframe;
|
|
|
|
char newname[64];
|
|
|
|
bArmature *arm;
|
|
|
|
Bone *bone;
|
|
|
|
float oldframe;
|
|
|
|
bAction *temp;
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
arm = get_armature(armob);
|
|
|
|
|
|
|
|
|
|
|
|
if (G.obedit){
|
|
|
|
error ("Not in editmode");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arm){
|
|
|
|
error ("Must have an armature selected");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Get a new action */
|
|
|
|
result = add_empty_action();
|
|
|
|
|
|
|
|
/* Assign the new action a unique name */
|
|
|
|
sprintf (newname, "%s.BAKED", act->id.name+2);
|
|
|
|
rename_id(&result->id, newname);
|
|
|
|
|
|
|
|
actlen = calc_action_end(act);
|
|
|
|
|
|
|
|
oldframe = G.scene->r.cfra;
|
|
|
|
|
|
|
|
temp = armob->action;
|
|
|
|
armob->action = act;
|
|
|
|
|
|
|
|
for (curframe=1; curframe<ceil(actlen+1); curframe++){
|
|
|
|
|
|
|
|
/* Apply the old action */
|
|
|
|
|
|
|
|
G.scene->r.cfra = curframe;
|
|
|
|
|
|
|
|
/* Apply the object ipo */
|
|
|
|
get_pose_from_action(&armob->pose, act, curframe);
|
|
|
|
apply_pose_armature(arm, armob->pose, 1);
|
|
|
|
clear_object_constraint_status(armob);
|
|
|
|
where_is_armature_time(armob, curframe);
|
|
|
|
|
|
|
|
/* For each channel: set avail keys with current values */
|
|
|
|
for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){
|
|
|
|
|
|
|
|
/* Copy the constraints from the armature (if any) */
|
|
|
|
|
|
|
|
bone = get_named_bone(arm, pchan->name);
|
|
|
|
if (bone){
|
|
|
|
|
|
|
|
Mat4ToQuat(pchan->obmat, pchan->quat);
|
|
|
|
Mat4ToSize(pchan->obmat, pchan->size);
|
|
|
|
VECCOPY(pchan->loc, pchan->obmat[3]);
|
|
|
|
|
|
|
|
/* Apply to keys */
|
|
|
|
set_action_key_time (result, pchan, AC_QUAT_X, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_QUAT_Y, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_QUAT_Z, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_QUAT_W, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_LOC_X, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_LOC_Y, 1, curframe);
|
|
|
|
set_action_key_time (result, pchan, AC_LOC_Z, 1, curframe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make another pass to ensure all keyframes are set to linear interpolation mode */
|
|
|
|
for (achan = result->chanbase.first; achan; achan=achan->next){
|
|
|
|
IpoCurve* icu;
|
|
|
|
for (icu = achan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
icu->ipo= IPO_LIN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
notice ("Made new action \"%s\"", newname);
|
|
|
|
G.scene->r.cfra = oldframe;
|
|
|
|
armob->action = temp;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void select_actionchannel_by_name (bAction *act, char *name, int select)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (!strcmp (chan->name, name)){
|
|
|
|
act->achan = chan;
|
|
|
|
if (select){
|
|
|
|
chan->flag |= ACHAN_SELECTED;
|
|
|
|
hilight_channel (act, chan, 1);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
chan->flag &= ~ACHAN_SELECTED;
|
|
|
|
hilight_channel (act, chan, 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void remake_action_ipos(bAction *act)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
IpoCurve *icu;
|
|
|
|
|
|
|
|
for (chan= act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (chan->ipo){
|
|
|
|
for (icu = chan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
sort_time_ipocurve(icu);
|
|
|
|
testhandles_ipocurve(icu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
if (conchan->ipo){
|
|
|
|
for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
sort_time_ipocurve(icu);
|
|
|
|
testhandles_ipocurve(icu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void duplicate_actionchannel_keys(void)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
|
|
|
|
act=G.saction->action;
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Find selected items */
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
duplicate_ipo_keys(chan->ipo);
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
duplicate_ipo_keys(conchan->ipo);
|
|
|
|
}
|
|
|
|
|
|
|
|
transform_actionchannel_keys ('g');
|
|
|
|
}
|
|
|
|
|
|
|
|
static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan){
|
|
|
|
bAction *act;
|
|
|
|
bActionChannel *chan;
|
|
|
|
IpoCurve *icu;
|
|
|
|
bActionChannel *firstchan=NULL;
|
|
|
|
bConstraintChannel *conchan, *firstconchan=NULL;
|
|
|
|
int foundsel=0;
|
|
|
|
float firstvert=-1, foundx=-1;
|
|
|
|
int i;
|
|
|
|
short mval[2];
|
|
|
|
float ymin, ymax;
|
|
|
|
rctf rectf;
|
|
|
|
*index=0;
|
|
|
|
|
|
|
|
*rchan=NULL;
|
|
|
|
act=G.saction->action; /* We presume that we are only called during a valid action */
|
|
|
|
|
|
|
|
getmouseco_areawin (mval);
|
|
|
|
|
|
|
|
mval[0]-=7;
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
|
|
|
|
|
|
|
|
mval[0]+=14;
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
|
|
|
|
|
|
|
|
ymax = count_action_levels (act) * (CHANNELHEIGHT + CHANNELSKIP);
|
|
|
|
|
|
|
|
*sel=0;
|
|
|
|
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
|
|
|
|
/* Check action channel */
|
|
|
|
ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
|
|
|
|
for (icu=chan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
for (i=0; i<icu->totvert; i++){
|
|
|
|
if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
|
|
|
|
if (!firstchan){
|
|
|
|
firstchan=chan;
|
|
|
|
firstvert=icu->bezt[i].vec[1][0];
|
|
|
|
*sel = icu->bezt[i].f2 & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (icu->bezt[i].f2 & 1){
|
|
|
|
if (!foundsel){
|
|
|
|
foundsel=1;
|
|
|
|
foundx = icu->bezt[i].vec[1][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
|
|
|
|
*index=icu->bezt[i].vec[1][0];
|
|
|
|
*sel = 0;
|
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ymax=ymin;
|
|
|
|
|
|
|
|
/* Check constraint channels */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
|
|
|
|
for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
for (i=0; i<icu->totvert; i++){
|
|
|
|
if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
|
|
|
|
if (!firstchan){
|
|
|
|
firstchan=chan;
|
|
|
|
firstconchan=conchan;
|
|
|
|
firstvert=icu->bezt[i].vec[1][0];
|
|
|
|
*sel = icu->bezt[i].f2 & 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (icu->bezt[i].f2 & 1){
|
|
|
|
if (!foundsel){
|
|
|
|
foundsel=1;
|
|
|
|
foundx = icu->bezt[i].vec[1][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
|
|
|
|
*index=icu->bezt[i].vec[1][0];
|
|
|
|
*sel = 0;
|
|
|
|
*rchan = conchan;
|
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ymax=ymin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*rchan = firstconchan;
|
|
|
|
*index=firstvert;
|
|
|
|
return firstchan;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mouse_action(void)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
short sel;
|
|
|
|
float selx;
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
short mval[2];
|
|
|
|
|
|
|
|
act=G.saction->action;
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
getmouseco_areawin (mval);
|
|
|
|
|
|
|
|
chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
|
|
|
|
|
|
|
|
if (chan){
|
|
|
|
if (!(G.qual & LR_SHIFTKEY)){
|
|
|
|
deselect_actionchannel_keys(act, 0);
|
|
|
|
deselect_actionchannels(act, 0);
|
|
|
|
act->achan = chan;
|
|
|
|
chan->flag |= ACHAN_SELECTED;
|
|
|
|
hilight_channel (act, chan, 1);
|
|
|
|
sel = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conchan)
|
|
|
|
select_ipo_key(conchan->ipo, selx, sel);
|
|
|
|
else
|
|
|
|
select_ipo_key(chan->ipo, selx, sel);
|
|
|
|
|
|
|
|
allqueue(REDRAWIPO, 0);
|
|
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
|
|
allqueue(REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void borderselect_action(void)
|
|
|
|
{
|
|
|
|
rcti rect;
|
|
|
|
rctf rectf;
|
|
|
|
int val;
|
|
|
|
short mval[2];
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
bAction *act;
|
|
|
|
float ymin, ymax;
|
|
|
|
|
|
|
|
act=G.saction->action;
|
|
|
|
val= get_border (&rect, 3);
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (val){
|
|
|
|
mval[0]= rect.xmin;
|
|
|
|
mval[1]= rect.ymin+2;
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
|
|
|
|
mval[0]= rect.xmax;
|
|
|
|
mval[1]= rect.ymax-2;
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
|
|
|
|
|
|
|
|
ymax=count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
|
|
|
|
/* Check action */
|
|
|
|
ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
|
|
|
|
borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val);
|
|
|
|
|
|
|
|
ymax=ymin;
|
|
|
|
|
|
|
|
/* Check constraints */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
|
|
|
|
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
|
|
|
|
|
|
|
|
ymax=ymin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
allqueue(REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWIPO, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bActionChannel* get_hilighted_action_channel(bAction* action)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
|
|
|
|
if (!action)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (chan=action->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED)
|
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_exprap_action(int mode)
|
|
|
|
{
|
|
|
|
if(G.saction->action && G.saction->action->id.lib) return;
|
|
|
|
|
|
|
|
error ("Not yet implemented!");
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_posebuf(void)
|
|
|
|
{
|
|
|
|
if (g_posebuf){
|
|
|
|
clear_pose(g_posebuf);
|
|
|
|
MEM_freeN (g_posebuf);
|
|
|
|
}
|
|
|
|
g_posebuf=NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void copy_posebuf (void)
|
|
|
|
{
|
|
|
|
Object *ob;
|
|
|
|
|
|
|
|
free_posebuf();
|
|
|
|
|
|
|
|
ob=G.obpose;
|
|
|
|
if (!ob){
|
|
|
|
error ("Copybuf is empty");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
filter_pose_keys();
|
|
|
|
copy_pose(&g_posebuf, ob->pose, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flip_name (char *name)
|
|
|
|
{
|
|
|
|
|
|
|
|
char prefix[128]={""}; /* The part before the facing */
|
|
|
|
char suffix[128]={""}; /* The part after the facing */
|
|
|
|
char replace[128]={""}; /* The replacement string */
|
|
|
|
|
|
|
|
char *index=NULL;
|
|
|
|
/* Find the last period */
|
|
|
|
|
|
|
|
strcpy (prefix, name);
|
|
|
|
|
|
|
|
/* Check for an instance of .Right */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "Right");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "Left");
|
|
|
|
strcpy (suffix, index+6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Che ck for an instance of .RIGHT */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "RIGHT");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "LEFT");
|
|
|
|
strcpy (suffix, index+6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Check for an instance of .right */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "right");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "left");
|
|
|
|
strcpy (suffix, index+6);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for an instance of .left */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "left");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "right");
|
|
|
|
strcpy (suffix, index+5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for an instance of .LEFT */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "LEFT");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "RIGHT");
|
|
|
|
strcpy (suffix, index+5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for an instance of .Left */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, "Left");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, "Right");
|
|
|
|
strcpy (suffix, index+5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for an instance of .L */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, ".L");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, ".R");
|
|
|
|
strcpy (suffix, index+2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for an instance of .l */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, ".l");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, ".r");
|
|
|
|
strcpy (suffix, index+2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checl for an instance of .R */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, ".R");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, ".L");
|
|
|
|
strcpy (suffix, index+2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checl for an instance of .r */
|
|
|
|
if (!index){
|
|
|
|
index = strstr (prefix, ".r");
|
|
|
|
if (index){
|
|
|
|
*index=0;
|
|
|
|
strcpy (replace, ".l");
|
|
|
|
strcpy (suffix, index+2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf (name, "%s%s%s", prefix, replace, suffix);
|
|
|
|
}
|
|
|
|
|
|
|
|
void paste_posebuf (int flip){
|
|
|
|
Object *ob;
|
|
|
|
bPoseChannel *temp, *chan;
|
|
|
|
float eul[4];
|
|
|
|
Base *base;
|
|
|
|
int newchan = 0;
|
|
|
|
|
|
|
|
ob=G.obpose;
|
|
|
|
if (!ob)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_posebuf){
|
|
|
|
error ("Copybuf is empty");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
collect_pose_garbage(ob);
|
|
|
|
|
|
|
|
/* Safely merge all of the channels in this pose into
|
|
|
|
any existing pose */
|
|
|
|
if (ob->pose){
|
2003-01-28 11:14:38 +00:00
|
|
|
if (U.uiflag & KEYINSERTACT){
|
2002-10-12 11:37:38 +00:00
|
|
|
/* Display "Avail, all" dialog */
|
|
|
|
}
|
|
|
|
for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (chan->flag & POSE_KEY){
|
|
|
|
temp = copy_pose_channel (chan);
|
|
|
|
if (flip){
|
|
|
|
flip_name (temp->name);
|
|
|
|
temp->loc[0]*=-1;
|
|
|
|
|
|
|
|
QuatToEul(temp->quat, eul);
|
|
|
|
eul[1]*=-1;
|
|
|
|
eul[2]*=-1;
|
|
|
|
EulToQuat(eul, temp->quat);
|
|
|
|
}
|
|
|
|
|
|
|
|
temp = set_pose_channel (ob->pose, temp);
|
|
|
|
|
2003-01-28 11:14:38 +00:00
|
|
|
if (U.uiflag & KEYINSERTACT){
|
2002-10-12 11:37:38 +00:00
|
|
|
/* Set keys on pose */
|
|
|
|
if (chan->flag & POSE_ROT){
|
|
|
|
set_action_key(ob->action, temp, AC_QUAT_X, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_QUAT_Y, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_QUAT_Z, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_QUAT_W, newchan);
|
|
|
|
};
|
|
|
|
if (chan->flag & POSE_SIZE){
|
|
|
|
set_action_key(ob->action, temp, AC_SIZE_X, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_SIZE_Y, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_SIZE_Z, newchan);
|
|
|
|
};
|
|
|
|
if (chan->flag & POSE_LOC){
|
|
|
|
set_action_key(ob->action, temp, AC_LOC_X, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_LOC_Y, newchan);
|
|
|
|
set_action_key(ob->action, temp, AC_LOC_Z, newchan);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-28 11:14:38 +00:00
|
|
|
if (U.uiflag & KEYINSERTACT){
|
2002-10-12 11:37:38 +00:00
|
|
|
remake_action_ipos(ob->action);
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
allqueue (REDRAWVIEW3D, 0);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update deformation children */
|
|
|
|
if (G.obpose->type == OB_ARMATURE){
|
|
|
|
for (base= FIRSTBASE; base; base= base->next){
|
|
|
|
if (G.obpose==base->object->parent){
|
|
|
|
if (base->object->partype==PARSKEL)
|
|
|
|
makeDispList(base->object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_action_key (struct bAction *act, struct bPoseChannel *chan, int adrcode, short makecurve)
|
|
|
|
{
|
|
|
|
set_action_key_time (act, chan, adrcode, makecurve, frame_to_float(CFRA));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time)
|
|
|
|
{
|
|
|
|
bActionChannel *achan;
|
|
|
|
char ipstr[256];
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!chan)
|
|
|
|
return;
|
|
|
|
/* See if this action channel exists already */
|
|
|
|
for (achan=act->chanbase.first; achan; achan=achan->next){
|
|
|
|
if (!strcmp (chan->name, achan->name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!achan){
|
|
|
|
if (!makecurve)
|
|
|
|
return;
|
|
|
|
achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
|
|
|
|
strcpy (achan->name, chan->name);
|
|
|
|
BLI_addtail (&act->chanbase, achan);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure the channel appears selected in the action window */
|
|
|
|
achan->flag |= ACHAN_SELECTED;
|
|
|
|
|
|
|
|
/* Ensure this action channel has a valid Ipo */
|
|
|
|
if (!achan->ipo){
|
|
|
|
sprintf (ipstr, "%s.%s", act->id.name+2, chan->name);
|
|
|
|
ipstr[23]=0;
|
|
|
|
achan->ipo= add_ipo(ipstr, ID_AC);
|
|
|
|
}
|
|
|
|
|
|
|
|
insertactionkey(act, achan, chan, adrcode, makecurve, time);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float cfra)
|
|
|
|
{
|
|
|
|
IpoCurve *icu;
|
|
|
|
void *poin;
|
|
|
|
float curval;
|
|
|
|
int type;
|
|
|
|
ID *id;
|
|
|
|
|
|
|
|
if (!act){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (act->id.lib){
|
|
|
|
error ("Can't pose libactions");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
act->achan=achan;
|
|
|
|
act->pchan=chan;
|
|
|
|
|
|
|
|
id=(ID*) act;
|
|
|
|
|
|
|
|
/* First see if this curve exists */
|
|
|
|
if (!makecurve){
|
|
|
|
if (!achan->ipo)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (icu = achan->ipo->curve.first; icu; icu=icu->next){
|
|
|
|
if (icu->adrcode == adrcode)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!icu)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
icu = get_ipocurve (id, GS(id->name), adrcode, achan->ipo);
|
|
|
|
|
|
|
|
if(icu) {
|
|
|
|
poin= get_ipo_poin(id, icu, &type);
|
|
|
|
if(poin) {
|
|
|
|
curval= read_ipo_poin(poin, type);
|
|
|
|
// cfra= frame_to_float(CFRA);
|
|
|
|
insert_vert_ipo(icu, cfra, curval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bAction *add_empty_action(void)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
|
|
|
|
act= alloc_libblock(&G.main->action, ID_AC, "Action");
|
|
|
|
act->id.flag |= LIB_FAKEUSER;
|
|
|
|
act->id.us++;
|
|
|
|
return act;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void transform_actionchannel_keys(char mode)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
TransVert *tv;
|
|
|
|
int /*sel=0,*/ i;
|
|
|
|
bActionChannel *chan;
|
|
|
|
short mvals[2], mvalc[2], cent[2];
|
|
|
|
float sval[2], cval[2], lastcval[2];
|
|
|
|
short cancel=0;
|
|
|
|
float fac=0.0F;
|
|
|
|
int loop=1;
|
|
|
|
int tvtot=0;
|
|
|
|
float deltax, startx;
|
|
|
|
float cenf[2];
|
|
|
|
int invert=0, firsttime=1;
|
|
|
|
char str[256];
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
|
|
|
|
act=G.saction->action;
|
|
|
|
|
|
|
|
/* Ensure that partial selections result in beztriple selections */
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
tvtot+=fullselect_ipo_keys(chan->ipo);
|
|
|
|
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
tvtot+=fullselect_ipo_keys(conchan->ipo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If nothing is selected, bail out */
|
|
|
|
if (!tvtot)
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
/* Build the transvert structure */
|
|
|
|
tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
|
|
|
|
tvtot=0;
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
/* Add the actionchannel */
|
|
|
|
tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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]);
|
|
|
|
|
|
|
|
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++) {
|
|
|
|
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 (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
|
|
|
|
PIL_sleep_ms(1);
|
|
|
|
} else {
|
|
|
|
for (i=0; i<tvtot; i++){
|
|
|
|
tv[i].loc[0]=tv[i].oldloc[0];
|
|
|
|
|
|
|
|
switch (mode){
|
|
|
|
case 'g':
|
|
|
|
deltax = cval[0]-sval[0];
|
|
|
|
fac= deltax;
|
|
|
|
|
|
|
|
apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & AUTOGRABGRID);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & 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);
|
|
|
|
|
|
|
|
tv[i].loc[0]-= startx;
|
|
|
|
tv[i].loc[0]*=fac;
|
|
|
|
tv[i].loc[0]+= startx;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode=='s'){
|
|
|
|
sprintf(str, "sizeX: %.3f", fac);
|
|
|
|
headerprint(str);
|
|
|
|
}
|
|
|
|
else if (mode=='g'){
|
|
|
|
sprintf(str, "deltaX: %.3f", fac);
|
|
|
|
headerprint(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (G.saction->lock){
|
|
|
|
do_all_actions();
|
|
|
|
allqueue (REDRAWVIEW3D, 0);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
force_draw_all();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
addqueue (curarea->win, REDRAWALL, 0);
|
|
|
|
force_draw ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lastcval[0]= cval[0];
|
|
|
|
lastcval[1]= cval[1];
|
|
|
|
firsttime= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the curve */
|
|
|
|
/* Depending on the lock status, draw necessary views */
|
|
|
|
|
|
|
|
do_all_actions();
|
|
|
|
remake_action_ipos(act);
|
|
|
|
allqueue (REDRAWVIEW3D, 0);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
MEM_freeN (tv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void deselect_actionchannel_keys (bAction *act, int test)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
int sel=1;;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Determine if this is selection or deselection */
|
|
|
|
|
|
|
|
if (test){
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
/* Test the channel ipos */
|
|
|
|
if (is_ipo_key_selected(chan->ipo)){
|
|
|
|
sel = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test the constraint ipos */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
if (is_ipo_key_selected(conchan->ipo)){
|
|
|
|
sel = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sel=0;
|
|
|
|
|
|
|
|
/* Set the flags */
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
set_ipo_key_selection(chan->ipo, sel);
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
set_ipo_key_selection(conchan->ipo, sel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void deselect_actionchannels (bAction *act, int test)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
int sel=1;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* See if we should be selecting or deselecting */
|
|
|
|
if (test){
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (!sel)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (chan->flag & ACHAN_SELECTED){
|
|
|
|
sel=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sel){
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
|
|
|
|
sel=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sel=0;
|
|
|
|
|
|
|
|
/* Now set the flags */
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
select_poseelement_by_name(chan->name, sel);
|
|
|
|
|
|
|
|
if (sel)
|
|
|
|
chan->flag |= ACHAN_SELECTED;
|
|
|
|
else
|
|
|
|
chan->flag &= ~ACHAN_SELECTED;
|
|
|
|
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
if (sel)
|
|
|
|
conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
|
|
|
|
else
|
|
|
|
conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hilight_channel (bAction *act, bActionChannel *chan, short select)
|
|
|
|
{
|
|
|
|
bActionChannel *curchan;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
|
|
|
|
if (curchan==chan && select)
|
|
|
|
curchan->flag |= ACHAN_HILIGHTED;
|
|
|
|
else
|
|
|
|
curchan->flag &= ~ACHAN_HILIGHTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mouse_actionchannels(bAction *act, short *mval)
|
|
|
|
{
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *clickconchan=NULL;
|
|
|
|
float click;
|
|
|
|
int wsize;
|
|
|
|
int sel;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
|
|
|
|
|
|
|
|
|
|
|
|
click = (wsize-(mval[1]+G.v2d->cur.ymin));
|
|
|
|
click += CHANNELHEIGHT/2;
|
|
|
|
click /= (CHANNELHEIGHT+CHANNELSKIP);
|
|
|
|
|
|
|
|
if (click<0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if ((int)click==0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
click--;
|
|
|
|
|
|
|
|
/* Check for click in a constraint */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
|
|
|
|
if ((int)click==0){
|
|
|
|
clickconchan=conchan;
|
|
|
|
chan=act->chanbase.last;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
click--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!chan){
|
|
|
|
if (clickconchan){
|
|
|
|
if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT)
|
|
|
|
sel = 0;
|
|
|
|
else
|
|
|
|
sel =1;
|
|
|
|
|
|
|
|
/* Channel names clicking */
|
|
|
|
if (G.qual & LR_SHIFTKEY){
|
|
|
|
// select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
|
|
|
|
if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT){
|
|
|
|
clickconchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
|
|
|
|
// hilight_channel(act, chan, 0);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT;
|
|
|
|
// hilight_channel(act, chan, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
deselect_actionchannels (act, 0); // Auto clear
|
|
|
|
clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT;
|
|
|
|
// hilight_channel(act, chan, 1);
|
|
|
|
// act->achan = chan;
|
|
|
|
// select_poseelement_by_name(chan->name, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
/* Choose the mode */
|
|
|
|
if (chan->flag & ACHAN_SELECTED)
|
|
|
|
sel = 0;
|
|
|
|
else
|
|
|
|
sel =1;
|
|
|
|
|
|
|
|
/* Channel names clicking */
|
|
|
|
if (G.qual & LR_SHIFTKEY){
|
|
|
|
select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
|
|
|
|
if (chan->flag & ACHAN_SELECTED){
|
|
|
|
chan->flag &= ~ACHAN_SELECTED;
|
|
|
|
hilight_channel(act, chan, 0);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
chan->flag |= ACHAN_SELECTED;
|
|
|
|
hilight_channel(act, chan, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
deselect_actionchannels (act, 0); // Auto clear
|
|
|
|
chan->flag |= ACHAN_SELECTED;
|
|
|
|
hilight_channel(act, chan, 1);
|
|
|
|
act->achan = chan;
|
|
|
|
select_poseelement_by_name(chan->name, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
allqueue (REDRAWVIEW3D, 0);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void delete_actionchannel_keys(void)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
bActionChannel *chan;
|
|
|
|
bConstraintChannel *conchan;
|
|
|
|
|
|
|
|
act = G.saction->action;
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!okee("Erase selected keys"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
|
|
|
|
/* Check action channel keys*/
|
|
|
|
delete_ipo_keys(chan->ipo);
|
|
|
|
|
|
|
|
/* Delete constraint channel keys */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
delete_ipo_keys(conchan->ipo);
|
|
|
|
}
|
|
|
|
|
|
|
|
remake_action_ipos (act);
|
|
|
|
allspace(REMAKEIPO, 0);
|
|
|
|
allqueue(REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWIPO, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
static void delete_actionchannels (void)
|
|
|
|
{
|
|
|
|
bConstraintChannel *conchan, *nextconchan;
|
|
|
|
bActionChannel *chan, *next;
|
|
|
|
bAction *act;
|
|
|
|
int freechan;
|
|
|
|
|
|
|
|
act=G.saction->action;
|
|
|
|
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (chan=act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (chan->flag & ACHAN_SELECTED)
|
|
|
|
break;
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
|
|
|
|
{
|
|
|
|
if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
|
|
|
|
chan=act->chanbase.last;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!chan && !conchan)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!okee("Erase selected channels"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (chan=act->chanbase.first; chan; chan=next){
|
|
|
|
freechan = 0;
|
|
|
|
next=chan->next;
|
|
|
|
|
|
|
|
/* Remove action channels */
|
|
|
|
if (chan->flag & ACHAN_SELECTED){
|
|
|
|
if (chan->ipo)
|
|
|
|
chan->ipo->id.us--; /* Release the ipo */
|
|
|
|
freechan = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove constraint channels */
|
|
|
|
for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
|
|
|
|
nextconchan=conchan->next;
|
|
|
|
if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
|
|
|
|
if (conchan->ipo)
|
|
|
|
conchan->ipo->id.us--;
|
|
|
|
BLI_freelinkN(&chan->constraintChannels, conchan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (freechan)
|
|
|
|
BLI_freelinkN (&act->chanbase, chan);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
|
|
|
|
}
|
2003-01-28 03:11:27 +00:00
|
|
|
|
|
|
|
static void sethandles_actionchannel_keys(int code)
|
|
|
|
{
|
|
|
|
bAction *act;
|
|
|
|
bActionChannel *chan;
|
|
|
|
|
|
|
|
/* Get the selected action, exit if none are selected
|
|
|
|
*/
|
|
|
|
act = G.saction->action;
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Loop through the channels and set the beziers
|
|
|
|
* of the selected keys based on the integer code
|
|
|
|
*/
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
sethandles_ipo_keys(chan->ipo, code);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up and redraw stuff
|
|
|
|
*/
|
|
|
|
remake_action_ipos (act);
|
|
|
|
allspace(REMAKEIPO, 0);
|
|
|
|
allqueue(REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWIPO, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
}
|
|
|
|
|
2003-01-28 03:59:33 +00:00
|
|
|
static void set_ipotype_actionchannels(void) {
|
|
|
|
|
|
|
|
bAction *act;
|
|
|
|
bActionChannel *chan;
|
|
|
|
short event;
|
|
|
|
|
|
|
|
/* Get the selected action, exit if none are selected
|
|
|
|
*/
|
|
|
|
act = G.saction->action;
|
|
|
|
if (!act)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Present a popup menu asking the user what type
|
|
|
|
* of IPO curve he/she/GreenBTH wants. ;)
|
|
|
|
*/
|
|
|
|
event= pupmenu("Channel Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
|
|
|
|
if(event < 1) return;
|
|
|
|
|
|
|
|
/* Loop through the channels and for the selected ones set
|
|
|
|
* the type for each Ipo curve in the channel Ipo (based on
|
|
|
|
* the value from the popup).
|
|
|
|
*/
|
|
|
|
for (chan = act->chanbase.first; chan; chan=chan->next){
|
|
|
|
if (chan->flag & ACHAN_SELECTED){
|
|
|
|
if (chan->ipo)
|
|
|
|
setipotype_ipo(chan->ipo, event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up and redraw stuff
|
|
|
|
*/
|
|
|
|
remake_action_ipos (act);
|
|
|
|
allspace(REMAKEIPO, 0);
|
|
|
|
allqueue(REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWIPO, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
}
|
2003-01-28 03:11:27 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
void winqreadactionspace(unsigned short event, short val, char ascii)
|
|
|
|
{
|
|
|
|
SpaceAction *saction;
|
|
|
|
bAction *act;
|
|
|
|
int doredraw= 0;
|
|
|
|
short mval[2];
|
|
|
|
float dx,dy;
|
|
|
|
int cfra;
|
|
|
|
|
|
|
|
if(curarea->win==0) return;
|
|
|
|
|
|
|
|
saction= curarea->spacedata.first;
|
|
|
|
if (!saction)
|
|
|
|
return;
|
|
|
|
|
|
|
|
act=saction->action;
|
|
|
|
if(val) {
|
|
|
|
|
|
|
|
if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
|
|
|
|
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
|
|
|
|
switch(event) {
|
|
|
|
case UI_BUT_EVENT:
|
|
|
|
do_blenderbuttons(val);
|
|
|
|
break;
|
|
|
|
case HOMEKEY:
|
|
|
|
do_action_buttons(B_ACTHOME);
|
|
|
|
break;
|
2003-01-28 19:54:19 +00:00
|
|
|
|
|
|
|
case CKEY:
|
|
|
|
/* scroll the window so the current
|
|
|
|
* frame is in the center.
|
|
|
|
*/
|
|
|
|
center_currframe();
|
|
|
|
break;
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
case DKEY:
|
|
|
|
if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
|
|
|
|
duplicate_actionchannel_keys();
|
|
|
|
remake_action_ipos(act);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DELKEY:
|
|
|
|
case XKEY:
|
|
|
|
if (mval[0]<ACTWIDTH)
|
|
|
|
delete_actionchannels ();
|
|
|
|
else
|
|
|
|
delete_actionchannel_keys ();
|
|
|
|
break;
|
|
|
|
case GKEY:
|
|
|
|
if (mval[0]>=ACTWIDTH)
|
|
|
|
transform_actionchannel_keys ('g');
|
|
|
|
break;
|
|
|
|
case SKEY:
|
|
|
|
if (mval[0]>=ACTWIDTH)
|
|
|
|
transform_actionchannel_keys ('s');
|
|
|
|
break;
|
|
|
|
case AKEY:
|
|
|
|
if (mval[0]<ACTWIDTH){
|
|
|
|
deselect_actionchannels (act, 1);
|
|
|
|
allqueue (REDRAWVIEW3D, 0);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
deselect_actionchannel_keys (act, 1);
|
|
|
|
allqueue (REDRAWACTION, 0);
|
|
|
|
allqueue(REDRAWNLA, 0);
|
|
|
|
allqueue (REDRAWIPO, 0);
|
|
|
|
}
|
|
|
|
break;
|
2003-01-28 03:11:27 +00:00
|
|
|
|
|
|
|
/*** set the Ipo handles ***/
|
|
|
|
case VKEY:
|
|
|
|
sethandles_actionchannel_keys(HD_VECT);
|
|
|
|
break;
|
|
|
|
case HKEY:
|
|
|
|
if(G.qual & LR_SHIFTKEY) sethandles_actionchannel_keys(HD_AUTO);
|
|
|
|
else sethandles_actionchannel_keys(HD_ALIGN);
|
|
|
|
break;
|
|
|
|
|
2003-01-28 03:59:33 +00:00
|
|
|
/*** set the Ipo type ***/
|
|
|
|
case TKEY:
|
|
|
|
set_ipotype_actionchannels();
|
|
|
|
break;
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
case BKEY:
|
|
|
|
borderselect_action();
|
|
|
|
break;
|
|
|
|
case RIGHTMOUSE:
|
|
|
|
if (mval[0]<ACTWIDTH)
|
|
|
|
mouse_actionchannels(act, mval);
|
|
|
|
else
|
|
|
|
mouse_action();
|
|
|
|
break;
|
|
|
|
case LEFTMOUSE:
|
|
|
|
if (mval[0]>ACTWIDTH){
|
|
|
|
do {
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
|
|
|
|
areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
|
|
|
|
|
|
|
|
cfra= (int)dx;
|
|
|
|
if(cfra< 1) cfra= 1;
|
|
|
|
|
|
|
|
if( cfra!=CFRA ) {
|
|
|
|
CFRA= cfra;
|
|
|
|
update_for_newframe();
|
|
|
|
force_draw_plus(SPACE_VIEW3D);
|
|
|
|
force_draw_plus(SPACE_IPO);
|
|
|
|
force_draw_plus(SPACE_BUTS);
|
|
|
|
}
|
|
|
|
|
|
|
|
} while(get_mbut()&L_MOUSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case MIDDLEMOUSE:
|
2003-01-28 11:14:38 +00:00
|
|
|
case WHEELUPMOUSE:
|
|
|
|
case WHEELDOWNMOUSE:
|
2003-01-28 12:14:47 +00:00
|
|
|
view2dmove(event); /* in drawipo.c */
|
2002-10-12 11:37:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(doredraw) addqueue(curarea->win, REDRAW, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|