orange: cleaning up / (msvc) compile fixes to the new editnla functions (experimental...
[blender.git] / source / blender / src / editaction.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <math.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include "MEM_guardedalloc.h"
41
42 #include "PIL_time.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_ipo_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_userdef_types.h"
55 #include "DNA_constraint_types.h"
56 #include "DNA_key_types.h"
57 #include "DNA_mesh_types.h"
58 #include "DNA_nla_types.h"
59 #include "DNA_lattice_types.h"
60
61 #include "BKE_action.h"
62 #include "BKE_armature.h"
63 #include "BKE_constraint.h"
64 #include "BKE_curve.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
67 #include "BKE_ipo.h"
68 #include "BKE_key.h"
69 #include "BKE_library.h"
70 #include "BKE_main.h"
71 #include "BKE_utildefines.h"
72 #include "BKE_object.h" /* for where_is_object in obanim -> action baking */
73
74 #include "BIF_butspace.h"
75 #include "BIF_editaction.h"
76 #include "BIF_editarmature.h"
77 #include "BIF_editnla.h"
78 #include "BIF_editview.h"
79 #include "BIF_gl.h"
80 #include "BIF_interface.h"
81 #include "BIF_mywindow.h"
82 #include "BIF_poseobject.h"
83 #include "BIF_screen.h"
84 #include "BIF_space.h"
85 #include "BIF_toolbox.h"
86
87 #include "BSE_edit.h"
88 #include "BSE_drawipo.h"
89 #include "BSE_headerbuttons.h"
90 #include "BSE_editipo.h"
91 #include "BSE_trans_types.h"
92
93 #include "BDR_editobject.h"
94
95 #include "mydevice.h"
96 #include "blendef.h"
97 #include "nla.h"
98
99 extern int count_action_levels (bAction *act);
100
101 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
102
103 /* Local Function prototypes, are forward needed */
104 static void hilight_channel (bAction *act, bActionChannel *chan, short hilight);
105
106 static void up_sel_action(void);
107 static void down_sel_action(void);
108 static void top_sel_action(void);
109 static void bottom_sel_action(void);
110
111 /* Implementation */
112
113 short showsliders = 0;
114 short ACTWIDTH = NAMEWIDTH;
115
116 /* messy call... */
117 static void select_poseelement_by_name (char *name, int select)
118 {
119         /* Syncs selection of channels with selection of object elements in posemode */
120         Object *ob= OBACT;
121         bPoseChannel *pchan;
122         
123         if (!ob || ob->type!=OB_ARMATURE)
124                 return;
125         
126         if(select==2) {
127                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
128                         pchan->bone->flag &= ~(BONE_ACTIVE);
129         }
130         
131         pchan= get_pose_channel(ob->pose, name);
132         if(pchan) {
133                 if(select)
134                         pchan->bone->flag |= (BONE_SELECTED);
135                 else 
136                         pchan->bone->flag &= ~(BONE_SELECTED);
137                 if(select==2)
138                         pchan->bone->flag |= (BONE_ACTIVE);
139         }
140 }
141
142 bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
143 {
144         bArmature               *arm;
145         bAction                 *result=NULL;
146         bActionChannel *achan;
147         bAction                 *temp;
148         bPoseChannel    *pchan;
149         ID                              *id;
150         float                   actstart, actend;
151         int                             oldframe;
152         int                             curframe;
153         char                    newname[64];
154
155         if (!act)
156                 return NULL;
157         
158         arm = get_armature(armob);
159
160         if (G.obedit){
161                 error ("Actions can't be baked in Edit Mode");
162                 return NULL;
163         }
164
165         if (!arm || armob->pose==NULL){
166                 error ("Select an armature before baking");
167                 return NULL;
168         }
169         
170         /* Get a new action */
171         result = add_empty_action(ID_PO);
172         id= (ID *)armob;
173
174         /* Assign the new action a unique name */
175         sprintf (newname, "%s.BAKED", act->id.name+2);
176         rename_id(&result->id, newname);
177
178         calc_action_range(act, &actstart, &actend);
179
180         oldframe = G.scene->r.cfra;
181
182         temp = armob->action;
183         armob->action = result;
184         
185         for (curframe=1; curframe<ceil(actend+1.0f); curframe++){
186
187                 /* Apply the old action */
188                 
189                 G.scene->r.cfra = curframe;
190
191                 /* Apply the object ipo */
192                 extract_pose_from_action(armob->pose, act, curframe);
193
194                 where_is_pose(armob);
195                 
196                 /* For each channel: set quats and locs if channel is a bone */
197                 for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){
198
199                         /* Apply to keys */
200                         insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
201                         insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
202                         insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
203                         insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
204                         insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
205                         insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
206                         insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
207                         insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
208                         insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
209                         insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
210                 }
211         }
212
213
214         /* Make another pass to ensure all keyframes are set to linear interpolation mode */
215         for (achan = result->chanbase.first; achan; achan=achan->next){
216                 IpoCurve* icu;
217                 if(achan->ipo) {
218                         for (icu = achan->ipo->curve.first; icu; icu=icu->next){
219                                 icu->ipo= IPO_LIN;
220                         }
221                 }
222         }
223
224         notice ("Made a new action named \"%s\"", newname);
225         G.scene->r.cfra = oldframe;
226         armob->action = temp;
227                 
228         /* restore */
229         extract_pose_from_action(armob->pose, act, G.scene->r.cfra);
230         where_is_pose(armob);
231         
232         allqueue(REDRAWACTION, 1);
233         
234         return result;
235 }
236
237 /* apparently within active object context */
238 /* called extern, like on bone selection */
239 void select_actionchannel_by_name (bAction *act, char *name, int select)
240 {
241         bActionChannel *chan;
242
243         if (!act)
244                 return;
245
246         for (chan = act->chanbase.first; chan; chan=chan->next){
247                 if (!strcmp (chan->name, name)){
248                         if (select){
249                                 chan->flag |= ACHAN_SELECTED;
250                                 hilight_channel (act, chan, 1);
251                         }
252                         else{
253                                 chan->flag &= ~ACHAN_SELECTED;
254                                 hilight_channel (act, chan, 0);
255                         }
256                         return;
257                 }
258         }
259 }
260
261 /* called on changing action ipos or keys */
262 void remake_action_ipos(bAction *act)
263 {
264         bActionChannel *chan;
265         bConstraintChannel *conchan;
266         IpoCurve                *icu;
267
268         for (chan= act->chanbase.first; chan; chan=chan->next){
269                 if (chan->ipo){
270                         for (icu = chan->ipo->curve.first; icu; icu=icu->next){
271                                 sort_time_ipocurve(icu);
272                                 testhandles_ipocurve(icu);
273                         }
274                 }
275                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
276                         if (conchan->ipo){
277                                 for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
278                                         sort_time_ipocurve(icu);
279                                         testhandles_ipocurve(icu);
280                                 }
281                         }
282                 }
283         }
284         
285         synchronize_action_strips();
286 }
287
288 static void remake_meshaction_ipos(Ipo *ipo)
289 {
290         /* this puts the bezier triples in proper
291          * order and makes sure the bezier handles
292          * aren't too strange.
293          */
294         IpoCurve *icu;
295
296         for (icu = ipo->curve.first; icu; icu=icu->next){
297                 sort_time_ipocurve(icu);
298                 testhandles_ipocurve(icu);
299         }
300 }
301
302 static void meshkey_do_redraw(Key *key)
303 {
304         remake_meshaction_ipos(key->ipo);
305
306         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
307         
308         allspace(REMAKEIPO, 0);
309         allqueue(REDRAWACTION, 0);
310         allqueue(REDRAWIPO, 0);
311         allqueue(REDRAWNLA, 0);
312
313 }
314
315 void duplicate_meshchannel_keys(Key *key)
316 {
317         duplicate_ipo_keys(key->ipo);
318         transform_meshchannel_keys ('g', key);
319 }
320
321
322 void duplicate_actionchannel_keys(void)
323 {
324         bAction *act;
325         bActionChannel *chan;
326         bConstraintChannel *conchan;
327
328         act=G.saction->action;
329         if (!act)
330                 return;
331
332         /* Find selected items */
333         for (chan = act->chanbase.first; chan; chan=chan->next){
334                 if((chan->flag & ACHAN_HIDDEN)==0) {
335                         duplicate_ipo_keys(chan->ipo);
336                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
337                                 duplicate_ipo_keys(conchan->ipo);
338                 }
339         }
340
341         transform_actionchannel_keys ('g', 0);
342 }
343
344 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan)
345 {
346         bAction *act;
347         bActionChannel *chan;
348         IpoCurve *icu;
349         bActionChannel *firstchan=NULL;
350         bConstraintChannel *conchan, *firstconchan=NULL;
351         rctf    rectf;
352         float firstvert=-1, foundx=-1;
353         float ymin, ymax, xmin, xmax;
354         int i;
355         int     foundsel=0;
356         short mval[2];
357         
358         *index=0;
359
360         *rchan=NULL;
361         act= G.saction->action; /* We presume that we are only called during a valid action */
362         
363         getmouseco_areawin (mval);
364
365         mval[0]-=7;
366         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
367         mval[0]+=14;
368         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
369
370         ymax = count_action_levels(act) * (CHANNELHEIGHT + CHANNELSKIP);
371         ymax += CHANNELHEIGHT/2;
372         
373         /* if action is mapped in NLA, it returns a correction */
374         if(G.saction->pin==0 && OBACT) {
375                 xmin= get_action_frame(OBACT, rectf.xmin);
376                 xmax= get_action_frame(OBACT, rectf.xmax);
377         }
378         else {
379                 xmin= rectf.xmin;
380                 xmax= rectf.xmax;
381         }
382         
383         *sel=0;
384
385         for (chan=act->chanbase.first; chan; chan=chan->next){
386                 if((chan->flag & ACHAN_HIDDEN)==0) {
387
388                         /* Check action channel */
389                         ymin= ymax-(CHANNELHEIGHT+CHANNELSKIP);
390                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)) && chan->ipo){
391                                 for (icu=chan->ipo->curve.first; icu; icu=icu->next){
392                                         for (i=0; i<icu->totvert; i++){
393                                                 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
394                                                         if (!firstchan){
395                                                                 firstchan=chan;
396                                                                 firstvert=icu->bezt[i].vec[1][0];
397                                                                 *sel = icu->bezt[i].f2 & 1;     
398                                                         }
399                                                         
400                                                         if (icu->bezt[i].f2 & 1){ 
401                                                                 if (!foundsel){
402                                                                         foundsel=1;
403                                                                         foundx = icu->bezt[i].vec[1][0];
404                                                                 }
405                                                         }
406                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
407                                                                 *index=icu->bezt[i].vec[1][0];
408                                                                 *sel = 0;
409                                                                 return chan;
410                                                         }
411                                                 }
412                                         }
413                                 }
414                         }
415                         ymax=ymin;
416                         
417                         /* Check constraint channels */
418                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
419                                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
420                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo) {
421                                         for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
422                                                 for (i=0; i<icu->totvert; i++){
423                                                         if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
424                                                                 if (!firstchan){
425                                                                         firstchan=chan;
426                                                                         firstconchan=conchan;
427                                                                         firstvert=icu->bezt[i].vec[1][0];
428                                                                         *sel = icu->bezt[i].f2 & 1;     
429                                                                 }
430                                                                 
431                                                                 if (icu->bezt[i].f2 & 1){ 
432                                                                         if (!foundsel){
433                                                                                 foundsel=1;
434                                                                                 foundx = icu->bezt[i].vec[1][0];
435                                                                         }
436                                                                 }
437                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
438                                                                         *index=icu->bezt[i].vec[1][0];
439                                                                         *sel = 0;
440                                                                         *rchan = conchan;
441                                                                         return chan;
442                                                                 }
443                                                         }
444                                                 }
445                                         }
446                                 }
447                                 ymax=ymin;
448                         }
449                 }
450         }       
451         
452         *rchan = firstconchan;
453         *index=firstvert;
454         return firstchan;
455 }
456
457 static IpoCurve *get_nearest_meshchannel_key (float *index, short *sel)
458 {
459         /* This function tries to find the RVK key that is
460          * closest to the user's mouse click
461          */
462     Key      *key;
463     IpoCurve *icu; 
464     IpoCurve *firsticu=NULL;
465     int      foundsel=0;
466     float    firstvert=-1, foundx=-1;
467         int      i;
468     short    mval[2];
469     float    ymin, ymax, ybase;
470     rctf     rectf;
471
472     *index=0;
473
474     key = get_action_mesh_key();
475         
476     /* lets get the mouse position and process it so 
477      * we can start testing selections
478      */
479     getmouseco_areawin (mval);
480     mval[0]-=7;
481     areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
482     mval[0]+=14;
483     areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
484
485     ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
486         ybase += CHANNELHEIGHT/2;
487     *sel=0;
488
489     /* lets loop through the IpoCurves trying to find the closest
490      * bezier
491      */
492         if (!key->ipo) return NULL;
493     for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
494         /* lets not deal with the "speed" Ipo
495          */
496         if (!icu->adrcode) continue;
497
498         ymax = ybase    - (CHANNELHEIGHT+CHANNELSKIP)*(icu->adrcode-1);
499         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
500
501         /* Does this curve coorespond to the right
502          * strip?
503          */
504         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
505                         
506             /* loop through the beziers in the curve
507              */
508             for (i=0; i<icu->totvert; i++){
509
510                 /* Is this bezier in the right area?
511                  */
512                 if (icu->bezt[i].vec[1][0] > rectf.xmin && 
513                     icu->bezt[i].vec[1][0] <= rectf.xmax ){
514
515                     /* if no other curves have been picked ...
516                      */
517                     if (!firsticu){
518                         /* mark this curve/bezier as the first
519                          * selected
520                          */
521                         firsticu=icu;
522                         firstvert=icu->bezt[i].vec[1][0];
523
524                         /* sel = (is the bezier is already selected) ? 1 : 0;
525                          */
526                         *sel = icu->bezt[i].f2 & 1;     
527                     }
528
529                     /* if the bezier is selected ...
530                      */
531                     if (icu->bezt[i].f2 & 1){ 
532                         /* if we haven't found a selected one yet ...
533                          */
534                         if (!foundsel){
535                             /* record the found x value
536                              */
537                             foundsel=1;
538                             foundx = icu->bezt[i].vec[1][0];
539                         }
540                     }
541
542                     /* if the bezier is unselected and not at the x
543                      * position of a previous found selected bezier ...
544                      */
545                     else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
546                         /* lets return this found curve/bezier
547                          */
548                         *index=icu->bezt[i].vec[1][0];
549                         *sel = 0;
550                         return icu;
551                     }
552                 }
553             }
554         }
555         }
556         
557     /* return what we've found
558      */
559     *index=firstvert;
560     return firsticu;
561 }
562
563 /* apparently within active object context */
564 static void mouse_action(int selectmode)
565 {
566         bAction *act;
567         short sel;
568         float   selx;
569         bActionChannel *chan;
570         bConstraintChannel *conchan;
571         short   mval[2];
572
573         act=G.saction->action;
574         if (!act)
575                 return;
576
577         getmouseco_areawin (mval);
578
579         chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
580
581         if (chan){
582                 if (selectmode == SELECT_REPLACE) {
583                         selectmode = SELECT_ADD;
584                         
585                         deselect_actionchannel_keys(act, 0);
586                         deselect_actionchannels(act, 0);
587                         
588                         chan->flag |= ACHAN_SELECTED;
589                         hilight_channel (act, chan, 1);
590                         select_poseelement_by_name(chan->name, 2);      /* 2 is activate */
591                 }
592                 
593                 if (conchan)
594                         select_ipo_key(conchan->ipo, selx, selectmode);
595                 else
596                         select_ipo_key(chan->ipo, selx, selectmode);
597
598                 
599                 std_rmouse_transform(transform_actionchannel_keys);
600                 
601                 allqueue(REDRAWIPO, 0);
602                 allqueue(REDRAWVIEW3D, 0);
603                 allqueue(REDRAWACTION, 0);
604                 allqueue(REDRAWNLA, 0);
605                 allqueue(REDRAWOOPS, 0);
606                 allqueue(REDRAWBUTSALL, 0);
607         }
608 }
609
610 static void mouse_mesh_action(int selectmode, Key *key)
611 {
612         /* Handle a right mouse click selection in an
613          * action window displaying RVK data
614          */
615
616     IpoCurve *icu;
617     short  sel;
618     float  selx;
619     short  mval[2];
620
621     /* going to assume that the only reason 
622      * we got here is because it has been 
623      * determined that we are a mesh with
624      * the right properties (i.e., have key
625      * data, etc)
626      */
627
628         /* get the click location, and the cooresponding
629          * ipo curve and selection time value
630          */
631     getmouseco_areawin (mval);
632     icu = get_nearest_meshchannel_key(&selx, &sel);
633
634     if (icu){
635         if (selectmode == SELECT_REPLACE) {
636                         /* if we had planned to replace the
637                          * selection, then we will first deselect
638                          * all of the keys, and if the clicked on
639                          * key had been unselected, we will select 
640                          * it, otherwise, we are done.
641                          */
642             deselect_meshchannel_keys(key, 0);
643
644             if (sel == 0)
645                 selectmode = SELECT_ADD;
646             else
647                                 /* the key is selected so we should
648                                  * deselect -- but everything is now deselected
649                                  * so we are done.
650                                  */
651                                 return;
652         }
653                 
654                 /* select the key using the given mode
655                  * and redraw as mush stuff as needed.
656                  */
657                 select_icu_key(icu, selx, selectmode);
658
659                 BIF_undo_push("Select Action key");
660         allqueue(REDRAWIPO, 0);
661         allqueue(REDRAWVIEW3D, 0);
662         allqueue(REDRAWACTION, 0);
663         allqueue(REDRAWNLA, 0);
664
665     }
666 }
667
668 void borderselect_action(void)
669
670         rcti rect;
671         rctf rectf;
672         int val, selectmode;            
673         short   mval[2];
674         bActionChannel *chan;
675         bConstraintChannel *conchan;
676         bAction *act;
677         float   ymin, ymax;
678
679         act=G.saction->action;
680
681
682         if (!act)
683                 return;
684
685         if ( (val = get_border(&rect, 3)) ){
686     if (val == LEFTMOUSE)
687       selectmode = SELECT_ADD;
688     else
689       selectmode = SELECT_SUBTRACT;
690
691                 mval[0]= rect.xmin;
692                 mval[1]= rect.ymin+2;
693                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
694                 mval[0]= rect.xmax;
695                 mval[1]= rect.ymax-2;
696                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
697                 
698                 /* if action is mapped in NLA, it returns a correction */
699                 if(G.saction->pin==0 && OBACT) {
700                         rectf.xmin= get_action_frame(OBACT, rectf.xmin);
701                         rectf.xmax= get_action_frame(OBACT, rectf.xmax);
702                 }
703                 
704                 ymax= count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP);
705                 ymax += CHANNELHEIGHT/2;
706                 
707                 for (chan=act->chanbase.first; chan; chan=chan->next){
708                         if((chan->flag & ACHAN_HIDDEN)==0) {
709                                 
710                                 /* Check action */
711                                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
712                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
713                                         borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
714                                                                    selectmode);
715
716                                 ymax=ymin;
717
718                                 /* Check constraints */
719                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
720                                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
721                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
722                                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
723                                                                    selectmode);
724                                         
725                                         ymax=ymin;
726                                 }
727                         }
728                 }       
729                 BIF_undo_push("Border Select Action");
730                 allqueue(REDRAWNLA, 0);
731                 allqueue(REDRAWACTION, 0);
732                 allqueue(REDRAWIPO, 0);
733         }
734 }
735
736 void borderselect_mesh(Key *key)
737
738         rcti     rect;
739         int      val, adrcodemax, adrcodemin;
740         short    mval[2];
741         float    xmin, xmax;
742         int      (*select_function)(BezTriple *);
743         IpoCurve *icu;
744
745         if ( (val = get_border(&rect, 3)) ){
746                 /* set the selection function based on what
747                  * mouse button had been used in the border
748                  * select
749                  */
750                 if (val == LEFTMOUSE)
751                         select_function = select_bezier_add;
752                 else
753                         select_function = select_bezier_subtract;
754
755                 /* get the minimum and maximum adrcode numbers
756                  * for the IpoCurves (this is the number that
757                  * relates an IpoCurve to the keyblock it
758                  * controls).
759                  */
760                 mval[0]= rect.xmin;
761                 mval[1]= rect.ymin+2;
762                 adrcodemax = get_nearest_key_num(key, mval, &xmin);
763                 adrcodemax = (adrcodemax >= key->totkey) ? key->totkey : adrcodemax;
764
765                 mval[0]= rect.xmax;
766                 mval[1]= rect.ymax-2;
767                 adrcodemin = get_nearest_key_num(key, mval, &xmax);
768                 adrcodemin = (adrcodemin < 1) ? 1 : adrcodemin;
769
770                 /* Lets loop throug the IpoCurves and do borderselect
771                  * on the curves with adrcodes in our selected range.
772                  */
773                 if(key->ipo) {
774                         for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
775                                 /* lets not deal with the "speed" Ipo
776                                  */
777                                 if (!icu->adrcode) continue;
778                                 if ( (icu->adrcode >= adrcodemin) && 
779                                          (icu->adrcode <= adrcodemax) ) {
780                                         borderselect_icu_key(icu, xmin, xmax, select_function);
781                                 }
782                         }
783                 }
784                 /* redraw stuff */
785                 BIF_undo_push("Border select Action Key");
786                 allqueue(REDRAWNLA, 0);
787                 allqueue(REDRAWACTION, 0);
788                 allqueue(REDRAWIPO, 0);
789         }
790 }
791
792 /* ******************** action API ***************** */
793
794 /* generic get current action call, for action window context */
795 bAction *ob_get_action(Object *ob)
796 {
797         bActionStrip *strip;
798         
799         if(ob->action)
800                 return ob->action;
801         
802         for (strip=ob->nlastrips.first; strip; strip=strip->next){
803                 if (strip->flag & ACTSTRIP_SELECT)
804                         return strip->act;
805         }
806         return NULL;
807 }
808
809 /* used by ipo, outliner, buttons to find the active channel */
810 bActionChannel* get_hilighted_action_channel(bAction* action)
811 {
812         bActionChannel *chan;
813
814         if (!action)
815                 return NULL;
816
817         for (chan=action->chanbase.first; chan; chan=chan->next){
818                 if((chan->flag & ACHAN_HIDDEN)==0)
819                         if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED)
820                                 return chan;
821         }
822
823         return NULL;
824
825 }
826
827 void set_exprap_action(int mode)
828 {
829         if(G.saction->action && G.saction->action->id.lib) return;
830
831         error ("Not yet implemented!");
832 }
833
834 bAction *add_empty_action(int blocktype)
835 {
836         bAction *act;
837         char *str= "Action";
838         
839         if(blocktype==ID_OB)
840                 str= "ObAction";
841         else if(blocktype==ID_KE)
842                 str= "ShapeAction";
843         
844         act= alloc_libblock(&G.main->action, ID_AC, str);
845         act->id.flag |= LIB_FAKEUSER;
846         act->id.us++;
847         return act;
848 }
849
850 void transform_actionchannel_keys(int mode, int dummy)
851 {
852         bAction *act;
853         TransVert *tv;
854         Object *ob= OBACT;
855         bConstraintChannel *conchan;
856         bActionChannel  *chan;
857         float   deltax, startx;
858         float   minx, maxx, cenf[2];
859         float   sval[2], cval[2], lastcval[2];
860         float   fac=0.0f;
861         int             loop=1;
862         int             tvtot=0;
863         int             invert=0, firsttime=1;
864         int             i;
865         short   cancel=0;
866         short   mvals[2], mvalc[2], cent[2];
867         char    str[256];
868
869         act=G.saction->action;
870
871         /* Ensure that partial selections result in beztriple selections */
872         for (chan=act->chanbase.first; chan; chan=chan->next){
873                 if((chan->flag & ACHAN_HIDDEN)==0) {
874                         tvtot+=fullselect_ipo_keys(chan->ipo);
875
876                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
877                                 tvtot+=fullselect_ipo_keys(conchan->ipo);
878                 }
879         }
880         
881         /* If nothing is selected, bail out */
882         if (!tvtot)
883                 return;
884         
885         
886         /* Build the transvert structure */
887         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
888         
889         tvtot=0;
890         for (chan=act->chanbase.first; chan; chan=chan->next){
891                 if((chan->flag & ACHAN_HIDDEN)==0) {
892                         /* Add the actionchannel */
893                         tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
894                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
895                                 tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
896                 }
897         }
898         
899         /* min max, only every other three */
900         minx= maxx= tv[1].loc[0];
901         for (i=1; i<tvtot; i+=3){
902                 if(minx>tv[i].loc[0]) minx= tv[i].loc[0];
903                 if(maxx<tv[i].loc[0]) maxx= tv[i].loc[0];
904         }
905         
906         /* Do the event loop */
907         cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
908         cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
909         areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
910
911         getmouseco_areawin (mvals);
912         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
913
914         if(G.saction->pin==0 && OBACT)
915                 sval[0]= get_action_frame(OBACT, sval[0]);
916         
917         /* used for drawing */
918         if(mode=='t') {
919                 G.saction->flag |= SACTION_MOVING;
920                 G.saction->timeslide= sval[0];
921         }
922         
923         startx=sval[0];
924         while (loop) {
925                 
926                 if(mode=='t' && minx==maxx)
927                         break;
928                 
929                 /*              Get the input */
930                 /*              If we're cancelling, reset transformations */
931                 /*                      Else calc new transformation */
932                 /*              Perform the transformations */
933                 while (qtest()) {
934                         short val;
935                         unsigned short event= extern_qread(&val);
936
937                         if (val) {
938                                 switch (event) {
939                                 case LEFTMOUSE:
940                                 case SPACEKEY:
941                                 case RETKEY:
942                                         loop=0;
943                                         break;
944                                 case XKEY:
945                                         break;
946                                 case ESCKEY:
947                                 case RIGHTMOUSE:
948                                         cancel=1;
949                                         loop=0;
950                                         break;
951                                 default:
952                                         arrows_move_cursor(event);
953                                         break;
954                                 };
955                         }
956                 }
957
958                 if (cancel) {
959                         for (i=0; i<tvtot; i++) {
960                                 tv[i].loc[0]=tv[i].oldloc[0];
961                                 tv[i].loc[1]=tv[i].oldloc[1];
962                         }
963                 } else {
964                         getmouseco_areawin (mvalc);
965                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
966                         
967                         if(G.saction->pin==0 && OBACT)
968                                 cval[0]= get_action_frame(OBACT, cval[0]);
969
970                         if(mode=='t')
971                                 G.saction->timeslide= cval[0];
972                         
973                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
974                                 PIL_sleep_ms(1);
975                         } else {
976                                 
977                                 for (i=0; i<tvtot; i++){
978                                         tv[i].loc[0]=tv[i].oldloc[0];
979
980                                         switch (mode){
981                                         case 't':
982                                                 if( sval[0] > minx && sval[0] < maxx) {
983                                                         float timefac, cvalc= CLAMPIS(cval[0], minx, maxx);
984                                                         
985                                                         /* left half */
986                                                         if(tv[i].oldloc[0] < sval[0]) {
987                                                                 timefac= ( sval[0] - tv[i].oldloc[0])/(sval[0] - minx);
988                                                                 tv[i].loc[0]= cvalc - timefac*( cvalc - minx);
989                                                         }
990                                                         else {
991                                                                 timefac= (tv[i].oldloc[0] - sval[0])/(maxx - sval[0]);
992                                                                 tv[i].loc[0]= cvalc + timefac*(maxx- cvalc);
993                                                         }
994                                                 }
995                                                 break;
996                                         case 'g':
997                                                 deltax = cval[0]-sval[0];
998                                                 fac= deltax;
999                                                 
1000                                                 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
1001
1002                                                 tv[i].loc[0]+=fac;
1003                                                 break;
1004                                         case 's':
1005                                                 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
1006                                                 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
1007                                                 fac= fabs(deltax/startx);
1008                                                 
1009                                                 apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & USER_AUTOSIZEGRID);
1010                 
1011                                                 if (invert){
1012                                                         if (i % 03 == 0){
1013                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
1014                                                         }
1015                                                         if (i % 03 == 2){
1016                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
1017                                                         }
1018         
1019                                                         fac*=-1;
1020                                                 }
1021                                                 startx= (G.scene->r.cfra);
1022                                                 if(G.saction->pin==0 && OBACT)
1023                                                         startx= get_action_frame(OBACT, startx);
1024                                                         
1025                                                 tv[i].loc[0]-= startx;
1026                                                 tv[i].loc[0]*=fac;
1027                                                 tv[i].loc[0]+= startx;
1028                 
1029                                                 break;
1030                                         }
1031                                 }
1032         
1033                                 if (mode=='s'){
1034                                         sprintf(str, "sizeX: %.3f", fac);
1035                                         headerprint(str);
1036                                 }
1037                                 else if (mode=='g'){
1038                                         sprintf(str, "deltaX: %.3f", fac);
1039                                         headerprint(str);
1040                                 }
1041                                 else if (mode=='t') {
1042                                         float fac= 2.0*(cval[0]-sval[0])/(maxx-minx);
1043                                         CLAMP(fac, -1.0f, 1.0f);
1044                                         sprintf(str, "TimeSlide: %.3f", fac);
1045                                         headerprint(str);
1046                                 }
1047                 
1048                                 if (G.saction->lock) {
1049                                         if(ob) {
1050                                                 ob->ctime= -1234567.0f;
1051                                                 if(ob->pose || ob_get_key(ob))
1052                                                         DAG_object_flush_update(G.scene, ob, OB_RECALC);
1053                                                 else
1054                                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
1055                                         }
1056                                         force_draw_plus(SPACE_VIEW3D, 0);
1057                                 }
1058                                 else {
1059                                         force_draw(0);
1060                                 }
1061                         }
1062                 }
1063                 
1064                 lastcval[0]= cval[0];
1065                 lastcval[1]= cval[1];
1066                 firsttime= 0;
1067         }
1068         
1069         /*              Update the curve */
1070         /*              Depending on the lock status, draw necessary views */
1071
1072         if(ob) {
1073                 ob->ctime= -1234567.0f;
1074
1075                 if(ob->pose || ob_get_key(ob))
1076                         DAG_object_flush_update(G.scene, ob, OB_RECALC);
1077                 else
1078                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
1079         }
1080         
1081         remake_action_ipos(act);
1082
1083         G.saction->flag &= ~SACTION_MOVING;
1084         
1085         if(cancel==0) BIF_undo_push("Transform Action");
1086         allqueue (REDRAWVIEW3D, 0);
1087         allqueue (REDRAWACTION, 0);
1088         allqueue(REDRAWNLA, 0);
1089         allqueue (REDRAWIPO, 0);
1090         MEM_freeN (tv);
1091 }
1092
1093 void transform_meshchannel_keys(char mode, Key *key)
1094 {
1095         /* this is the function that determines what happens
1096          * to those little blocky rvk key things you have selected 
1097          * after you press a 'g' or an 's'. I'd love to say that
1098          * I have an intimate knowledge of all of what this function
1099          * is doing, but instead I'm just going to pretend.
1100          */
1101     TransVert *tv;
1102     int /*sel=0,*/  i;
1103     short       mvals[2], mvalc[2], cent[2];
1104     float       sval[2], cval[2], lastcval[2];
1105     short       cancel=0;
1106     float       fac=0.0F;
1107     int         loop=1;
1108     int         tvtot=0;
1109     float       deltax, startx;
1110     float       cenf[2];
1111     int         invert=0, firsttime=1;
1112     char        str[256];
1113
1114         /* count all of the selected beziers, and
1115          * set all 3 control handles to selected
1116          */
1117     tvtot=fullselect_ipo_keys(key->ipo);
1118     
1119     /* If nothing is selected, bail out 
1120          */
1121     if (!tvtot)
1122         return;
1123         
1124         
1125     /* Build the transvert structure 
1126          */
1127     tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
1128     tvtot=0;
1129
1130     tvtot = add_trans_ipo_keys(key->ipo, tv, tvtot);
1131
1132     /* Do the event loop 
1133          */
1134     cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
1135     cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
1136     areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
1137
1138     getmouseco_areawin (mvals);
1139     areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
1140
1141     startx=sval[0];
1142     while (loop) {
1143         /* Get the input
1144                  * If we're cancelling, reset transformations
1145                  * Else calc new transformation
1146                  * Perform the transformations 
1147                  */
1148         while (qtest()) {
1149             short val;
1150             unsigned short event= extern_qread(&val);
1151
1152             if (val) {
1153                 switch (event) {
1154                 case LEFTMOUSE:
1155                 case SPACEKEY:
1156                 case RETKEY:
1157                     loop=0;
1158                     break;
1159                 case XKEY:
1160                     break;
1161                 case ESCKEY:
1162                 case RIGHTMOUSE:
1163                     cancel=1;
1164                     loop=0;
1165                     break;
1166                 default:
1167                     arrows_move_cursor(event);
1168                     break;
1169                 };
1170             }
1171         }
1172         
1173         if (cancel) {
1174             for (i=0; i<tvtot; i++) {
1175                 tv[i].loc[0]=tv[i].oldloc[0];
1176                 tv[i].loc[1]=tv[i].oldloc[1];
1177             }
1178         } 
1179                 else {
1180             getmouseco_areawin (mvalc);
1181             areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
1182                         
1183             if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
1184                 PIL_sleep_ms(1);
1185             } else {
1186                 for (i=0; i<tvtot; i++){
1187                     tv[i].loc[0]=tv[i].oldloc[0];
1188
1189                     switch (mode){
1190                     case 'g':
1191                         deltax = cval[0]-sval[0];
1192                         fac= deltax;
1193                                                 
1194                         apply_keyb_grid(&fac, 0.0, 1.0, 0.1, 
1195                                         U.flag & USER_AUTOGRABGRID);
1196
1197                         tv[i].loc[0]+=fac;
1198                         break;
1199                     case 's':
1200                         startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1201                                                      -curarea->winrct.xmin)/2);
1202                         deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1203                                                      -curarea->winrct.xmin)/2);
1204                         fac= fabs(deltax/startx);
1205                                                 
1206                         apply_keyb_grid(&fac, 0.0, 0.2, 0.1, 
1207                                         U.flag & USER_AUTOSIZEGRID);
1208                 
1209                         if (invert){
1210                             if (i % 03 == 0){
1211                                 memcpy (tv[i].loc, tv[i].oldloc, 
1212                                         sizeof(tv[i+2].oldloc));
1213                             }
1214                             if (i % 03 == 2){
1215                                 memcpy (tv[i].loc, tv[i].oldloc, 
1216                                         sizeof(tv[i-2].oldloc));
1217                             }
1218                                                         
1219                             fac*=-1;
1220                         }
1221                         startx= (G.scene->r.cfra);
1222                         
1223                         tv[i].loc[0]-= startx;
1224                         tv[i].loc[0]*=fac;
1225                         tv[i].loc[0]+= startx;
1226                 
1227                         break;
1228                     }
1229                 }
1230             }
1231                         /* Display a message showing the magnitude of
1232                          * the grab/scale we are performing
1233                          */
1234             if (mode=='s'){
1235                 sprintf(str, "sizeX: %.3f", fac);
1236                 headerprint(str);
1237             }
1238             else if (mode=='g'){
1239                 sprintf(str, "deltaX: %.3f", fac);
1240                 headerprint(str);
1241             }
1242         
1243             if (G.saction->lock){
1244                                 /* doubt any of this code ever gets
1245                                  * executed, but it might in the
1246                                  * future
1247                                  */
1248                                  
1249                                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
1250                 allqueue (REDRAWVIEW3D, 0);
1251                 allqueue (REDRAWACTION, 0);
1252                 allqueue (REDRAWIPO, 0);
1253                 allqueue(REDRAWNLA, 0);
1254                 force_draw_all(0);
1255             }
1256             else {
1257                 addqueue (curarea->win, REDRAWALL, 0);
1258                 force_draw(0);
1259             }
1260         }
1261                 
1262         lastcval[0]= cval[0];
1263         lastcval[1]= cval[1];
1264         firsttime= 0;
1265     }
1266         
1267         /* fix up the Ipocurves and redraw stuff
1268          */
1269     meshkey_do_redraw(key);
1270         BIF_undo_push("Transform Action Keys");
1271
1272     MEM_freeN (tv);
1273
1274         /* did you understand all of that? I pretty much understand
1275          * what it does, but the specifics seem a little weird and crufty.
1276          */
1277 }
1278
1279 void deselect_actionchannel_keys (bAction *act, int test)
1280 {
1281         bActionChannel  *chan;
1282         bConstraintChannel *conchan;
1283         int             sel=1;;
1284
1285         if (!act)
1286                 return;
1287
1288         /* Determine if this is selection or deselection */
1289         
1290         if (test){
1291                 for (chan=act->chanbase.first; chan; chan=chan->next){
1292                         if((chan->flag & ACHAN_HIDDEN)==0) {
1293                                 /* Test the channel ipos */
1294                                 if (is_ipo_key_selected(chan->ipo)){
1295                                         sel = 0;
1296                                         break;
1297                                 }
1298
1299                                 /* Test the constraint ipos */
1300                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1301                                         if (is_ipo_key_selected(conchan->ipo)){
1302                                                 sel = 0;
1303                                                 break;
1304                                         }
1305                                 }
1306
1307                                 if (sel == 0)
1308                                         break;
1309                         }
1310                 }
1311         }
1312         else
1313                 sel=0;
1314         
1315         /* Set the flags */
1316         for (chan=act->chanbase.first; chan; chan=chan->next){
1317                 if((chan->flag & ACHAN_HIDDEN)==0) {
1318                         set_ipo_key_selection(chan->ipo, sel);
1319                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1320                                 set_ipo_key_selection(conchan->ipo, sel);
1321                 }
1322         }
1323 }
1324
1325 void deselect_meshchannel_keys (Key *key, int test)
1326 {
1327         /* should deselect the rvk keys
1328          */
1329     int         sel=1;
1330
1331     /* Determine if this is selection or deselection */
1332     if (test){
1333         if (is_ipo_key_selected(key->ipo)){
1334             sel = 0;
1335         }
1336     }
1337     else {
1338         sel=0;
1339     }
1340         
1341     /* Set the flags */
1342     set_ipo_key_selection(key->ipo, sel);
1343 }
1344
1345 /* apparently within active object context */
1346 void deselect_actionchannels (bAction *act, int test)
1347 {
1348         bActionChannel *chan;
1349         bConstraintChannel *conchan;
1350         int                     sel=1;  
1351
1352         if (!act)
1353                 return;
1354
1355         /* See if we should be selecting or deselecting */
1356         if (test){
1357                 for (chan=act->chanbase.first; chan; chan=chan->next){
1358                         if((chan->flag & ACHAN_HIDDEN)==0) {
1359                                 if (!sel)
1360                                         break;
1361
1362                                 if (chan->flag & ACHAN_SELECTED){
1363                                         sel=0;
1364                                         break;
1365                                 }
1366                                 if (sel){
1367                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1368                                                 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1369                                                         sel=0;
1370                                                         break;
1371                                                 }
1372                                         }
1373                                 }
1374                         }
1375                 }
1376         }
1377         else
1378                 sel=0;
1379
1380         /* Now set the flags */
1381         for (chan=act->chanbase.first; chan; chan=chan->next){
1382                 if((chan->flag & ACHAN_HIDDEN)==0) {
1383                         select_poseelement_by_name(chan->name, sel);
1384
1385                         if (sel)
1386                                 chan->flag |= ACHAN_SELECTED;
1387                         else
1388                                 chan->flag &= ~ACHAN_SELECTED;
1389
1390                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1391                                 if (sel)
1392                                         conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1393                                 else
1394                                         conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1395                         }
1396                 }
1397         }
1398
1399 }
1400
1401 static void hilight_channel (bAction *act, bActionChannel *chan, short select)
1402 {
1403         bActionChannel *curchan;
1404
1405         if (!act)
1406                 return;
1407
1408         for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
1409                 if (curchan==chan && select)
1410                         curchan->flag |= ACHAN_HILIGHTED;
1411                 else
1412                         curchan->flag &= ~ACHAN_HILIGHTED;
1413         }
1414 }
1415
1416 /* select_mode = SELECT_REPLACE
1417  *             = SELECT_ADD
1418  *             = SELECT_SUBTRACT
1419  *             = SELECT_INVERT
1420  */
1421
1422 /* exported for outliner (ton) */
1423 /* apparently within active object context */
1424 int select_channel(bAction *act, bActionChannel *chan,
1425                           int selectmode) 
1426 {
1427         /* Select the channel based on the selection mode
1428          */
1429         int flag;
1430
1431         switch (selectmode) {
1432         case SELECT_ADD:
1433                 chan->flag |= ACHAN_SELECTED;
1434                 break;
1435         case SELECT_SUBTRACT:
1436                 chan->flag &= ~ACHAN_SELECTED;
1437                 break;
1438         case SELECT_INVERT:
1439                 chan->flag ^= ACHAN_SELECTED;
1440                 break;
1441         }
1442         flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0;
1443
1444         hilight_channel(act, chan, flag);
1445         select_poseelement_by_name(chan->name, flag);
1446
1447         return flag;
1448 }
1449
1450 static int select_constraint_channel(bAction *act, 
1451                                      bConstraintChannel *conchan, 
1452                                      int selectmode) {
1453         /* Select the constraint channel based on the selection mode
1454          */
1455         int flag;
1456
1457         switch (selectmode) {
1458         case SELECT_ADD:
1459                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1460                 break;
1461         case SELECT_SUBTRACT:
1462                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1463                 break;
1464         case SELECT_INVERT:
1465                 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
1466                 break;
1467         }
1468         flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
1469
1470         return flag;
1471 }
1472
1473 /* lefthand side */
1474 static void mouse_actionchannels(bAction *act, short *mval,
1475                                  short *mvalo, int selectmode) {
1476         /* Select action channels, based on mouse values.
1477          * If mvalo is NULL we assume it is a one click
1478          * action, other wise we treat it like it is a
1479          * border select with mval[0],mval[1] and
1480          * mvalo[0], mvalo[1] forming the corners of
1481          * a rectangle.
1482          */
1483         bActionChannel *chan;
1484         float   click, x,y;
1485         int   clickmin, clickmax;
1486         int             wsize, sel;
1487         bConstraintChannel *conchan;
1488
1489         if (!act)
1490                 return;
1491   
1492         if (selectmode == SELECT_REPLACE) {
1493                 deselect_actionchannels (act, 0);
1494                 selectmode = SELECT_ADD;
1495         }
1496
1497         /* wsize is the greatest possible height (in pixels) that would be
1498          * needed to draw all of the action channels and constraint
1499          * channels.
1500          */
1501         wsize =  count_action_levels(act)*(CHANNELHEIGHT+CHANNELSKIP);
1502         wsize += CHANNELHEIGHT/2;
1503
1504     areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1505     clickmin = (int) ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1506         
1507         /* Only one click */
1508         if (mvalo == NULL) {
1509                 clickmax = clickmin;
1510         }
1511         /* Two click values (i.e., border select */
1512         else {
1513                 areamouseco_to_ipoco(G.v2d, mvalo, &x, &y);
1514                 click = ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1515
1516                 if ( ((int) click) < clickmin) {
1517                         clickmax = clickmin;
1518                         clickmin = (int) click;
1519                 }
1520                 else {
1521                         clickmax = (int) click;
1522                 }
1523         }
1524
1525         if (clickmax < 0) {
1526                 return;
1527         }
1528
1529         /* clickmin and clickmax now coorespond to indices into
1530          * the collection of channels and constraint channels.
1531          * What we need to do is apply the selection mode on all
1532          * channels and constraint channels between these indices.
1533          * This is done by traversing the channels and constraint
1534          * channels, for each item decrementing clickmin and clickmax.
1535          * When clickmin is less than zero we start selecting stuff,
1536          * until clickmax is less than zero or we run out of channels
1537          * and constraint channels.
1538          */
1539
1540         for (chan = act->chanbase.first; chan; chan=chan->next){
1541                 if((chan->flag & ACHAN_HIDDEN)==0) {
1542                         if (clickmax < 0) break;
1543
1544                         if ( clickmin <= 0) {
1545                                 /* Select the channel with the given mode. If the
1546                                  * channel is freshly selected then set it to the
1547                                  * active channel for the action
1548                                  */
1549                                 sel = (chan->flag & ACHAN_SELECTED);
1550                                 select_channel(act, chan, selectmode);
1551                                 /* messy... */
1552                                 select_poseelement_by_name(chan->name, 2);
1553                                 
1554                         }
1555                         --clickmin;
1556                         --clickmax;
1557
1558                         /* Check for click in a constraint */
1559                         for (conchan=chan->constraintChannels.first; 
1560                                  conchan; conchan=conchan->next){
1561                                 if (clickmax < 0) break;
1562                                 if ( clickmin <= 0) {
1563                                         select_constraint_channel(act, conchan, selectmode);
1564                                 }
1565                                 --clickmin;
1566                                 --clickmax;
1567                         }
1568                 }
1569         }
1570
1571         allqueue (REDRAWIPO, 0);
1572         allqueue (REDRAWVIEW3D, 0);
1573         allqueue (REDRAWACTION, 0);
1574         allqueue (REDRAWNLA, 0);
1575         allqueue (REDRAWOOPS, 0);
1576         allqueue (REDRAWBUTSALL, 0);
1577 }
1578
1579 void delete_meshchannel_keys(Key *key)
1580 {
1581         if (!okee("Erase selected keys"))
1582                 return;
1583
1584         BIF_undo_push("Delete Action keys");
1585         delete_ipo_keys(key->ipo);
1586
1587         meshkey_do_redraw(key);
1588 }
1589
1590 void delete_actionchannel_keys(void)
1591 {
1592         bAction *act;
1593         bActionChannel *chan;
1594         bConstraintChannel *conchan;
1595
1596         act = G.saction->action;
1597         if (!act)
1598                 return;
1599
1600         if (!okee("Erase selected keys"))
1601                 return;
1602
1603         for (chan = act->chanbase.first; chan; chan=chan->next){
1604                 if((chan->flag & ACHAN_HIDDEN)==0) {
1605
1606                         /* Check action channel keys*/
1607                         delete_ipo_keys(chan->ipo);
1608
1609                         /* Delete constraint channel keys */
1610                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1611                                 delete_ipo_keys(conchan->ipo);
1612                 }
1613         }
1614
1615         remake_action_ipos (act);
1616         BIF_undo_push("Delete Action keys");
1617         allspace(REMAKEIPO, 0);
1618         allqueue(REDRAWACTION, 0);
1619         allqueue(REDRAWIPO, 0);
1620         allqueue(REDRAWNLA, 0);
1621
1622 }
1623
1624 static void delete_actionchannels (void)
1625 {
1626         bConstraintChannel *conchan=NULL, *nextconchan;
1627         bActionChannel *chan, *next;
1628         bAction *act;
1629         int freechan;
1630
1631         act=G.saction->action;
1632
1633         if (!act)
1634                 return;
1635
1636         for (chan=act->chanbase.first; chan; chan=chan->next){
1637                 if((chan->flag & ACHAN_HIDDEN)==0) {
1638                         if (chan->flag & ACHAN_SELECTED)
1639                                 break;
1640                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1641                         {
1642                                 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1643                                         chan=act->chanbase.last;
1644                                         break;
1645                                 }
1646                         }
1647                 }
1648         }
1649
1650         if (!chan && !conchan)
1651                 return;
1652
1653         if (!okee("Erase selected channels"))
1654                 return;
1655
1656         for (chan=act->chanbase.first; chan; chan=next){
1657                 freechan = 0;
1658                 next=chan->next;
1659                 if((chan->flag & ACHAN_HIDDEN)==0) {
1660                         
1661                         /* Remove action channels */
1662                         if (chan->flag & ACHAN_SELECTED){
1663                                 if (chan->ipo)
1664                                         chan->ipo->id.us--;     /* Release the ipo */
1665                                 freechan = 1;
1666                         }
1667                         
1668                         /* Remove constraint channels */
1669                         for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
1670                                 nextconchan=conchan->next;
1671                                 if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1672                                         if (conchan->ipo)
1673                                                 conchan->ipo->id.us--;
1674                                         BLI_freelinkN(&chan->constraintChannels, conchan);
1675                                 }
1676                         }
1677                         
1678                         if (freechan)
1679                                 BLI_freelinkN (&act->chanbase, chan);
1680                 }
1681         }
1682
1683         BIF_undo_push("Delete Action channels");
1684         allqueue (REDRAWACTION, 0);
1685         allqueue(REDRAWNLA, 0);
1686
1687 }
1688
1689 void sethandles_meshchannel_keys(int code, Key *key)
1690 {
1691         
1692     sethandles_ipo_keys(key->ipo, code);
1693
1694         BIF_undo_push("Set handles Action keys");
1695         meshkey_do_redraw(key);
1696 }
1697
1698 void sethandles_actionchannel_keys(int code)
1699 {
1700         bAction *act;
1701         bActionChannel *chan;
1702
1703         /* Get the selected action, exit if none are selected 
1704          */
1705         act = G.saction->action;
1706         if (!act)
1707                 return;
1708
1709         /* Loop through the channels and set the beziers
1710          * of the selected keys based on the integer code
1711          */
1712         for (chan = act->chanbase.first; chan; chan=chan->next){
1713                 if((chan->flag & ACHAN_HIDDEN)==0)
1714                         sethandles_ipo_keys(chan->ipo, code);
1715         }
1716
1717         /* Clean up and redraw stuff
1718          */
1719         remake_action_ipos (act);
1720         BIF_undo_push("Set handles Action channel");
1721         allspace(REMAKEIPO, 0);
1722         allqueue(REDRAWACTION, 0);
1723         allqueue(REDRAWIPO, 0);
1724         allqueue(REDRAWNLA, 0);
1725 }
1726
1727 void set_ipotype_actionchannels(int ipotype) 
1728 {
1729
1730         bAction *act; 
1731         bActionChannel *chan;
1732         short event;
1733
1734         /* Get the selected action, exit if none are selected 
1735          */
1736         act = G.saction->action;
1737         if (!act)
1738                 return;
1739
1740         if (ipotype == SET_IPO_POPUP) {
1741                 /* Present a popup menu asking the user what type
1742                  * of IPO curve he/she/GreenBTH wants. ;)
1743                  */
1744                 event
1745                         =  pupmenu("Channel Ipo Type %t|"
1746                                            "Constant %x1|"
1747                                            "Linear %x2|"
1748                                            "Bezier %x3");
1749                 if(event < 1) return;
1750                 ipotype = event;
1751         }
1752         
1753         /* Loop through the channels and for the selected ones set
1754          * the type for each Ipo curve in the channel Ipo (based on
1755          * the value from the popup).
1756          */
1757         for (chan = act->chanbase.first; chan; chan=chan->next){
1758                 if((chan->flag & ACHAN_HIDDEN)==0) {
1759                         if (chan->flag & ACHAN_SELECTED){
1760                                 if (chan->ipo)
1761                                         setipotype_ipo(chan->ipo, ipotype);
1762                         }
1763                 }
1764         }
1765
1766         /* Clean up and redraw stuff
1767          */
1768         remake_action_ipos (act);
1769         BIF_undo_push("Set Ipo type Action channel");
1770         allspace(REMAKEIPO, 0);
1771         allqueue(REDRAWACTION, 0);
1772         allqueue(REDRAWIPO, 0);
1773         allqueue(REDRAWNLA, 0);
1774 }
1775
1776 void set_extendtype_actionchannels(int extendtype)
1777 {
1778         bAction *act; 
1779         bActionChannel *chan;
1780         short event;
1781
1782         /* Get the selected action, exit if none are selected 
1783          */
1784         act = G.saction->action;
1785         if (!act)
1786                 return;
1787
1788         if (extendtype == SET_EXTEND_POPUP) {
1789                 /* Present a popup menu asking the user what type
1790                  * of IPO curve he/she/GreenBTH wants. ;)
1791                  */
1792                 event
1793                         =  pupmenu("Channel Extending Type %t|"
1794                                            "Constant %x1|"
1795                                            "Extrapolation %x2|"
1796                                            "Cyclic %x3|"
1797                                            "Cyclic extrapolation %x4");
1798                 if(event < 1) return;
1799                 extendtype = event;
1800         }
1801         
1802         /* Loop through the channels and for the selected ones set
1803          * the type for each Ipo curve in the channel Ipo (based on
1804          * the value from the popup).
1805          */
1806         for (chan = act->chanbase.first; chan; chan=chan->next){
1807                 if((chan->flag & ACHAN_HIDDEN)==0) {
1808                         if (chan->flag & ACHAN_SELECTED) {
1809                                 if (chan->ipo) {
1810                                         switch (extendtype) {
1811                                         case SET_EXTEND_CONSTANT:
1812                                                 setexprap_ipoloop(chan->ipo, IPO_HORIZ);
1813                                                 break;
1814                                         case SET_EXTEND_EXTRAPOLATION:
1815                                                 setexprap_ipoloop(chan->ipo, IPO_DIR);
1816                                                 break;
1817                                         case SET_EXTEND_CYCLIC:
1818                                                 setexprap_ipoloop(chan->ipo, IPO_CYCL);
1819                                                 break;
1820                                         case SET_EXTEND_CYCLICEXTRAPOLATION:
1821                                                 setexprap_ipoloop(chan->ipo, IPO_CYCLX);
1822                                                 break;
1823                                         }
1824                                 }
1825                         }
1826                 }
1827         }
1828
1829         /* Clean up and redraw stuff
1830          */
1831         remake_action_ipos (act);
1832         BIF_undo_push("Set Ipo type Action channel");
1833         allspace(REMAKEIPO, 0);
1834         allqueue(REDRAWACTION, 0);
1835         allqueue(REDRAWIPO, 0);
1836         allqueue(REDRAWNLA, 0);
1837 }
1838
1839 void set_snap_actionchannels(void) 
1840 {
1841         
1842         bAction *act; 
1843         bActionChannel *chan;
1844         
1845         /* Get the selected action, exit if none are selected 
1846                 */
1847         act = G.saction->action;
1848         if (!act)
1849                 return;
1850         
1851         /* Loop through the channels */
1852         for (chan = act->chanbase.first; chan; chan=chan->next){
1853                 if((chan->flag & ACHAN_HIDDEN)==0) {
1854                         if (chan->ipo) {
1855                                 snap_ipo_keys(chan->ipo);
1856                         }
1857                 }
1858         }
1859         
1860         /* Clean up and redraw stuff */
1861         remake_action_ipos (act);
1862         BIF_undo_push("Snap Ipo Action channel");
1863         allspace(REMAKEIPO, 0);
1864         allqueue(REDRAWACTION, 0);
1865         allqueue(REDRAWIPO, 0);
1866         allqueue(REDRAWNLA, 0);
1867 }
1868
1869
1870 static void select_all_keys_frames(bAction *act, short *mval, 
1871                                                         short *mvalo, int selectmode) {
1872         
1873         /* This function tries to select all action keys in
1874          * every channel for a given range of keyframes that
1875          * are within the mouse values mval and mvalo (usually
1876          * the result of a border select). If mvalo is passed as
1877          * NULL then the selection is treated as a one-click and
1878          * the function tries to select all keys within half a
1879          * frame of the click point.
1880          */
1881         
1882         rcti rect;
1883         rctf rectf;
1884         bActionChannel *chan;
1885         bConstraintChannel *conchan;
1886
1887         if (!act)
1888                 return;
1889
1890         if (selectmode == SELECT_REPLACE) {
1891                 deselect_actionchannel_keys(act, 0);
1892                 selectmode = SELECT_ADD;
1893         }
1894
1895         if (mvalo == NULL) {
1896                 rect.xmin = rect.xmax = mval[0];
1897                 rect.ymin = rect.ymax = mval[1];
1898         }
1899         else {
1900                 if (mval[0] < mvalo[0] ) {
1901                         rect.xmin = mval[0];
1902                         rect.xmax = mvalo[0];
1903                 }
1904                 else {
1905                         rect.xmin = mvalo[0];
1906                         rect.xmax = mval[0];
1907                 }
1908                 if (mval[1] < mvalo[1] ) {
1909                         rect.ymin = mval[1];
1910                         rect.ymax = mvalo[1];
1911                 }
1912                 else {
1913                         rect.ymin = mvalo[1];
1914                         rect.ymax = mval[1];
1915                 }
1916         }
1917
1918         mval[0]= rect.xmin;
1919         mval[1]= rect.ymin+2;
1920         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1921         mval[0]= rect.xmax;
1922         mval[1]= rect.ymax-2;
1923         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1924
1925         if (mvalo == NULL) {
1926                 rectf.xmin = rectf.xmin - 0.5;
1927                 rectf.xmax = rectf.xmax + 0.5;
1928         }
1929     
1930         for (chan=act->chanbase.first; chan; chan=chan->next){
1931                 if((chan->flag & ACHAN_HIDDEN)==0) {
1932                         borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
1933                                                                  selectmode);
1934                         for (conchan=chan->constraintChannels.first; conchan; 
1935                                  conchan=conchan->next){
1936                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1937                                                                          selectmode);
1938                         }
1939                 }
1940         }       
1941
1942         allqueue(REDRAWNLA, 0);
1943         allqueue(REDRAWACTION, 0);
1944         allqueue(REDRAWIPO, 0);
1945 }
1946
1947
1948 static void select_all_keys_channels(bAction *act, short *mval, 
1949                               short *mvalo, int selectmode) {
1950         bActionChannel    *chan;
1951         float              click, x,y;
1952         int                clickmin, clickmax;
1953         int                wsize;
1954         bConstraintChannel *conchan;
1955
1956         /* This function selects all the action keys that
1957          * are in the mouse selection range defined by
1958          * the ordered pairs mval and mvalo (usually
1959          * these 2 are obtained from a border select).
1960          * If mvalo is NULL, then the selection is
1961          * treated like a one-click action, and at most
1962          * one channel is selected.
1963          */
1964
1965         /* If the action is null then abort
1966          */
1967         if (!act)
1968                 return;
1969
1970         if (selectmode == SELECT_REPLACE) {
1971                 deselect_actionchannel_keys(act, 0);
1972                 selectmode = SELECT_ADD;
1973         }
1974
1975         /* wsize is the greatest possible height (in pixels) that would be
1976          * needed to draw all of the action channels and constraint
1977          * channels.
1978          */
1979
1980         wsize =  count_action_levels(act)*(CHANNELHEIGHT+CHANNELSKIP);
1981         wsize += CHANNELHEIGHT/2;
1982         
1983     areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1984     clickmin = (int) ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1985         
1986         /* Only one click */
1987         if (mvalo == NULL) {
1988                 clickmax = clickmin;
1989         }
1990         /* Two click values (i.e., border select) */
1991         else {
1992
1993                 areamouseco_to_ipoco(G.v2d, mvalo, &x, &y);
1994                 click = ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1995                 
1996                 if ( ((int) click) < clickmin) {
1997                         clickmax = clickmin;
1998                         clickmin = (int) click;
1999                 }
2000                 else {
2001                         clickmax = (int) click;
2002                 }
2003         }
2004
2005         if (clickmax < 0) {
2006                 return;
2007         }
2008
2009         for (chan = act->chanbase.first; chan; chan=chan->next){
2010                 if((chan->flag & ACHAN_HIDDEN)==0) {
2011                         if (clickmax < 0) break;
2012
2013                         if ( clickmin <= 0) {
2014                                 /* Select the channel with the given mode. If the
2015                                  * channel is freshly selected then set it to the
2016                                  * active channel for the action
2017                                  */
2018                                 select_ipo_bezier_keys(chan->ipo, selectmode);
2019                         }
2020                         --clickmin;
2021                         --clickmax;
2022
2023                         /* Check for click in a constraint */
2024                         for (conchan=chan->constraintChannels.first; 
2025                                  conchan; conchan=conchan->next){
2026                                 if (clickmax < 0) break;
2027                                 if ( clickmin <= 0) {
2028                                         select_ipo_bezier_keys(chan->ipo, selectmode);
2029                                 }
2030                                 --clickmin;
2031                                 --clickmax;
2032                         }
2033                 }
2034         }
2035   
2036         allqueue (REDRAWIPO, 0);
2037         allqueue (REDRAWVIEW3D, 0);
2038         allqueue (REDRAWACTION, 0);
2039         allqueue (REDRAWNLA, 0);
2040   
2041 }
2042
2043 static void borderselect_function(void (*select_func)(bAction *act, 
2044                                                      short *mval, 
2045                                                      short *mvalo, 
2046                                                      int selectmode)) {
2047         /* This function executes an arbitrary selection
2048          * function as part of a border select. This
2049          * way the same function that is used for
2050          * right click selection points can generally
2051          * be used as the argument to this function
2052          */
2053         rcti rect;
2054         short   mval[2], mvalo[2];
2055         bAction *act;
2056         int val;                
2057
2058         /* Get the selected action, exit if none are selected 
2059          */
2060         act=G.saction->action;
2061         if (!act)
2062                 return;
2063
2064         /* Let the user draw a border (or abort)
2065          */
2066         if ( (val=get_border (&rect, 3)) ) {
2067                 mval[0]= rect.xmin;
2068                 mval[1]= rect.ymin+2;
2069                 mvalo[0]= rect.xmax;
2070                 mvalo[1]= rect.ymax-2;
2071
2072                 /* if the left mouse was used, do an additive
2073                  * selection with the user defined selection
2074                  * function.
2075                  */
2076                 if (val == LEFTMOUSE)
2077                         select_func(act, mval, mvalo, SELECT_ADD);
2078                 
2079                 /* if the right mouse was used, do a subtractive
2080                  * selection with the user defined selection
2081                  * function.
2082                  */
2083                 else if (val == RIGHTMOUSE)
2084                         select_func(act, mval, mvalo, SELECT_SUBTRACT);
2085         }
2086         BIF_undo_push("Border select Action");
2087         
2088 }
2089
2090 static void clever_keyblock_names(Key *key, short* mval){
2091     int        but=0, i, keynum;
2092     char       str[64];
2093         float      x;
2094         KeyBlock   *kb;
2095         /* get the keynum cooresponding to the y value
2096          * of the mouse pointer, return if this is
2097          * an invalid key number (and we don't deal
2098          * with the speed ipo).
2099          */
2100
2101     keynum = get_nearest_key_num(key, mval, &x);
2102     if ( (keynum < 1) || (keynum >= key->totkey) )
2103         return;
2104
2105         kb= key->block.first;
2106         for (i=0; i<keynum; ++i) kb = kb->next; 
2107
2108         if (kb->name[0] == '\0') {
2109                 sprintf(str, "Key %d", keynum);
2110         }
2111         else {
2112                 strcpy(str, kb->name);
2113         }
2114
2115         if ( (kb->slidermin >= kb->slidermax) ) {
2116                 kb->slidermin = 0.0;
2117                 kb->slidermax = 1.0;
2118         }
2119
2120     add_numbut(but++, TEX, "KB: ", 0, 24, str, 
2121                "Does this really need a tool tip?");
2122         add_numbut(but++, NUM|FLO, "Slider Min:", 
2123                            -10000, kb->slidermax, &kb->slidermin, 0);
2124         add_numbut(but++, NUM|FLO, "Slider Max:", 
2125                            kb->slidermin, 10000, &kb->slidermax, 0);
2126
2127     if (do_clever_numbuts(str, but, REDRAW)) {
2128                 strcpy(kb->name, str);
2129         allqueue (REDRAWACTION, 0);
2130                 allspace(REMAKEIPO, 0);
2131         allqueue (REDRAWIPO, 0);
2132         }
2133
2134         
2135 }
2136
2137 static void numbuts_action(void)
2138 {
2139         /* now called from action window event loop, plus reacts on mouseclick */
2140         /* removed Hos grunts for that reason! :) (ton) */
2141     Key *key;
2142     short mval[2];
2143
2144     if ( (key = get_action_mesh_key()) ) {
2145         getmouseco_areawin (mval);
2146                 if (mval[0]<NAMEWIDTH) {
2147                         clever_keyblock_names(key, mval);
2148                 }
2149     }
2150 }
2151
2152 void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
2153 {
2154         extern void do_actionbuts(unsigned short event); // drawaction.c
2155         SpaceAction *saction;
2156         bAction *act;
2157         Key *key;
2158         float dx,dy;
2159         int doredraw= 0;
2160         int     cfra;
2161         short   mval[2];
2162         unsigned short event= evt->event;
2163         short val= evt->val;
2164         short mousebut = L_MOUSE;
2165
2166         if(curarea->win==0) return;
2167
2168         saction= curarea->spacedata.first;
2169         if (!saction)
2170                 return;
2171
2172         act=saction->action;
2173         if(val) {
2174                 
2175                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
2176                 
2177                 /* swap mouse buttons based on user preference */
2178                 if (U.flag & USER_LMOUSESELECT) {
2179                         if (event == LEFTMOUSE) {
2180                                 event = RIGHTMOUSE;
2181                                 mousebut = L_MOUSE;
2182                         } else if (event == RIGHTMOUSE) {
2183                                 event = LEFTMOUSE;
2184                                 mousebut = R_MOUSE;
2185                         }
2186                 }
2187                 
2188                 getmouseco_areawin(mval);
2189
2190                 key = get_action_mesh_key();
2191
2192                 switch(event) {
2193                 case UI_BUT_EVENT:
2194                         do_actionbuts(val);     // window itself
2195                         break;
2196                 
2197                 case HOMEKEY:
2198                         do_action_buttons(B_ACTHOME);   // header
2199                         break;
2200
2201                 case AKEY:
2202                         if (key) {
2203                                 if (mval[0]<ACTWIDTH){
2204                                         /* to do ??? */
2205                                 }
2206                                 else{
2207                                         deselect_meshchannel_keys(key, 1);
2208                                         allqueue (REDRAWACTION, 0);
2209                                         allqueue(REDRAWNLA, 0);
2210                                         allqueue (REDRAWIPO, 0);
2211                                 }
2212                         }
2213                         else {
2214                                 if (mval[0]<NAMEWIDTH){
2215                                         deselect_actionchannels (act, 1);
2216                                         allqueue (REDRAWVIEW3D, 0);
2217                                         allqueue (REDRAWACTION, 0);
2218                                         allqueue(REDRAWNLA, 0);
2219                                         allqueue (REDRAWIPO, 0);
2220                                 }
2221                                 else if (mval[0]>ACTWIDTH){
2222                                         deselect_actionchannel_keys (act, 1);
2223                                         allqueue (REDRAWACTION, 0);
2224                                         allqueue(REDRAWNLA, 0);
2225                                         allqueue (REDRAWIPO, 0);
2226                                 }
2227                         }
2228                         break;
2229
2230                 case BKEY:
2231                         if (key) {
2232                                 if (mval[0]<ACTWIDTH){
2233                                         /* to do?? */
2234                                 }
2235                                 else {
2236                                         borderselect_mesh(key);
2237                                 }
2238                         }
2239                         else {
2240
2241                                 /* If the border select is initiated in the
2242                                  * part of the action window where the channel
2243                                  * names reside, then select the channels
2244                                  */
2245                                 if (mval[0]<NAMEWIDTH){
2246                                         borderselect_function(mouse_actionchannels);
2247                                         BIF_undo_push("Select Action");
2248                                 }
2249                                 else if (mval[0]>ACTWIDTH){
2250
2251                                         /* If the border select is initiated in the
2252                                          * vertical scrollbar, then (de)select all keys
2253                                          * for the channels in the selection region
2254                                          */
2255                                         if (IN_2D_VERT_SCROLL(mval)) {
2256                                                 borderselect_function(select_all_keys_channels);
2257                                         }
2258
2259                                         /* If the border select is initiated in the
2260                                          * horizontal scrollbar, then (de)select all keys
2261                                          * for the keyframes in the selection region
2262                                          */
2263                                         else if (IN_2D_HORIZ_SCROLL(mval)) {
2264                                                 borderselect_function(select_all_keys_frames);
2265                                         }
2266
2267                                         /* Other wise, select the action keys
2268                                          */
2269                                         else {
2270                                                 borderselect_action();
2271                                         }
2272                                 }
2273                         }
2274                         break;
2275
2276                 case CKEY:
2277                         /* scroll the window so the current
2278                          * frame is in the center.
2279                          */
2280                         center_currframe();
2281                         break;
2282
2283                 case DKEY:
2284                         if (key) {
2285                                 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH) {
2286                                         duplicate_meshchannel_keys(key);
2287                                 }
2288                         }
2289                         else if (act) {
2290                                 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
2291                                         duplicate_actionchannel_keys();
2292                                         remake_action_ipos(act);
2293                                 }
2294                         }
2295                         break;
2296
2297                 case GKEY:
2298                         if (mval[0]>=ACTWIDTH) {
2299                                 if (key) {
2300                                         transform_meshchannel_keys('g', key);
2301                                 }
2302                                 else if (act) {
2303                                         transform_actionchannel_keys ('g', 0);
2304                                 }
2305                         }
2306                         break;
2307
2308                 case HKEY:
2309                         if(G.qual & LR_SHIFTKEY) {
2310                                 if(okee("Set Keys to Auto Handle")) {
2311                                         if (key)
2312                                                 sethandles_meshchannel_keys(HD_AUTO, key);
2313                                         else
2314                                                 sethandles_actionchannel_keys(HD_AUTO);
2315                                 }
2316                         }
2317                         else {
2318                                 if(okee("Toggle Keys Aligned Handle")) {
2319                                         if (key)
2320                                                 sethandles_meshchannel_keys(HD_ALIGN, key);
2321                                         else
2322                                                 sethandles_actionchannel_keys(HD_ALIGN);
2323                                 }
2324                         }
2325                         break;
2326                         
2327                 case NKEY:
2328                         if(G.qual==0) {
2329                                 numbuts_action();
2330                                 
2331                                 /* no panel (yet). current numbuts are not easy to put in panel... */
2332                                 //add_blockhandler(curarea, ACTION_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
2333                                 //scrarea_queue_winredraw(curarea);
2334                         }
2335                         break;
2336                         
2337                 case SKEY: 
2338                         if (mval[0]>=ACTWIDTH) {
2339                                 if(G.qual & LR_SHIFTKEY) {
2340                                         if(okee("Snap to frame"))
2341                                                 set_snap_actionchannels();
2342                                 }
2343                                 else {
2344                                         if (key)
2345                                                 transform_meshchannel_keys('s', key);
2346                                         else if (act)
2347                                                 transform_actionchannel_keys ('s', 0);
2348                                 }
2349                         }
2350                         break;
2351
2352                         /*** set the Ipo type  ***/
2353                 case TKEY:
2354                         if (key) {
2355                                 /* to do */
2356                         }
2357                         else {
2358                                 if(G.qual & LR_SHIFTKEY)
2359                                         set_ipotype_actionchannels(SET_IPO_POPUP);
2360                                 else
2361                                         transform_actionchannel_keys ('t', 0);
2362                         }
2363                         break;
2364
2365                 case VKEY:
2366                         if(okee("Set Keys to Vector Handle")) {
2367                                 if (key)
2368                                         sethandles_meshchannel_keys(HD_VECT, key);
2369                                 else
2370                                         sethandles_actionchannel_keys(HD_VECT);
2371                         }
2372                         break;
2373
2374                 case PAGEUPKEY:
2375                         if (key) {
2376                                 /* to do */
2377                         }
2378                         else {
2379                                 if(G.qual & LR_SHIFTKEY) {
2380                                         top_sel_action();
2381                                 }
2382                                 else
2383                                 {
2384                                         up_sel_action();
2385                                 }
2386                                 
2387                         }
2388                         break;
2389                 case PAGEDOWNKEY:
2390                         if (key) {
2391                                 /* to do */
2392                         }
2393                         else {
2394                                 if(G.qual & LR_SHIFTKEY) {
2395                                         bottom_sel_action();
2396                                 }
2397                                 else
2398                                 down_sel_action();
2399                                 
2400                         }
2401                         break;
2402                 case DELKEY:
2403                 case XKEY:
2404                         if (key) {
2405                                 delete_meshchannel_keys(key);
2406                         }
2407                         else {
2408                                 if (mval[0]<NAMEWIDTH)
2409                                         delete_actionchannels ();
2410                                 else
2411                                         delete_actionchannel_keys ();
2412                         }
2413                         break;
2414                 /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
2415                  * based on user preference USER_LMOUSESELECT
2416                  */
2417                 case LEFTMOUSE:
2418                         if(view2dmove(LEFTMOUSE)) // only checks for sliders
2419                                 break;
2420                         else if (mval[0]>ACTWIDTH){
2421                                 do {
2422                                         getmouseco_areawin(mval);
2423                                         
2424                                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
2425                                         
2426                                         cfra= (int)dx;
2427                                         if(cfra< 1) cfra= 1;
2428                                         
2429                                         if( cfra!=CFRA ) {
2430                                                 CFRA= cfra;
2431                                                 update_for_newframe();
2432                                                 force_draw_all(0);                                      }
2433                                         else PIL_sleep_ms(30);
2434                                         
2435                                 } while(get_mbut() & mousebut);
2436                                 break;
2437                         }
2438                         /* passed on as selection */
2439                 case RIGHTMOUSE:
2440                         /* Clicking in the channel area selects the
2441                          * channel or constraint channel
2442                          */
2443                         if (mval[0]<NAMEWIDTH) {
2444                                 if(act) {
2445                                         if(G.qual & LR_SHIFTKEY)
2446                                                 mouse_actionchannels(act, mval, NULL,  SELECT_INVERT);
2447                                         else
2448                                                 mouse_actionchannels(act, mval, NULL,  SELECT_REPLACE);
2449                                         
2450                                         BIF_undo_push("Select Action");
2451                                 }
2452                                 else numbuts_action();
2453                         }
2454                         else if (mval[0]>ACTWIDTH) {
2455                 
2456                                 /* Clicking in the vertical scrollbar selects
2457                                  * all of the keys for that channel at that height
2458                                  */
2459                                 if (IN_2D_VERT_SCROLL(mval)) {
2460                                         if(G.qual & LR_SHIFTKEY)
2461                                                 select_all_keys_channels(act, mval, NULL, 
2462                                                                                                  SELECT_INVERT);
2463                                         else
2464                                                 select_all_keys_channels(act, mval, NULL, 
2465                                                                                                  SELECT_REPLACE);
2466                                 }
2467                 
2468                                 /* Clicking in the horizontal scrollbar selects
2469                                  * all of the keys within 0.5 of the nearest integer
2470                                  * frame
2471                                  */
2472                                 else if (IN_2D_HORIZ_SCROLL(mval)) {
2473                                         if(G.qual & LR_SHIFTKEY)
2474                                                 select_all_keys_frames(act, mval, NULL, 
2475                                                                                            SELECT_INVERT);
2476                                         else
2477                                                 select_all_keys_frames(act, mval, NULL, 
2478                                                                                            SELECT_REPLACE);
2479                                         BIF_undo_push("Select all Action");
2480                                 }
2481                                 
2482                                 /* Clicking in the main area of the action window
2483                                  * selects keys
2484                                  */
2485                                 else {
2486                                         if (key) {
2487                                                 if(G.qual & LR_SHIFTKEY)
2488                                                         mouse_mesh_action(SELECT_INVERT, key);
2489                                                 else
2490                                                         mouse_mesh_action(SELECT_REPLACE, key);
2491                                         }
2492                                         else {
2493                                                 if(G.qual & LR_SHIFTKEY)
2494                                                         mouse_action(SELECT_INVERT);
2495                                                 else
2496                                                         mouse_action(SELECT_REPLACE);
2497                                         }
2498                                 }
2499                         }
2500                         break;
2501                 case PADPLUSKEY:
2502                         view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
2503                         test_view2d(G.v2d, sa->winx, sa->winy);
2504                         view2d_do_locks(curarea, V2D_LOCK_COPY);
2505
2506                         doredraw= 1;
2507                         break;
2508                 case PADMINUS:
2509                         view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
2510                         test_view2d(G.v2d, sa->winx, sa->winy);
2511                         view2d_do_locks(curarea, V2D_LOCK_COPY);
2512                         
2513                         doredraw= 1;
2514                         break;
2515                 case MIDDLEMOUSE:
2516                 case WHEELUPMOUSE:
2517                 case WHEELDOWNMOUSE:
2518                         view2dmove(event);      /* in drawipo.c */
2519                         break;
2520                 }
2521         }
2522
2523         if(doredraw) addqueue(curarea->win, REDRAW, 1);
2524         
2525 }
2526
2527 Key *get_action_mesh_key(void) 
2528 {
2529         /* gets the key data from the currently selected
2530          * mesh/lattice. If a mesh is not selected, or does not have
2531          * key data, then we return NULL (currently only
2532          * returns key data for RVK type meshes). If there
2533          * is an action that is pinned, return null
2534          */
2535     Object *ob;
2536     Key    *key;
2537
2538     ob = OBACT;
2539     if (!ob) return NULL;
2540
2541         if (G.saction->pin) return NULL;
2542
2543     if (ob->type==OB_MESH ) {
2544                 key = ((Mesh *)ob->data)->key;
2545     }
2546         else if (ob->type==OB_LATTICE ) {
2547                 key = ((Lattice *)ob->data)->key;
2548         }
2549         else return NULL;
2550
2551         if (key) {
2552                 if (key->type == KEY_RELATIVE)
2553                         return key;
2554         }
2555
2556     return NULL;
2557 }
2558
2559 int get_nearest_key_num(Key *key, short *mval, float *x) {
2560         /* returns the key num that cooresponds to the
2561          * y value of the mouse click. Does not check
2562          * if this is a valid keynum. Also gives the Ipo
2563          * x coordinate.
2564          */
2565     int num;
2566     float ybase, y;
2567
2568     areamouseco_to_ipoco(G.v2d, mval, x, &y);
2569
2570     ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
2571     num = (int) ((ybase - y + CHANNELHEIGHT/2) / (CHANNELHEIGHT+CHANNELSKIP));
2572
2573     return (num + 1);
2574 }
2575
2576
2577
2578 void top_sel_action()
2579 {
2580         bAction *act;
2581         bActionChannel *chan;
2582         
2583         /* Get the selected action, exit if none are selected */
2584         act = G.saction->action;
2585         if (!act) return;
2586         
2587         for (chan=act->chanbase.first; chan; chan=chan->next){
2588                 if((chan->flag & ACHAN_HIDDEN)==0) {
2589                         if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2590                                 /* take it out off the chain keep data */
2591                                 BLI_remlink (&act->chanbase, chan);
2592                                 /* make it first element */
2593                                 BLI_insertlinkbefore(&act->chanbase,act->chanbase.first, chan);
2594                                 chan->flag |= ACHAN_MOVED;
2595                                 /* restart with rest of list */
2596                                 chan=chan->next;
2597                         }
2598                 }
2599         }
2600     /* clear temp flags */
2601         for (chan=act->chanbase.first; chan; chan=chan->next){
2602                 chan->flag = chan->flag & ~ACHAN_MOVED;
2603         }
2604         
2605         /* Clean up and redraw stuff */
2606         remake_action_ipos (act);
2607         BIF_undo_push("Top Action channel");
2608         allspace(REMAKEIPO, 0);
2609         allqueue(REDRAWACTION, 0);
2610         allqueue(REDRAWIPO, 0);
2611         allqueue(REDRAWNLA, 0);
2612 }
2613
2614 void up_sel_action()
2615 {
2616         bAction *act;
2617         bActionChannel *chan;
2618         bActionChannel *prev;
2619         
2620         /* Get the selected action, exit if none are selected */
2621         act = G.saction->action;
2622         if (!act) return;
2623         
2624         for (chan=act->chanbase.first; chan; chan=chan->next){
2625                 if((chan->flag & ACHAN_HIDDEN)==0) {
2626                         if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2627                                 prev = chan->prev;
2628                                 if (prev){
2629                                         /* take it out off the chain keep data */
2630                                         BLI_remlink (&act->chanbase, chan);
2631                                         /* push it up */
2632                                         BLI_insertlinkbefore(&act->chanbase,prev, chan);
2633                                         chan->flag |= ACHAN_MOVED;
2634                                         /* restart with rest of list */
2635                                         chan=chan->next;
2636                                 }
2637                         }
2638                 }
2639         }
2640         /* clear temp flags */
2641         for (chan=act->chanbase.first; chan; chan=chan->next){
2642                 chan->flag = chan->flag & ~ACHAN_MOVED;
2643         }
2644         
2645         /* Clean up and redraw stuff
2646         */
2647         remake_action_ipos (act);
2648         BIF_undo_push("Up Action channel");
2649         allspace(REMAKEIPO, 0);
2650         allqueue(REDRAWACTION, 0);
2651         allqueue(REDRAWIPO, 0);
2652         allqueue(REDRAWNLA, 0);
2653 }
2654
2655 void down_sel_action()
2656 {
2657         bAction *act;
2658         bActionChannel *chan;
2659         bActionChannel *next;
2660         
2661         /* Get the selected action, exit if none are selected */
2662         act = G.saction->action;
2663         if (!act) return;
2664         
2665         for (chan=act->chanbase.last; chan; chan=chan->prev){
2666                 if((chan->flag & ACHAN_HIDDEN)==0) {
2667                         if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2668                                 next = chan->next;
2669                                 if (next) next = next->next;
2670                                 if (next){
2671                                         /* take it out off the chain keep data */
2672                                         BLI_remlink (&act->chanbase, chan);
2673                                         /* move it down */
2674                                         BLI_insertlinkbefore(&act->chanbase,next, chan);
2675                                         chan->flag |= ACHAN_MOVED;
2676                                 }
2677                                 else {
2678                                         /* take it out off the chain keep data */
2679                                         BLI_remlink (&act->chanbase, chan);
2680                                         /* add at end */
2681                                         BLI_addtail(&act->chanbase,chan);
2682                                         chan->flag |= ACHAN_MOVED;
2683                                 }
2684                         }
2685                 }
2686         }
2687         /* clear temp flags */
2688         for (chan=act->chanbase.first; chan; chan=chan->next){
2689                 chan->flag = chan->flag & ~ACHAN_MOVED;
2690         }
2691         
2692         /* Clean up and redraw stuff
2693         */
2694         remake_action_ipos (act);
2695         BIF_undo_push("Down Action channel");
2696         allspace(REMAKEIPO, 0);
2697         allqueue(REDRAWACTION, 0);
2698         allqueue(REDRAWIPO, 0);
2699         allqueue(REDRAWNLA, 0);
2700 }
2701
2702 void bottom_sel_action()
2703 {
2704         bAction *act;
2705         bActionChannel *chan;
2706         
2707         /* Get the selected action, exit if none are selected */
2708         act = G.saction->action;
2709         if (!act) return;
2710         
2711         for (chan=act->chanbase.last; chan; chan=chan->prev){
2712                 if((chan->flag & ACHAN_HIDDEN)==0) {
2713                         if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)) {
2714                                 /* take it out off the chain keep data */
2715                                 BLI_remlink (&act->chanbase, chan);
2716                                 /* add at end */
2717                                 BLI_addtail(&act->chanbase,chan);
2718                                 chan->flag |= ACHAN_MOVED;
2719                         }
2720                 }               
2721         }
2722         /* clear temp flags */
2723         for (chan=act->chanbase.first; chan; chan=chan->next){
2724                 chan->flag = chan->flag & ~ACHAN_MOVED;
2725         }
2726         
2727         /* Clean up and redraw stuff
2728         */
2729         remake_action_ipos (act);
2730         BIF_undo_push("Bottom Action channel");
2731         allspace(REMAKEIPO, 0);
2732         allqueue(REDRAWACTION, 0);
2733         allqueue(REDRAWIPO, 0);
2734         allqueue(REDRAWNLA, 0);
2735 }
2736
2737 void world2bonespace(float boneSpaceMat[][4], float worldSpace[][4], float restPos[][4], float armPos[][4])
2738 {
2739         float imatarm[4][4], imatbone[4][4], tmat[4][4], t2mat[4][4];
2740         
2741         Mat4Invert(imatarm, armPos);
2742         Mat4Invert(imatbone, restPos);
2743         Mat4MulMat4(tmat, imatarm, worldSpace);
2744         Mat4MulMat4(t2mat, tmat, imatbone);
2745         Mat4MulMat4(boneSpaceMat, restPos, t2mat);
2746 }
2747
2748
2749 bAction* bake_obIPO_to_action (Object *ob)
2750 {
2751         bArmature               *arm;
2752         bAction                 *result=NULL;
2753         bActionChannel  *achan;
2754         bAction                 *temp;
2755         bPoseChannel    *pchan;
2756         Bone                    *bone;
2757         ID                              *id;
2758         ListBase                elems;
2759         float                   actstart, actend;
2760         int                     oldframe,testframe;
2761         int                     curframe;
2762         char                    newname[64];
2763         float                   quat[4],tmat[4][4],startpos[4][4],imat[4][4],mat3[3][3];
2764         CfraElem                *firstcfra, *lastcfra;
2765         
2766         arm = get_armature(ob);
2767         
2768         if (arm) {      
2769         
2770                 oldframe = CFRA;
2771                 result = add_empty_action(ID_PO);
2772                 id = (ID *)ob;
2773                 
2774                 sprintf (newname, "TESTOBBAKE");
2775                 rename_id(&result->id, newname);
2776                 
2777                 if(ob!=G.obedit) { // make sure object is not in edit mode
2778                         if(ob->ipo) {
2779                                 /* convert the ipo to a list of 'current frame elements' */
2780                                 
2781                                 temp = ob->action;
2782                                 ob->action = result;
2783                                 
2784                                 elems.first= elems.last= NULL;
2785                                 make_cfra_list(ob->ipo, &elems);
2786                                 /* set the beginning armature location */
2787                                 firstcfra=elems.first;
2788                                 lastcfra=elems.last;
2789                                 CFRA=firstcfra->cfra;
2790                                 
2791                                 where_is_object(ob);
2792                                 Mat4CpyMat4(startpos,ob->obmat);
2793                                 
2794                                 /* loop from first key to last, sampling every 10 */
2795                                 for (testframe = firstcfra->cfra; testframe<=lastcfra->cfra; testframe=testframe+10) { 
2796                                         CFRA=testframe;
2797                                         where_is_object(ob);
2798
2799                                         for (bone = arm->bonebase.first; bone; bone=bone->next) {
2800                                                 if (!bone->parent) { /* this is a root bone, so give it a key! */
2801                                                         world2bonespace(tmat,ob->obmat,bone->arm_mat,startpos);
2802                                                         Mat4ToQuat(tmat,quat);
2803                                                         printf("Frame: %i %f, %f, %f, %f\n",CFRA,quat[0],quat[1],quat[2],quat[3]);
2804                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_X,tmat[3][0]);
2805                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_Y,tmat[3][1]);
2806                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_Z,tmat[3][2]);
2807                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_X,quat[1]);
2808                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_Y,quat[2]);
2809                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_Z,quat[3]);
2810                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_W,quat[0]);
2811                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_X,size[0]);
2812                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_Y,size[1]);
2813                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_Z,size[2]);
2814                                                 }
2815                                         }
2816                                 }
2817                                 BLI_freelistN(&elems);  
2818                         }
2819                 }
2820                 CFRA = oldframe;
2821         }
2822         return result;  
2823 }
2824
2825 bAction* bake_everything_to_action (Object *ob)
2826 {
2827         bArmature               *arm;
2828         bAction                 *result=NULL;
2829         bActionChannel  *achan;
2830         bAction                 *temp;
2831         bPoseChannel    *pchan;
2832         Bone                    *bone;
2833         ID                              *id;
2834         ListBase                elems;
2835         float                   actstart, actend;
2836         int                     oldframe,testframe;
2837         int                     curframe;
2838         char                    newname[64];
2839         float                   quat[4],tmat[4][4],startpos[4][4],imat[4][4],mat3[3][3];
2840         CfraElem                *firstcfra, *lastcfra;
2841         
2842         arm = get_armature(ob);
2843         
2844         if (arm) {      
2845         
2846                 oldframe = CFRA;
2847                 result = add_empty_action(ID_PO);
2848                 id = (ID *)ob;
2849                 
2850                 sprintf (newname, "TESTOBBAKE");
2851                 rename_id(&result->id, newname);
2852                 
2853                 if(ob!=G.obedit) { // make sure object is not in edit mode
2854                         if(ob->ipo) {
2855                                 /* convert the ipo to a list of 'current frame elements' */
2856                                 
2857                                 temp = ob->action;
2858                                 ob->action = result;
2859                                 
2860                                 elems.first= elems.last= NULL;
2861                                 make_cfra_list(ob->ipo, &elems);
2862                                 /* set the beginning armature location */
2863                                 firstcfra=elems.first;
2864                                 lastcfra=elems.last;
2865                                 CFRA=firstcfra->cfra;
2866                                 
2867                                 where_is_object(ob);
2868                                 Mat4CpyMat4(startpos,ob->obmat);
2869                                 
2870                                 /* loop from first key to last, sampling every 10 */
2871                                 for (testframe = firstcfra->cfra; testframe<=lastcfra->cfra; testframe=testframe+10) { 
2872                                         CFRA=testframe;
2873                                         
2874                                         do_all_pose_actions(ob);
2875                                         where_is_object(ob);
2876                                         for (bone = arm->bonebase.first; bone; bone=bone->next) {
2877                                                 if (!bone->parent) { /* this is a root bone, so give it a key! */
2878                                                         world2bonespace(tmat,ob->obmat,bone->arm_mat,startpos);
2879                                                         
2880                                                         Mat4ToQuat(tmat,quat);
2881                                                         printf("Frame: %i %f, %f, %f, %f\n",CFRA,quat[0],quat[1],quat[2],quat[3]);
2882                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_X,tmat[3][0]);
2883                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_Y,tmat[3][1]);
2884                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_LOC_Z,tmat[3][2]);
2885                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_X,quat[1]);
2886                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_Y,quat[2]);
2887                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_Z,quat[3]);
2888                                                         insertmatrixkey(id, ID_PO, bone->name, NULL, AC_QUAT_W,quat[0]);
2889                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_X,size[0]);
2890                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_Y,size[1]);
2891                                                         //insertmatrixkey(id, ID_PO, bone->name, NULL, AC_SIZE_Z,size[2]);
2892                                                 }
2893                                         }
2894                                 }
2895                                 BLI_freelistN(&elems);  
2896                         }
2897                 }
2898                 CFRA = oldframe;
2899         }
2900         return result;  
2901 }