This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/src/editnla.c
Kent Mein cd4a60f536 sgefants patch to remove the License Key stuff.
(I noticed its not completely gone yet from the blender/source dir)
But its a big step in the right direction if it doesn't enable
all of the functionatlity already...

(Using cscope for LICENSE_KEY_VALID still turns up some stuff)

Kent
--
mein@cs.umn.edu
2002-12-06 19:48:37 +00:00

1648 lines
40 KiB
C

/**
* $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 *****
* This file is a horrible mess: An attmept to cram some
* final functionality into blender before it is too late.
*
* Hopefully it can be tidied up at a later date...
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "PIL_time.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_nla.h"
#include "BKE_action.h"
#include "BIF_screen.h"
#include "BIF_interface.h"
#include "BIF_buttons.h"
#include "BIF_space.h"
#include "BIF_mywindow.h"
#include "BIF_editview.h"
#include "BIF_toolbox.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_ipo_types.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "DNA_action_types.h"
#include "DNA_nla_types.h"
#include "DNA_constraint_types.h"
#include "BSE_editipo.h"
#include "BSE_editnla_types.h"
#include "BSE_headerbuttons.h"
#include "BSE_drawipo.h"
#include "BSE_trans_types.h"
#include "BSE_edit.h"
#include "BDR_editobject.h"
#include "interface.h"
#include "blendef.h"
#include "mydevice.h"
#include "blendertimer.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* Note: A lot of these pretty much duplicate the behaviour of the
action windows. The functions should be shared, not copy-pasted */
typedef struct NlaParam{
SpaceNla *snla;
unsigned short event;
short val;
}NlaParam;
static void deselect_nlachannel_keys (int test);
static void deselect_nlachannels(int test);
static void transform_nlachannel_keys(char mode);
static void delete_nlachannel_keys(void);
static void delete_nlachannels(void);
static void duplicate_nlachannel_keys(void);
static void borderselect_nla(void);
static void mouse_nla(void);
static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
static void mouse_nlachannels(short mval[2]);
static void add_nlablock(short mval[2]);
static bActionStrip *get_active_nlastrip(void);
static void convert_nla(short mval[2]);
extern int count_nla_levels(void); /* From drawnla.c */
extern int nla_filter (Base* base, int flags); /* From drawnla.c */
/* ******************** SPACE: NLA ********************** */
/* Protected creator function */
int calc_memleak (void* ptr){
int doredraw= 0;
short mval[2];
float dx,dy;
int cfra;
SpaceNla *snla;
NlaParam *params=(NlaParam*) ptr;
unsigned short event;
short val ;
if (!ptr)
return -1;
snla= params->snla;
event = params->event;
val = params->val;
if(curarea->win==0) return 0;
if (!snla)
return 0;
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_nla_buttons(B_NLAHOME);
break;
case DKEY:
if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
duplicate_nlachannel_keys();
update_for_newframe();
}
break;
case DELKEY:
case XKEY:
if (mval[0]>=NLAWIDTH)
delete_nlachannel_keys ();
else
delete_nlachannels();
update_for_newframe();
break;
case GKEY:
if (mval[0]>=NLAWIDTH)
transform_nlachannel_keys ('g');
update_for_newframe();
break;
case SKEY:
if (mval[0]>=NLAWIDTH)
transform_nlachannel_keys ('s');
update_for_newframe();
break;
case BKEY:
borderselect_nla();
break;
case CKEY:
convert_nla(mval);
break;
case AKEY:
if (G.qual & LR_SHIFTKEY){
add_nlablock(mval);
allqueue (REDRAWNLA, 0);
allqueue (REDRAWVIEW3D, 0);
}
else{
if (mval[0]>=NLAWIDTH)
deselect_nlachannel_keys(1);
else{
deselect_nlachannels(1);
allqueue (REDRAWVIEW3D, 0);
}
allqueue (REDRAWNLA, 0);
allqueue (REDRAWIPO, 0);
}
break;
case RIGHTMOUSE:
if (mval[0]>=NLAWIDTH)
mouse_nla();
else
mouse_nlachannels(mval);
break;
case LEFTMOUSE:
if (mval[0]>NLAWIDTH){
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);
}
} while(get_mbut()&L_MOUSE);
}
break;
case MIDDLEMOUSE:
view2dmove(); /* in drawipo.c */
break;
}
}
if(doredraw) scrarea_queue_winredraw(curarea);
return 0;
}
void winqreadnlaspace(unsigned short event, short val, char ascii)
{
NlaParam param;
Base *base;
bActionStrip *strip, *next;
short mval[2];
float dx, dy;
int cfra;
param.event = event;
param.val = val;
param.snla = curarea->spacedata.first;
/* Call the protected (&obfuscated) eventloop function */
calc_memleak(&param); /* enable NLA */
}
static void convert_nla(short mval[2])
{
short event;
float ymax, ymin;
Base *base;
float x,y;
int sel=0;
bActionStrip *strip, *nstrip;
/* Find out what strip we're over */
ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
areamouseco_to_ipoco(G.v2d, mval, &x, &y);
for (base=G.scene->base.first; base; base=base->next){
if (nla_filter(base, 0)){
/* Check object ipo */
ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
if (y>=ymin && y<=ymax)
break;
ymax=ymin;
if (base->object->type==OB_ARMATURE){
/* Check action ipo */
ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
if (y>=ymin && y<=ymax)
break;
ymax=ymin;
/* Check nlastrips */
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
if (y>=ymin && y<=ymax){
sel = 1;
break;
}
ymax=ymin;
}
if (sel)
break;
}
}
}
if (!base)
return;
if (base->object->type==OB_ARMATURE){
event = pupmenu("Convert%t|Action to NLAstrip%x1");
switch (event){
case 1:
if (base->object->action){
/* Make new actionstrip */
nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
deselect_nlachannel_keys(0);
/* Link the action to the nstrip */
nstrip->act = base->object->action;
nstrip->actstart = calc_action_start(base->object->action); /* MAKE THIS THE FIRST FRAME OF THE ACTION */
nstrip->actend = calc_action_end(base->object->action);
nstrip->start = nstrip->actstart;
nstrip->end = nstrip->actend;
nstrip->flag = ACTSTRIP_SELECT;
nstrip->repeat = 1.0;
BLI_addtail(&base->object->nlastrips, nstrip);
/* Unlink action */
base->object->action = NULL;
allqueue (REDRAWNLA, 0);
}
break;
default:
break;
}
}
}
static void add_nlablock(short mval[2])
{
/* Make sure we are over an armature */
Base *base;
bAction *act=NULL;
bActionStrip *strip;
float ymin, ymax;
float x, y;
rctf rectf;
short event;
char *str;
short nr;
int cur;
areamouseco_to_ipoco(G.v2d, mval, &x, &y);
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_nla_levels();
ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
for (base=G.scene->base.first; base; base=base->next){
/* Handle object ipo selection */
if (nla_filter(base, 0)){
/* STUPID STUPID STUPID */
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* Handle object ipos */
if (base->object->type==OB_ARMATURE){
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
break;
}
ymax=ymin;
/* Handle action ipos & Action strips */
if (base->object->type==OB_ARMATURE){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP)*(BLI_countlist(&base->object->nlastrips) + 1);
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
break;
ymax=ymin;
}
}
}
/* Make sure we have an armature */
if (!base){
error ("Not an armature!");
return;
}
/* Popup action menu */
IDnames_to_pupstring(&str, "Add action", NULL, &G.main->action, (ID *)G.scene, &nr);
event = pupmenu(str);
if (event!=-1){
for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
if (cur==event){
break;
}
}
}
MEM_freeN(str);
/* Bail out if no action was chosen */
if (!act){
return;
}
/* Initialize the new action block */
strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
deselect_nlachannel_keys(0);
/* Link the action to the strip */
strip->act = act;
strip->actstart = 1.0;
strip->actend = calc_action_end(act);
strip->start = G.scene->r.cfra; /* Should be mval[0] */
strip->end = strip->start + (strip->actend-strip->actstart);
strip->flag = ACTSTRIP_SELECT;
strip->repeat = 1.0;
act->id.us++;
BLI_addtail(&base->object->nlastrips, strip);
}
static void mouse_nlachannels(short mval[2])
{
/* Find which strip has been clicked */
// bActionChannel *chan;
bConstraintChannel *conchan=NULL;
bActionStrip *strip;
float click;
int wsize;
int sel;
Base *base;
wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
click = (wsize-(mval[1]+G.v2d->cur.ymin));
click += NLACHANNELHEIGHT/2;
click /= (NLACHANNELHEIGHT+NLACHANNELSKIP);
if (click<0)
return;
for (base = G.scene->base.first; base; base=base->next){
if (nla_filter(base, 0)){
/* See if this is a base selected */
if ((int)click==0)
break;
click--;
/* Check for click in a constraint */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if ((int)click==0){
base=G.scene->base.last;
break;
}
click--;
}
/* See if this is an action */
if (base->object->type==OB_ARMATURE && base->object->action){
if ((int)click==0){
break;
}
click--;
}
/* See if this is an nla strip */
for (strip = base->object->nlastrips.first; strip; strip=strip->next){
if ((int)click==0){
base=G.scene->base.last;
break;
}
click--;
}
}
}
if (!base && !conchan)
return;
/* Handle constraint strip selection */
if (conchan){
if (conchan->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 (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
// hilight_channel(act, chan, 0);
}
else{
conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
// hilight_channel(act, chan, 1);
}
}
else{
deselect_nlachannels (0); // Auto clear
conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
// hilight_channel(act, chan, 1);
// act->achan = chan;
// select_poseelement_by_name(chan->name, 1);
}
}
/* Handle object strip selection */
else if (base)
{
/* Choose the mode */
if (base->flag & 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 (base->flag & SELECT){
base->flag &= ~SELECT;
// hilight_channel(act, chan, 0);
}
else{
base->flag |= SELECT;
// hilight_channel(act, chan, 1);
}
}
else{
deselect_nlachannels (0); // Auto clear
base->flag |= SELECT;
// 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);
}
void init_nlaspace(ScrArea *sa)
{
SpaceNla *snla;
snla= MEM_callocN(sizeof(SpaceNla), "initnlaspace");
BLI_addhead(&sa->spacedata, snla);
snla->spacetype= SPACE_NLA;
snla->v2d.tot.xmin= 1.0;
snla->v2d.tot.ymin= 0.0;
snla->v2d.tot.xmax= 1000.0;
snla->v2d.tot.ymax= 1000.0;
snla->v2d.cur.xmin= -5.0;
snla->v2d.cur.ymin= 0.0;
snla->v2d.cur.xmax= 65.0;
snla->v2d.cur.ymax= 1000.0;
snla->v2d.min[0]= 0.0;
snla->v2d.min[1]= 0.0;
snla->v2d.max[0]= 1000.0;
snla->v2d.max[1]= 1000.0;
snla->v2d.minzoom= 0.1F;
snla->v2d.maxzoom= 10;
snla->v2d.scroll= R_SCROLL+B_SCROLL;
snla->v2d.keepaspect= 0;
snla->v2d.keepzoom= V2D_LOCKZOOM_Y;
snla->v2d.keeptot= 0;
snla->lock = 0;
};
static void deselect_nlachannel_keys (int test)
{
Base *base;
int sel=1;
bActionChannel *chan;
bActionStrip *strip;
bConstraintChannel *conchan;
/* Determine if this is selection or deselection */
if (test){
for (base=G.scene->base.first; base && sel; base=base->next){
/* Test object ipos */
if (is_ipo_key_selected(base->object->ipo)){
sel = 0;
break;
}
/* Test object constraint ipos */
if (sel){
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if (is_ipo_key_selected(conchan->ipo)){
sel=0;
break;
}
}
}
/* Test action ipos */
if (sel){
if (base->object->type==OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
if (is_ipo_key_selected(chan->ipo)){
sel=0;
break;
}
/* Test action constraints */
if (sel){
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
if (is_ipo_key_selected(conchan->ipo)){
sel=0;
break;
}
}
}
}
}
}
/* Test NLA strips */
if (sel){
if (base->object->type==OB_ARMATURE){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT){
sel = 0;
break;
}
}
}
}
}
}
else
sel=0;
/* Set the flags */
for (base=G.scene->base.first; base; base=base->next){
/* Set the object ipos */
set_ipo_key_selection(base->object->ipo, sel);
/* Set the object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
set_ipo_key_selection(conchan->ipo, sel);
}
/* Set the action ipos */
if (base->object->type==OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
set_ipo_key_selection(chan->ipo, sel);
/* Set the action constraint ipos */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
set_ipo_key_selection(conchan->ipo, sel);
}
}
/* Set the nlastrips */
if (base->object->type==OB_ARMATURE){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (sel)
strip->flag |= ACTSTRIP_SELECT;
else
strip->flag &= ~ACTSTRIP_SELECT;
}
}
}
}
static void transform_nlachannel_keys(char mode)
{
Base *base;
TransVert *tv;
int /*sel=0,*/ i;
short mvals[2], mvalc[2];
// short 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];
bActionChannel *chan;
bActionStrip *strip;
bConstraintChannel *conchan;
/* Ensure that partial selections result in beztriple selections */
for (base=G.scene->base.first; base; base=base->next){
/* Check object ipos */
tvtot+=fullselect_ipo_keys(base->object->ipo);
/* Check object constraint ipos */
for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
tvtot+=fullselect_ipo_keys(conchan->ipo);
/* Check action ipos */
if (base->object->type == OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
tvtot+=fullselect_ipo_keys(chan->ipo);
/* Check action constraint ipos */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
tvtot+=fullselect_ipo_keys(conchan->ipo);
}
}
/* Check nlastrips */
if (base->object->type==OB_ARMATURE){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT)
tvtot+=2;
}
}
}
/* If nothing is selected, bail out */
if (!tvtot)
return;
/* Build the transvert structure */
tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
tvtot=0;
for (base=G.scene->base.first; base; base=base->next){
/* Manipulate object ipos */
tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
/* Manipulate object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
/* Manipulate action ipos */
if (base->object->type==OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
/* Manipulate action constraint ipos */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
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(1);
}
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 & 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 & 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, "sizeX: %.3f", fac);
headerprint(str);
}
else if (mode=='g'){
sprintf(str, "deltaX: %.3f", fac);
headerprint(str);
}
if (G.snla->lock){
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWNLA, 0);
allqueue (REDRAWIPO, 0);
force_draw_all();
}
else {
addqueue (curarea->win, REDRAWALL, 0);
force_draw ();
}
}
lastcval[0]= cval[0];
lastcval[1]= cval[1];
firsttime= 0;
}
allspace(REMAKEALLIPO, 0);
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWNLA, 0);
allqueue (REDRAWIPO, 0);
MEM_freeN (tv);
}
static void delete_nlachannel_keys(void)
{
Base *base;
bActionChannel *chan;
bConstraintChannel *conchan;
bActionStrip *strip, *nextstrip;
if (!okee("Erase selected keys"))
return;
for (base = G.scene->base.first; base; base=base->next){
/* Delete object ipos */
delete_ipo_keys(base->object->ipo);
/* Delete object constraint keys */
for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
delete_ipo_keys(conchan->ipo);
/* Delete NLA strips */
if (base->object->type==OB_ARMATURE){
for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
nextstrip=strip->next;
if (strip->flag & ACTSTRIP_SELECT){
free_actionstrip(strip);
BLI_remlink(&base->object->nlastrips, strip);
MEM_freeN(strip);
}
}
}
/* Delete action ipos */
if (base->object->type==OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
delete_ipo_keys(chan->ipo);
/* Delete action constraint keys */
for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
delete_ipo_keys(conchan->ipo);
}
}
}
allspace(REMAKEALLIPO, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWIPO, 0);
}
static void duplicate_nlachannel_keys(void)
{
Base *base;
bActionChannel *chan;
bConstraintChannel *conchan;
bActionStrip *strip, *laststrip;
/* Find selected items */
for (base = G.scene->base.first; base; base=base->next){
/* Duplicate object keys */
duplicate_ipo_keys(base->object->ipo);
/* Duplicate object constraint keys */
for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
duplicate_ipo_keys(conchan->ipo);
/* Duplicate nla strips */
if (base->object->type == OB_ARMATURE){
laststrip = base->object->nlastrips.last;
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT){
bActionStrip *newstrip;
copy_actionstrip(&newstrip, &strip);
BLI_addtail(&base->object->nlastrips, newstrip);
strip->flag &= ~ACTSTRIP_SELECT;
newstrip->flag |= ACTSTRIP_SELECT;
}
if (strip==laststrip)
break;
}
}
/* Duplicate actionchannel keys */
if (base->object->type == OB_ARMATURE && base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
duplicate_ipo_keys(chan->ipo);
/* Duplicate action constraint keys */
for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
duplicate_ipo_keys(conchan->ipo);
}
}
}
transform_nlachannel_keys ('g');
}
static void borderselect_nla(void)
{
Base *base;
rcti rect;
rctf rectf;
int val;
short mval[2];
float ymin, ymax;
bActionStrip *strip;
bConstraintChannel *conchan;
val= get_border (&rect, 3);
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_nla_levels();
ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
for (base=G.scene->base.first; base; base=base->next){
/* Check object ipos */
if (nla_filter(base, 0)){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (base->object->ipo){
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax, val);
}
ymax=ymin;
/* Check object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
ymax=ymin;
}
/* Check action ipos */
if (ACTIVE_ARMATURE(base)){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (base->object->action){
bActionChannel *chan;
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val);
/* Check action constraint ipos */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
}
}
}
ymax=ymin;
} /* End of if armature */
/* Skip nlastrips */
if (base->object->type==OB_ARMATURE){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
//
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
if (val==1)
strip->flag |= ACTSTRIP_SELECT;
else
strip->flag &= ~ACTSTRIP_SELECT;
}
}
ymax=ymin;
}
}
} /* End of object filter */
}
allqueue(REDRAWNLA, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWIPO, 0);
}
}
static void mouse_nla(void)
{
short sel;
float selx;
short mval[2];
Base *base;
bAction *act;
bActionChannel *chan;
bActionStrip *rstrip;
bConstraintChannel *conchan;
getmouseco_areawin (mval);
/* Try object ipo selection */
base=get_nearest_nlachannel_ob_key(&selx, &sel);
if (base){
if (!(G.qual & LR_SHIFTKEY)){
deselect_nlachannel_keys(0);
sel = 0;
}
select_ipo_key(base->object->ipo, selx, sel);
/* Try object constraint selection */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
select_ipo_key(conchan->ipo, selx, sel);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWNLA, 0);
return;
}
/* Try action ipo selection */
act=get_nearest_nlachannel_ac_key(&selx, &sel);
if (act){
if (!(G.qual & LR_SHIFTKEY)){
deselect_nlachannel_keys(0);
sel = 0;
}
for (chan=act->chanbase.first; chan; chan=chan->next){
select_ipo_key(chan->ipo, selx, sel);
/* Try action constraint selection */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
select_ipo_key(conchan->ipo, selx, sel);
}
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWNLA, 0);
return;
}
/* Try nla strip selection */
base=get_nearest_nlastrip(&rstrip, &sel);
if (base){
if (!(G.qual & LR_SHIFTKEY)){
deselect_nlachannel_keys(0);
sel = 0;
}
if (sel)
rstrip->flag &= ~ACTSTRIP_SELECT;
else
rstrip->flag |= ACTSTRIP_SELECT;
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWNLA, 0);
return;
}
}
static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
/* This function is currently more complicated than it seems like it should be.
* However, this will be needed once the nla strip timeline is more complex */
{
Base *base, *firstbase=NULL;
short mval[2];
short foundsel = 0;
rctf rectf;
float ymin, ymax;
bActionStrip *strip, *firststrip, *foundstrip;
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_nla_levels();
ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
for (base = G.scene->base.first; base; base=base->next){
if (nla_filter(base, 0)){
/* Skip object ipos */
// if (base->object->ipo)
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (base->object->type==OB_ARMATURE){
/* Skip action ipos */
if (base->object->action)
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* Do Ytest */
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
/* Do XTest */
if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
if (!firstbase){
firstbase=base;
firststrip=strip;
*sel = strip->flag & ACTSTRIP_SELECT;
}
if (strip->flag & ACTSTRIP_SELECT){
if (!foundsel){
foundsel=1;
foundstrip = strip;
}
}
else if (foundsel && strip != foundstrip){
*rstrip=strip;
*sel = 0;
return base;
}
}
}
ymax=ymin;
}
}
}
}
*rstrip=firststrip;
return firstbase;
}
static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
{
Base *base;
IpoCurve *icu;
Base *firstbase=NULL;
bConstraintChannel *conchan;
int foundsel=0;
float firstvert=-1, foundx=-1;
int i;
short mval[2];
float ymin, ymax;
rctf rectf;
*index=0;
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_nla_levels();
ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
*sel=0;
for (base=G.scene->base.first; base; base=base->next){
/* Handle object ipo selection */
if (nla_filter(base, 0)){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (base->object->ipo){
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
for (icu=base->object->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 (!firstbase){
firstbase=base;
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 base;
}
}
}
}
}
}
ymax=ymin;
/* Handle object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
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 (!firstbase){
firstbase=base;
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 base;
}
}
}
}
}
ymax=ymin;
}
/* Skip action ipos */
if (ACTIVE_ARMATURE(base)){
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
}
/* Skip nlastrips */
if (base->object->type==OB_ARMATURE){
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
}
}
}
*index=firstvert;
return firstbase;
}
static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
{
Base *base;
IpoCurve *icu;
bAction *firstact=NULL;
int foundsel=0;
float firstvert=-1, foundx=-1;
int i;
short mval[2];
float ymin, ymax;
rctf rectf;
bActionChannel *chan;
bConstraintChannel *conchan;
*index=0;
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_nla_levels();
ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
*sel=0;
for (base=G.scene->base.first; base; base=base->next){
/* Handle object ipo selection */
if (nla_filter(base, 0)){
/* Skip object ipo */
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
ymax=ymin;
/* Handle action ipos */
if (ACTIVE_ARMATURE(base)){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
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 (!firstact){
firstact=base->object->action;
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 base->object->action;
}
}
}
}
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
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 (!firstact){
firstact=base->object->action;
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 base->object->action;
}
}
}
}
}
ymax=ymin;
}
}
}
ymax=ymin;
}
/* Skip nlastrips */
if (base->object->type==OB_ARMATURE){
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
}
}
}
*index=firstvert;
return firstact;
}
static bActionStrip *get_active_nlastrip(void)
/* For now just returns the first selected strip */
{
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next){
if (nla_filter(base, 0) && base->object->type==OB_ARMATURE){
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT)
return strip;
}
}
}
return NULL;
}
void clever_numbuts_nla(void){
bActionStrip *strip;
int but=0;
/* Determine if an nla strip has been selected */
strip = get_active_nlastrip();
if (!strip)
return;
add_numbut(but++, LABEL, "Timeline Range:", 1.0, 18000.0, 0, 0);
add_numbut(but++, NUM|FLO, "Strip Start:", 1.0, 18000.0, &strip->start, "First frame in the timeline");
add_numbut(but++, NUM|FLO, "Strip End:", 1.0, 18000.0, &strip->end, "Last frame in the timeline");
add_numbut(but++, LABEL, "Action Range:", 1.0, 18000.0, 0, 0);
add_numbut(but++, NUM|FLO, "Action Start:", 1.0, 18000.0, &strip->actstart, "First frame of the action to map to the playrange");
add_numbut(but++, NUM|FLO, "Action End:", 1.0, 18000.0, &strip->actend, "Last frame of the action to map to the playrange");
add_numbut(but++, LABEL, "Blending:", 1.0, 18000.0, 0, 0);
add_numbut(but++, NUM|FLO, "Blendin:", 0.0, 18000.0, &strip->blendin, "Number of frames of ease-in");
add_numbut(but++, NUM|FLO, "Blendout:", 0.0, 18000.0, &strip->blendout, "Number of frames of ease-out");
add_numbut(but++, LABEL, "Options:", 1.0, 18000.0, 0, 0);
add_numbut(but++, NUM|FLO, "Repeat:", 0.0001, 18000.0, &strip->repeat, "Number of times the action should repeat");
add_numbut(but++, NUM|FLO, "Stride:", 0.0001, 1000.0, &strip->stridelen, "Distance covered by one complete cycle of the action specified in the Action Range");
{
/* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
short hold= (strip->flag & ACTSTRIP_HOLDLASTFRAME) ? 1 : 0;
short frompath=(strip->flag & ACTSTRIP_USESTRIDE) ? 1 : 0;
add_numbut(but++, TOG|SHO, "Use Path", 0, 0, &frompath, "Plays action based on position on path & stride length. Only valid for armatures that are parented to a path");
add_numbut(but++, TOG|SHO, "Hold", 0, 0, &hold, "Toggles whether or not to continue displaying the last frame past the end of the strip");
add_numbut(but++, TOG|SHO, "Add", 0, 0, &strip->mode, "Toggles additive blending mode");
do_clever_numbuts("Action", but, REDRAW);
/* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
if (hold) strip->flag |= ACTSTRIP_HOLDLASTFRAME;
else strip->flag &= ~ACTSTRIP_HOLDLASTFRAME;
if (frompath) strip->flag |= ACTSTRIP_USESTRIDE;
else strip->flag &= ~ACTSTRIP_USESTRIDE;
}
if (strip->end<strip->start)
strip->end=strip->start;
if (strip->blendin>(strip->end-strip->start))
strip->blendin = strip->end-strip->start;
if (strip->blendout>(strip->end-strip->start))
strip->blendout = strip->end-strip->start;
if (strip->blendin > (strip->end-strip->start-strip->blendout))
strip->blendin = (strip->end-strip->start-strip->blendout);
if (strip->blendout > (strip->end-strip->start-strip->blendin))
strip->blendout = (strip->end-strip->start-strip->blendin);
update_for_newframe();
allqueue (REDRAWNLA, 0);
allqueue (REDRAWVIEW3D, 0);
}
static void deselect_nlachannels(int test){
int sel = 1;
Base *base;
bConstraintChannel *conchan;
if (test){
for (base=G.scene->base.first; base; base=base->next){
/* Check base flags for previous selection */
if (base->flag & SELECT){
sel=0;
break;
}
/* Check constraint flags for previous selection */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
sel=0;
base = G.scene->base.last;
break;
}
}
}
}
else
sel = 0;
/* Select objects */
for (base=G.scene->base.first; base; base=base->next){
if (sel){
if (nla_filter(base, 0))
base->flag |= SELECT;
}
else
base->flag &= ~SELECT;
/* Select constraint channels */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if (sel){
if (nla_filter(base, 0))
conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
}
else
conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
}
}
}
static void delete_nlachannels(void){
Base *base;
bConstraintChannel *conchan, *nextchan;
int sel=0;
/* See if there is anything selected */
for (base = G.scene->base.first; base && (!sel); base=base->next){
/* Check constraints */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
sel = 1;
break;
}
}
}
if (!sel)
return;
if (okee ("Delete selected channels")){
for (base=G.scene->base.first; base; base=base->next){
for (conchan=base->object->constraintChannels.first; conchan; conchan=nextchan){
nextchan = conchan->next;
if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
/* If we're the active constraint, unlink us */
if (conchan==base->object->activecon)
base->object->activecon = NULL;
if (conchan->ipo)
conchan->ipo->id.us--;
BLI_freelinkN(&base->object->constraintChannels, conchan);
}
}
}
}
}